Bläddra i källkod

feat: add book knowledge helpers

Lukas Goldschmidt 1 månad sedan
förälder
incheckning
e9d8b3a99a
1 ändrade filer med 107 tillägg och 1 borttagningar
  1. 107 1
      index.js

+ 107 - 1
index.js

@@ -25,6 +25,42 @@ function http(plugin) {
         timeout: DEFAULT_TIMEOUT_MS,
     });
 }
+function normalizeSourceFile(value) {
+    if (!value)
+        return undefined;
+    const trimmed = value.trim();
+    return trimmed.length > 0 ? trimmed : undefined;
+}
+function buildSourceQuery(sourceFile) {
+    return sourceFile
+        .replace(/\.pdf$/i, "")
+        .replace(/[-_]/g, " ")
+        .trim();
+}
+function filterBySource(results, sourceFile) {
+    return results.filter((r) => r?.metadata?.source_file && r.metadata.source_file === sourceFile);
+}
+function summarizeKnowledgeResults(results) {
+    const pages = results
+        .map((r) => r?.metadata?.page)
+        .filter((v) => typeof v === "number");
+    const chapters = results
+        .map((r) => r?.metadata?.chapter)
+        .filter((v) => typeof v === "number");
+    const created = results
+        .map((r) => r?.created_at)
+        .filter((v) => typeof v === "string");
+    return {
+        count: results.length,
+        pageRange: pages.length ? [Math.min(...pages), Math.max(...pages)] : null,
+        chapterRange: chapters.length
+            ? [Math.min(...chapters), Math.max(...chapters)]
+            : null,
+        createdAtRange: created.length
+            ? [created.sort()[0], created.sort()[created.length - 1]]
+            : null,
+    };
+}
 export const activate = (plugin) => {
     const client = http(plugin);
     // write conversational memory
@@ -47,16 +83,86 @@ export const activate = (plugin) => {
         return res.data;
     };
     // search knowledge base
-    plugin.searchKnowledge = async ({ query, userId }) => {
+    plugin.searchKnowledge = async ({ query, userId, limit }) => {
         const finalUserId = userId || getKnowledgeUserId(plugin);
         if (!query)
             throw new Error("Missing query for knowledge search");
         const res = await client.post(`/knowledge/search`, {
             query,
             userId: finalUserId,
+            limit,
+        });
+        return res.data;
+    };
+    // list knowledge sources (books)
+    plugin.listKnowledgeSources = async ({ userId } = {}) => {
+        const finalUserId = userId || getKnowledgeUserId(plugin);
+        const res = await client.post(`/knowledge/sources`, {
+            user_id: finalUserId,
         });
         return res.data;
     };
+    // describe a single book by source_file (metadata summary)
+    plugin.describeKnowledgeBook = async ({ sourceFile, userId }) => {
+        const finalUserId = userId || getKnowledgeUserId(plugin);
+        const normalized = normalizeSourceFile(sourceFile);
+        if (!normalized)
+            throw new Error("Missing sourceFile for knowledge describe");
+        const res = await client.post(`/knowledge/search`, {
+            query: buildSourceQuery(normalized),
+            userId: finalUserId,
+            limit: 200,
+        });
+        const filtered = filterBySource(res.data?.results || [], normalized);
+        const summary = summarizeKnowledgeResults(filtered);
+        return {
+            sourceFile: normalized,
+            summary,
+            sample: filtered.slice(0, 5),
+            hintQuery: buildSourceQuery(normalized),
+        };
+    };
+    // search within a single book (client-side filtered)
+    plugin.searchKnowledgeBook = async ({ query, sourceFile, userId, limit = 8 }) => {
+        const finalUserId = userId || getKnowledgeUserId(plugin);
+        const normalized = normalizeSourceFile(sourceFile);
+        if (!query)
+            throw new Error("Missing query for knowledge search");
+        if (!normalized)
+            throw new Error("Missing sourceFile for book search");
+        const res = await client.post(`/knowledge/search`, {
+            query,
+            userId: finalUserId,
+            limit: Math.max(limit, 20),
+        });
+        const filtered = filterBySource(res.data?.results || [], normalized);
+        return {
+            sourceFile: normalized,
+            results: filtered.slice(0, limit),
+        };
+    };
+    // search across a set of books
+    plugin.searchKnowledgeBooks = async ({ query, sourceFiles, userId, limit = 8 }) => {
+        const finalUserId = userId || getKnowledgeUserId(plugin);
+        if (!query)
+            throw new Error("Missing query for knowledge search");
+        if (!Array.isArray(sourceFiles) || sourceFiles.length === 0) {
+            throw new Error("Missing sourceFiles for multi-book search");
+        }
+        const res = await client.post(`/knowledge/search`, {
+            query,
+            userId: finalUserId,
+            limit: Math.max(limit * 3, 20),
+        });
+        const normalizedSources = sourceFiles
+            .map((s) => normalizeSourceFile(s))
+            .filter(Boolean);
+        const filtered = (res.data?.results || []).filter((r) => normalizedSources.includes(r?.metadata?.source_file));
+        return {
+            sourceFiles: normalizedSources,
+            results: filtered.slice(0, limit),
+        };
+    };
     // write to knowledge base
     plugin.writeKnowledge = async ({ text, userId }) => {
         const finalUserId = userId || getKnowledgeUserId(plugin);