mirror of
https://github.com/JefferyHcool/BiliNote.git
synced 2026-06-05 07:41:44 +08:00
feat(chat): 基于 RAG 的笔记内容 AI 问答功能
实现类似 Google NotebookLM 的效果:笔记生成后自动向量化, 用户可针对笔记内容进行 LLM 问答。 ### 后端 - 新增 VectorStoreManager(ChromaDB),按标题/转录分块建立向量索引 - 新增 chat_service.py RAG 问答:检索相关片段 → 构建 prompt → 调用 LLM - 新增 /chat/index, /chat/ask, /chat/status API 端点 - 笔记生成完成后自动建立向量索引 ### 前端 - 使用 @ant-design/x Bubble.List + Sender 组件构建聊天面板 - 新增 chatStore(Zustand + persist)持久化聊天记录 - MarkdownViewer 右侧嵌入 ChatPanel,通过"AI 问答"按钮切换 - 首次打开自动检查/触发索引,支持重新索引 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
74
backend/app/routers/chat.py
Normal file
74
backend/app/routers/chat.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.services.chat_service import chat as chat_service
|
||||
from app.services.vector_store import VectorStoreManager
|
||||
from app.utils.logger import get_logger
|
||||
from app.utils.response import ResponseWrapper as R
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class IndexRequest(BaseModel):
|
||||
task_id: str
|
||||
|
||||
|
||||
class ChatMessage(BaseModel):
|
||||
role: str
|
||||
content: str
|
||||
|
||||
|
||||
class AskRequest(BaseModel):
|
||||
task_id: str
|
||||
question: str
|
||||
history: list[ChatMessage] = []
|
||||
provider_id: str
|
||||
model_name: str
|
||||
|
||||
|
||||
@router.post("/chat/index")
|
||||
def index_task(data: IndexRequest):
|
||||
"""为笔记建立向量索引。"""
|
||||
try:
|
||||
store = VectorStoreManager()
|
||||
store.index_task(data.task_id)
|
||||
return R.success(msg="索引完成")
|
||||
except Exception as e:
|
||||
logger.error(f"索引失败: {e}")
|
||||
return R.error(msg=f"索引失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/chat/status")
|
||||
def chat_status(task_id: str):
|
||||
"""检查笔记是否已建立向量索引。"""
|
||||
try:
|
||||
store = VectorStoreManager()
|
||||
indexed = store.is_indexed(task_id)
|
||||
return R.success(data={"indexed": indexed})
|
||||
except Exception as e:
|
||||
logger.error(f"查询索引状态失败: {e}")
|
||||
return R.success(data={"indexed": False})
|
||||
|
||||
|
||||
@router.post("/chat/ask")
|
||||
def ask_question(data: AskRequest):
|
||||
"""基于笔记内容的 RAG 问答。"""
|
||||
try:
|
||||
history = [{"role": m.role, "content": m.content} for m in data.history]
|
||||
result = chat_service(
|
||||
task_id=data.task_id,
|
||||
question=data.question,
|
||||
history=history,
|
||||
provider_id=data.provider_id,
|
||||
model_name=data.model_name,
|
||||
)
|
||||
return R.success(data=result)
|
||||
except ValueError as e:
|
||||
return R.error(msg=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Chat 问答失败: {e}", exc_info=True)
|
||||
return R.error(msg=f"问答失败: {str(e)}")
|
||||
Reference in New Issue
Block a user