Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
"""
|
| 2 |
-
AI ๊ธ ํ๋ณ๊ธฐ v5.
|
| 3 |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 4 |
-
|
| 5 |
-
โ
LLM ๊ต์ฐจ๊ฒ์ฆ
|
| 6 |
โ
ํ์ : Brave Search ๋ณ๋ ฌ(์ต๋20) + KCI/RISS/ARXIV + Gemini + CopyKiller ๋ณด๊ณ ์
|
| 7 |
โ
๋ฌธ์: PDFยทDOCXยทHWPยทHWPXยทTXT ์
๋ก๋ โ ์น์
๋ณ ํํธ๋งต + PDF ๋ณด๊ณ ์
|
| 8 |
"""
|
|
@@ -688,6 +688,283 @@ def analyze_model_fingerprint(text, sentences):
|
|
| 688 |
base = 85 if mx>=50 else 65 if mx>=35 else 45 if mx>=20 else 25 if mx>=10 else 10
|
| 689 |
return {"score":min(95, base + multi_bonus),"model_scores":{k:v for k,v in ms.items() if k not in ("๋น๊ฒฉ์AI","์์ดAI") or v > 0}}
|
| 690 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 691 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 692 |
# ํ์ง
|
| 693 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -835,30 +1112,40 @@ AIํ๋ฅ : 75%
|
|
| 835 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 836 |
# ์ข
ํฉ ํ์ (์ผ๊ด๋ ๊ธฐ์ค)
|
| 837 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 838 |
-
def compute_verdict(scores, llm_score=-1, sent_avg=-1):
|
| 839 |
-
w={"ํต๊ณ":.
|
| 840 |
ws=sum(scores[k]*w[k] for k in w)
|
| 841 |
|
| 842 |
-
# โ
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
if
|
| 848 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 849 |
|
| 850 |
-
# โ
|
| 851 |
-
if
|
| 852 |
-
ws
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
|
| 854 |
hi=sum(1 for v in scores.values() if v>=50)
|
| 855 |
if hi>=4: ws+=8
|
| 856 |
elif hi>=3: ws+=5
|
| 857 |
elif hi>=2: ws+=2
|
| 858 |
|
| 859 |
-
# โ
์ธ๊ฐ ๊ฒฉ์๋ฌธ ํ ์ธ
|
| 860 |
-
if style
|
| 861 |
-
ws
|
| 862 |
|
| 863 |
lo=sum(1 for v in scores.values() if v<20)
|
| 864 |
if lo>=3: ws-=8
|
|
@@ -876,10 +1163,12 @@ def quick_score(text):
|
|
| 876 |
sc={"ํต๊ณ":analyze_statistics(text,sents,words)["score"],"๋ฌธ์ฒด":analyze_korean_style(text,sents,morphs)["score"],
|
| 877 |
"๋ฐ๋ณต์ฑ":analyze_repetition(text,sents,words)["score"],"๊ตฌ์กฐ":analyze_structure(text,sents)["score"],
|
| 878 |
"์ง๋ฌธ":analyze_model_fingerprint(text,sents)["score"]}
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
|
|
|
|
|
|
| 883 |
|
| 884 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 885 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -1433,26 +1722,41 @@ def run_detection(text, progress=gr.Progress()):
|
|
| 1433 |
if not text or len(text.strip())<50: return "<div style='padding:20px;text-align:center;color:#888;'>โ ๏ธ ์ต์ 50์</div>",""
|
| 1434 |
text=text.strip()
|
| 1435 |
progress(0.05); sents=split_sentences(text); words=split_words(text); morphs=get_morphemes(text)
|
| 1436 |
-
progress(0.
|
| 1437 |
-
progress(0.
|
| 1438 |
-
progress(0.
|
| 1439 |
-
progress(0.
|
| 1440 |
-
progress(0.
|
| 1441 |
-
progress(0.
|
|
|
|
|
|
|
| 1442 |
progress(0.75); lr=llm_cross_check(text)
|
| 1443 |
sc={"ํต๊ณ":s1["score"],"๋ฌธ์ฒด":s2["score"],"๋ฐ๋ณต์ฑ":s3["score"],"๊ตฌ์กฐ":s4["score"],"์ง๋ฌธ":s5["score"]}
|
| 1444 |
-
|
| 1445 |
-
|
| 1446 |
-
|
| 1447 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1448 |
progress(0.95)
|
| 1449 |
cm={"ai_high":("#FF4444","#FFE0E0","๋์"),"ai_medium":("#FF8800","#FFF0DD","์ค๊ฐ~๋์"),"ai_low":("#DDAA00","#FFFBE0","์ค๊ฐ"),"uncertain":("#888","#F0F0F0","๋ฎ์"),"human":("#22AA44","#E0FFE8","๋งค์ฐ ๋ฎ์")}
|
| 1450 |
fg,bg,conf=cm.get(level,("#888","#F0F0F0","?"))
|
| 1451 |
-
ms=s5.get("model_scores",{}); tm=max(ms,key=ms.get) if ms else "N/A"; tms=ms.get(tm,0)
|
| 1452 |
-
mt=f"{tm} ({tms}์ )" if tms>=15 else "ํน์ ๋ถ๊ฐ"
|
| 1453 |
|
| 1454 |
-
|
| 1455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1456 |
|
| 1457 |
def gb(l,s,w="",desc=""):
|
| 1458 |
c="#FF4444" if s>=70 else "#FF8800" if s>=50 else "#DDAA00" if s>=35 else "#22AA44"
|
|
@@ -1460,15 +1764,20 @@ def run_detection(text, progress=gr.Progress()):
|
|
| 1460 |
dt=f"<div style='font-size:9px;color:#888;margin-top:1px;'>{desc}</div>" if desc else ""
|
| 1461 |
return f"<div style='margin:4px 0;'><div style='display:flex;justify-content:space-between;'><span style='font-size:11px;font-weight:600;'>{l}{wt}</span><span style='font-size:11px;font-weight:700;color:{c};'>{s}</span></div><div style='background:#E8E8E8;border-radius:4px;height:7px;'><div style='background:{c};height:100%;width:{s}%;border-radius:4px;'></div></div>{dt}</div>"
|
| 1462 |
|
|
|
|
| 1463 |
mb=""
|
| 1464 |
for mn in ["GPT","Claude","Gemini","Perplexity"]:
|
| 1465 |
-
s=
|
| 1466 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1467 |
|
| 1468 |
# LLM ์น์
|
| 1469 |
ls=""
|
| 1470 |
if lr["score"]>=0:
|
| 1471 |
-
lsc=lr["score"]
|
| 1472 |
lr_rows="".join(f"<div style='font-size:9px;color:#555;'>{mn}: {lr['detail'].get(mn,'โ')}</div>" for _,mn in LLM_JUDGES)
|
| 1473 |
ls=f"<div style='margin-top:8px;padding:8px;background:#F8F8FF;border-radius:6px;border:1px solid #E0E0FF;'><div style='font-size:10px;font-weight:700;margin-bottom:3px;'>๐ค LLM ๊ต์ฐจ๊ฒ์ฆ (ํ๊ท {lsc}%)</div>{lr_rows}</div>"
|
| 1474 |
else: ls="<div style='margin-top:6px;padding:4px 8px;background:#F5F5F5;border-radius:4px;color:#999;font-size:9px;'>๐ค GROQ_API_KEY ๋ฏธ์ค์ </div>"
|
|
@@ -1479,20 +1788,62 @@ def run_detection(text, progress=gr.Progress()):
|
|
| 1479 |
c="#22AA44" if s>=70 else "#4ECDC4" if s>=55 else "#DDAA00" if s>=40 else "#FF8800"
|
| 1480 |
return f"<div style='margin:2px 0;display:flex;align-items:center;gap:4px;'><span style='width:50px;font-size:10px;'>{l}</span><div style='flex:1;background:#E8E8E8;border-radius:3px;height:5px;'><div style='background:{c};height:100%;width:{s}%;'></div></div><span style='font-size:9px;color:{c};width:18px;text-align:right;'>{s}</span></div>"
|
| 1481 |
|
| 1482 |
-
# ํ์ ์ด์
|
| 1483 |
-
reasons
|
| 1484 |
-
if sc["๋ฌธ์ฒด"]
|
| 1485 |
-
elif sc["๋ฌธ์ฒด"]
|
| 1486 |
-
if
|
| 1487 |
-
elif
|
| 1488 |
-
if
|
| 1489 |
-
|
| 1490 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1491 |
if not reasons: reasons.append("์ธ๊ฐ์ ํํ์ด ์ฐ์ธํ๋ฉฐ AI ํจํด์ด ์ฝํจ")
|
| 1492 |
-
reason_html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1493 |
|
| 1494 |
html=f"""<div style="font-family:'Pretendard','Noto Sans KR',sans-serif;max-width:720px;margin:0 auto;">
|
| 1495 |
-
<!-- ํ์ ์นด๋ -->
|
| 1496 |
<div style="background:{bg};border:2px solid {fg};border-radius:14px;padding:20px;margin-bottom:12px;">
|
| 1497 |
<div style="display:flex;align-items:center;gap:16px;">
|
| 1498 |
<div style="text-align:center;min-width:100px;">
|
|
@@ -1516,12 +1867,13 @@ def run_detection(text, progress=gr.Progress()):
|
|
| 1516 |
|
| 1517 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
|
| 1518 |
<div style="background:#FAFAFA;border-radius:8px;padding:10px;">
|
| 1519 |
-
<div style="font-size:10px;font-weight:700;margin-bottom:4px;">๐ AI ํ์ง 5์ถ</div>
|
| 1520 |
-
{gb('โ ํต๊ณ',sc['ํต๊ณ'],'.
|
| 1521 |
-
{gb('โก ๋ฌธ์ฒด',sc['๋ฌธ์ฒด'],'.
|
| 1522 |
-
{gb('โข ๋ฐ๋ณต',sc['๋ฐ๋ณต์ฑ'],'.
|
| 1523 |
-
{gb('โฃ ๊ตฌ์กฐ',sc['๊ตฌ์กฐ'],'.
|
| 1524 |
-
{gb('โค ์ง๋ฌธ',sc['์ง๋ฌธ'],'.
|
|
|
|
| 1525 |
</div>
|
| 1526 |
<div style="background:#FAFAFA;border-radius:8px;padding:10px;">
|
| 1527 |
<div style="font-size:10px;font-weight:700;margin-bottom:4px;">๐ ๋ชจ๋ธ ์ง๋ฌธ</div>
|
|
@@ -1535,9 +1887,9 @@ def run_detection(text, progress=gr.Progress()):
|
|
| 1535 |
</div>
|
| 1536 |
</div>
|
| 1537 |
</div>
|
| 1538 |
-
{ls}
|
| 1539 |
</div>"""
|
| 1540 |
-
log=f"AI:{fs}์ [{verdict}] ์ ๋ขฐ:{conf} | ๋ชจ๋ธ:{mt} | ํ์ง:{qr['grade']}({qr['score']})\n์ถ: ํต๊ณ{sc['ํต๊ณ']} ๋ฌธ์ฒด{sc['๋ฌธ์ฒด']} ๋ฐ๋ณต{sc['๋ฐ๋ณต์ฑ']} ๊ตฌ์กฐ{sc['๊ตฌ์กฐ']} ์ง๋ฌธ{sc['์ง๋ฌธ']}"
|
| 1541 |
return html, log
|
| 1542 |
|
| 1543 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -1630,7 +1982,7 @@ def run_document_analysis(file, progress=gr.Progress()):
|
|
| 1630 |
sents_all = split_sentences(full_text)
|
| 1631 |
words_all = split_words(full_text)
|
| 1632 |
morphs_all = get_morphemes(full_text)
|
| 1633 |
-
total_score, total_verdict, total_level, total_axes = quick_score(full_text)
|
| 1634 |
quality = analyze_quality(full_text, sents_all, words_all, morphs_all)
|
| 1635 |
|
| 1636 |
# LLM ๊ต์ฐจ๊ฒ์ฆ (์ ์ฒด)
|
|
@@ -1639,7 +1991,7 @@ def run_document_analysis(file, progress=gr.Progress()):
|
|
| 1639 |
if llm_result["score"] >= 0:
|
| 1640 |
_sent_scores = [score_sentence(s)[0] for s in sents_all]
|
| 1641 |
_sent_avg = sum(_sent_scores)/len(_sent_scores) if _sent_scores else -1
|
| 1642 |
-
total_score, total_verdict, total_level = compute_verdict(total_axes, llm_result["score"], sent_avg=_sent_avg)
|
| 1643 |
|
| 1644 |
# ์น์
๋ณ ๋ถ์
|
| 1645 |
progress(0.45, f"{len(sections)}๊ฐ ์น์
๋ถ์...")
|
|
@@ -1648,7 +2000,7 @@ def run_document_analysis(file, progress=gr.Progress()):
|
|
| 1648 |
if len(sec.strip()) < 20:
|
| 1649 |
section_results.append({"idx": i+1, "text": sec, "score": -1, "verdict": "๋๋ฌด ์งง์", "skipped": True})
|
| 1650 |
continue
|
| 1651 |
-
s_score, s_verdict, s_level, s_axes = quick_score(sec)
|
| 1652 |
# ๋ฌธ์ฅ๋ณ ํ์ด๋ผ์ดํธ
|
| 1653 |
sec_sents = split_sentences(sec)
|
| 1654 |
sent_scores = []
|
|
|
|
| 1 |
"""
|
| 2 |
+
AI ๊ธ ํ๋ณ๊ธฐ v5.1 โ 5์ถ+Perplexity+Humanizer+๋ชจ๋ธ์ถ์ + ํ์ง + LLM๊ต์ฐจ๊ฒ์ฆ + ํ์
|
| 3 |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 4 |
+
โ
v5.1 3๋ ํฌ๋ฌ: Perplexity ํ๋ฅ ๋ถ์ ยท Humanizer/Bypasser ํ์ง ยท AI ๋ชจ๋ธ ์ถ์
|
| 5 |
+
โ
5์ถ AI ํ์ง | 6ํญ๋ชฉ ํ์ง | LLM ๊ต์ฐจ๊ฒ์ฆ (GPT-OSS-120B ยท Qwen3-32B ยท Kimi-K2)
|
| 6 |
โ
ํ์ : Brave Search ๋ณ๋ ฌ(์ต๋20) + KCI/RISS/ARXIV + Gemini + CopyKiller ๋ณด๊ณ ์
|
| 7 |
โ
๋ฌธ์: PDFยทDOCXยทHWPยทHWPXยทTXT ์
๋ก๋ โ ์น์
๋ณ ํํธ๋งต + PDF ๋ณด๊ณ ์
|
| 8 |
"""
|
|
|
|
| 688 |
base = 85 if mx>=50 else 65 if mx>=35 else 45 if mx>=20 else 25 if mx>=10 else 10
|
| 689 |
return {"score":min(95, base + multi_bonus),"model_scores":{k:v for k,v in ms.items() if k not in ("๋น๊ฒฉ์AI","์์ดAI") or v > 0}}
|
| 690 |
|
| 691 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 692 |
+
# โ
โ
โ
ํฌ๋ฌ ๊ธฐ๋ฅ โ โ Perplexity ๊ธฐ๋ฐ AI ํ๋ฅ (v5.1)
|
| 693 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 694 |
+
# AI ํ
์คํธ๋ ์์ธก ๊ฐ๋ฅ๋๊ฐ ๋์ (๋ฎ์ Perplexity) โ ๋ฌธ์/ํํ์ n-gram ๊ธฐ๋ฐ
|
| 695 |
+
def analyze_perplexity(text, sentences, morphemes):
|
| 696 |
+
"""ํ๊ตญ์ด ํนํ Perplexity + Burstiness โ ๋ฌธ์ ์ํธ๋กํผ ๋ณด์ """
|
| 697 |
+
if len(sentences) < 2: return {"score": 40, "entropy": 0, "variance": 0, "order": 0, "zipf": 0}
|
| 698 |
+
|
| 699 |
+
# === 1. ๋ฌธ์ ๋ฐ์ด๊ทธ๋จ ์ํธ๋กํผ (ํํ์๋ณด๋ค ์์ ์ ) ===
|
| 700 |
+
chars = [c for c in text if c.strip()]
|
| 701 |
+
char_score = 45
|
| 702 |
+
if len(chars) >= 30:
|
| 703 |
+
cbigrams = [(chars[i], chars[i+1]) for i in range(len(chars)-1)]
|
| 704 |
+
cb_freq = Counter(cbigrams)
|
| 705 |
+
total_cb = len(cbigrams)
|
| 706 |
+
char_entropy = -sum((cnt/total_cb)*math.log2(cnt/total_cb) for cnt in cb_freq.values())
|
| 707 |
+
# AI ํ๊ตญ์ด: ~7~9๋นํธ, ์ธ๊ฐ: ~9~12๋นํธ
|
| 708 |
+
if char_entropy < 7.5: char_score = 78
|
| 709 |
+
elif char_entropy < 8.5: char_score = 62
|
| 710 |
+
elif char_entropy < 9.5: char_score = 42
|
| 711 |
+
elif char_entropy < 10.5: char_score = 25
|
| 712 |
+
else: char_score = 12
|
| 713 |
+
|
| 714 |
+
# === 2. ๋ฌธ์ฅ ๊ธธ์ด Burstiness (CV) ===
|
| 715 |
+
sl = [len(s) for s in sentences]
|
| 716 |
+
burst_score = 45
|
| 717 |
+
if len(sl) >= 3:
|
| 718 |
+
avg = sum(sl)/len(sl)
|
| 719 |
+
std = math.sqrt(sum((l-avg)**2 for l in sl)/len(sl))
|
| 720 |
+
cv = std/(avg+1e-10)
|
| 721 |
+
if cv < 0.15: burst_score = 82
|
| 722 |
+
elif cv < 0.25: burst_score = 62
|
| 723 |
+
elif cv < 0.40: burst_score = 38
|
| 724 |
+
elif cv < 0.60: burst_score = 20
|
| 725 |
+
else: burst_score = 8
|
| 726 |
+
|
| 727 |
+
# === 3. ๋ฌธ์ฅ๊ฐ ์ดํ๋ฐ๋(TTR) ํธ์ฐจ ===
|
| 728 |
+
sent_ttr = []
|
| 729 |
+
for s in sentences:
|
| 730 |
+
sw = split_words(s)
|
| 731 |
+
if len(sw) >= 3:
|
| 732 |
+
sent_ttr.append(len(set(sw))/len(sw))
|
| 733 |
+
ttr_score = 42
|
| 734 |
+
if len(sent_ttr) >= 3:
|
| 735 |
+
avg_ttr = sum(sent_ttr)/len(sent_ttr)
|
| 736 |
+
std_ttr = math.sqrt(sum((t-avg_ttr)**2 for t in sent_ttr)/len(sent_ttr))
|
| 737 |
+
if std_ttr < 0.04: ttr_score = 75
|
| 738 |
+
elif std_ttr < 0.08: ttr_score = 55
|
| 739 |
+
elif std_ttr < 0.15: ttr_score = 35
|
| 740 |
+
else: ttr_score = 15
|
| 741 |
+
|
| 742 |
+
# === 4. ์ข
๊ฒฐ์ด๋ฏธ ์ํธ๋กํผ ===
|
| 743 |
+
endings = [s.rstrip('.!?\u2026')[-3:] for s in sentences if len(s) >= 5]
|
| 744 |
+
end_score = 40
|
| 745 |
+
if len(endings) >= 3:
|
| 746 |
+
ef = Counter(endings)
|
| 747 |
+
end_ent = -sum((c/len(endings))*math.log2(c/len(endings)) for c in ef.values())
|
| 748 |
+
max_ent = math.log2(len(ef)) if len(ef) > 1 else 1
|
| 749 |
+
norm_ent = end_ent / (max_ent + 1e-10)
|
| 750 |
+
if norm_ent < 0.5: end_score = 72
|
| 751 |
+
elif norm_ent < 0.7: end_score = 50
|
| 752 |
+
elif norm_ent < 0.85: end_score = 32
|
| 753 |
+
else: end_score = 15
|
| 754 |
+
|
| 755 |
+
final = int(char_score * 0.30 + burst_score * 0.30 + ttr_score * 0.20 + end_score * 0.20)
|
| 756 |
+
return {"score": final, "entropy": char_score, "variance": burst_score, "order": ttr_score, "zipf": end_score}
|
| 757 |
+
|
| 758 |
+
|
| 759 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 760 |
+
# โ
โ
โ
ํฌ๋ฌ ๊ธฐ๋ฅ โก โ Humanizer/Bypasser ํ์ง (v5.1)
|
| 761 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 762 |
+
# ํจ๋ฌํ๋ ์ด์ฆ ๋๊ตฌ(QuillBot ๋ฑ)๋ก ์์ ๋ AI ๊ธ์ ์์กด ํ์ ํ์ง
|
| 763 |
+
|
| 764 |
+
# Humanizer ํน์ ํจํด
|
| 765 |
+
HUMANIZER_OVERSUBST = re.compile(r'ํ์ฉํ๋ค|์ด์ฉํ๋ค|์ฌ์ฉํ๋ค|์ ์ฉํ๋ค|๋์
ํ๋ค|์ฑํํ๋ค|์ํํ๋ค|์งํํ๋ค|์ค์ํ๋ค|์คํํ๋ค')
|
| 766 |
+
HUMANIZER_AWKWARD = re.compile(r'๊ทธ๊ฒ์|์ด๊ฒ์|์ ๊ฒ์|ํด๋น ์ฌํญ|์์ ์ธ๊ธํ|์ ์ ํ|์๊ธฐํ|๊ธฐ์ ๋')
|
| 767 |
+
HUMANIZER_PASSIVE = re.compile(r'๋์ด์ง[๊ณ ๋๋ฉฐ]|ํ๊ฒ ๋์[๋ค์ต]|์ํ๋[์์ด]|์งํ๋[์์ด]|์ค์๋[์์ด]|ํ์ฉ๋[์์ด]')
|
| 768 |
+
|
| 769 |
+
def analyze_humanizer(text, sentences, words, morphemes):
|
| 770 |
+
"""Humanizer/Bypasser ํ์ง โ AI ์๋ฌธ ํจ๋ฌํ๋ ์ด์ฆ ํ์ ๋ถ์"""
|
| 771 |
+
if len(sentences) < 2: return {"score": 20, "signals": []}
|
| 772 |
+
signals = []
|
| 773 |
+
|
| 774 |
+
# === 1. ๋์์ด ๊ณผ๋ค ์นํ ํจํด ===
|
| 775 |
+
# Humanizer๋ ๊ฐ์ ์๋ฏธ๋ฅผ ๋ค์ํ ๋์์ด๋ก ๋ฐ๊ฟ โ ๋น์์ฐ์ ์ดํ ๋ถ์ฐ
|
| 776 |
+
content_words = [f for f, t in morphemes if t in ('NNG', 'NNP', 'VV', 'VA')]
|
| 777 |
+
if len(content_words) >= 10:
|
| 778 |
+
cw_freq = Counter(content_words)
|
| 779 |
+
# Hapax ratio ๊ทน๋จ์ ์ผ๋ก ๋์ผ๋ฉด ๋์์ด ์นํ ์์ฌ
|
| 780 |
+
hapax = sum(1 for c in cw_freq.values() if c == 1)
|
| 781 |
+
hapax_ratio = hapax / len(cw_freq) if cw_freq else 0
|
| 782 |
+
# ์์ฐ์ด: 0.4~0.7, Humanizer: 0.8+ (๋ชจ๋ ๋จ์ด๋ฅผ ๋ค ๋ฐ๊ฟ์)
|
| 783 |
+
if hapax_ratio > 0.95 and len(content_words) >= 30:
|
| 784 |
+
signals.append(("๋์์ด๊ณผ๋ค์นํ", 20, "ํต์ฌ ์ดํ๊ฐ ๊ณผ๋ํ๊ฒ ๋ถ์ฐ"))
|
| 785 |
+
elif hapax_ratio > 0.90 and len(content_words) >= 25:
|
| 786 |
+
signals.append(("๋์์ด์นํ์์ฌ", 12, "์ดํ ๋ฐ๋ณต ํํผ ํจํด"))
|
| 787 |
+
|
| 788 |
+
# === 2. ๊ตฌ์กฐ ๋ณด์กด + ์ดํ๋ง ๋ณ๊ฒฝ ํจํด ===
|
| 789 |
+
# ์๋ฌธ AI์ ๋ฌธ์ฅ ๊ตฌ์กฐ(๊ธธ์ด, ์ด์)๋ ์ ์ง๋๋ฉด์ ๋จ์ด๋ง ๋ฐ๋
|
| 790 |
+
sl = [len(s) for s in sentences]
|
| 791 |
+
if len(sl) >= 4:
|
| 792 |
+
avg = sum(sl) / len(sl)
|
| 793 |
+
cv = math.sqrt(sum((l - avg)**2 for l in sl) / len(sl)) / (avg + 1e-10)
|
| 794 |
+
# ๋ฌธ์ฅ ๊ธธ์ด ๊ท ์ผ + ์ดํ ๋ค์ = Humanizer ํจํด
|
| 795 |
+
unique_ratio = len(set(words)) / len(words) if words else 0
|
| 796 |
+
if cv < 0.20 and unique_ratio > 0.80 and len(sentences) >= 5:
|
| 797 |
+
signals.append(("๊ตฌ์กฐ๋ณด์กด์ดํ๋ณ๊ฒฝ", 18, "๋ฌธ์ฅ ๊ตฌ์กฐ ๊ท ์ผ + ๋น์ ์์ ์ดํ ๋ค์์ฑ"))
|
| 798 |
+
|
| 799 |
+
# === 3. ์์กด AI ํจํด ===
|
| 800 |
+
# Humanizer๊ฐ ๋์น๊ธฐ ์ฌ์ด AI ํ์
|
| 801 |
+
residual = 0
|
| 802 |
+
# ์ ์์ฌ ์์น ๊ท์น์ฑ (Humanizer๋ ์ ์์ฌ๋ฅผ ์ ์ ๋ฐ๊ฟ)
|
| 803 |
+
conn_positions = []
|
| 804 |
+
for i, s in enumerate(sentences):
|
| 805 |
+
stripped = s.strip()
|
| 806 |
+
for c in ['๋ํ','ํนํ','ํํธ','๋๋ถ์ด','์์ธ๋ฌ','๋์๊ฐ','์ด์','๊ฒ๋ค๊ฐ','๋ฐ๋ฉด','๊ฒฐ๊ตญ']:
|
| 807 |
+
if stripped.startswith(c):
|
| 808 |
+
conn_positions.append(i)
|
| 809 |
+
break
|
| 810 |
+
if len(conn_positions) >= 2:
|
| 811 |
+
# ๋ฑ๊ฐ๊ฒฉ ์ ์์ฌ = AI ์๋ฌธ ๊ตฌ์กฐ ์์กด
|
| 812 |
+
gaps = [conn_positions[i] - conn_positions[i-1] for i in range(1, len(conn_positions))]
|
| 813 |
+
if gaps and max(gaps) - min(gaps) <= 1: # ๊ฑฐ์ ๋ฑ๊ฐ๊ฒฉ
|
| 814 |
+
signals.append(("์ ์์ฌ๋ฑ๊ฐ๊ฒฉ์์กด", 15, "์ ์์ฌ ๋ฐฐ์น๊ฐ ๊ท์น์ (AI ์๋ฌธ ๊ตฌ์กฐ ์์กด)"))
|
| 815 |
+
residual += 15
|
| 816 |
+
|
| 817 |
+
# === 4. ๋ถ์์ฐ์ค๋ฌ์ด ๋์ฒด ํํ ===
|
| 818 |
+
oversubst = len(HUMANIZER_OVERSUBST.findall(text))
|
| 819 |
+
awkward = len(HUMANIZER_AWKWARD.findall(text))
|
| 820 |
+
passive = len(HUMANIZER_PASSIVE.findall(text))
|
| 821 |
+
if oversubst >= 3:
|
| 822 |
+
signals.append(("์ ์ฌ๋์ฌ๋๋ฌด", 12, f"ํ์ฉ/์ด์ฉ/์ฌ์ฉ/์ ์ฉ ๋ฑ {oversubst}๊ฐ"))
|
| 823 |
+
if awkward >= 2:
|
| 824 |
+
signals.append(("์ด์ํ์ง์์ด", 10, f"ํด๋น/์ ์ /์๊ธฐ ๋ฑ {awkward}๊ฐ"))
|
| 825 |
+
if passive >= 3:
|
| 826 |
+
signals.append(("์ด์คํผ๋๊ณผ๋ค", 15, f"๋์ด์ง/์ํ๋ ๋ฑ {passive}๊ฐ"))
|
| 827 |
+
|
| 828 |
+
# === 5. ๋ฌธ์ฅ ์ ํ ๋จ์กฐ + ์ด๋ฏธ ๋ค์ = Humanizer ์๊ทธ๋์ฒ ===
|
| 829 |
+
# AI ์๋ฌธ: ๋ฌธ์ฅ์ ํ ๋จ์กฐ + ์ด๋ฏธ ๋จ์กฐ
|
| 830 |
+
# ์ธ๊ฐ: ๋ฌธ์ฅ์ ํ ๋ค์ + ์ด๋ฏธ ๋ค์
|
| 831 |
+
# Humanizer: ๋ฌธ์ฅ์ ํ ๋จ์กฐ(๋ฐ๊ฟ ์ ์์) + ์ด๋ฏธ ๋ค์(๋ฐ๊ฟ) โ ๋ถ์กฐํ
|
| 832 |
+
endings = [s.rstrip('.!?')[-2:] for s in sentences if len(s) >= 4]
|
| 833 |
+
end_types = len(set(endings)) / len(endings) if endings else 0
|
| 834 |
+
has_question = any(s.strip().endswith('?') for s in sentences)
|
| 835 |
+
has_exclaim = any(s.strip().endswith('!') for s in sentences)
|
| 836 |
+
sent_type_variety = sum([has_question, has_exclaim])
|
| 837 |
+
if sent_type_variety == 0 and end_types > 0.85 and len(sentences) >= 6:
|
| 838 |
+
signals.append(("์ ํ๋จ์กฐ์ด๋ฏธ๋ค์", 12, "์์ ๋ฌธ๋ง + ์ข
๊ฒฐ์ด๋ฏธ ๊ณผ๋ค ๋ค์ = Humanizer ํจํด"))
|
| 839 |
+
|
| 840 |
+
# === 6. ๋ฌธ์ฅ ์์ ํจํด ๋ถ์ผ์น ===
|
| 841 |
+
# Humanizer๋ ๋ฌธ๋๋ฅผ ๋ค์ํ๊ฒ ๋ฐ๊พธ๋ ค ํ๋, ํ๊ตญ์ด์์๋ ๋ถ์์ฐ์ค๋ฌ์ ์ ๋ฐ
|
| 842 |
+
starters = [s.strip()[:3] for s in sentences if len(s) >= 6]
|
| 843 |
+
starter_unique = len(set(starters)) / len(starters) if starters else 0
|
| 844 |
+
if starter_unique >= 0.98 and len(sentences) >= 7:
|
| 845 |
+
signals.append(("๋ฌธ๋๊ณผ๋ค๋ค์", 8, "๋ชจ๋ ๋ฌธ์ฅ ์์์ด ๋ค๋ฆ (์์ฐ์ค๋ฝ์ง ์์ ๋ค์์ฑ)"))
|
| 846 |
+
|
| 847 |
+
total = sum(s[1] for s in signals)
|
| 848 |
+
# ์ ์ํ
|
| 849 |
+
if total >= 45: score = 85
|
| 850 |
+
elif total >= 30: score = 68
|
| 851 |
+
elif total >= 20: score = 52
|
| 852 |
+
elif total >= 10: score = 35
|
| 853 |
+
else: score = 15
|
| 854 |
+
|
| 855 |
+
return {"score": score, "signals": signals, "total_evidence": total}
|
| 856 |
+
|
| 857 |
+
# โโโโโโโ๏ฟฝ๏ฟฝ๏ฟฝโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 858 |
+
# โ
โ
โ
ํฌ๋ฌ ๊ธฐ๋ฅ โข โ AI ๋ชจ๋ธ ์ถ์ (v5.1)
|
| 859 |
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 860 |
+
# ๋ชจ๋ธ๋ณ ๊ณ ์ ํน์ฑ์ผ๋ก ์์ฑ ๋ชจ๋ธ ์ถ์
|
| 861 |
+
|
| 862 |
+
MODEL_PROFILES = {
|
| 863 |
+
"GPT": {
|
| 864 |
+
"style": ["๊ฒฉ์์ฒด ~์ต๋๋ค", "๋ํ/ํนํ ์ ์์ฌ", "~์ ๋ํด", "~๊ฒ์ผ๋ก ์์๋ฉ๋๋ค"],
|
| 865 |
+
"markers": ["๋ค์ํ", "์ค์ํ ์ญํ ", "๊ธ์ ์ ์ธ", "๋๋ถ์ ", "์ฃผ๋ชฉํ ๋งํ", "์ดํด๋ณด๊ฒ ์ต๋๋ค"],
|
| 866 |
+
"structure": "๊ท ์ผํ ๋ฌธ๋จ, ์๋ก -๋ณธ๋ก -๊ฒฐ๋ก ๊ตฌ์กฐ, ๋งํฌ๋ค์ด ์ ํธ",
|
| 867 |
+
"endings": ["์ต๋๋ค", "์์ต๋๋ค", "๋ฉ๋๋ค", "์
๋๋ค"],
|
| 868 |
+
"connectors": ["๋ํ", "ํนํ", "ํํธ", "์ด์ฒ๋ผ"],
|
| 869 |
+
},
|
| 870 |
+
"Claude": {
|
| 871 |
+
"style": ["๋งฅ๋ฝ ์ ์", "๊ท ํ ์กํ", "์ฌ๋ ค ๊น์ ์ด์กฐ", "์๋ณด ํ ์ฃผ์ฅ"],
|
| 872 |
+
"markers": ["ํฅ๋ฏธ๋ก์ด ์ง๋ฌธ", "๋ณต์กํ ์ฃผ์ ", "๋งฅ๋ฝ์์", "๊ท ํ ์กํ", "์ดํด๋ณด๊ฒ ์ต๋๋ค", "ํ ๊ฐ์ง ์ฃผ์ํ "],
|
| 873 |
+
"structure": "์์ฐ์ค๋ฌ์ด ํ๋ฆ, ์๋ณด-์ฃผ์ฅ ๊ตฌ๋ฌธ ์ ํธ, ๋ถ๋๋ฌ์ด ์ ํ",
|
| 874 |
+
"endings": ["๋ค์", "์
๋๋ค", "์์ต๋๋ค", "์ต๋๋ค"],
|
| 875 |
+
"connectors": ["ํํธ", "๋ฌผ๋ก ", "๋ค๋ง", "์ด์ ๊ด๋ จํด"],
|
| 876 |
+
},
|
| 877 |
+
"Gemini": {
|
| 878 |
+
"style": ["์ ๋ณด ๋์ดํ", "~์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค", "๊ฒ์ ๊ฒฐ๊ณผ ๊ธฐ๋ฐ"],
|
| 879 |
+
"markers": ["์์๋ณด๊ฒ ์ต๋๋ค", "๋์์ด ๋์
จ์ผ๋ฉด", "์ถ๊ฐ ์ง๋ฌธ", "์ฐธ๊ณ ๋ก"],
|
| 880 |
+
"structure": "๋ฆฌ์คํธ/๋ฒํธ ๋งค๊ธฐ๊ธฐ ์ ํธ, ํค๋ ํ์ฉ, ์ ๋ณด ๋ฐ๋ ๋์",
|
| 881 |
+
"endings": ["์ต๋๋ค", "์์ต๋๋ค", "์ธ์"],
|
| 882 |
+
"connectors": ["๋ํ", "๊ทธ๋ฆฌ๊ณ ", "์ฐธ๊ณ ๋ก"],
|
| 883 |
+
},
|
| 884 |
+
"Perplexity": {
|
| 885 |
+
"style": ["์ถ์ฒ ์ธ์ฉํ", "~์ ๋ฐ๋ฅด๋ฉด", "์์น ์ ์", "๊ฒ์ผ๋ก ๋ํ๋ฌ๋ค"],
|
| 886 |
+
"markers": ["์ ๋ฐ๋ฅด๋ฉด", "๊ฒ์ผ๋ก ๋ํ๋ฌ", "๊ฒ์ผ๋ก ์กฐ์ฌ๋", "๊ฒ์ผ๋ก ์ง๊ณ๋", "๋ฐํํ", "๋ณด๋์ ๋ฐ๋ฅด๋ฉด"],
|
| 887 |
+
"structure": "ํฉํธ ์ค์ฌ, ์์น ์ธ์ฉ ๋ค์, ์ถ์ฒ ๋ช
์ ์คํ์ผ",
|
| 888 |
+
"endings": ["์ต๋๋ค", "๋ํ๋ฌ๋ค", "๋ฐํ๋ค", "์ ํ๋ค"],
|
| 889 |
+
"connectors": ["ํํธ", "๋ํ", "์ด์"],
|
| 890 |
+
},
|
| 891 |
+
}
|
| 892 |
+
|
| 893 |
+
def estimate_model(text, sentences, morphemes, model_scores):
|
| 894 |
+
"""AI ๋ชจ๋ธ ์ถ์ โ ๋ณตํฉ ์ฆ๊ฑฐ ๊ธฐ๋ฐ"""
|
| 895 |
+
evidence = {m: {"score": 0, "reasons": []} for m in MODEL_PROFILES}
|
| 896 |
+
|
| 897 |
+
sl = text.lower()
|
| 898 |
+
|
| 899 |
+
for model, profile in MODEL_PROFILES.items():
|
| 900 |
+
# 1. FP ์ ์ ๋ฐ์ (๊ธฐ์กด ์ง๋ฌธ ๋ถ์)
|
| 901 |
+
fp_score = model_scores.get(model, 0)
|
| 902 |
+
evidence[model]["score"] += fp_score * 0.4
|
| 903 |
+
if fp_score >= 20:
|
| 904 |
+
evidence[model]["reasons"].append(f"์ง๋ฌธ ๋งค์นญ {fp_score}์ ")
|
| 905 |
+
|
| 906 |
+
# 2. ๋ง์ปค ๋งค์นญ
|
| 907 |
+
marker_cnt = sum(1 for m in profile["markers"] if m in text)
|
| 908 |
+
if marker_cnt >= 2:
|
| 909 |
+
evidence[model]["score"] += marker_cnt * 8
|
| 910 |
+
evidence[model]["reasons"].append(f"ํน์ ํํ {marker_cnt}๊ฐ")
|
| 911 |
+
|
| 912 |
+
# 3. ์ข
๊ฒฐ์ด๋ฏธ ํจํด
|
| 913 |
+
end_match = 0
|
| 914 |
+
for s in sentences:
|
| 915 |
+
for e in profile["endings"]:
|
| 916 |
+
if s.rstrip('.!?').endswith(e):
|
| 917 |
+
end_match += 1; break
|
| 918 |
+
if sentences:
|
| 919 |
+
end_ratio = end_match / len(sentences)
|
| 920 |
+
if end_ratio > 0.7:
|
| 921 |
+
evidence[model]["score"] += 12
|
| 922 |
+
evidence[model]["reasons"].append(f"์ข
๊ฒฐ์ด๋ฏธ {end_ratio:.0%} ์ผ์น")
|
| 923 |
+
|
| 924 |
+
# 4. ์ ์์ฌ ํจํด
|
| 925 |
+
conn_match = sum(1 for s in sentences if any(s.strip().startswith(c) for c in profile["connectors"]))
|
| 926 |
+
if conn_match >= 2:
|
| 927 |
+
evidence[model]["score"] += conn_match * 4
|
| 928 |
+
evidence[model]["reasons"].append(f"์ ์์ฌ ํจํด {conn_match}ํ")
|
| 929 |
+
|
| 930 |
+
# Perplexity ํนํ: ์์น + ์ถ์ฒ ์ธ์ฉ
|
| 931 |
+
number_citations = len(re.findall(r'\d+[%๋ง์ต์กฐ]|์ ๋ฐ๋ฅด๋ฉด|๊ฒ์ผ๋ก ๋ํ๋ฌ|๋ฐํํ', text))
|
| 932 |
+
if number_citations >= 3:
|
| 933 |
+
evidence["Perplexity"]["score"] += number_citations * 5
|
| 934 |
+
evidence["Perplexity"]["reasons"].append(f"์์น/์ธ์ฉ {number_citations}ํ")
|
| 935 |
+
|
| 936 |
+
# Claude ํนํ: ์๋ณด-์ฃผ์ฅ ๊ตฌ๋ฌธ
|
| 937 |
+
concession_cnt = len(AI_CONCESSION.findall(text))
|
| 938 |
+
if concession_cnt >= 1:
|
| 939 |
+
evidence["Claude"]["score"] += concession_cnt * 10
|
| 940 |
+
evidence["Claude"]["reasons"].append(f"์๋ณด-์ฃผ์ฅ ๊ตฌ๋ฌธ {concession_cnt}ํ")
|
| 941 |
+
|
| 942 |
+
# ์ ๋ ฌ ๋ฐ ํ์
|
| 943 |
+
ranked = sorted(evidence.items(), key=lambda x: x[1]["score"], reverse=True)
|
| 944 |
+
top = ranked[0]
|
| 945 |
+
second = ranked[1] if len(ranked) > 1 else None
|
| 946 |
+
|
| 947 |
+
if top[1]["score"] < 10:
|
| 948 |
+
return {"model": "ํน์ ๋ถ๊ฐ", "confidence": "๋ฎ์", "detail": evidence, "ranked": ranked}
|
| 949 |
+
|
| 950 |
+
# ์ ๋ขฐ๋ ๊ณ์ฐ
|
| 951 |
+
gap = top[1]["score"] - (second[1]["score"] if second else 0)
|
| 952 |
+
if gap >= 20 and top[1]["score"] >= 30:
|
| 953 |
+
conf = "๋์"
|
| 954 |
+
elif gap >= 10 and top[1]["score"] >= 20:
|
| 955 |
+
conf = "์ค๏ฟฝ๏ฟฝ"
|
| 956 |
+
else:
|
| 957 |
+
conf = "๋ฎ์"
|
| 958 |
+
|
| 959 |
+
return {
|
| 960 |
+
"model": top[0],
|
| 961 |
+
"confidence": conf,
|
| 962 |
+
"score": top[1]["score"],
|
| 963 |
+
"reasons": top[1]["reasons"],
|
| 964 |
+
"detail": evidence,
|
| 965 |
+
"ranked": ranked
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 969 |
# ํ์ง
|
| 970 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
|
|
| 1112 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1113 |
# ์ข
ํฉ ํ์ (์ผ๊ด๋ ๊ธฐ์ค)
|
| 1114 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1115 |
+
def compute_verdict(scores, llm_score=-1, sent_avg=-1, ppx_score=-1, hum_score=-1):
|
| 1116 |
+
w={"ํต๊ณ":.06,"๋ฌธ์ฒด":.25,"๋ฐ๋ณต์ฑ":.10,"๊ตฌ์กฐ":.12,"์ง๋ฌธ":.30}
|
| 1117 |
ws=sum(scores[k]*w[k] for k in w)
|
| 1118 |
|
| 1119 |
+
# โ
Perplexity ์ถ ํตํฉ (17%)
|
| 1120 |
+
if ppx_score >= 0: ws += ppx_score * 0.17
|
| 1121 |
+
|
| 1122 |
+
# โ
๊ต์ฐจ ์ ํธ ๋ถ์คํธ
|
| 1123 |
+
style=scores["๋ฌธ์ฒด"]; fp=scores["์ง๋ฌธ"]; rep=scores["๋ฐ๋ณต์ฑ"]; struct=scores["๊ตฌ์กฐ"]
|
| 1124 |
+
if style>=35 and fp>=35: ws+=8
|
| 1125 |
+
elif style>=30 and fp>=25: ws+=4
|
| 1126 |
+
if style>=30 and rep>=25 and fp>=20: ws+=4
|
| 1127 |
+
if fp>=45: ws+=3
|
| 1128 |
+
if struct>=50 and style>=30: ws+=3
|
| 1129 |
+
# Perplexity + ์ง๋ฌธ ๋์ ๋ถ์คํธ
|
| 1130 |
+
if ppx_score>=55 and fp>=35: ws+=5
|
| 1131 |
+
if ppx_score>=65 and style>=35: ws+=3
|
| 1132 |
|
| 1133 |
+
# โ
Humanizer ํ์ง ์ ํน๋ณ ๋ถ์คํธ
|
| 1134 |
+
if hum_score>=50:
|
| 1135 |
+
ws=max(ws, 45) # Humanizer ํ์ธ โ ์ต์ AI ์์ฌ ์ค๊ฐ
|
| 1136 |
+
ws += (hum_score-50)*0.15
|
| 1137 |
+
|
| 1138 |
+
# โ
๋ฌธ์ฅ ์์ค ๋ถ์คํธ
|
| 1139 |
+
if sent_avg>=0 and sent_avg>ws: ws=ws*0.80+sent_avg*0.20
|
| 1140 |
|
| 1141 |
hi=sum(1 for v in scores.values() if v>=50)
|
| 1142 |
if hi>=4: ws+=8
|
| 1143 |
elif hi>=3: ws+=5
|
| 1144 |
elif hi>=2: ws+=2
|
| 1145 |
|
| 1146 |
+
# โ
์ธ๊ฐ ๊ฒฉ์๋ฌธ ํ ์ธ
|
| 1147 |
+
if style<40 and fp<=20 and rep<22 and struct<35 and (ppx_score<0 or ppx_score<40):
|
| 1148 |
+
ws-=5
|
| 1149 |
|
| 1150 |
lo=sum(1 for v in scores.values() if v<20)
|
| 1151 |
if lo>=3: ws-=8
|
|
|
|
| 1163 |
sc={"ํต๊ณ":analyze_statistics(text,sents,words)["score"],"๋ฌธ์ฒด":analyze_korean_style(text,sents,morphs)["score"],
|
| 1164 |
"๋ฐ๋ณต์ฑ":analyze_repetition(text,sents,words)["score"],"๊ตฌ์กฐ":analyze_structure(text,sents)["score"],
|
| 1165 |
"์ง๋ฌธ":analyze_model_fingerprint(text,sents)["score"]}
|
| 1166 |
+
sent_scores=[score_sentence(s)[0] for s in sents]
|
| 1167 |
+
sent_avg=sum(sent_scores)/len(sent_scores) if sent_scores else -1
|
| 1168 |
+
ppx=analyze_perplexity(text,sents,morphs)
|
| 1169 |
+
hum=analyze_humanizer(text,sents,words,morphs)
|
| 1170 |
+
fs,v,lv=compute_verdict(sc, sent_avg=sent_avg, ppx_score=ppx["score"], hum_score=hum["score"])
|
| 1171 |
+
return fs,v,lv,sc,ppx,hum
|
| 1172 |
|
| 1173 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1174 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
|
|
| 1722 |
if not text or len(text.strip())<50: return "<div style='padding:20px;text-align:center;color:#888;'>โ ๏ธ ์ต์ 50์</div>",""
|
| 1723 |
text=text.strip()
|
| 1724 |
progress(0.05); sents=split_sentences(text); words=split_words(text); morphs=get_morphemes(text)
|
| 1725 |
+
progress(0.12); s1=analyze_statistics(text,sents,words)
|
| 1726 |
+
progress(0.22); s2=analyze_korean_style(text,sents,morphs)
|
| 1727 |
+
progress(0.30); s3=analyze_repetition(text,sents,words)
|
| 1728 |
+
progress(0.38); s4=analyze_structure(text,sents)
|
| 1729 |
+
progress(0.45); s5=analyze_model_fingerprint(text,sents)
|
| 1730 |
+
progress(0.52); ppx=analyze_perplexity(text,sents,morphs)
|
| 1731 |
+
progress(0.58); hum=analyze_humanizer(text,sents,words,morphs)
|
| 1732 |
+
progress(0.65); qr=analyze_quality(text,sents,words,morphs)
|
| 1733 |
progress(0.75); lr=llm_cross_check(text)
|
| 1734 |
sc={"ํต๊ณ":s1["score"],"๋ฌธ์ฒด":s2["score"],"๋ฐ๋ณต์ฑ":s3["score"],"๊ตฌ์กฐ":s4["score"],"์ง๋ฌธ":s5["score"]}
|
| 1735 |
+
sent_scores=[score_sentence(s)[0] for s in sents]
|
| 1736 |
+
sent_avg=sum(sent_scores)/len(sent_scores) if sent_scores else -1
|
| 1737 |
+
|
| 1738 |
+
# โ
๋ชจ๋ธ ์ถ์
|
| 1739 |
+
ms_raw=s5.get("model_scores",{})
|
| 1740 |
+
model_est=estimate_model(text,sents,morphs,ms_raw)
|
| 1741 |
+
|
| 1742 |
+
fs,verdict,level=compute_verdict(sc,lr["score"],sent_avg=sent_avg,ppx_score=ppx["score"],hum_score=hum["score"])
|
| 1743 |
progress(0.95)
|
| 1744 |
cm={"ai_high":("#FF4444","#FFE0E0","๋์"),"ai_medium":("#FF8800","#FFF0DD","์ค๊ฐ~๋์"),"ai_low":("#DDAA00","#FFFBE0","์ค๊ฐ"),"uncertain":("#888","#F0F0F0","๋ฎ์"),"human":("#22AA44","#E0FFE8","๋งค์ฐ ๋ฎ์")}
|
| 1745 |
fg,bg,conf=cm.get(level,("#888","#F0F0F0","?"))
|
|
|
|
|
|
|
| 1746 |
|
| 1747 |
+
# ๋ชจ๋ธ ์ถ์ ํ์
|
| 1748 |
+
est_model=model_est.get("model","ํน์ ๋ถ๊ฐ")
|
| 1749 |
+
est_conf=model_est.get("confidence","๋ฎ์")
|
| 1750 |
+
est_reasons=model_est.get("reasons",[])
|
| 1751 |
+
if est_model!="ํน์ ๋ถ๊ฐ" and est_conf!="๋ฎ์":
|
| 1752 |
+
mt=f"{est_model} (์ ๋ขฐ: {est_conf})"
|
| 1753 |
+
elif est_model!="ํน์ ๋ถ๊ฐ":
|
| 1754 |
+
mt=f"{est_model} (์ฐธ๊ณ )"
|
| 1755 |
+
else:
|
| 1756 |
+
mt="ํน์ ๋ถ๊ฐ"
|
| 1757 |
+
|
| 1758 |
+
ai_sents=sum(1 for s in sent_scores if s>=40)
|
| 1759 |
+
human_sents=sum(1 for s in sent_scores if s<20)
|
| 1760 |
|
| 1761 |
def gb(l,s,w="",desc=""):
|
| 1762 |
c="#FF4444" if s>=70 else "#FF8800" if s>=50 else "#DDAA00" if s>=35 else "#22AA44"
|
|
|
|
| 1764 |
dt=f"<div style='font-size:9px;color:#888;margin-top:1px;'>{desc}</div>" if desc else ""
|
| 1765 |
return f"<div style='margin:4px 0;'><div style='display:flex;justify-content:space-between;'><span style='font-size:11px;font-weight:600;'>{l}{wt}</span><span style='font-size:11px;font-weight:700;color:{c};'>{s}</span></div><div style='background:#E8E8E8;border-radius:4px;height:7px;'><div style='background:{c};height:100%;width:{s}%;border-radius:4px;'></div></div>{dt}</div>"
|
| 1766 |
|
| 1767 |
+
# ๋ชจ๋ธ ์ง๋ฌธ ๋ฐ
|
| 1768 |
mb=""
|
| 1769 |
for mn in ["GPT","Claude","Gemini","Perplexity"]:
|
| 1770 |
+
s=ms_raw.get(mn,0); mc="#FF4444" if s>=40 else "#FF8800" if s>=20 else "#CCC"
|
| 1771 |
+
# ์ถ์ ๋ชจ๋ธ ํ์
|
| 1772 |
+
tag=""
|
| 1773 |
+
if mn==est_model and est_conf!="๋ฎ์":
|
| 1774 |
+
tag=f" <span style='background:#FF4444;color:white;font-size:7px;padding:0 3px;border-radius:3px;'>์ถ์ </span>"
|
| 1775 |
+
mb+=f"<div style='display:flex;align-items:center;gap:4px;margin:2px 0;'><span style='width:66px;font-size:10px;font-weight:600;'>{mn}{tag}</span><div style='flex:1;background:#E8E8E8;border-radius:3px;height:5px;'><div style='background:{mc};height:100%;width:{s}%;'></div></div><span style='font-size:9px;width:18px;text-align:right;color:{mc};'>{s}</span></div>"
|
| 1776 |
|
| 1777 |
# LLM ์น์
|
| 1778 |
ls=""
|
| 1779 |
if lr["score"]>=0:
|
| 1780 |
+
lsc=lr["score"]
|
| 1781 |
lr_rows="".join(f"<div style='font-size:9px;color:#555;'>{mn}: {lr['detail'].get(mn,'โ')}</div>" for _,mn in LLM_JUDGES)
|
| 1782 |
ls=f"<div style='margin-top:8px;padding:8px;background:#F8F8FF;border-radius:6px;border:1px solid #E0E0FF;'><div style='font-size:10px;font-weight:700;margin-bottom:3px;'>๐ค LLM ๊ต์ฐจ๊ฒ์ฆ (ํ๊ท {lsc}%)</div>{lr_rows}</div>"
|
| 1783 |
else: ls="<div style='margin-top:6px;padding:4px 8px;background:#F5F5F5;border-radius:4px;color:#999;font-size:9px;'>๐ค GROQ_API_KEY ๋ฏธ์ค์ </div>"
|
|
|
|
| 1788 |
c="#22AA44" if s>=70 else "#4ECDC4" if s>=55 else "#DDAA00" if s>=40 else "#FF8800"
|
| 1789 |
return f"<div style='margin:2px 0;display:flex;align-items:center;gap:4px;'><span style='width:50px;font-size:10px;'>{l}</span><div style='flex:1;background:#E8E8E8;border-radius:3px;height:5px;'><div style='background:{c};height:100%;width:{s}%;'></div></div><span style='font-size:9px;color:{c};width:18px;text-align:right;'>{s}</span></div>"
|
| 1790 |
|
| 1791 |
+
# โ
ํ์ ์ด์ (3๋ ํฌ๋ฌ ํตํฉ)
|
| 1792 |
+
reasons=[]
|
| 1793 |
+
if sc["๋ฌธ์ฒด"]>=70: reasons.append("๊ฒฉ์์ฒด ์ข
๊ฒฐ์ด๋ฏธ๊ฐ ๋๋ถ๋ถ, AIํ ์ ์์ฌยท์ํฌํํ ๋ค์ ๊ฐ์ง")
|
| 1794 |
+
elif sc["๋ฌธ์ฒด"]>=50: reasons.append("๊ฒฉ์์ฒด์ AIํ ํํ์ด ํผ์ฌ")
|
| 1795 |
+
if ppx["score"]>=65: reasons.append(f"ํ
์คํธ ์์ธก ๊ฐ๋ฅ๋๊ฐ ๋งค์ฐ ๋์ (Perplexity {ppx['score']}์ )")
|
| 1796 |
+
elif ppx["score"]>=50: reasons.append(f"ํ
์คํธ ์์ธก ๊ฐ๋ฅ๋๊ฐ ๋์ (Perplexity {ppx['score']}์ )")
|
| 1797 |
+
if hum["score"]>=50:
|
| 1798 |
+
hum_sigs=", ".join(s[0] for s in hum["signals"][:3])
|
| 1799 |
+
reasons.append(f"โ ๏ธ Humanizer/ํจ๋ฌํ๋ ์ด์ฆ ํ์ ๊ฐ์ง ({hum_sigs})")
|
| 1800 |
+
if sc["ํต๊ณ"]>=60: reasons.append("๋ฌธ์ฅ ๊ธธ์ด๊ฐ ๋งค์ฐ ๊ท ์ผํ์ฌ ๊ธฐ๊ณ์ ํจํด")
|
| 1801 |
+
if sc["๋ฐ๋ณต์ฑ"]>=50: reasons.append("๋ฌธ๋ ์ ์์ฌ ๋ฐ๋ณต, n-gram ํจํด ๊ฐ์ง")
|
| 1802 |
+
if sc["๊ตฌ์กฐ"]>=50: reasons.append("์ถ์์ ์์์ด ๋ค์, ๊ตฌ์ฒด์ ์ฌ์ค ๋ถ์กฑ")
|
| 1803 |
+
if est_model!="ํน์ ๋ถ๊ฐ" and est_conf!="๋ฎ์":
|
| 1804 |
+
est_why=", ".join(est_reasons[:2]) if est_reasons else ""
|
| 1805 |
+
reasons.append(f"๐ ์ถ์ ๋ชจ๋ธ: <b>{est_model}</b> ({est_why})")
|
| 1806 |
if not reasons: reasons.append("์ธ๊ฐ์ ํํ์ด ์ฐ์ธํ๋ฉฐ AI ํจํด์ด ์ฝํจ")
|
| 1807 |
+
reason_html='<br>'.join(f"โข {r}" for r in reasons)
|
| 1808 |
+
|
| 1809 |
+
# โ
Perplexity ์นด๋
|
| 1810 |
+
ppx_c="#FF4444" if ppx["score"]>=65 else "#FF8800" if ppx["score"]>=50 else "#DDAA00" if ppx["score"]>=35 else "#22AA44"
|
| 1811 |
+
ppx_html=f"""<div style='margin-top:8px;padding:8px;background:linear-gradient(135deg,#FFF8F0,#FFF0FF);border-radius:6px;border:1px solid #E8D0FF;'>
|
| 1812 |
+
<div style='font-size:10px;font-weight:700;margin-bottom:4px;'>๐ง Perplexity ๋ถ์ <span style='color:{ppx_c};font-size:12px;font-weight:900;'>{ppx["score"]}์ </span></div>
|
| 1813 |
+
<div style='display:grid;grid-template-columns:1fr 1fr;gap:2px;'>
|
| 1814 |
+
<span style='font-size:9px;color:#777;'>์ํธ๋กํผ: {ppx.get("entropy",0)}</span>
|
| 1815 |
+
<span style='font-size:9px;color:#777;'>๋ถ์ฐ๊ท ์ผ: {ppx.get("variance",0)}</span>
|
| 1816 |
+
<span style='font-size:9px;color:#777;'>์ด์์์ธก: {ppx.get("order",0)}</span>
|
| 1817 |
+
<span style='font-size:9px;color:#777;'>Zipf์ ํฉ: {ppx.get("zipf",0)}</span>
|
| 1818 |
+
</div>
|
| 1819 |
+
</div>"""
|
| 1820 |
+
|
| 1821 |
+
# โ
Humanizer ํ์ง ์นด๋
|
| 1822 |
+
hum_html=""
|
| 1823 |
+
if hum["score"]>=30:
|
| 1824 |
+
hc="#FF4444" if hum["score"]>=65 else "#FF8800" if hum["score"]>=50 else "#DDAA00"
|
| 1825 |
+
sig_rows="".join(f"<div style='font-size:9px;color:#555;'>๐ธ {s[0]}: {s[2]}</div>" for s in hum["signals"][:4])
|
| 1826 |
+
hum_html=f"""<div style='margin-top:8px;padding:8px;background:linear-gradient(135deg,#FFF0F0,#FFF5F0);border-radius:6px;border:1px solid #FFD0D0;'>
|
| 1827 |
+
<div style='font-size:10px;font-weight:700;margin-bottom:3px;'>๐ก๏ธ Humanizer ํ์ง <span style='color:{hc};font-size:12px;font-weight:900;'>{hum["score"]}์ </span></div>
|
| 1828 |
+
{sig_rows}
|
| 1829 |
+
</div>"""
|
| 1830 |
+
|
| 1831 |
+
# โ
๋ชจ๋ธ ์ถ์ ์นด๋
|
| 1832 |
+
est_html=""
|
| 1833 |
+
if est_model!="ํน์ ๋ถ๊ฐ":
|
| 1834 |
+
ec="#FF4444" if est_conf=="๋์" else "#FF8800" if est_conf=="์ค๊ฐ" else "#DDAA00"
|
| 1835 |
+
ranked_html=""
|
| 1836 |
+
for m, ev in model_est.get("ranked",[])[:4]:
|
| 1837 |
+
ms_c="#FF4444" if ev["score"]>=30 else "#FF8800" if ev["score"]>=15 else "#CCC"
|
| 1838 |
+
bar_w=min(100,int(ev["score"]*1.5))
|
| 1839 |
+
ranked_html+=f"<div style='display:flex;align-items:center;gap:4px;margin:1px 0;'><span style='width:55px;font-size:9px;font-weight:600;'>{m}</span><div style='flex:1;background:#E8E8E8;border-radius:3px;height:4px;'><div style='background:{ms_c};height:100%;width:{bar_w}%;border-radius:3px;'></div></div><span style='font-size:8px;color:{ms_c};'>{ev['score']:.0f}</span></div>"
|
| 1840 |
+
est_html=f"""<div style='margin-top:8px;padding:8px;background:linear-gradient(135deg,#F0F8FF,#F0FFF0);border-radius:6px;border:1px solid #D0E8FF;'>
|
| 1841 |
+
<div style='font-size:10px;font-weight:700;margin-bottom:3px;'>๐ฏ AI ๋ชจ๋ธ ์ถ์ : <span style='color:{ec};font-size:12px;font-weight:900;'>{est_model}</span> <span style='font-size:9px;color:#888;'>(์ ๋ขฐ: {est_conf})</span></div>
|
| 1842 |
+
{ranked_html}
|
| 1843 |
+
<div style='font-size:8px;color:#999;margin-top:2px;'>๊ทผ๊ฑฐ: {", ".join(est_reasons[:3]) if est_reasons else "๋ณตํฉ ์งํ"}</div>
|
| 1844 |
+
</div>"""
|
| 1845 |
|
| 1846 |
html=f"""<div style="font-family:'Pretendard','Noto Sans KR',sans-serif;max-width:720px;margin:0 auto;">
|
|
|
|
| 1847 |
<div style="background:{bg};border:2px solid {fg};border-radius:14px;padding:20px;margin-bottom:12px;">
|
| 1848 |
<div style="display:flex;align-items:center;gap:16px;">
|
| 1849 |
<div style="text-align:center;min-width:100px;">
|
|
|
|
| 1867 |
|
| 1868 |
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
|
| 1869 |
<div style="background:#FAFAFA;border-radius:8px;padding:10px;">
|
| 1870 |
+
<div style="font-size:10px;font-weight:700;margin-bottom:4px;">๐ AI ํ์ง 5์ถ + Perplexity</div>
|
| 1871 |
+
{gb('โ ํต๊ณ',sc['ํต๊ณ'],'.06','Burstinessยท๋ณต์ก๋ ๊ท ์ผ์ฑ')}
|
| 1872 |
+
{gb('โก ๋ฌธ์ฒด',sc['๋ฌธ์ฒด'],'.25','๊ฒฉ์ยท์ ์์ฌยท์๋ณด๊ตฌ๋ฌธ')}
|
| 1873 |
+
{gb('โข ๋ฐ๋ณต',sc['๋ฐ๋ณต์ฑ'],'.10','n-gramยท๋ฌธ๋ยท์ข
๊ฒฐ๋ค์์ฑ')}
|
| 1874 |
+
{gb('โฃ ๊ตฌ์กฐ',sc['๊ตฌ์กฐ'],'.12','์ถ์์ฑ/๊ตฌ์ฒด์ฑ')}
|
| 1875 |
+
{gb('โค ์ง๋ฌธ',sc['์ง๋ฌธ'],'.30','GPT/Claude/Gemini/PPX')}
|
| 1876 |
+
{gb('โฅ PPX',ppx['score'],'.17','์์ธก๊ฐ๋ฅ๋ยท์ํธ๋กํผ')}
|
| 1877 |
</div>
|
| 1878 |
<div style="background:#FAFAFA;border-radius:8px;padding:10px;">
|
| 1879 |
<div style="font-size:10px;font-weight:700;margin-bottom:4px;">๐ ๋ชจ๋ธ ์ง๋ฌธ</div>
|
|
|
|
| 1887 |
</div>
|
| 1888 |
</div>
|
| 1889 |
</div>
|
| 1890 |
+
{ppx_html}{hum_html}{est_html}{ls}
|
| 1891 |
</div>"""
|
| 1892 |
+
log=f"AI:{fs}์ [{verdict}] ์ ๋ขฐ:{conf} | ๋ชจ๋ธ:{mt} | PPX:{ppx['score']} HUM:{hum['score']} | ํ์ง:{qr['grade']}({qr['score']})\n์ถ: ํต๊ณ{sc['ํต๊ณ']} ๋ฌธ์ฒด{sc['๋ฌธ์ฒด']} ๋ฐ๋ณต{sc['๋ฐ๋ณต์ฑ']} ๊ตฌ์กฐ{sc['๊ตฌ์กฐ']} ์ง๋ฌธ{sc['์ง๋ฌธ']} PPX{ppx['score']} HUM{hum['score']}"
|
| 1893 |
return html, log
|
| 1894 |
|
| 1895 |
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
|
|
| 1982 |
sents_all = split_sentences(full_text)
|
| 1983 |
words_all = split_words(full_text)
|
| 1984 |
morphs_all = get_morphemes(full_text)
|
| 1985 |
+
total_score, total_verdict, total_level, total_axes, total_ppx, total_hum = quick_score(full_text)
|
| 1986 |
quality = analyze_quality(full_text, sents_all, words_all, morphs_all)
|
| 1987 |
|
| 1988 |
# LLM ๊ต์ฐจ๊ฒ์ฆ (์ ์ฒด)
|
|
|
|
| 1991 |
if llm_result["score"] >= 0:
|
| 1992 |
_sent_scores = [score_sentence(s)[0] for s in sents_all]
|
| 1993 |
_sent_avg = sum(_sent_scores)/len(_sent_scores) if _sent_scores else -1
|
| 1994 |
+
total_score, total_verdict, total_level = compute_verdict(total_axes, llm_result["score"], sent_avg=_sent_avg, ppx_score=total_ppx["score"], hum_score=total_hum["score"])
|
| 1995 |
|
| 1996 |
# ์น์
๋ณ ๋ถ์
|
| 1997 |
progress(0.45, f"{len(sections)}๊ฐ ์น์
๋ถ์...")
|
|
|
|
| 2000 |
if len(sec.strip()) < 20:
|
| 2001 |
section_results.append({"idx": i+1, "text": sec, "score": -1, "verdict": "๋๋ฌด ์งง์", "skipped": True})
|
| 2002 |
continue
|
| 2003 |
+
s_score, s_verdict, s_level, s_axes, _, _ = quick_score(sec)
|
| 2004 |
# ๋ฌธ์ฅ๋ณ ํ์ด๋ผ์ดํธ
|
| 2005 |
sec_sents = split_sentences(sec)
|
| 2006 |
sent_scores = []
|