feat: add rebuild all embeddings button for RAG initialization
This commit is contained in:
1 parent
578ea082c3
commit
6ec51104c8
2 files changed
+67
No files matched your search
@@ -17,6 +17,7 @@ import {
|
||||
getActiveWorkId,
|
||||
setActiveWorkId,
|
||||
getAllWorks,
|
||||
rebuildAllEmbeddings,
|
||||
} from '../lib/settings';
|
||||
import SettingsTree from './SettingsTree';
|
||||
import { useI18n } from '../lib/useI18n';
|
||||
@@ -486,6 +487,7 @@ function ApiConfigForm({ data, onChange }) {
|
||||
const [testStatus, setTestStatus] = useState(null);
|
||||
const [fetchedModels, setFetchedModels] = useState(null);
|
||||
const [fetchedEmbedModels, setFetchedEmbedModels] = useState(null);
|
||||
const [rebuildStatus, setRebuildStatus] = useState(null); // null | 'loading' | {done, total, failed}
|
||||
const [savedProfiles, setSavedProfiles] = useState([]);
|
||||
const [profileName, setProfileName] = useState('');
|
||||
const [showSaveInput, setShowSaveInput] = useState(false);
|
||||
@@ -557,6 +559,20 @@ function ApiConfigForm({ data, onChange }) {
|
||||
} catch { setFetchedEmbedModels(null); setTestStatus({ success: false, error: t('apiConfig.fetchEmbedModelsFailed') }); }
|
||||
};
|
||||
|
||||
const handleRebuildEmbeddings = async () => {
|
||||
setRebuildStatus({ done: 0, total: 0, failed: 0 });
|
||||
try {
|
||||
const result = await rebuildAllEmbeddings((done, total, failed) => {
|
||||
setRebuildStatus({ done, total, failed });
|
||||
});
|
||||
setRebuildStatus({ ...result, finished: true });
|
||||
setTimeout(() => setRebuildStatus(null), 5000);
|
||||
} catch {
|
||||
setRebuildStatus({ error: true });
|
||||
setTimeout(() => setRebuildStatus(null), 3000);
|
||||
}
|
||||
};
|
||||
|
||||
const currentProvider = PROVIDERS.find(p => p.key === data.provider) || PROVIDERS[7];
|
||||
const isCustom = data.provider === 'custom';
|
||||
|
||||
@@ -689,6 +705,28 @@ function ApiConfigForm({ data, onChange }) {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 重建向量按钮 */}
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<button
|
||||
style={{ padding: '8px 16px', border: '1px solid var(--accent)', borderRadius: 'var(--radius-md)', background: 'var(--bg-primary)', cursor: rebuildStatus && !rebuildStatus.finished ? 'wait' : 'pointer', fontSize: 12, color: 'var(--accent)', fontWeight: 500, opacity: rebuildStatus && !rebuildStatus.finished ? 0.7 : 1 }}
|
||||
onClick={handleRebuildEmbeddings}
|
||||
disabled={rebuildStatus && !rebuildStatus.finished && !rebuildStatus.error}
|
||||
>
|
||||
{rebuildStatus && !rebuildStatus.finished && !rebuildStatus.error
|
||||
? `向量化中... ${rebuildStatus.done}/${rebuildStatus.total}`
|
||||
: '🔄 重建所有设定向量'}
|
||||
</button>
|
||||
{rebuildStatus?.finished && (
|
||||
<span style={{ marginLeft: 8, fontSize: 11, color: rebuildStatus.failed > 0 ? 'var(--warning)' : 'var(--success)' }}>
|
||||
✓ 完成!{rebuildStatus.done - rebuildStatus.failed}/{rebuildStatus.total} 成功{rebuildStatus.failed > 0 ? `,${rebuildStatus.failed} 失败` : ''}
|
||||
</span>
|
||||
)}
|
||||
{rebuildStatus?.error && (
|
||||
<span style={{ marginLeft: 8, fontSize: 11, color: 'var(--error)' }}>重建失败</span>
|
||||
)}
|
||||
<div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>首次开启或更换嵌入模型后,需要重建向量才能使用 RAG 智能检索</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -565,6 +565,35 @@ export async function moveSettingsNode(id, newParentId) {
|
||||
return nodes[idx];
|
||||
}
|
||||
|
||||
// 重新计算所有条目的 embedding (Async)
|
||||
export async function rebuildAllEmbeddings(onProgress) {
|
||||
const nodes = await getSettingsNodes();
|
||||
const { apiConfig } = getProjectSettings();
|
||||
const items = nodes.filter(n => n.type === 'item');
|
||||
let done = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const item of items) {
|
||||
try {
|
||||
const textToEmbed = extractTextForEmbedding(item);
|
||||
const embedding = await getEmbedding(textToEmbed, apiConfig);
|
||||
const idx = nodes.findIndex(n => n.id === item.id);
|
||||
if (idx !== -1 && embedding) {
|
||||
nodes[idx].embedding = embedding;
|
||||
} else if (!embedding) {
|
||||
failed++;
|
||||
}
|
||||
} catch {
|
||||
failed++;
|
||||
}
|
||||
done++;
|
||||
onProgress?.(done, items.length, failed);
|
||||
}
|
||||
|
||||
await saveSettingsNodes(nodes);
|
||||
return { total: items.length, done, failed };
|
||||
}
|
||||
|
||||
// 获取指定分类下的所有 item 节点(递归) (Async)
|
||||
export async function getItemsByCategory(category) {
|
||||
const nodes = await getSettingsNodes();
|
||||
|
||||
Reference in new issue
Block a user