"""ローカルナレッジベース(backend/knowledge_base/**.md)を GUI から閲覧するための読み取り専用 API。 コンテキスト注入に使われるファイルそのものを一覧・表示するだけで、ここからの編集はできない。 埋め込み済みかどうか(indexed)は local_knowledge_docs テーブルを引いて付ける。 """ from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel from sqlalchemy.orm import Session as DBSession from app.core.memory_kb.local_knowledge import list_kb_files, read_kb_file from app.db.database import get_db from app.db.models import LocalKnowledgeDoc router = APIRouter(prefix="/api/kb", tags=["knowledge-base"]) class KbFileInfo(BaseModel): path: str name: str # ナレッジベース直下のファイルは空文字。UI ではこの単位でグループ表示する directory: str title: str preview: str size: int updated_at: datetime # 埋め込み済み(=話題に応じた自動注入の対象になっている)か indexed: bool class KbFileContent(BaseModel): path: str name: str title: str content: str size: int updated_at: datetime @router.get("/files", response_model=list[KbFileInfo]) def list_files(db: DBSession = Depends(get_db)): """ナレッジベース配下の Markdown を一覧で返す(本文は含めず、先頭のプレビューのみ)。""" indexed_paths = { # DB 側は OS 依存の区切り文字で保存されているため、比較用に posix 形式へ寄せる path.replace("\\", "/") for (path,) in db.query(LocalKnowledgeDoc.path).all() } return [ KbFileInfo(**info, indexed=info["path"] in indexed_paths) for info in list_kb_files() ] @router.get("/file", response_model=KbFileContent) def get_file(path: str = Query(..., description="ナレッジベースディレクトリからの相対パス")): """1ファイルの全文を返す。""" file = read_kb_file(path) if file is None: raise HTTPException(status_code=404, detail="Knowledge base file not found") return KbFileContent(**file)