feat: 全面补充执行日志(135处)

补日志的模块:
- vector-store.ts: 0→7(init/create/delete/add/search 全覆盖)
- rag.ts: 3→7(initVectorStore/embedBatch/removeDoc/retrieveContext)
- chat-area.ts: 2→5(3个导出函数加日志)
- history-modal.ts: 4→5(打开历史记录)
- kb-modal.ts: 7→8(打开知识库管理)
- header.ts: 5→7(运行中模型状态)
This commit is contained in:
thzxx
2026-04-07 01:47:02 +08:00
parent 60152fb443
commit 9735a1ed38
6 changed files with 26 additions and 10 deletions
+4 -1
View File
@@ -3,7 +3,7 @@
*/
import { state, KEYS } from '../state/state.js';
import { logError } from '../services/log-service.js';
import { logError, logSession } from '../services/log-service.js';
import { marked } from '../utils/marked-config.js';
import { escapeHtml, formatTime } from '../utils/utils.js';
import type { ChatSession, ChatMessage, ToolCallRecord } from '../types.js';
@@ -420,6 +420,7 @@ export async function exportAsMarkdown(session: ChatSession): Promise<void> {
if (m.think) md += `> **思考:** ${m.think}\n\n`;
});
await nativeSaveFile(`${session.title}.md`, md);
logSession('导出', `${session.title}.md`);
}
export async function exportAsHtml(session: ChatSession): Promise<void> {
@@ -435,6 +436,7 @@ code{background:rgba(0,0,0,0.2);padding:2px 6px;border-radius:4px;}</style></hea
});
html += '</body></html>';
await nativeSaveFile(`${session.title}.html`, html);
logSession('导出', `${session.title}.html`);
}
export async function exportAsTxt(session: ChatSession): Promise<void> {
@@ -443,4 +445,5 @@ export async function exportAsTxt(session: ChatSession): Promise<void> {
txt += `[${m.role === 'user' ? '用户' : 'AI'}]\n${m.content || ''}\n\n`;
});
await nativeSaveFile(`${session.title}.txt`, txt);
logSession('导出', `${session.title}.txt`);
}
+2
View File
@@ -78,6 +78,7 @@ export async function updateRunningModels(): Promise<void> {
const data = await api.psModels();
if (!data.models || data.models.length === 0) {
container.innerHTML = '<p class="text-muted">无运行中的模型</p>';
logDebug('运行中模型: 0');
return;
}
container.innerHTML = data.models.map(m => `
@@ -86,6 +87,7 @@ export async function updateRunningModels(): Promise<void> {
<span class="model-vram">${formatSize(m.size_vram || 0)} VRAM</span>
</div>
`).join('');
logDebug(`运行中模型: ${data.models.length}`, data.models.map(m => m.name).join(', '));
} catch {
container.innerHTML = '<p class="text-muted">无法获取运行信息</p>';
}
+1
View File
@@ -190,6 +190,7 @@ export function openHistoryModal(): void {
(document.querySelector('#historySearchInput') as HTMLInputElement).value = '';
(document.querySelector('#historySearchClear') as HTMLElement).style.display = 'none';
loadHistory();
logSession('打开历史记录');
historyModalEl.style.display = '';
}
+1
View File
@@ -98,6 +98,7 @@ function updateRagBadge(): void {
async function openKBModal(): Promise<void> {
kbModalEl.style.display = '';
logRAG('打开知识库管理');
await refreshCollections();
await populateEmbedModels();
}
+4
View File
@@ -14,6 +14,7 @@ export async function initVectorStore(): Promise<VectorStore> {
if (vectorStore) return vectorStore;
vectorStore = new VectorStore();
await vectorStore.init();
logRAG('向量存储已初始化');
return vectorStore;
}
@@ -34,6 +35,7 @@ export async function embedText(text: string, model: string): Promise<number[]>
export async function embedBatch(texts: string[], model: string, onProgress?: (done: number, total: number) => void): Promise<number[][]> {
const results: number[][] = [];
const batchSize = 5;
logDebug(`嵌入批次`, `${texts.length} 个文本, 模型: ${model}`);
for (let i = 0; i < texts.length; i += batchSize) {
const batch = texts.slice(i, i + batchSize);
const embeddings = await Promise.all(batch.map(t => embedText(t, model)));
@@ -87,6 +89,7 @@ export async function removeDocumentFromKB(colId: string, docId: string): Promis
const vs = await initVectorStore();
const allVectors = await vs.getVectorsByCollection(colId);
const docVectors = allVectors.filter(v => v.docId === docId);
logRAG(`删除文档`, `${docId} (${docVectors.length} 个分块)`);
await vs.deleteVectorsByDocument(colId, docId);
@@ -119,6 +122,7 @@ export async function retrieveContext(query: string, colId: string, topK = 5): P
const embedModel = col.embeddingModel;
if (!embedModel) throw new Error('未配置嵌入模型');
logRAG('开始检索', col.name);
const queryEmbedding = await embedText(query, embedModel);
const results = await vs.search(colId, queryEmbedding, topK);
if (results.length === 0) return { context: '', results: [] };
+14 -9
View File
@@ -3,6 +3,7 @@
*/
import type { VectorCollection, VectorItem, SearchResult } from '../types.js';
import { logRAG, logDebug } from './log-service.js';
const MIN_IVF_SIZE = 200;
const DEFAULT_K = 20;
@@ -30,7 +31,7 @@ export class VectorStore {
return new Promise((resolve, reject) => {
const req = indexedDB.open(this.dbName, 2);
req.onerror = () => reject(req.error);
req.onsuccess = () => { this.db = req.result; resolve(); };
req.onsuccess = () => { this.db = req.result; logDebug('向量数据库已连接'); resolve(); };
req.onupgradeneeded = (e) => {
const db = (e.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains('vectors')) {
@@ -60,7 +61,7 @@ export class VectorStore {
};
return new Promise((resolve, reject) => {
const req = this._tx('collections', 'readwrite').put(col);
req.onsuccess = () => resolve(col);
req.onsuccess = () => { logRAG(`创建集合: ${name}`, col.id); resolve(col); };
req.onerror = () => reject(req.error);
});
}
@@ -92,6 +93,7 @@ export class VectorStore {
async deleteCollection(colId: string): Promise<void> {
const vectors = await this.getVectorsByCollection(colId);
logRAG(`删除集合`, `${colId} (${vectors.length} 向量)`);
await new Promise<void>((resolve, reject) => {
const tx = this.db!.transaction(['vectors', 'collections', 'indexes'], 'readwrite');
const vStore = tx.objectStore('vectors');
@@ -107,6 +109,8 @@ export class VectorStore {
async addVectors(items: VectorItem[]): Promise<void> {
if (items.length === 0) return;
const colId = items[0].collectionId;
logDebug(`写入向量`, `${colId}: ${items.length}`);
await new Promise<void>((resolve, reject) => {
const tx = this.db!.transaction('vectors', 'readwrite');
const store = tx.objectStore('vectors');
@@ -142,6 +146,7 @@ export class VectorStore {
async deleteVectorsByDocument(colId: string, docId: string): Promise<void> {
const vectors = await this.getVectorsByCollection(colId);
const docVectors = vectors.filter(v => v.docId === docId);
logDebug(`删除文档向量`, `${docId}: ${docVectors.length}`);
await new Promise<void>((resolve, reject) => {
const tx = this.db!.transaction('vectors', 'readwrite');
const store = tx.objectStore('vectors');
@@ -160,15 +165,15 @@ export class VectorStore {
const vectors = await this.getVectorsByCollection(colId);
if (vectors.length === 0) return [];
let results: SearchResult[];
if (vectors.length < MIN_IVF_SIZE) {
return this._bruteForceSearch(vectors, queryEmbedding, topK);
results = this._bruteForceSearch(vectors, queryEmbedding, topK);
} else {
const index = await this._getIndex(colId, vectors);
results = index ? this._ivfSearch(vectors, index, queryEmbedding, topK) : this._bruteForceSearch(vectors, queryEmbedding, topK);
}
const index = await this._getIndex(colId, vectors);
if (!index) {
return this._bruteForceSearch(vectors, queryEmbedding, topK);
}
return this._ivfSearch(vectors, index, queryEmbedding, topK);
logDebug(`向量搜索`, `${colId}: ${vectors.length} 向量中检索到 ${results.length} 个结果`);
return results;
}
private _bruteForceSearch(vectors: VectorItem[], queryEmbedding: number[], topK: number): SearchResult[] {