prepare_data.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. from __future__ import annotations
  2. import re
  3. from pathlib import Path
  4. from app.config import Settings, get_settings
  5. from app.embeddings import create_embedding_provider
  6. from app.milvus_store import IndexedDocument, MilvusVectorStore
  7. from app.sql_store import initialize_database
  8. def split_document(path: Path) -> list[IndexedDocument]:
  9. text = path.read_text(encoding="utf-8").strip()
  10. if not text:
  11. raise ValueError(f"Milvus 原始文档为空:{path}")
  12. metadata_lines = {
  13. line.split(":", 1)[0]: line.split(":", 1)[1].strip()
  14. for line in text.splitlines()
  15. if ":" in line
  16. }
  17. policy_type = metadata_lines.get("政策类型", "")
  18. category = metadata_lines.get("适用类目", "")
  19. if not policy_type or not category:
  20. raise ValueError(f"文档缺少政策类型或适用类目:{path.name}")
  21. # 课程文档以二级标题作为稳定 Chunk 边界,保留章节语义和来源定位。
  22. sections = [
  23. section.strip()
  24. for section in re.split(r"(?=^## )", text, flags=re.MULTILINE)
  25. if section.strip()
  26. ]
  27. title = text.splitlines()[0].lstrip("# ")
  28. return [
  29. IndexedDocument(
  30. content=section,
  31. source=path.name,
  32. doc_type="commerce_policy",
  33. chunk_index=index,
  34. policy_type=policy_type,
  35. category=category,
  36. metadata={"title": title},
  37. )
  38. for index, section in enumerate(sections)
  39. ]
  40. def prepare_sqlite(settings: Settings) -> int:
  41. return initialize_database(
  42. path=settings.sqlite_path,
  43. source_path=settings.orders_source_path,
  44. reset=True,
  45. )
  46. def prepare_milvus(settings: Settings) -> tuple[int, int, int]:
  47. document_paths = sorted(settings.documents_path.glob("*.md"))
  48. if not document_paths:
  49. raise FileNotFoundError(f"Milvus 原始文档不存在:{settings.documents_path}")
  50. # 先完成所有文档校验和切分,再连接 Milvus,避免半批脏数据。
  51. documents = [
  52. document
  53. for path in document_paths
  54. for document in split_document(path)
  55. ]
  56. embeddings = create_embedding_provider(settings)
  57. store = MilvusVectorStore(
  58. uri=settings.milvus_uri,
  59. token=settings.milvus_token.get_secret_value(),
  60. collection_name=settings.milvus_collection,
  61. embeddings=embeddings,
  62. )
  63. # 演示数据采用全量重建,确保 Schema、索引和向量维度保持一致。
  64. store.create_collection(recreate=True)
  65. inserted = store.insert_documents(documents)
  66. return len(document_paths), inserted, embeddings.dimension
  67. def main() -> None:
  68. settings = get_settings()
  69. print("数据准备开始")
  70. print(f"- SQLite 原始订单:{settings.orders_source_path}")
  71. print(f"- Milvus 原始文档:{settings.documents_path}")
  72. sqlite_rows = prepare_sqlite(settings)
  73. document_count, chunk_count, dimension = prepare_milvus(settings)
  74. print(f"SQLite 完成:database={settings.sqlite_path},rows={sqlite_rows}")
  75. print(
  76. "Milvus 完成:"
  77. f"collection={settings.milvus_collection},"
  78. f"documents={document_count},chunks={chunk_count},dimension={dimension}"
  79. )
  80. if __name__ == "__main__":
  81. main()