GDL2IR_V2 / app.py
Estazz's picture
Upload folder using huggingface_hub
bc46b62 verified
# -*- coding: utf-8 -*-
"""
Gradio Web UI for GDL -> IR(v0.95) pipeline
功能:
- 上传 GDL 文本文件(.txt/.gdl)与可选 Schema(默认自动发现 poker_gdl_ir.schema.v0.95.zh.json)
- 运行 parse -> normalize -> map_to_v095 -> validate -> report 全流程
- 在线预览 IR(JSON)、Issues(JSON)、Report(Markdown)
- 支持将结果作为文件下载
"""
from __future__ import annotations
import io
import json
import pathlib
from typing import Tuple, Any
import tempfile
import gradio as gr
from gdl_parser_v2 import parse_gdl
from normalizer_v2 import normalize_ir
from mapper_v2 import map_to_v095
from validator_v2 import validate_with_schema
from gap_detector_v2 import make_report
def _auto_discover_schema(cli_arg: str | None) -> pathlib.Path:
candidates = []
if cli_arg:
candidates.append(cli_arg)
here = pathlib.Path(__file__).resolve().parent
candidates.append(str(here / "poker_gdl_ir.schema.v0.95.zh.json"))
candidates.append("poker_gdl_ir.schema.v0.95.zh.json")
candidates.append("/mnt/data/poker_gdl_ir.schema.v0.95.zh.json")
for c in candidates:
try:
p = pathlib.Path(c)
if p.exists():
return p
except Exception:
pass
raise FileNotFoundError("未找到 Schema。请上传或将 poker_gdl_ir.schema.v0.95.zh.json 放在程序目录/当前目录。")
def _read_as_bytes(maybe_file: Any) -> bytes:
# Gradio File with type="binary" returns bytes directly.
if maybe_file is None:
raise gr.Error("未提供文件")
if isinstance(maybe_file, (bytes, bytearray)):
return bytes(maybe_file)
if isinstance(maybe_file, str): # filepath
return pathlib.Path(maybe_file).read_bytes()
if hasattr(maybe_file, "read") and callable(getattr(maybe_file, "read")):
return maybe_file.read()
if isinstance(maybe_file, dict):
data = maybe_file.get("data")
if isinstance(data, (bytes, bytearray)):
return bytes(data)
raise gr.Error("无法读取上传的文件内容")
def run_pipeline(gdl_file: Any, schema_file: Any | None) -> Tuple[str, str, str, bytes, bytes, bytes]:
if gdl_file is None:
raise gr.Error("请先上传 GDL 文件")
# 读取 GDL 文本
gdl_bytes = _read_as_bytes(gdl_file)
try:
gdl_txt = gdl_bytes.decode("utf-8")
except Exception:
# 尝试 gbk / latin-1 以容错
for enc in ("utf-8-sig", "gbk", "latin-1"):
try:
gdl_txt = gdl_bytes.decode(enc)
break
except Exception:
continue
else:
raise gr.Error("无法解码 GDL 文本,请确认编码为 UTF-8")
# 解析 -> 规整 -> 映射
gdl_ast = parse_gdl(gdl_txt)
nz = normalize_ir(gdl_ast, gdl_txt)
ir = map_to_v095(nz, gdl_txt)
# Schema 路径:优先使用上传,其次自动发现
if schema_file is not None:
try:
schema_bytes = _read_as_bytes(schema_file)
tmp = tempfile.NamedTemporaryFile(suffix=".json", delete=False)
tmp.write(schema_bytes)
tmp.flush()
tmp.close()
schema_path = pathlib.Path(tmp.name)
except Exception:
raise gr.Error("读取 Schema 失败,请确认文件格式正确")
else:
try:
schema_path = _auto_discover_schema(None)
except FileNotFoundError as e:
raise gr.Error(str(e))
# 校验(兼容 2/3 元组)
ret = validate_with_schema(ir, str(schema_path))
if isinstance(ret, tuple) and len(ret) == 3:
ok, issues, schema_msg = ret
elif isinstance(ret, tuple) and len(ret) == 2:
ok, issues = ret
schema_msg = f"Schema: {'OK' if ok else 'FAIL'}; issues={len(issues)}"
else:
ok = bool(ret)
issues = []
schema_msg = f"Schema: {'OK' if ok else 'FAIL'}"
report_md = make_report(ir)
ir_json_str = json.dumps(ir, ensure_ascii=False, indent=2)
issues_json_str = json.dumps(issues, ensure_ascii=False, indent=2)
# 准备下载的文件内容
ir_bytes = ir_json_str.encode("utf-8")
issues_bytes = issues_json_str.encode("utf-8")
report_bytes = report_md.encode("utf-8")
return (
ir_json_str,
issues_json_str,
report_md,
ir_bytes,
issues_bytes,
report_bytes,
)
def _save_temp(name_hint: str, data: bytes) -> str:
suffix = pathlib.Path(name_hint).suffix or ""
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
tmp.write(data)
tmp.flush()
tmp.close()
return tmp.name
with gr.Blocks(title="GDL → IR(v0.95) Web UI") as demo:
gr.Markdown("""
**GDL → IR(v0.95) 一键转换与校验**
- 上传 GDL 文本文件(.txt/.gdl)
- 可选上传 Schema(若不上传,将自动发现同目录中的 `poker_gdl_ir.schema.v0.95.zh.json`)
- 生成:IR(JSON)、Issues(JSON)、自检报告(Markdown)
"""
)
with gr.Row():
gdl_in = gr.File(label="GDL 文件 (.txt/.gdl)", file_types=[".txt", ".gdl"], type="binary")
schema_in = gr.File(label="Schema 文件 (可选)", file_types=[".json"], type="binary")
run_btn = gr.Button("运行转换与校验")
with gr.Tab("IR 预览"):
ir_json = gr.Code(label="IR (v0.95)", language="json")
ir_dl = gr.File(label="下载 IR JSON", interactive=False)
with gr.Tab("Issues 预览"):
issues_json = gr.Code(label="Schema 校验问题", language="json")
issues_dl = gr.File(label="下载 Issues JSON", interactive=False)
with gr.Tab("自检报告"):
report_md = gr.Markdown()
report_dl = gr.File(label="下载 自检报告.md", interactive=False)
def _on_click(gdl_file, schema_file):
ir_str, issues_str, report_str, ir_b, issues_b, report_b = run_pipeline(gdl_file, schema_file)
ir_path = _save_temp("ir.v0.95.json", ir_b)
issues_path = _save_temp("issues.json", issues_b)
report_path = _save_temp("selfcheck.md", report_b)
return ir_str, ir_path, issues_str, issues_path, report_str, report_path
run_btn.click(
_on_click,
inputs=[gdl_in, schema_in],
outputs=[ir_json, ir_dl, issues_json, issues_dl, report_md, report_dl]
)
if __name__ == "__main__":
demo.launch(share=True)