Spaces:
Sleeping
Sleeping
Upload public_routes.py
Browse files
backend/media_analysis/public_routes.py
CHANGED
|
@@ -62,9 +62,18 @@ def media_analyze_public():
|
|
| 62 |
paper = {"paper_id": str(idx), "metadata_row_index": idx,
|
| 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 |
-
#
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 69 |
provider = os.getenv("WATERSCOPE_PUBLIC_MEDIA_PROVIDER", "deepseek").strip().lower()
|
| 70 |
if provider not in ("azure", "deepseek"):
|
|
@@ -90,15 +99,23 @@ def media_analyze_public():
|
|
| 90 |
except ValueError: pass
|
| 91 |
return jsonify({"error": "Media analysis is busy; please retry shortly"}), 429
|
| 92 |
try:
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 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:
|
|
|
|
| 62 |
paper = {"paper_id": str(idx), "metadata_row_index": idx,
|
| 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 |
+
# The resolver scans the entire question for numbered media labels. This
|
| 66 |
+
# public single-media endpoint must receive exactly ONE unique media label;
|
| 67 |
+
# instructional examples must never accidentally become requested sources.
|
| 68 |
+
refs = {
|
| 69 |
+
("table" if m.group(1).lower() == "table" else "figure", int(m.group(2)))
|
| 70 |
+
for m in re.finditer(r"\b(fig(?:ure)?\.?|table)\s*0*(\d+)\b", question, re.I)
|
| 71 |
+
}
|
| 72 |
+
if not refs:
|
| 73 |
return jsonify({"error": "Specify Figure N or Table N"}), 400
|
| 74 |
+
if len(refs) != 1:
|
| 75 |
+
return jsonify({"error": "Please analyze one numbered figure or table at a time"}), 400
|
| 76 |
+
requested_kind, requested_number = next(iter(refs))
|
| 77 |
# Fixed provider and model on server, not client. Hard bound to avoid runaway bills.
|
| 78 |
provider = os.getenv("WATERSCOPE_PUBLIC_MEDIA_PROVIDER", "deepseek").strip().lower()
|
| 79 |
if provider not in ("azure", "deepseek"):
|
|
|
|
| 99 |
except ValueError: pass
|
| 100 |
return jsonify({"error": "Media analysis is busy; please retry shortly"}), 429
|
| 101 |
try:
|
| 102 |
+
# IMPORTANT: pass the user's media reference unchanged to the resolver.
|
| 103 |
+
# Appending example labels such as "Table 1 or Figure 2" makes the
|
| 104 |
+
# image selector load both sources, even for a single-table request.
|
| 105 |
+
result = analyze_media_question(question.strip(), [paper], enabled=True,
|
|
|
|
|
|
|
| 106 |
provider=provider, model=model, max_output_tokens=4096 if export_csv else 1600,
|
| 107 |
evidence_mode="combined", export_csv=export_csv,
|
| 108 |
analysis_mode="extract_all" if export_csv else "interpret")
|
| 109 |
+
# Fail closed if an upstream change ever introduces unrelated media.
|
| 110 |
+
sources = result.get("sources") or result.get("source_identifiers") or []
|
| 111 |
+
if len(sources) != 1:
|
| 112 |
+
return jsonify({"error": "Media source mismatch: expected exactly one source"}), 502
|
| 113 |
+
src_label = str(sources[0].get("label") or "")
|
| 114 |
+
src_match = re.search(r"\b(fig(?:ure)?|table)[\s_.-]*0*(\d+)\b", src_label, re.I)
|
| 115 |
+
if (not src_match or
|
| 116 |
+
("table" if src_match.group(1).lower() == "table" else "figure") != requested_kind or
|
| 117 |
+
int(src_match.group(2)) != requested_number):
|
| 118 |
+
return jsonify({"error": "Media source mismatch: requested and returned labels differ"}), 502
|
| 119 |
# Do not send large duplicate tabular records: CSV already carries the data.
|
| 120 |
result.pop("structured_data", None)
|
| 121 |
if "answer" in result:
|