Spaces:
Running
Running
Add VHL audit file upload UI
Browse files
app.py
CHANGED
|
@@ -6,14 +6,73 @@ import gradio as gr
|
|
| 6 |
import requests
|
| 7 |
|
| 8 |
HF_ROUTER_URL = "https://router.huggingface.co/v1/chat/completions"
|
|
|
|
|
|
|
|
|
|
| 9 |
DEFAULT_MODEL = "zai-org/GLM-5.1:zai-org"
|
| 10 |
MODEL_CHOICES = [
|
| 11 |
"zai-org/GLM-5.1:zai-org",
|
| 12 |
"zai-org/GLM-5.1:fireworks-ai",
|
| 13 |
"zai-org/GLM-5.1:novita",
|
| 14 |
]
|
| 15 |
-
DEFAULT_SYSTEM = "You are a strict
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
|
| 19 |
def _extract_text(response_json: dict[str, Any]) -> tuple[str, str]:
|
|
@@ -30,7 +89,15 @@ def _extract_text(response_json: dict[str, Any]) -> tuple[str, str]:
|
|
| 30 |
return str(content), str(reasoning)
|
| 31 |
|
| 32 |
|
| 33 |
-
def call_router(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
token = os.getenv("HF_TOKEN")
|
| 35 |
if not token:
|
| 36 |
return (
|
|
@@ -45,6 +112,10 @@ def call_router(model: str, system_prompt: str, user_prompt: str, max_completion
|
|
| 45 |
),
|
| 46 |
)
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
body: dict[str, Any] = {
|
| 49 |
"model": model,
|
| 50 |
"stream": False,
|
|
@@ -65,7 +136,7 @@ def call_router(model: str, system_prompt: str, user_prompt: str, max_completion
|
|
| 65 |
"Content-Type": "application/json",
|
| 66 |
},
|
| 67 |
json=body,
|
| 68 |
-
timeout=
|
| 69 |
)
|
| 70 |
|
| 71 |
try:
|
|
@@ -83,7 +154,7 @@ def call_router(model: str, system_prompt: str, user_prompt: str, max_completion
|
|
| 83 |
|
| 84 |
with gr.Blocks(title="GLM-5.1 Lab") as demo:
|
| 85 |
gr.Markdown("# GLM-5.1 Lab")
|
| 86 |
-
gr.Markdown("Direct Hugging Face router probe for `GLM-5.1` provider variants.")
|
| 87 |
|
| 88 |
with gr.Row():
|
| 89 |
model = gr.Dropdown(MODEL_CHOICES, value=DEFAULT_MODEL, label="Model")
|
|
@@ -93,6 +164,7 @@ with gr.Blocks(title="GLM-5.1 Lab") as demo:
|
|
| 93 |
|
| 94 |
system_prompt = gr.Textbox(value=DEFAULT_SYSTEM, lines=4, label="System prompt")
|
| 95 |
user_prompt = gr.Textbox(value=DEFAULT_USER, lines=12, label="User prompt")
|
|
|
|
| 96 |
run_btn = gr.Button("Run")
|
| 97 |
|
| 98 |
content_out = gr.Textbox(lines=10, label="Assistant content")
|
|
@@ -101,7 +173,7 @@ with gr.Blocks(title="GLM-5.1 Lab") as demo:
|
|
| 101 |
|
| 102 |
run_btn.click(
|
| 103 |
fn=call_router,
|
| 104 |
-
inputs=[model, system_prompt, user_prompt, max_tokens, temperature, json_mode],
|
| 105 |
outputs=[content_out, reasoning_out, raw_out],
|
| 106 |
)
|
| 107 |
|
|
|
|
| 6 |
import requests
|
| 7 |
|
| 8 |
HF_ROUTER_URL = "https://router.huggingface.co/v1/chat/completions"
|
| 9 |
+
ROUTER_TIMEOUT_SECONDS = 600
|
| 10 |
+
MAX_UPLOADED_FILES = 6
|
| 11 |
+
MAX_UPLOADED_FILE_CHARS = 1_200_000
|
| 12 |
DEFAULT_MODEL = "zai-org/GLM-5.1:zai-org"
|
| 13 |
MODEL_CHOICES = [
|
| 14 |
"zai-org/GLM-5.1:zai-org",
|
| 15 |
"zai-org/GLM-5.1:fireworks-ai",
|
| 16 |
"zai-org/GLM-5.1:novita",
|
| 17 |
]
|
| 18 |
+
DEFAULT_SYSTEM = """You are a strict clinical phenotype extraction auditor.
|
| 19 |
+
Return valid JSON only. Do not rewrite the full extraction unless explicitly asked."""
|
| 20 |
+
DEFAULT_USER = """Audit the uploaded grounded disease-layer output against the uploaded source sentence index.
|
| 21 |
+
|
| 22 |
+
Check:
|
| 23 |
+
- all evidence ids resolve to source sentences
|
| 24 |
+
- no phenotype row aggregates unrelated sentences
|
| 25 |
+
- qualifiers are supported by the exact evidence sentence
|
| 26 |
+
- lab, imaging, test, management, inheritance, gene, prevalence, prognosis, and therapy items are routed outside phenotypes
|
| 27 |
+
- ambiguous standalone targets are not left contextless
|
| 28 |
+
- trigger factors are specific and point to a defined episode or phenotype context
|
| 29 |
+
- ancillary and context rows stay grounded
|
| 30 |
+
- missing clinically important findings from the source are listed only when clearly supported
|
| 31 |
+
|
| 32 |
+
Return this JSON shape:
|
| 33 |
+
{
|
| 34 |
+
"overall": "pass|minor_issues|major_issues",
|
| 35 |
+
"high_priority_fixes": [],
|
| 36 |
+
"missing_supported_findings": [],
|
| 37 |
+
"schema_or_grounding_violations": [],
|
| 38 |
+
"rows_to_downgrade_or_omit": [],
|
| 39 |
+
"notes": []
|
| 40 |
+
}"""
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _uploaded_file_path(uploaded_file: Any) -> str:
|
| 44 |
+
if hasattr(uploaded_file, "name"):
|
| 45 |
+
return str(uploaded_file.name)
|
| 46 |
+
return str(uploaded_file)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def _read_uploaded_files(uploaded_files: Any) -> str:
|
| 50 |
+
if not uploaded_files:
|
| 51 |
+
return ""
|
| 52 |
+
|
| 53 |
+
files = uploaded_files if isinstance(uploaded_files, list) else [uploaded_files]
|
| 54 |
+
chunks = []
|
| 55 |
+
for uploaded_file in files[:MAX_UPLOADED_FILES]:
|
| 56 |
+
path = _uploaded_file_path(uploaded_file)
|
| 57 |
+
filename = os.path.basename(path)
|
| 58 |
+
try:
|
| 59 |
+
with open(path, "r", encoding="utf-8", errors="replace") as handle:
|
| 60 |
+
text = handle.read(MAX_UPLOADED_FILE_CHARS + 1)
|
| 61 |
+
except OSError as exc:
|
| 62 |
+
chunks.append(
|
| 63 |
+
f'\n\n<uploaded_file name="{filename}" read_error="{type(exc).__name__}">'
|
| 64 |
+
f"\n{exc}\n</uploaded_file>"
|
| 65 |
+
)
|
| 66 |
+
continue
|
| 67 |
+
|
| 68 |
+
truncated = len(text) > MAX_UPLOADED_FILE_CHARS
|
| 69 |
+
if truncated:
|
| 70 |
+
text = text[:MAX_UPLOADED_FILE_CHARS]
|
| 71 |
+
chunks.append(
|
| 72 |
+
f'\n\n<uploaded_file name="{filename}" truncated="{str(truncated).lower()}">'
|
| 73 |
+
f"\n{text}\n</uploaded_file>"
|
| 74 |
+
)
|
| 75 |
+
return "".join(chunks)
|
| 76 |
|
| 77 |
|
| 78 |
def _extract_text(response_json: dict[str, Any]) -> tuple[str, str]:
|
|
|
|
| 89 |
return str(content), str(reasoning)
|
| 90 |
|
| 91 |
|
| 92 |
+
def call_router(
|
| 93 |
+
model: str,
|
| 94 |
+
system_prompt: str,
|
| 95 |
+
user_prompt: str,
|
| 96 |
+
uploaded_files: Any,
|
| 97 |
+
max_completion_tokens: int,
|
| 98 |
+
temperature: float,
|
| 99 |
+
json_mode: bool,
|
| 100 |
+
):
|
| 101 |
token = os.getenv("HF_TOKEN")
|
| 102 |
if not token:
|
| 103 |
return (
|
|
|
|
| 112 |
),
|
| 113 |
)
|
| 114 |
|
| 115 |
+
file_context = _read_uploaded_files(uploaded_files)
|
| 116 |
+
if file_context:
|
| 117 |
+
user_prompt = f"{user_prompt.rstrip()}\n\n<uploaded_files>{file_context}\n</uploaded_files>"
|
| 118 |
+
|
| 119 |
body: dict[str, Any] = {
|
| 120 |
"model": model,
|
| 121 |
"stream": False,
|
|
|
|
| 136 |
"Content-Type": "application/json",
|
| 137 |
},
|
| 138 |
json=body,
|
| 139 |
+
timeout=ROUTER_TIMEOUT_SECONDS,
|
| 140 |
)
|
| 141 |
|
| 142 |
try:
|
|
|
|
| 154 |
|
| 155 |
with gr.Blocks(title="GLM-5.1 Lab") as demo:
|
| 156 |
gr.Markdown("# GLM-5.1 Lab")
|
| 157 |
+
gr.Markdown("Direct Hugging Face router probe for `GLM-5.1` provider variants. Upload JSON files to append them to the user prompt.")
|
| 158 |
|
| 159 |
with gr.Row():
|
| 160 |
model = gr.Dropdown(MODEL_CHOICES, value=DEFAULT_MODEL, label="Model")
|
|
|
|
| 164 |
|
| 165 |
system_prompt = gr.Textbox(value=DEFAULT_SYSTEM, lines=4, label="System prompt")
|
| 166 |
user_prompt = gr.Textbox(value=DEFAULT_USER, lines=12, label="User prompt")
|
| 167 |
+
uploaded_files = gr.File(file_count="multiple", type="filepath", label="Optional files to append")
|
| 168 |
run_btn = gr.Button("Run")
|
| 169 |
|
| 170 |
content_out = gr.Textbox(lines=10, label="Assistant content")
|
|
|
|
| 173 |
|
| 174 |
run_btn.click(
|
| 175 |
fn=call_router,
|
| 176 |
+
inputs=[model, system_prompt, user_prompt, uploaded_files, max_tokens, temperature, json_mode],
|
| 177 |
outputs=[content_out, reasoning_out, raw_out],
|
| 178 |
)
|
| 179 |
|