bsenst commited on
Commit
fe535b3
·
1 Parent(s): d491d8b

chore: commit local edits before pushing to HF Space

Browse files
app.py CHANGED
@@ -4,6 +4,10 @@ from pathlib import Path
4
 
5
  import gradio as gr
6
  import pandas as pd
 
 
 
 
7
 
8
  from src.parser import filter_df_by_fachgruppe, parse_ebm_xml_to_dataframe
9
  from src.rag_pipeline import EbmRAGPipeline, build_pipeline_from_paths
@@ -20,10 +24,62 @@ PIPELINE: EbmRAGPipeline | None = None
20
  def get_pipeline() -> EbmRAGPipeline:
21
  global PIPELINE
22
  if PIPELINE is None:
 
 
 
 
 
 
23
  PIPELINE = build_pipeline_from_paths(DATA_XML, STORE_DIR)
24
  return PIPELINE
25
 
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def format_retrieved(results: list[dict]) -> str:
28
  if not results:
29
  return "No retrieved documents."
 
4
 
5
  import gradio as gr
6
  import pandas as pd
7
+ import subprocess
8
+ import sys
9
+ import os
10
+ import traceback
11
 
12
  from src.parser import filter_df_by_fachgruppe, parse_ebm_xml_to_dataframe
13
  from src.rag_pipeline import EbmRAGPipeline, build_pipeline_from_paths
 
24
  def get_pipeline() -> EbmRAGPipeline:
25
  global PIPELINE
26
  if PIPELINE is None:
27
+ # Ensure vector store exists. Try to download full EBM and build; on failure, fall back to demo XML.
28
+ try:
29
+ ensure_vector_store()
30
+ except Exception:
31
+ # Log and continue; build_pipeline_from_paths will attempt to load or build and may raise a clearer error
32
+ print("Warning: ensure_vector_store failed:\n" + traceback.format_exc())
33
  PIPELINE = build_pipeline_from_paths(DATA_XML, STORE_DIR)
34
  return PIPELINE
35
 
36
 
37
+ def ensure_vector_store() -> None:
38
+ """Try to prepare the FAISS store before the app starts.
39
+
40
+ Steps:
41
+ - If the store already exists, do nothing.
42
+ - Attempt to download the full EBM ZIP (scripts/download_full_ebm.py).
43
+ - Attempt to build the FAISS store (scripts/build_database.py).
44
+ - If building fails due to missing Fachgruppe 001 data, fall back to using the local demo XML by
45
+ disabling the Fachgruppe filter via environment variable `SKIP_FG_FILTER=1`.
46
+ """
47
+ root = Path(__file__).resolve().parent
48
+ store_dir = STORE_DIR
49
+ if store_dir.exists() and (store_dir / "index.faiss").exists() and (store_dir / "metadata.jsonl").exists():
50
+ return
51
+
52
+ # Try to download full EBM
53
+ download_script = root / "scripts" / "download_full_ebm.py"
54
+ build_script = root / "scripts" / "build_database.py"
55
+
56
+ if download_script.exists():
57
+ try:
58
+ print("Attempting to download full KBV EBM archive...")
59
+ subprocess.run([sys.executable, str(download_script)], check=True, timeout=600)
60
+ except Exception:
61
+ print("Download script failed:\n" + traceback.format_exc())
62
+
63
+ # Try to build the FAISS store
64
+ if build_script.exists():
65
+ try:
66
+ print("Attempting to build FAISS store from XML...")
67
+ subprocess.run([sys.executable, str(build_script), "--xml", str(DATA_XML), "--store", str(STORE_DIR)], check=True, timeout=600)
68
+ except subprocess.CalledProcessError as e:
69
+ print("Build script failed with CalledProcessError:\n" + traceback.format_exc())
70
+ # If the build failed due to empty Fachgruppe 001, allow fallback to demo XML
71
+ # The build scripts raise ValueError in that case; detect it by inspecting output/exception
72
+ # Fallback: disable fachgruppe filter so demo XML (with 2 entries) can be used
73
+ print("Falling back to demo XML: disabling Fachgruppe-001 filter for this run.")
74
+ os.environ["SKIP_FG_FILTER"] = "1"
75
+ except Exception:
76
+ print("Build script failed:\n" + traceback.format_exc())
77
+ print("Falling back to demo XML: disabling Fachgruppe-001 filter for this run.")
78
+ os.environ["SKIP_FG_FILTER"] = "1"
79
+ else:
80
+ print("No build script found; continuing and relying on existing data/ebm.xml")
81
+
82
+
83
  def format_retrieved(results: list[dict]) -> str:
84
  if not results:
85
  return "No retrieved documents."
scripts/build_database.py CHANGED
@@ -26,6 +26,11 @@ def main() -> None:
26
 
27
  df = parse_ebm_xml_to_dataframe(str(xml_path))
28
  df = filter_df_by_fachgruppe(df)
 
 
 
 
 
29
  documents = dataframe_to_documents(df)
30
  store, embeddings = EbmVectorStore.build(documents, embedding_model=embedding_model)
31
  store.save(store_dir, embeddings=embeddings)
 
26
 
27
  df = parse_ebm_xml_to_dataframe(str(xml_path))
28
  df = filter_df_by_fachgruppe(df)
29
+ if df.empty:
30
+ raise ValueError(
31
+ "No Fachgruppe 001 documents found in data/ebm.xml. "
32
+ "Please provide a full KBV EBM XML with Fachgruppe 001 entries."
33
+ )
34
  documents = dataframe_to_documents(df)
35
  store, embeddings = EbmVectorStore.build(documents, embedding_model=embedding_model)
36
  store.save(store_dir, embeddings=embeddings)
scripts/ingest_ebm.py CHANGED
@@ -24,6 +24,11 @@ def main() -> None:
24
 
25
  df = parse_ebm_xml_to_dataframe(str(xml_path))
26
  df = filter_df_by_fachgruppe(df)
 
 
 
 
 
27
  df.to_parquet(output_dir / "ebm.parquet", index=False)
28
  df.to_json(output_dir / "ebm.jsonl", orient="records", lines=True, force_ascii=False)
29
 
 
24
 
25
  df = parse_ebm_xml_to_dataframe(str(xml_path))
26
  df = filter_df_by_fachgruppe(df)
27
+ if df.empty:
28
+ raise ValueError(
29
+ "No Fachgruppe 001 documents found in data/ebm.xml. "
30
+ "Please provide a full KBV EBM XML with Fachgruppe 001 entries."
31
+ )
32
  df.to_parquet(output_dir / "ebm.parquet", index=False)
33
  df.to_json(output_dir / "ebm.jsonl", orient="records", lines=True, force_ascii=False)
34
 
src/parser.py CHANGED
@@ -109,5 +109,11 @@ def parse_ebm_xml_to_dataframe(xml_path: str) -> pd.DataFrame:
109
 
110
 
111
  def filter_df_by_fachgruppe(df: pd.DataFrame, fachgruppe: str = "001") -> pd.DataFrame:
 
 
 
 
 
 
112
  return df[df["fachgruppen"].apply(lambda x: isinstance(x, list) and fachgruppe in x)].reset_index(drop=True)
113
 
 
109
 
110
 
111
  def filter_df_by_fachgruppe(df: pd.DataFrame, fachgruppe: str = "001") -> pd.DataFrame:
112
+ # Allow skipping the fachgruppe filter (useful for demo XML fallback)
113
+ import os
114
+
115
+ if os.environ.get("SKIP_FG_FILTER") == "1":
116
+ return df.reset_index(drop=True)
117
+
118
  return df[df["fachgruppen"].apply(lambda x: isinstance(x, list) and fachgruppe in x)].reset_index(drop=True)
119
 
src/rag_pipeline.py CHANGED
@@ -134,6 +134,11 @@ def build_pipeline_from_paths(xml_path: str | Path, store_dir: str | Path, embed
134
  else:
135
  df = parse_ebm_xml_to_dataframe(str(xml_path))
136
  df = filter_df_by_fachgruppe(df)
 
 
 
 
 
137
  documents = dataframe_to_documents(df)
138
  store, embeddings = EbmVectorStore.build(documents, embedding_model=embedding_model)
139
  store.save(store_dir, embeddings=embeddings)
 
134
  else:
135
  df = parse_ebm_xml_to_dataframe(str(xml_path))
136
  df = filter_df_by_fachgruppe(df)
137
+ if df.empty:
138
+ raise ValueError(
139
+ "No Fachgruppe 001 documents found in data/ebm.xml. "
140
+ "Please provide a full KBV EBM XML with Fachgruppe 001 entries."
141
+ )
142
  documents = dataframe_to_documents(df)
143
  store, embeddings = EbmVectorStore.build(documents, embedding_model=embedding_model)
144
  store.save(store_dir, embeddings=embeddings)
src/vector_store.py CHANGED
@@ -42,7 +42,17 @@ class EbmVectorStore:
42
  document_to_search_text(EbmDocument(**{k: v for k, v in doc.items() if k != "search_text"}))
43
  for doc in docs
44
  ]
 
 
 
 
 
45
  embeddings = embedding_model.encode(texts)
 
 
 
 
 
46
  index = faiss.IndexFlatIP(embeddings.shape[1])
47
  index.add(embeddings)
48
  store = cls(index=index, documents=docs, embedding_model_name=embedding_model.model_name)
 
42
  document_to_search_text(EbmDocument(**{k: v for k, v in doc.items() if k != "search_text"}))
43
  for doc in docs
44
  ]
45
+ if not texts:
46
+ raise ValueError(
47
+ "Cannot build vector store: no documents available. "
48
+ "Check that data/ebm.xml contains Fachgruppe 001 entries or remove the Fachgruppe-001 filter."
49
+ )
50
  embeddings = embedding_model.encode(texts)
51
+ if embeddings.ndim != 2 or embeddings.shape[0] == 0:
52
+ raise ValueError(
53
+ "Embedding model returned invalid embeddings. "
54
+ "Expected a 2D array with one embedding per document."
55
+ )
56
  index = faiss.IndexFlatIP(embeddings.shape[1])
57
  index.add(embeddings)
58
  store = cls(index=index, documents=docs, embedding_model_name=embedding_model.model_name)