Spaces:
Running on Zero
Running on Zero
zhiyi commited on
Commit ·
29bb346
1
Parent(s): f943246
Fix hero contrast and validation repair errors
Browse files- app.py +8 -3
- tests/test_app.py +13 -1
app.py
CHANGED
|
@@ -452,6 +452,11 @@ def extract_pdf(paper: dict[str, Any], max_chars: int = 14000) -> str:
|
|
| 452 |
return "\n".join(pages)[:max_chars]
|
| 453 |
|
| 454 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 455 |
def validate_stage_with_repairs(
|
| 456 |
result: dict[str, Any],
|
| 457 |
model_type: type[BaseModel],
|
|
@@ -469,7 +474,7 @@ def validate_stage_with_repairs(
|
|
| 469 |
candidate = chat_json(
|
| 470 |
f"Repair the {stage_name} JSON. Preserve valid content, fill missing fields, and return only the complete corrected object.",
|
| 471 |
json.dumps({
|
| 472 |
-
"validation_errors":
|
| 473 |
"object_to_repair": candidate,
|
| 474 |
"source_context": source_context,
|
| 475 |
"schema": model_type.model_json_schema(),
|
|
@@ -703,7 +708,7 @@ def validate_report_with_repairs(report: dict[str, Any], context: dict[str, Any]
|
|
| 703 |
"Repair an incomplete algorithm research report. Preserve its chosen research type, outline, layouts, and valid content. "
|
| 704 |
"Fix only schema-invalid fields. Return the complete report as one JSON object and never invent source IDs.",
|
| 705 |
json.dumps({
|
| 706 |
-
"validation_errors":
|
| 707 |
"report_to_repair": candidate,
|
| 708 |
"evidence_cards": context.get("evidence_cards", []),
|
| 709 |
"schema": ResearchReport.model_json_schema(),
|
|
@@ -1017,7 +1022,7 @@ def run_research_ui(
|
|
| 1017 |
|
| 1018 |
|
| 1019 |
CSS = """
|
| 1020 |
-
.gradio-container{max-width:none!important;
|
| 1021 |
.preview-column{min-width:0}.input-column{max-width:430px;padding:14px!important;border:1px solid #dce5ef;border-radius:14px;background:#ffffffb8;box-shadow:0 10px 30px #1a38500d}
|
| 1022 |
.preview-toolbar{align-items:center!important;justify-content:flex-end!important;gap:6px!important;min-height:38px}
|
| 1023 |
.preview-title{margin-right:auto!important;min-width:180px}.download-chip{flex:0 0 auto!important;min-width:42px!important;max-width:52px!important;position:relative}
|
|
|
|
| 452 |
return "\n".join(pages)[:max_chars]
|
| 453 |
|
| 454 |
|
| 455 |
+
def serializable_validation_errors(exc: ValidationError) -> list[dict[str, Any]]:
|
| 456 |
+
"""Remove exception objects and raw inputs before sending validation feedback to the model."""
|
| 457 |
+
return exc.errors(include_url=False, include_context=False, include_input=False)
|
| 458 |
+
|
| 459 |
+
|
| 460 |
def validate_stage_with_repairs(
|
| 461 |
result: dict[str, Any],
|
| 462 |
model_type: type[BaseModel],
|
|
|
|
| 474 |
candidate = chat_json(
|
| 475 |
f"Repair the {stage_name} JSON. Preserve valid content, fill missing fields, and return only the complete corrected object.",
|
| 476 |
json.dumps({
|
| 477 |
+
"validation_errors": serializable_validation_errors(exc),
|
| 478 |
"object_to_repair": candidate,
|
| 479 |
"source_context": source_context,
|
| 480 |
"schema": model_type.model_json_schema(),
|
|
|
|
| 708 |
"Repair an incomplete algorithm research report. Preserve its chosen research type, outline, layouts, and valid content. "
|
| 709 |
"Fix only schema-invalid fields. Return the complete report as one JSON object and never invent source IDs.",
|
| 710 |
json.dumps({
|
| 711 |
+
"validation_errors": serializable_validation_errors(exc),
|
| 712 |
"report_to_repair": candidate,
|
| 713 |
"evidence_cards": context.get("evidence_cards", []),
|
| 714 |
"schema": ResearchReport.model_json_schema(),
|
|
|
|
| 1022 |
|
| 1023 |
|
| 1024 |
CSS = """
|
| 1025 |
+
.gradio-container{max-width:none!important;background:linear-gradient(145deg,#f7f9fc,#eef3f8)!important}.app-hero{margin:4px 4px 18px;padding:18px 22px;border:1px solid #dce5ef;border-radius:16px;background:linear-gradient(120deg,#0c1d2d,#153651);color:#fff;box-shadow:0 12px 35px #16334d1a}.app-hero h1{margin:0 0 5px;color:#fff!important;font-size:25px}.app-hero p{margin:0;color:#fff!important}.app-hero span{display:inline-block;margin-top:10px;padding:4px 8px;border:1px solid #ffffff2b;border-radius:999px;color:#82ead8;font-size:11px}
|
| 1026 |
.preview-column{min-width:0}.input-column{max-width:430px;padding:14px!important;border:1px solid #dce5ef;border-radius:14px;background:#ffffffb8;box-shadow:0 10px 30px #1a38500d}
|
| 1027 |
.preview-toolbar{align-items:center!important;justify-content:flex-end!important;gap:6px!important;min-height:38px}
|
| 1028 |
.preview-title{margin-right:auto!important;min-width:180px}.download-chip{flex:0 0 auto!important;min-width:42px!important;max-width:52px!important;position:relative}
|
tests/test_app.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
|
|
| 1 |
import unittest
|
| 2 |
from unittest.mock import patch
|
| 3 |
|
| 4 |
from pydantic import ValidationError
|
| 5 |
|
| 6 |
-
from app import ResearchReport, chat_json, deduplicate, infer_section_source_ids, normalize_comparison, normalize_process, parse_json_object, prepare_evidence_inputs, render_presentation, render_section_content, render_value, safe_slug, search_literature
|
| 7 |
|
| 8 |
|
| 9 |
def base_report(section):
|
|
@@ -97,6 +98,17 @@ class AppTests(unittest.TestCase):
|
|
| 97 |
with self.assertRaises(ValidationError):
|
| 98 |
ResearchReport.model_validate(base_report(section))
|
| 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
def test_comparison_requires_rows(self):
|
| 101 |
section = {"title": "Compare", "purpose": "Compare engineering alternatives fairly.", "takeaway": "No choice is universally optimal here.", "layout": "comparison", "content": {"columns": ["speed", "quality"], "rows": []}, "source_ids": []}
|
| 102 |
with self.assertRaises(ValidationError):
|
|
|
|
| 1 |
+
import json
|
| 2 |
import unittest
|
| 3 |
from unittest.mock import patch
|
| 4 |
|
| 5 |
from pydantic import ValidationError
|
| 6 |
|
| 7 |
+
from app import ResearchReport, chat_json, deduplicate, infer_section_source_ids, normalize_comparison, normalize_process, parse_json_object, prepare_evidence_inputs, render_presentation, render_section_content, render_value, safe_slug, search_literature, serializable_validation_errors
|
| 8 |
|
| 9 |
|
| 10 |
def base_report(section):
|
|
|
|
| 98 |
with self.assertRaises(ValidationError):
|
| 99 |
ResearchReport.model_validate(base_report(section))
|
| 100 |
|
| 101 |
+
def test_validation_feedback_is_json_serializable(self):
|
| 102 |
+
section = {"title": "Invalid", "purpose": "Trigger a custom validator error.", "takeaway": "The timeline is intentionally incomplete.", "layout": "timeline", "content": {"nodes": []}, "source_ids": []}
|
| 103 |
+
try:
|
| 104 |
+
ResearchReport.model_validate(base_report(section))
|
| 105 |
+
except ValidationError as exc:
|
| 106 |
+
errors = serializable_validation_errors(exc)
|
| 107 |
+
else:
|
| 108 |
+
self.fail("Expected report validation to fail")
|
| 109 |
+
json.dumps(errors)
|
| 110 |
+
self.assertNotIn("ctx", errors[0])
|
| 111 |
+
|
| 112 |
def test_comparison_requires_rows(self):
|
| 113 |
section = {"title": "Compare", "purpose": "Compare engineering alternatives fairly.", "takeaway": "No choice is universally optimal here.", "layout": "comparison", "content": {"columns": ["speed", "quality"], "rows": []}, "source_ids": []}
|
| 114 |
with self.assertRaises(ValidationError):
|