Spaces:
Running
Running
Download app.py from dev-strender/proofread-demo: direct link, hf CLI and curl.
- Browser
- Download file 4.79 kB
-
https://huggingface.co/spaces/dev-strender/proofread-demo/resolve/9c84f9d445e63e1b16bd1ab03855030fbe86034f/app.py
- Command line
-
hf download hf://spaces/dev-strender/proofread-demo@9c84f9d445e63e1b16bd1ab03855030fbe86034f/app.py
-
curl -L -o app.py https://huggingface.co/spaces/dev-strender/proofread-demo/resolve/9c84f9d445e63e1b16bd1ab03855030fbe86034f/app.py
4.79 kB
| """์กฐ์ ์ผ๋ณด ๋ณธ๋ฌธ ๊ต์ด ๋ฐ๋ชจ (Streamlit / HF Space). | |
| v34 ํ์ดํ๋ผ์ธ(prod 7-์คํ + ํ์ดํธ๋ฆฌ์คํธ ๋ณต์ + ์จ/๋ฅ ๊ท์น) ร combo ํ๋กฌํํธ๋ฅผ | |
| solar-eval ์์ง ๊ทธ๋๋ก ์คํํ๋ค. ๋ก์ง์ ์ ๋ถ runner.py โ ์ด ํ์ผ์ UI ๋ง ๋ด๋น. | |
| """ | |
| from __future__ import annotations | |
| import difflib | |
| import html | |
| import os | |
| import runner | |
| import streamlit as st | |
| SAMPLE_TEXT = ( | |
| "์ ๋ถ์ ๊ฐ๋ ฅํ ๋ถ๋์ฐ ๊ท์ ์๋ ๋ถ๊ตฌํ๊ณ ์๋๊ถ ์ํํธ ๋งค๋งค ๊ฑฐ๋ ๋น๋ฅ ์ " | |
| "์คํ๋ ค ์ฆ๊ฐ์ธ๋ฅผ ๋ณด์๋ค. ์์ค ์ํ์ ์ฃผํ ๋ด๋ณด ๋์ถ ๊ธ๋ฆฌ๊ฐ ๋ฎ์์ง๋ฉด์ " | |
| "์ค์์์์ ๊ตฌ๋งค ์ฌ๋ฆฌ๊ฐ ๋์ด์๋ฌ๊ธฐ ๋๋ฌธ์ด๋ผ๋ ๋ถ์์ด ๋์จ๋ค." | |
| ) | |
| LLM_STEPS = {"proofread", "basic_correction", "context_correction", "style_correction"} | |
| def diff_html(src: str, dst: str) -> tuple[str, int]: | |
| """์ด์ ๋จ์ diff ๋ฅผ HTML ๋ก. (๋งํฌ์ , ๋ฐ๋ ์ธ๊ทธ๋จผํธ ์) ๋ฐํ.""" | |
| a, b = src.split(), dst.split() | |
| sm = difflib.SequenceMatcher(a=a, b=b, autojunk=False) | |
| parts: list[str] = [] | |
| n_changed = 0 | |
| for op, i1, i2, j1, j2 in sm.get_opcodes(): | |
| before, after = html.escape(" ".join(a[i1:i2])), html.escape(" ".join(b[j1:j2])) | |
| if op == "equal": | |
| parts.append(after) | |
| continue | |
| n_changed += 1 | |
| if before: | |
| parts.append( | |
| f'<span style="background:rgba(230,80,80,.18);' | |
| f'text-decoration:line-through">{before}</span>' | |
| ) | |
| if after: | |
| parts.append(f'<span style="background:rgba(60,170,90,.22)">{after}</span>') | |
| return " ".join(parts), n_changed | |
| def get_pipeline(): | |
| return runner.build_pipeline() | |
| st.set_page_config(page_title="์กฐ์ ์ผ๋ณด ๋ณธ๋ฌธ ๊ต์ด ๋ฐ๋ชจ", page_icon="๐ฐ", layout="wide") | |
| st.title("๐ฐ ์กฐ์ ์ผ๋ณด ๋ณธ๋ฌธ ๊ต์ด ๋ฐ๋ชจ") | |
| st.caption( | |
| "pipeline_dev_v34 (FT ๊ต์ด + Solar 3-์คํ + ๊ฒฐ์ ๋ก ๊ท์น: ์ดํ ์นํ ยท ๋ณตํฉ์ด " | |
| "ํ์ดํธ๋ฆฌ์คํธ ๋ณต์ ยท ์จ/๋ฅ ๋ฐ์นจ ๊ท์น) ร prompt_dev_260825_combo โ " | |
| "temperature 0.0 ยท reasoning off. ํ๊ฐ ํ๋ค์ค์ ๊ฐ์ ์์ง์ ๊ทธ๋๋ก ์คํํฉ๋๋ค." | |
| ) | |
| with st.sidebar: | |
| st.subheader("์ค์ ") | |
| if not os.environ.get("UPSTAGE_API_KEY"): | |
| key = st.text_input( | |
| "UPSTAGE_API_KEY", | |
| type="password", | |
| help="HF Space ์์๋ Settings โ Secrets ๋ก ์ค์ ํ์ธ์.", | |
| ) | |
| if key: | |
| os.environ["UPSTAGE_API_KEY"] = key | |
| model = st.selectbox("๋ชจ๋ธ (step1โ3 ์ฃผ์ )", ["solar-pro4", "solar-pro2"], index=0) | |
| st.caption("FT ๊ต์ด ์คํ ์ ํ์ดํ๋ผ์ธ์ ๊ณ ์ ๋ ft:solar-news-correction ์ ์ฌ์ฉํฉ๋๋ค.") | |
| text = st.text_area("๊ธฐ์ฌ ๋ณธ๋ฌธ", value=SAMPLE_TEXT, height=180, max_chars=4000) | |
| if st.button("๊ต์ด ์คํ", type="primary", disabled=not text.strip()): | |
| if not os.environ.get("UPSTAGE_API_KEY"): | |
| st.error( | |
| "UPSTAGE_API_KEY ๊ฐ ํ์ํฉ๋๋ค โ ์ฌ์ด๋๋ฐ์ ์ ๋ ฅํ๊ฑฐ๋ Space Secrets ์ ์ค์ ํ์ธ์." | |
| ) | |
| st.stop() | |
| with st.spinner("๊ต์ด ์ค์ ๋๋คโฆ (ํ์ดํ๋ผ์ธ ์ต์ ์ค์ธก 37.5์ด, ๋ณดํต 10์ด ๋ด)"): | |
| try: | |
| result = runner.run_proofread(get_pipeline(), text.strip(), model=model) | |
| except Exception as e: # noqa: BLE001 โ ๋ฐ๋ชจ ํ๋ฉด์์๋ ์์ธ ์์ฝ๋ง ๋ณด์ฌ์ค๋ค | |
| st.error(f"์คํ ์คํจ: {type(e).__name__}: {e}") | |
| st.stop() | |
| markup, n_changed = diff_html(text.strip(), result["output"]) | |
| usage = result.get("usage") or {} | |
| c1, c2, c3 = st.columns(3) | |
| c1.metric("์์ ์๊ฐ", f"{result['elapsed_s']:.1f}s") | |
| c2.metric("๋ฐ๋ ๊ณณ", f"{n_changed}๊ณณ") | |
| c3.metric("ํ ํฐ (์ ๋ ฅ+์ถ๋ ฅ)", f"{usage.get('total_tokens', 0):,}") | |
| st.subheader("๊ต์ ๊ฒฐ๊ณผ (์๋ฌธ ๋๋น ๋ณ๊ฒฝ ํ์)") | |
| st.markdown( | |
| f'<div style="line-height:1.9;font-size:1.02rem">{markup}</div>', | |
| unsafe_allow_html=True, | |
| ) | |
| with st.expander("๊ต์ ์ ๋ฌธ (๋ณต์ฌ์ฉ)"): | |
| st.code(result["output"], language=None) | |
| with st.expander("ํ์ดํ๋ผ์ธ ์คํ ๋ณ ์ถ๋ ฅ"): | |
| prev = text.strip() | |
| for name, snapshot in result["step_outputs"].items(): | |
| kind = "LLM" if name in LLM_STEPS else "rule" | |
| changed = snapshot != prev | |
| st.markdown(f"**{name}** ยท {kind} ยท {'๋ณ๊ฒฝํจ' if changed else '๋ณ๊ฒฝ ์์'}") | |
| if changed: | |
| step_markup, _ = diff_html(prev, snapshot) | |
| st.markdown( | |
| f'<div style="line-height:1.8;font-size:.92rem;opacity:.9">{step_markup}</div>', | |
| unsafe_allow_html=True, | |
| ) | |
| prev = snapshot | |
| st.divider() | |