starfriend commited on
Commit
4c153ee
·
verified ·
1 Parent(s): 88bc2d3

Upload 2 files

Browse files
metadata_search/agent_orchestrator.py CHANGED
@@ -438,5 +438,5 @@ def agent_chat_payload(body: dict[str, Any]) -> dict[str, Any]:
438
  }
439
  if diagnostics is not None:
440
  payload["diagnostics"] = diagnostics
441
- payload["llm_backend"] = llm_backend_name()
442
  return payload
 
438
  }
439
  if diagnostics is not None:
440
  payload["diagnostics"] = diagnostics
441
+ payload["llm_backend"] = "deepseek_fallback" if str(strategy).startswith("deepseek_fallback:") else llm_backend_name()
442
  return payload
metadata_search/chat_api.py CHANGED
@@ -1,85 +1,106 @@
1
- """Chat API for the WaterScope research agent (HF Space answers)."""
2
-
3
- from __future__ import annotations
4
-
5
- import os
6
-
7
- from backend.chat_settings import MAX_CHAT_PAPERS, enhance_ordinal_question, focus_document_ids_for_question
8
- from backend.mcp_sync import use_mcp
9
- from backend.model import llm_backend_name
10
- from backend.paper_voice import prefix_context, sanitize_answer
11
- from backend.waterscope_agent import agent_answer
12
- from metadata_search.mcp_retrieval import build_context_for_documents, list_papers_catalog, list_saved_papers
13
-
14
-
15
- def _generate_answer(
16
- message: str,
17
- context: str,
18
- *,
19
- application: str | None = None,
20
- model: str | None = None,
21
- ) -> tuple[str, str, str]:
22
- answer, app_used, diagnostics = agent_answer(
23
- prefix_context(context),
24
- message,
25
- application=application or os.getenv("WATERSCOPE_APPLICATION", "auto"),
26
- model=model or os.getenv("WATERSCOPE_MODEL"),
27
- )
28
- return sanitize_answer(answer), f"waterscope:{app_used}", diagnostics
29
-
30
-
31
- def get_papers_payload() -> dict:
32
- papers = list_papers_catalog()
33
- saved_ids = {paper.get("document_id") for paper in list_saved_papers() if paper.get("document_id")}
34
- for paper in papers:
35
- paper["is_saved"] = paper.get("document_id") in saved_ids
36
- return {"papers": papers, "max_select": MAX_CHAT_PAPERS}
37
-
38
-
39
- def chat_payload(body: dict) -> dict:
40
- message = (body.get("message") or "").strip()
41
- document_ids = body.get("document_ids") or []
42
- application = body.get("application")
43
- agent_mode = bool(body.get("agent_mode"))
44
-
45
- if not message:
46
- raise ValueError("message is required")
47
-
48
- if agent_mode and not document_ids:
49
- from metadata_search.agent_orchestrator import agent_chat_payload
50
-
51
- return agent_chat_payload(body)
52
-
53
- if not document_ids:
54
- raise ValueError("Select at least one paper, or enable agent mode.")
55
- if len(document_ids) > MAX_CHAT_PAPERS:
56
- raise ValueError(f"Select at most {MAX_CHAT_PAPERS} papers.")
57
-
58
- document_ids = focus_document_ids_for_question(message, document_ids)
59
- context, sources = build_context_for_documents(document_ids, question=message)
60
- message = enhance_ordinal_question(message, sources)
61
-
62
- answer, strategy, diagnostics = _generate_answer(
63
- message,
64
- context,
65
- application=application,
66
- model=body.get("model"),
67
- )
68
-
69
- return {
70
- "answer": answer,
71
- "strategy": strategy,
72
- "include_excerpts": False,
73
- "sources": [
74
- {
75
- "document_id": source["document_id"],
76
- "title": source["title"],
77
- "file_name": source["file_name"],
78
- }
79
- for source in sources
80
- ],
81
- "chunks": [],
82
- "retrieval": "mcp" if use_mcp() else "direct",
83
- "diagnostics": diagnostics,
84
- "llm_backend": llm_backend_name(),
85
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Chat API for the WaterScope research agent (HF Space answers)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ from backend.chat_settings import MAX_CHAT_PAPERS, enhance_ordinal_question, focus_document_ids_for_question
8
+ from backend.mcp_sync import use_mcp
9
+ from backend.model import llm_backend_name
10
+ from backend.paper_voice import prefix_context, sanitize_answer
11
+ from backend.waterscope_agent import agent_answer
12
+ from metadata_search.mcp_retrieval import build_context_for_documents, list_papers_catalog, list_saved_papers
13
+
14
+
15
+ def _generate_answer(
16
+ message: str,
17
+ context: str,
18
+ *,
19
+ application: str | None = None,
20
+ model: str | None = None,
21
+ ) -> tuple[str, str, str]:
22
+ from backend.research_fallback import (
23
+ clear_llama_circuit, deepseek_research_answer, is_infrastructure_error,
24
+ llama_circuit_open, mark_llama_unavailable,
25
+ )
26
+ from backend.waterscope_agent import infer_application
27
+
28
+ requested_app = application or os.getenv("WATERSCOPE_APPLICATION", "auto")
29
+ app_used = infer_application(message, explicit=requested_app if requested_app != "auto" else None)
30
+ fallback_enabled = os.getenv("WATERSCOPE_ENABLE_RESEARCH_FALLBACK", "0") == "1"
31
+ if fallback_enabled and llama_circuit_open():
32
+ answer, fallback_model = deepseek_research_answer(prefix_context(context), message, app_used)
33
+ return sanitize_answer(answer), f"deepseek_fallback:{app_used}", f"provider=deepseek;model={fallback_model};reason=llama_circuit_open"
34
+
35
+ try:
36
+ answer, app_used, diagnostics = agent_answer(
37
+ prefix_context(context),
38
+ message,
39
+ application=requested_app,
40
+ model=model or os.getenv("WATERSCOPE_MODEL"),
41
+ )
42
+ clear_llama_circuit()
43
+ return sanitize_answer(answer), f"waterscope:{app_used}", diagnostics
44
+ except Exception as exc:
45
+ if not fallback_enabled or not is_infrastructure_error(exc):
46
+ raise
47
+ mark_llama_unavailable()
48
+ answer, fallback_model = deepseek_research_answer(prefix_context(context), message, app_used)
49
+ return sanitize_answer(answer), f"deepseek_fallback:{app_used}", f"provider=deepseek;model={fallback_model};reason=llama_unavailable"
50
+
51
+
52
+ def get_papers_payload() -> dict:
53
+ papers = list_papers_catalog()
54
+ saved_ids = {paper.get("document_id") for paper in list_saved_papers() if paper.get("document_id")}
55
+ for paper in papers:
56
+ paper["is_saved"] = paper.get("document_id") in saved_ids
57
+ return {"papers": papers, "max_select": MAX_CHAT_PAPERS}
58
+
59
+
60
+ def chat_payload(body: dict) -> dict:
61
+ message = (body.get("message") or "").strip()
62
+ document_ids = body.get("document_ids") or []
63
+ application = body.get("application")
64
+ agent_mode = bool(body.get("agent_mode"))
65
+
66
+ if not message:
67
+ raise ValueError("message is required")
68
+
69
+ if agent_mode and not document_ids:
70
+ from metadata_search.agent_orchestrator import agent_chat_payload
71
+
72
+ return agent_chat_payload(body)
73
+
74
+ if not document_ids:
75
+ raise ValueError("Select at least one paper, or enable agent mode.")
76
+ if len(document_ids) > MAX_CHAT_PAPERS:
77
+ raise ValueError(f"Select at most {MAX_CHAT_PAPERS} papers.")
78
+
79
+ document_ids = focus_document_ids_for_question(message, document_ids)
80
+ context, sources = build_context_for_documents(document_ids, question=message)
81
+ message = enhance_ordinal_question(message, sources)
82
+
83
+ answer, strategy, diagnostics = _generate_answer(
84
+ message,
85
+ context,
86
+ application=application,
87
+ model=body.get("model"),
88
+ )
89
+
90
+ return {
91
+ "answer": answer,
92
+ "strategy": strategy,
93
+ "include_excerpts": False,
94
+ "sources": [
95
+ {
96
+ "document_id": source["document_id"],
97
+ "title": source["title"],
98
+ "file_name": source["file_name"],
99
+ }
100
+ for source in sources
101
+ ],
102
+ "chunks": [],
103
+ "retrieval": "mcp" if use_mcp() else "direct",
104
+ "diagnostics": diagnostics,
105
+ "llm_backend": "deepseek_fallback" if strategy.startswith("deepseek_fallback:") else llm_backend_name(),
106
+ }