Add vector IO and text filtering
This commit is contained in:
@@ -102,6 +102,11 @@
|
||||
}
|
||||
};
|
||||
|
||||
const DEFAULT_FILTER_RULES = [
|
||||
{ start: '<think>', end: '</think>' },
|
||||
{ start: '<thinking>', end: '</thinking>' },
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// State
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -199,7 +204,7 @@
|
||||
if (opt.value) modelCache.push(opt.value);
|
||||
}
|
||||
}
|
||||
return {
|
||||
const result = {
|
||||
enabled: safeVal('vector-enabled', false),
|
||||
engine: safeRadio('vector-engine', 'online'),
|
||||
local: { modelId: safeVal('local-model-select', 'bge-small-zh') },
|
||||
@@ -211,6 +216,10 @@
|
||||
modelCache
|
||||
}
|
||||
};
|
||||
|
||||
// 收集过滤规则
|
||||
result.textFilterRules = collectFilterRules();
|
||||
return result;
|
||||
}
|
||||
|
||||
function loadVectorConfig(cfg) {
|
||||
@@ -240,6 +249,9 @@
|
||||
}
|
||||
if (cfg.online.model) $('vector-model-select').value = cfg.online.model;
|
||||
}
|
||||
|
||||
// 加载过滤规则
|
||||
renderFilterRules(cfg?.textFilterRules || DEFAULT_FILTER_RULES);
|
||||
}
|
||||
|
||||
function updateLocalModelDesc(modelId) {
|
||||
@@ -278,6 +290,67 @@
|
||||
if (guideBtn) guideBtn.onclick = e => { e.preventDefault(); openHfGuide(); };
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Filter Rules UI
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
function renderFilterRules(rules) {
|
||||
const list = $('filter-rules-list');
|
||||
if (!list) return;
|
||||
|
||||
const items = rules?.length ? rules : [];
|
||||
|
||||
setHtml(list, items.map((r, i) => `
|
||||
<div class="filter-rule-item" data-idx="${i}" style="display:flex;gap:6px;align-items:center">
|
||||
<input type="text" class="filter-rule-start" placeholder="起始(可空)" value="${h(r.start || '')}" style="flex:1;padding:6px 8px;font-size:.8125rem">
|
||||
<span style="color:var(--txt3)">→</span>
|
||||
<input type="text" class="filter-rule-end" placeholder="结束(可空)" value="${h(r.end || '')}" style="flex:1;padding:6px 8px;font-size:.8125rem">
|
||||
<button class="btn btn-sm btn-del filter-rule-del" style="padding:4px 8px">✕</button>
|
||||
</div>
|
||||
`).join(''));
|
||||
|
||||
// 绑定删除
|
||||
list.querySelectorAll('.filter-rule-del').forEach(btn => {
|
||||
btn.onclick = () => {
|
||||
btn.closest('.filter-rule-item')?.remove();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function collectFilterRules() {
|
||||
const list = $('filter-rules-list');
|
||||
if (!list) return [];
|
||||
|
||||
const rules = [];
|
||||
list.querySelectorAll('.filter-rule-item').forEach(item => {
|
||||
const start = item.querySelector('.filter-rule-start')?.value?.trim() || '';
|
||||
const end = item.querySelector('.filter-rule-end')?.value?.trim() || '';
|
||||
if (start || end) {
|
||||
rules.push({ start, end });
|
||||
}
|
||||
});
|
||||
return rules;
|
||||
}
|
||||
|
||||
function addFilterRule() {
|
||||
const list = $('filter-rules-list');
|
||||
if (!list) return;
|
||||
|
||||
const idx = list.querySelectorAll('.filter-rule-item').length;
|
||||
const div = document.createElement('div');
|
||||
div.className = 'filter-rule-item';
|
||||
div.dataset.idx = idx;
|
||||
div.style.cssText = 'display:flex;gap:6px;align-items:center';
|
||||
setHtml(div, `
|
||||
<input type="text" class="filter-rule-start" placeholder="起始(可空)" value="" style="flex:1;padding:6px 8px;font-size:.8125rem">
|
||||
<span style="color:var(--txt3)">→</span>
|
||||
<input type="text" class="filter-rule-end" placeholder="结束(可空)" value="" style="flex:1;padding:6px 8px;font-size:.8125rem">
|
||||
<button class="btn btn-sm btn-del filter-rule-del" style="padding:4px 8px">✕</button>
|
||||
`);
|
||||
div.querySelector('.filter-rule-del').onclick = () => div.remove();
|
||||
list.appendChild(div);
|
||||
}
|
||||
|
||||
function updateLocalModelStatus(status, message) {
|
||||
const dot = $('local-model-status').querySelector('.status-dot');
|
||||
const text = $('local-model-status').querySelector('.status-text');
|
||||
@@ -395,6 +468,10 @@
|
||||
config: { url: $('vector-api-url').value.trim(), key: $('vector-api-key').value.trim(), model: $('vector-model-select').value.trim() }
|
||||
});
|
||||
};
|
||||
|
||||
// 过滤规则:添加按钮
|
||||
$('btn-add-filter-rule').onclick = addFilterRule;
|
||||
|
||||
$('btn-gen-vectors').onclick = () => {
|
||||
if (vectorGenerating) return;
|
||||
postMsg('VECTOR_GENERATE', { config: getVectorConfig() });
|
||||
@@ -403,6 +480,20 @@
|
||||
if (confirm('确定清除当前聊天的向量数据?')) postMsg('VECTOR_CLEAR');
|
||||
};
|
||||
$('btn-cancel-vectors').onclick = () => postMsg('VECTOR_CANCEL_GENERATE');
|
||||
|
||||
// 导入导出
|
||||
$('btn-export-vectors').onclick = () => {
|
||||
$('btn-export-vectors').disabled = true;
|
||||
$('vector-io-status').textContent = '导出中...';
|
||||
postMsg('VECTOR_EXPORT');
|
||||
};
|
||||
|
||||
$('btn-import-vectors').onclick = () => {
|
||||
// 让 parent 处理文件选择,避免 iframe 传大文件
|
||||
$('btn-import-vectors').disabled = true;
|
||||
$('vector-io-status').textContent = '导入中...';
|
||||
postMsg('VECTOR_IMPORT_PICK');
|
||||
};
|
||||
}
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Settings Modal
|
||||
@@ -1524,6 +1615,30 @@ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "
|
||||
updateVectorGenProgress(d.phase, d.current, d.total);
|
||||
break;
|
||||
|
||||
case 'VECTOR_EXPORT_RESULT':
|
||||
$('btn-export-vectors').disabled = false;
|
||||
if (d.success) {
|
||||
$('vector-io-status').textContent = `导出成功: ${d.filename} (${(d.size / 1024 / 1024).toFixed(2)}MB)`;
|
||||
} else {
|
||||
$('vector-io-status').textContent = '导出失败: ' + (d.error || '未知错误');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'VECTOR_IMPORT_RESULT':
|
||||
$('btn-import-vectors').disabled = false;
|
||||
if (d.success) {
|
||||
let msg = `导入成功: ${d.chunkCount} 片段, ${d.eventCount} 事件`;
|
||||
if (d.warnings?.length) {
|
||||
msg += '\n⚠️ ' + d.warnings.join('\n⚠️ ');
|
||||
}
|
||||
$('vector-io-status').textContent = msg;
|
||||
// 刷新统计
|
||||
postMsg('REQUEST_VECTOR_STATS');
|
||||
} else {
|
||||
$('vector-io-status').textContent = '导入失败: ' + (d.error || '未知错误');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'RECALL_LOG':
|
||||
setRecallLog(d.text || '');
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user