"use strict"; /* * AnythingLLM アップロード共通処理。 * lineworks-anythingllm.js のアップロード/埋め込みロジックを、 * workspaceSlug 等を引数化して csv-anythingllm.js から再利用できるようにしたもの。 * lineworks-anythingllm.js 自体は変更していない(既存の動作への影響を避けるため)。 */ const fs = require("fs"); const path = require("path"); // 拡張子からMIMEタイプを簡易判定 (AnythingLLM側の処理分岐に必要) function guessMimeType(filename) { const ext = path.extname(filename).toLowerCase(); const map = { ".pdf": "application/pdf", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".txt": "text/plain", ".md": "text/markdown", ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".csv": "text/csv", }; return map[ext] || "application/octet-stream"; } async function uploadFile(filepath, { baseUrl, apiKey, mimeType }) { const fileBuffer = fs.readFileSync(filepath); const blob = new Blob([fileBuffer], { type: mimeType || guessMimeType(filepath) }); const form = new FormData(); form.append("file", blob, path.basename(filepath)); const res = await fetch(`${baseUrl}/api/v1/document/upload`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}` }, body: form, }); if (!res.ok) { throw new Error(`AnythingLLMアップロード失敗: ${res.status} ${await res.text()}`); } const data = await res.json(); return data.documents?.[0]?.location; } // 一度に大量のファイルを埋め込もうとするとAnythingLLM/Ollama側でタイムアウトする // (fetch failed) ため、一定件数ごとにバッチ分割して順番に送信する async function addToWorkspaceEmbeddings(locations, { baseUrl, apiKey, workspaceSlug, batchSize = 50 }) { const totalBatches = Math.ceil(locations.length / batchSize); let succeededCount = 0; const failedBatches = []; for (let i = 0; i < locations.length; i += batchSize) { const batch = locations.slice(i, i + batchSize); const batchNumber = Math.floor(i / batchSize) + 1; console.log(` 埋め込み中... バッチ ${batchNumber}/${totalBatches} (${batch.length}件)`); try { const res = await fetch(`${baseUrl}/api/v1/workspace/${workspaceSlug}/update-embeddings`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ adds: batch, deletes: [] }), }); if (!res.ok) { throw new Error(`${res.status} ${await res.text()}`); } succeededCount += batch.length; } catch (err) { console.warn(` [警告] バッチ ${batchNumber} の埋め込みに失敗: ${err.message}`); failedBatches.push({ batchNumber, count: batch.length, reason: err.message }); } } console.log(`埋め込み完了: 成功 ${succeededCount}/${locations.length} 件`); if (failedBatches.length > 0) { console.warn(`失敗したバッチ: ${failedBatches.length}件`); failedBatches.forEach((b) => console.warn(` - バッチ${b.batchNumber} (${b.count}件): ${b.reason}`)); } return { succeededCount, failedBatches }; } async function listWorkspaces({ baseUrl, apiKey }) { const res = await fetch(`${baseUrl}/api/v1/workspaces`, { headers: { Authorization: `Bearer ${apiKey}` }, }); if (!res.ok) { throw new Error(`ワークスペース一覧の取得に失敗: ${res.status} ${await res.text()}`); } const data = await res.json(); return data.workspaces || []; } async function createWorkspace(name, { baseUrl, apiKey }) { const res = await fetch(`${baseUrl}/api/v1/workspace/new`, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ name }), }); if (!res.ok) { throw new Error(`ワークスペース作成に失敗: ${res.status} ${await res.text()}`); } const data = await res.json(); return data.workspace; } // 指定した名前/slugのワークスペースが存在すればそのslugを、無ければ新規作成して // 作成後の実際のslugを返す(AnythingLLMはslugを名前から自動生成するため、 // 希望した文字列と完全一致しない場合がある)。 async function ensureWorkspaceExists(name, { baseUrl, apiKey }) { const workspaces = await listWorkspaces({ baseUrl, apiKey }); const existing = workspaces.find((w) => w.slug === name || w.name === name); if (existing) { return existing.slug; } console.log(` ワークスペース「${name}」が見つからないため新規作成します...`); const created = await createWorkspace(name, { baseUrl, apiKey }); console.log(` ワークスペースを作成しました: ${created.name} (slug: ${created.slug})`); return created.slug; } module.exports = { uploadFile, addToWorkspaceEmbeddings, guessMimeType, listWorkspaces, createWorkspace, ensureWorkspaceExists, };