dev-strender's picture
feat(title-proofread): add optional body context input (v2 prompt)
cf207fa
"""Gradio UI — 제목 교열 sandbox 탭 (solar-pro2 단일 모델).
production extension 과 동일 모델(solar-pro2) 로 고정. 시스템/유저 프롬프트는
내부 default 사용 — UI 에 노출하지 않음.
본문 입력란 (optional):
- 비어있으면 → 제목만 보고 교열 (현 production 동작 = prompt_dev_v1)
- 있으면 → 본문 컨텍스트 활용 (prompt_dev_v2, 본문 의존 typo catch rate ↑)
"""
from __future__ import annotations
from typing import Any
import gradio as gr
from diff_utils import highlight_diff
from .runner import MODEL, run_title_proofread
# UI 단순화를 위해 category 는 입력 받지 않고 내부 고정.
DEFAULT_CATEGORY = "일반기사"
def build_title_proofread_tab(client: Any) -> None:
"""제목 교열 탭 빌더. `with gr.Tab(...)` 안에서 호출.
Args:
client: openai.OpenAI 호환 클라이언트 (Upstage base_url 설정).
"""
gr.Markdown(f"## 제목 교열 ({MODEL})")
gr.Markdown(
"본문을 함께 입력하면 동음이의어·이름·숫자 같은 *문맥 의존 오탈자* 를 "
"더 정확히 잡습니다. 비워두면 제목만 보고 교열합니다."
)
original = gr.Textbox(
label="제목 입력",
placeholder="예: 강남 3구, 매물 30% 늘었지만 거래량 15% 줄어유",
lines=1,
)
body = gr.Textbox(
label="기사 본문 (선택)",
placeholder=(
"본문을 paste 하면 본문에 명시된 단어·이름·숫자를 근거로 더 "
"정확하게 교정합니다. 비워두면 제목만 보고 교열합니다."
),
lines=8,
max_lines=20,
)
with gr.Accordion("추론 옵션", open=False):
with gr.Row():
temperature = gr.Slider(
minimum=0.0,
maximum=1.0,
step=0.1,
value=0.0,
label="temperature",
)
reasoning_effort = gr.Radio(
choices=["low", "medium", "high"],
value="low",
label="reasoning_effort",
)
run_btn = gr.Button(
"▶ 교열 실행 (⌘+Enter / Ctrl+Enter)",
variant="primary",
elem_id="title-proofread-run-btn",
)
# ─── 결과 — 단일 컬럼 ───
output = gr.Textbox(label="교정 결과", lines=2, interactive=False)
diff_html = gr.HTML(label="원본 대비 diff")
def _empty():
return gr.update(value=""), gr.update(value="")
def _on_run(
original_text: str,
body_text: str,
temperature_val: float,
reasoning_effort_val: str,
):
if not original_text or not original_text.strip():
gr.Warning("제목이 비어 있습니다.")
return _empty()
if client is None:
gr.Warning("UPSTAGE_API_KEY 미설정.")
return _empty()
orig_clean = original_text.strip()
body_clean = (body_text or "").strip()
result = run_title_proofread(
client=client,
original=orig_clean,
category=DEFAULT_CATEGORY,
body=body_clean,
temperature=temperature_val,
reasoning_effort=reasoning_effort_val,
)
if result.get("error"):
gr.Warning(f"{MODEL} 호출 실패: {result['error']}")
return _empty()
out_text = result["output"]
diff = highlight_diff(orig_clean, out_text) if out_text else ""
return gr.update(value=out_text), gr.update(value=diff)
run_btn.click(
_on_run,
inputs=[
original,
body,
temperature,
reasoning_effort,
],
outputs=[
output,
diff_html,
],
)