Files
Pine 107727ea5e feat: Refactor DpmOverlays to use ShowCard for rendering cards and add ToolStatusToast for operation status notifications
- Moved card rendering logic from DpmOverlays to a new ShowCard component for better reusability.
- Introduced ToolStatusToast to display real-time operation statuses in the top right corner.
- Updated PageHeader to conditionally render credits based on the current path.
- Modified PromptPanel to change tool names and update prompt titles.
- Enhanced ScreenLayout to include ToolStatusToast.
- Updated styles for new components and adjusted existing styles for consistency.
- Implemented statusBus utility for dispatching tool status events.
- Updated useMqttControl to integrate tool status notifications during navigation and card display actions.
2026-08-19 12:28:35 +08:00

64 lines
2.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""知识库入库脚本:分块 → LLM 生成问答 → 双路向量索引 → 落盘 kb_index.json / kb_qa.json。
知识源 = backend/knowledge/ 下全部 *.mdpark.md / opc.md / park_data.md …)。
- 幂等:缓存有效时直接加载(不重新构建);--force 强制删除缓存重建。
- 首次运行会调用 DashScopetext-embedding-v4 向量化 + qwen-plus 生成问答),
耗时约数分钟,仅构建一次,之后命中缓存秒开。
用法(在 backend/ 目录下执行):
python scripts/ingest_kb.py # 有缓存则加载,无缓存则构建
python scripts/ingest_kb.py --force # 强制重建(任一知识文件变更后)
"""
import argparse
import sys
from pathlib import Path
BACKEND_DIR = Path(__file__).resolve().parent.parent
if str(BACKEND_DIR) not in sys.path:
sys.path.insert(0, str(BACKEND_DIR))
def main() -> None:
parser = argparse.ArgumentParser(description="知识库入库(分块 + 问答 + 双路向量索引)")
parser.add_argument("--force", action="store_true", help="删除缓存并强制重建")
parser.add_argument("--dry", action="store_true", help="只做分块预览,不调 API、不落盘")
args = parser.parse_args()
from app import rag
if args.dry:
chunks = rag._chunk_md(rag._kb_text())
print(f"[dry] 知识源 {len(list(rag.KB_DIR.glob(rag.KB_GLOB)))} 个文件,全库 "
f"{len(rag._kb_text())} 字 → {len(chunks)} 块(最长 {max(map(len, chunks))} 字)")
return
if args.force:
for p in (rag.META_FILE, rag.VECTOR_FILE, rag.QA_FILE, rag.LEGACY_INDEX_FILE):
if p.exists():
p.unlink()
print(f"[ingest] 已删除缓存 {p.name}")
print("[ingest] 知识源:")
for f in sorted(rag.KB_DIR.glob(rag.KB_GLOB)):
print(f" - {f.name} ({f.stat().st_size} B)")
idx = rag._load_index()
n_chunk = len(idx["chunks"])
n_vec = len(idx["embed_texts"])
dim = idx["embeddings"].shape[1]
n_q = sum(1 for qs in idx["questions"] for _ in qs)
print("[ingest] 入库完成:")
print(f" - 分块数: {n_chunk}")
print(f" - 生成问句数: {n_q}")
print(f" - 向量数: {n_vec}dim={dim},含原句+问句双路)")
print(f" - 向量矩阵: {rag.VECTOR_FILE}")
print(f" - 元数据: {rag.META_FILE}")
print(f" - 问答缓存: {rag.QA_FILE}")
print("[ingest] 成功。")
if __name__ == "__main__":
main()