| """Chosun proofreading demo — Gradio UI. |
| |
| Tabs: |
| - v24 (new): solar-pro3 with FT + self-consistency × 2 + tool-calling |
| judge. paragraph F1 47.04 (vs solar-pro2 prod_251231 mean 44.86). |
| - 제목 교열 (sandbox): solar-pro2 vs solar-pro3 side-by-side comparison |
| for newspaper title proofreading (default prompt hidden in UI). |
| """ |
|
|
| import os |
|
|
| import gradio as gr |
| from dotenv import load_dotenv |
| from openai import OpenAI |
| from pipelines import list_prompts |
| from postprocess import load_vocabulary |
|
|
| from blindtest import build_feedback_tab |
| from title_proofread import build_title_proofread_tab |
|
|
| load_dotenv() |
|
|
| _api_key = os.getenv("UPSTAGE_API_KEY", "") |
| client = OpenAI(api_key=_api_key, base_url="https://api.upstage.ai/v1") if _api_key else None |
|
|
| _vocab_path = os.path.join(os.path.dirname(__file__), "data", "vocabulary.csv") |
| vocabulary = load_vocabulary(_vocab_path) |
|
|
|
|
| prompt_choices = list_prompts() or ["dev_260429_v24"] |
|
|
|
|
| def _default_prompt(preferred_prefix: str, fallback: str) -> str: |
| matches = [p for p in prompt_choices if p.startswith(preferred_prefix)] |
| if matches: |
| return matches[-1] |
| return fallback |
|
|
|
|
| _v24_prompt = _default_prompt("dev_260429_v24", "dev_260429_v24") |
|
|
| with gr.Blocks(title="Chosun 교정교열 데모") as demo: |
| gr.Markdown("# Chosun 교정교열 데모") |
|
|
| with gr.Tabs(): |
| with gr.Tab("v24 (new · 260429)"): |
| build_feedback_tab( |
| client=client, |
| vocabulary=vocabulary, |
| pipeline_config=("260429_v24", "solar-pro3", _v24_prompt), |
| elem_id_prefix="v24", |
| ) |
|
|
| with gr.Tab("제목 교열 (sandbox)"): |
| build_title_proofread_tab(client=client) |
|
|
| _SHORTCUT_JS = """ |
| () => { |
| if (window.__chosunShortcutBound) return; |
| window.__chosunShortcutBound = true; |
| // Capture phase so Code-editor (Monaco) doesn't swallow the keystroke. |
| document.addEventListener('keydown', (e) => { |
| if (!((e.metaKey || e.ctrlKey) && e.key === 'Enter')) return; |
| // Pick the run button on the *visible* tab (others' buttons are hidden). |
| const ids = ['title-proofread-run-btn', 'v24-run-btn']; |
| for (const id of ids) { |
| const root = document.getElementById(id); |
| if (!root) continue; |
| if (root.offsetParent === null) continue; // hidden (different tab) |
| const btn = root.querySelector('button') || root; |
| e.preventDefault(); |
| e.stopPropagation(); |
| btn.click(); |
| return; |
| } |
| }, true); |
| } |
| """ |
| demo.load(None, None, None, js=_SHORTCUT_JS) |
|
|
| if __name__ == "__main__": |
| import uvicorn |
| from fastapi import FastAPI |
|
|
| app = FastAPI() |
|
|
| @app.get("/ping") |
| async def ping() -> dict: |
| return {"status": "ok"} |
|
|
| app = gr.mount_gradio_app(app, demo, path="/") |
| uvicorn.run(app, host="0.0.0.0", port=7860) |
|
|