Spaces:
Sleeping
Sleeping
Upload public_routes.py
Browse files
backend/media_analysis/public_routes.py
CHANGED
|
@@ -5,6 +5,7 @@ is per Python worker, not a distributed quota; add a gateway quota for productio
|
|
| 5 |
"""
|
| 6 |
from __future__ import annotations
|
| 7 |
import os
|
|
|
|
| 8 |
import time
|
| 9 |
from collections import defaultdict, deque
|
| 10 |
from threading import Lock, BoundedSemaphore
|
|
@@ -18,6 +19,20 @@ _guard = Lock()
|
|
| 18 |
_busy = BoundedSemaphore(value=1)
|
| 19 |
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
def _enabled():
|
| 22 |
return os.getenv("WATERSCOPE_ENABLE_PUBLIC_MEDIA", "0").lower() in ("1", "true", "yes")
|
| 23 |
|
|
@@ -48,7 +63,6 @@ def media_analyze_public():
|
|
| 48 |
"paper_title": str(row.get("Title") or row.get("title") or "")[:400],
|
| 49 |
"doi": str(row.get("DOI") or row.get("doi") or "")[:200]}
|
| 50 |
# Match only explicit Figure N or Table N; media is never chosen arbitrarily.
|
| 51 |
-
import re
|
| 52 |
if not re.search(r"\b(?:figure|fig\.?|table)\s*\d+\b", question, re.I):
|
| 53 |
return jsonify({"error": "Specify Figure N or Table N"}), 400
|
| 54 |
# Fixed provider and model on server, not client. Hard bound to avoid runaway bills.
|
|
@@ -76,12 +90,19 @@ def media_analyze_public():
|
|
| 76 |
except ValueError: pass
|
| 77 |
return jsonify({"error": "Media analysis is busy; please retry shortly"}), 429
|
| 78 |
try:
|
| 79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
provider=provider, model=model, max_output_tokens=4096 if export_csv else 1600,
|
| 81 |
evidence_mode="combined", export_csv=export_csv,
|
| 82 |
analysis_mode="extract_all" if export_csv else "interpret")
|
| 83 |
# Do not send large duplicate tabular records: CSV already carries the data.
|
| 84 |
result.pop("structured_data", None)
|
|
|
|
|
|
|
| 85 |
result["export_csv_requested"] = export_csv
|
| 86 |
return jsonify(result)
|
| 87 |
except (MediaSelectionError, VisionConfigurationError, ValueError, FileNotFoundError) as exc:
|
|
|
|
| 5 |
"""
|
| 6 |
from __future__ import annotations
|
| 7 |
import os
|
| 8 |
+
import re
|
| 9 |
import time
|
| 10 |
from collections import defaultdict, deque
|
| 11 |
from threading import Lock, BoundedSemaphore
|
|
|
|
| 19 |
_busy = BoundedSemaphore(value=1)
|
| 20 |
|
| 21 |
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def _public_answer_text(answer):
|
| 25 |
+
"""Keep internal media/index keys in provenance, but not user-facing prose."""
|
| 26 |
+
if not isinstance(answer, str):
|
| 27 |
+
return answer
|
| 28 |
+
# A common model artifact: "Table 1 (paper 12010, label table_01)".
|
| 29 |
+
answer = re.sub(
|
| 30 |
+
r"\s*\(\s*paper\s*[:#]?\s*\d+\s*[,;]\s*label\s*[:#]?\s*(?:table|figure|fig)[_.-]0*\d+\s*\)",
|
| 31 |
+
"", answer, flags=re.I)
|
| 32 |
+
# Other formats of the same internal metadata are not useful to a reader.
|
| 33 |
+
answer = re.sub(r"\bpaper\s+\d+\s*[,;]\s*label\s+(?:table|figure|fig)[_.-]0*\d+\b", "", answer, flags=re.I)
|
| 34 |
+
return answer
|
| 35 |
+
|
| 36 |
def _enabled():
|
| 37 |
return os.getenv("WATERSCOPE_ENABLE_PUBLIC_MEDIA", "0").lower() in ("1", "true", "yes")
|
| 38 |
|
|
|
|
| 63 |
"paper_title": str(row.get("Title") or row.get("title") or "")[:400],
|
| 64 |
"doi": str(row.get("DOI") or row.get("doi") or "")[:200]}
|
| 65 |
# Match only explicit Figure N or Table N; media is never chosen arbitrarily.
|
|
|
|
| 66 |
if not re.search(r"\b(?:figure|fig\.?|table)\s*\d+\b", question, re.I):
|
| 67 |
return jsonify({"error": "Specify Figure N or Table N"}), 400
|
| 68 |
# Fixed provider and model on server, not client. Hard bound to avoid runaway bills.
|
|
|
|
| 90 |
except ValueError: pass
|
| 91 |
return jsonify({"error": "Media analysis is busy; please retry shortly"}), 429
|
| 92 |
try:
|
| 93 |
+
model_question = question.strip() + (
|
| 94 |
+
"\n\nAnswer presentation: Use readable names (e.g., Table 1 or Figure 2). "
|
| 95 |
+
"Do not mention internal paper indexes, source labels like table_01, or "
|
| 96 |
+
"backend identifiers. Answer only what the question asks."
|
| 97 |
+
)
|
| 98 |
+
result = analyze_media_question(model_question, [paper], enabled=True,
|
| 99 |
provider=provider, model=model, max_output_tokens=4096 if export_csv else 1600,
|
| 100 |
evidence_mode="combined", export_csv=export_csv,
|
| 101 |
analysis_mode="extract_all" if export_csv else "interpret")
|
| 102 |
# Do not send large duplicate tabular records: CSV already carries the data.
|
| 103 |
result.pop("structured_data", None)
|
| 104 |
+
if "answer" in result:
|
| 105 |
+
result["answer"] = _public_answer_text(result["answer"])
|
| 106 |
result["export_csv_requested"] = export_csv
|
| 107 |
return jsonify(result)
|
| 108 |
except (MediaSelectionError, VisionConfigurationError, ValueError, FileNotFoundError) as exc:
|