VetNet-LCPS / vetcopilot-backend /scripts /init_knowledge_base.py
thomasm291678
v0.4.0-dapt: DAPT Qwen2.5-3B + LCPS 2.0 AI 引擎升级
b6c412f
Raw History Blame Contribute Delete
4.85 kB
"""
知识库初始化脚本 - 递归扫描 veterinary_articles 目录下所有 PDF
使用方法:
py -3.12 scripts/init_knowledge_base.py
"""
import os
import sys
import shutil
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from app.database import SessionLocal, init_db
from app.models.knowledge import KnowledgeDocument, KnowledgeChunk
from app.services import knowledge_service as ks
from app.config import settings
from app.utils.logger import logger
# 扫描目录:本地 veterinary_articles(含 site1/site2/site3)
ARTICLES_DIR = Path(r"C:\Users\HP\Documents\666666666666666666\veterinary_articles")
PDF_DEST_DIR = Path(settings.UPLOAD_DIR) / "knowledge_pdfs"
EXCLUDE_PATTERNS = [
"cover", "index", "contents", "front", "preface", "acknowledg",
"abbreviat", "glossary", "appendi", "reference", "bibliograph",
]
def should_include(filename: str) -> bool:
name_lower = filename.lower()
for pattern in EXCLUDE_PATTERNS:
if pattern in name_lower:
return False
return True
def main():
if not ARTICLES_DIR.exists():
print(f"错误:目录不存在: {ARTICLES_DIR}")
return
# 确保目标目录存在
PDF_DEST_DIR.mkdir(parents=True, exist_ok=True)
# 初始化数据库
print("初始化数据库...")
init_db()
# 初始化 FAISS 索引
print("初始化 FAISS 索引...")
ks.init_faiss_index()
# 递归扫描所有 PDF
print(f"\n扫描目录: {ARTICLES_DIR}")
pdf_files = sorted(ARTICLES_DIR.rglob("*.pdf"))
pdf_files = [f for f in pdf_files if not f.name.startswith("_")]
print(f"发现 {len(pdf_files)} 个 PDF 文件")
# 过滤
pdf_files = [f for f in pdf_files if should_include(f.name)]
print(f"过滤后剩余 {len(pdf_files)} 个文件待导入\n")
# 按站点分组统计
from collections import Counter
site_counts = Counter()
for f in pdf_files:
parts = f.parts
for p in parts:
if p.startswith("site"):
site_counts[p] += 1
break
else:
site_counts["other"] += 1
print("按站点分布:")
for site, cnt in site_counts.most_common():
print(f" {site}: {cnt} 个")
# 检查已存在
db = SessionLocal()
try:
existing_hashes = set()
all_docs = db.query(KnowledgeDocument).all()
for d in all_docs:
existing_hashes.add(d.file_hash)
imported = 0
skipped = 0
failed = 0
total = len(pdf_files)
for idx, pdf_path in enumerate(pdf_files):
file_hash = ks._compute_sha256(pdf_path)
if file_hash in existing_hashes:
if (idx + 1) % 100 == 0:
print(f" [{idx+1}/{total}] 已导入={imported} 跳过={skipped} 失败={failed}")
skipped += 1
continue
# 复制到知识库 PDF 目录
dest_name = pdf_path.name
dest_path = PDF_DEST_DIR / dest_name
# 处理重名
counter = 1
while dest_path.exists():
stem = pdf_path.stem
dest_name = f"{stem}_{counter}.pdf"
dest_path = PDF_DEST_DIR / dest_name
counter += 1
shutil.copy2(pdf_path, dest_path)
try:
result = ks.upload_document(dest_path, dest_name)
if result.get("duplicate"):
skipped += 1
continue
doc_id = result["id"]
# 同步处理(大文件可能需要较长时间)
ks.process_document(doc_id)
doc = db.query(KnowledgeDocument).filter(
KnowledgeDocument.id == doc_id
).first()
if doc and doc.status == "ready":
imported += 1
else:
status = doc.status if doc else "unknown"
error = doc.error_message if doc else ""
failed += 1
if idx < 5:
print(f" [失败] {pdf_path.name}: status={status} error={error[:80]}")
except Exception as e:
failed += 1
if idx < 5:
print(f" [异常] {pdf_path.name}: {e}")
if (idx + 1) % 50 == 0 or idx < 5:
print(f" [{idx+1}/{total}] 已导入={imported} 跳过={skipped} 失败={failed}")
print(f"\n{'='*50}")
print(f"导入完成!")
print(f" 成功导入: {imported}")
print(f" 跳过(已存在): {skipped}")
print(f" 失败: {failed}")
print(f"{'='*50}")
finally:
db.close()
if __name__ == "__main__":
main()