Import source: app/src/pages/RagCalculatorPage

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:25:33 +03:30
parent 05a87c4abb
commit a2478dff34
+129
View File
@@ -0,0 +1,129 @@
import { useState } from 'react';
import { useNav, useToast } from '../../teknav-ui.jsx';
import { LegalPage } from './shared.jsx';
export function RagCalculatorPage() {
const { navigate } = useNav();
const toast = useToast();
const [text, setText] = useState('');
const [chunkSize, setChunkSize] = useState(500);
const [overlap, setOverlap] = useState(50);
const [chunks, setChunks] = useState([]);
const handleCalculate = () => {
if (!text.trim()) {
toast('لطفاً ابتدا متنی را برای چانک‌بندی وارد کنید', 'error');
return;
}
if (chunkSize <= 0 || overlap < 0 || overlap >= chunkSize) {
toast('اندازه چانک یا همپوشانی نامعتبر است', 'error');
return;
}
const t = text.trim();
const result = [];
let start = 0;
while (start < t.length) {
let end = start + chunkSize;
if (end > t.length) end = t.length;
const content = t.substring(start, end);
const estimatedTokens = Math.round(content.length / 3.8);
result.push({
id: result.length + 1,
content,
charCount: content.length,
tokenCount: estimatedTokens,
range: [start, end],
});
start += (chunkSize - overlap);
if (start >= t.length || end === t.length) break;
}
setChunks(result);
toast(`تکه‌بندی با موفقیت انجام شد (${result.length} چانک)`, 'success');
};
const copyToClipboard = (val) => {
if (!val) return;
navigator.clipboard.writeText(val);
toast('کپی شد!', 'success');
};
return (
<LegalPage title="محاسبه‌گر چانک و زمینه RAG" subtitle="شبیه‌سازی اندازه تکه‌ها (Chunks)، همپوشانی (Overlap) و تخمین توکن برای سیستم‌های پرسش و پاسخ با بازیابی اطلاعات.">
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
<div>
<label style={{ fontSize: 13, fontWeight: 700, color: '#0F2A2E', display: 'block', marginBottom: 8 }}>متن نمونه:</label>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="متن فارسی مورد نظر برای شبیه‌سازی RAG را در این قسمت بنویسید..."
style={{ width: '100%', minHeight: 140, background: '#FAF7F0', border: '1px solid #D8D0C4', borderRadius: 8, padding: '12px 16px', fontSize: 14, fontFamily: 'Vazirmatn, sans-serif', color: '#263238', outline: 'none', lineHeight: 1.7, resize: 'vertical', boxSizing: 'border-box' }}
/>
</div>
<div style={{ background: '#FAF7F0', border: '1px solid #E4DDD2', borderRadius: 10, padding: 18 }}>
<h3 style={{ fontSize: 14, fontWeight: 800, color: '#0F2A2E', marginBottom: 12 }}>پارامترهای شبیه‌سازی</h3>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
<div>
<label style={{ fontSize: 12, color: '#5F6B6D', display: 'block', marginBottom: 5 }}>اندازه هر تکه (به کاراکتر):</label>
<input type="number" value={chunkSize} onChange={(e) => setChunkSize(Number(e.target.value))} style={{ width: '100%', padding: '10px 12px', border: '1px solid #D8D0C4', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn, sans-serif' }} />
</div>
<div>
<label style={{ fontSize: 12, color: '#5F6B6D', display: 'block', marginBottom: 5 }}>اندازه همپوشانی (Overlap):</label>
<input type="number" value={overlap} onChange={(e) => setOverlap(Number(e.target.value))} style={{ width: '100%', padding: '10px 12px', border: '1px solid #D8D0C4', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn, sans-serif' }} />
</div>
</div>
</div>
<div style={{ display: 'flex', gap: 12 }}>
<button onClick={handleCalculate} style={{ background: '#0F6B73', color: '#fff', border: 'none', borderRadius: 8, padding: '12px 28px', fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
محاسبه و شبیه‌سازی
</button>
<button onClick={() => navigate('/tools')} style={{ background: 'transparent', color: '#5F6B6D', border: '1px solid #D8D0C4', borderRadius: 8, padding: '12px 20px', fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
بازگشت
</button>
</div>
{chunks.length > 0 && (
<div style={{ marginTop: 10 }}>
<h3 style={{ fontSize: 15, fontWeight: 800, color: '#0F2A2E', marginBottom: 12 }}>نتایج شبیه‌سازی تکه‌بندی:</h3>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 20 }}>
{[
['طول کل کاراکترها', text.length],
['تعداد تخمینی توکن‌ها', Math.round(text.length / 3.8)],
['تعداد چانک‌های خروجی', chunks.length],
].map(([lbl, val]) => (
<div key={lbl} style={{ background: '#FAF7F0', border: '1px solid #E4DDD2', borderRadius: 8, padding: 12, textAlign: 'center' }}>
<div style={{ fontSize: 11, color: '#5F6B6D', marginBottom: 4 }}>{lbl}</div>
<div style={{ fontSize: 16, fontWeight: 800, color: '#0F2A2E' }}>{val.toLocaleString('fa-IR')}</div>
</div>
))}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
{chunks.map((c) => (
<div key={c.id} style={{ border: '1px solid #E4DDD2', borderRadius: 10, overflow: 'hidden' }}>
<div style={{ background: '#FAF7F0', borderBottom: '1px solid #E4DDD2', padding: '10px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontSize: 12, fontWeight: 800, color: '#0F2A2E' }}>چانک #{c.id.toLocaleString('fa-IR')} (اندیس {c.range[0].toLocaleString('fa-IR')} تا {c.range[1].toLocaleString('fa-IR')})</span>
<div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
<span style={{ fontSize: 11, color: '#5F6B6D' }}>{c.charCount.toLocaleString('fa-IR')} کاراکتر · {c.tokenCount.toLocaleString('fa-IR')} توکن تخمینی</span>
<button onClick={() => copyToClipboard(c.content)} style={{ background: '#fff', border: '1px solid #D8D0C4', borderRadius: 4, padding: '3px 8px', fontSize: 11, cursor: 'pointer', fontFamily: 'Vazirmatn, sans-serif' }}>کپی</button>
</div>
</div>
<div style={{ padding: 16, fontSize: 13, lineHeight: 1.8, color: '#263238', background: '#fff', whiteSpace: 'pre-wrap' }}>
{c.content}
</div>
</div>
))}
</div>
</div>
)}
</div>
</LegalPage>
);
}