seawolf2357 commited on
Commit
040bfa1
Β·
verified Β·
1 Parent(s): 5df96e9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -5
app.py CHANGED
@@ -502,17 +502,108 @@ def analyze_quality(text, sentences, words, morphemes):
502
  # ═══════════════════════════════════════════════
503
  LLM_JUDGES = [("openai/gpt-oss-120b","GPT-OSS 120B"),("qwen/qwen3-32b","Qwen3 32B"),("moonshotai/kimi-k2-instruct-0905","Kimi-K2")]
504
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  def llm_cross_check(text):
506
  if not GROQ_KEY: return {"score":-1,"detail":{}}
507
- prompt = f"AI ν…μŠ€νŠΈ 탐지 μ „λ¬Έκ°€λ‘œμ„œ 뢄석. 1) AI vs μ‚¬λžŒ+κ·Όκ±°3 2) λ§ˆμ§€λ§‰μ€„: \"AIν™•λ₯ : XX%\"\n\n[ν…μŠ€νŠΈ]\n{text[:2000]}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  votes=[]; rpt={}
509
  for mid,mn in LLM_JUDGES:
510
  resp,err = call_groq(mid,prompt)
511
  if resp:
512
- pm = re.search(r'AI\s*ν™•λ₯ [:\s]*(\d+)',resp)
513
- if pm: p=int(pm.group(1)); votes.append(p); rpt[mn]=f"{p}%"
514
- else: rpt[mn]="νŒŒμ‹±μ‹€νŒ¨"
515
- else: rpt[mn]=f"ERR"
 
 
 
 
 
516
  if votes: return {"score":int(sum(votes)/len(votes)),"detail":rpt}
517
  return {"score":-1,"detail":rpt}
518
 
 
502
  # ═══════════════════════════════════════════════
503
  LLM_JUDGES = [("openai/gpt-oss-120b","GPT-OSS 120B"),("qwen/qwen3-32b","Qwen3 32B"),("moonshotai/kimi-k2-instruct-0905","Kimi-K2")]
504
 
505
+ def _parse_ai_probability(raw_resp):
506
+ """LLM μ‘λ‹΅μ—μ„œ AI ν™•λ₯ (0~100)을 μΆ”μΆœ. ν•œκ΅­μ–΄/μ˜μ–΄ λ‹€μ–‘ν•œ ν˜•μ‹ λŒ€μ‘."""
507
+ if not raw_resp: return -1
508
+ # 1. <think> νƒœκ·Έ 뢄리
509
+ think_content = ''
510
+ think_m = re.search(r'<think>(.*?)</think>', raw_resp, flags=re.S)
511
+ if think_m: think_content = think_m.group(1)
512
+ resp = re.sub(r'<think>.*?</think>', '', raw_resp, flags=re.S).strip()
513
+ if not resp or len(resp) < 5:
514
+ resp = raw_resp # think만 있으면 원본 포함
515
+
516
+ # 2. νŠΉμ • ν‚€μ›Œλ“œ νŒ¨ν„΄ (높은 μš°μ„ μˆœμœ„ β€” 첫 λ§€μΉ­)
517
+ specific_patterns = [
518
+ r'AI\s*ν™•λ₯ \s*[::]\s*(?:μ•½\s*)?(\d+)\s*%?',
519
+ r'AI\s*[Pp]robability\s*[::]\s*(?:about|approximately?\s*)?(\d+)\s*%?',
520
+ r'[Pp]robability\s*(?:of\s*)?(?:being\s*)?AI\s*[::\-]\s*(?:about|approximately?\s*)?(\d+)\s*%?',
521
+ r'AI\s*(?:생성|μž‘μ„±|νŒμ •)?\s*ν™•λ₯ \s*[::]?\s*(?:μ•½\s*)?(\d+)',
522
+ r'(?:Score|Rating|Confidence)\s*[::]\s*(\d+)',
523
+ r'(\d+)\s*%\s*(?:의\s*)?(?:ν™•λ₯ |κ°€λŠ₯μ„±|probability|likely|chance|likelihood)',
524
+ r'(?:신뒰도|확신도)\s*[::]?\s*(?:μ•½\s*)?(\d+)\s*(?:%|νΌμ„ΌνŠΈ)',
525
+ r'(?:μ•½\s*)?(\d+)\s*(?:%|νΌμ„ΌνŠΈ)\s*(?:정도|μˆ˜μ€€)',
526
+ ]
527
+ for pat in specific_patterns:
528
+ m = re.search(pat, resp, re.I)
529
+ if m:
530
+ v = int(m.group(1))
531
+ if 0 <= v <= 100: return v
532
+
533
+ # 3. λ²”μš© νŒ¨ν„΄ β€” λ§ˆμ§€λ§‰ 5μ€„μ—μ„œλ§Œ 검색 (톡계 수치 μ˜€νƒ λ°©μ§€)
534
+ lines = [l.strip() for l in resp.strip().split('\n') if l.strip()]
535
+ for line in reversed(lines[-5:]):
536
+ # 라인에 AI/ν™•λ₯ /probability ν‚€μ›Œλ“œκ°€ 있으면 μš°μ„ 
537
+ if re.search(r'AI|ν™•λ₯ |[Pp]robab|μ‹ λ’°|판[정단]', line):
538
+ nums = re.findall(r'(\d+)\s*%', line)
539
+ if nums:
540
+ v = int(nums[-1])
541
+ if 0 <= v <= 100: return v
542
+ nums = re.findall(r'(\d+)\s*νΌμ„ΌνŠΈ', line)
543
+ if nums:
544
+ v = int(nums[-1])
545
+ if 0 <= v <= 100: return v
546
+
547
+ # 4. 전체 ν…μŠ€νŠΈμ—μ„œ λ§ˆμ§€λ§‰ XX% (단, AI/ν™•λ₯  근처만)
548
+ all_pcts = list(re.finditer(r'(\d+)\s*(?:%|νΌμ„ΌνŠΈ|percent)', resp, re.I))
549
+ for m in reversed(all_pcts):
550
+ v = int(m.group(1))
551
+ # μ£Όλ³€ 50자 내에 AI/ν™•λ₯  ν‚€μ›Œλ“œ μžˆλŠ”μ§€
552
+ ctx_start = max(0, m.start()-50)
553
+ ctx = resp[ctx_start:m.end()+20]
554
+ if re.search(r'AI|ν™•λ₯ |[Pp]robab|μ‹ λ’°|판[정단]|κ°€λŠ₯μ„±|likelihood', ctx, re.I):
555
+ if 0 <= v <= 100: return v
556
+
557
+ # 5. μ΅œν›„ μˆ˜λ‹¨: μ „μ²΄μ—μ„œ λ§ˆμ§€λ§‰ XX%
558
+ if all_pcts:
559
+ v = int(all_pcts[-1].group(1))
560
+ if 5 <= v <= 99: return v # 100% μ œμ™Έ (톡계 수치 μ˜€νƒ λ°©μ§€)
561
+
562
+ # 6. think λ‚΄λΆ€ 폴백 (λ³Έλ¬Έ νŒŒμ‹± μ‹€νŒ¨ μ‹œ)
563
+ if think_content:
564
+ for pat in specific_patterns:
565
+ m = re.search(pat, think_content, re.I)
566
+ if m:
567
+ v = int(m.group(1))
568
+ if 0 <= v <= 100: return v
569
+ # think λ‚΄λΆ€ λ§ˆμ§€λ§‰ XX%
570
+ think_pcts = re.findall(r'(\d+)\s*%', think_content)
571
+ if think_pcts:
572
+ v = int(think_pcts[-1])
573
+ if 5 <= v <= 99: return v
574
+
575
+ return -1
576
+
577
  def llm_cross_check(text):
578
  if not GROQ_KEY: return {"score":-1,"detail":{}}
579
+ # ν•œκ΅­μ–΄+μ˜μ–΄ 병행 ν”„λ‘¬ν”„νŠΈ (GPT-OSSλŠ” μ˜μ–΄ λͺ¨λΈμ΄λ―€λ‘œ)
580
+ prompt = f"""Analyze whether this text was written by AI.
581
+
582
+ [Instructions]
583
+ 1. Determine AI vs Human with 3 brief reasons
584
+ 2. IMPORTANT - Your LAST line MUST be exactly this format:
585
+ AIν™•λ₯ : XX%
586
+ (Replace XX with your estimated probability 0-100)
587
+
588
+ Example of correct last line:
589
+ AIν™•λ₯ : 75%
590
+
591
+ [Text to analyze]
592
+ {text[:2000]}"""
593
+
594
  votes=[]; rpt={}
595
  for mid,mn in LLM_JUDGES:
596
  resp,err = call_groq(mid,prompt)
597
  if resp:
598
+ p = _parse_ai_probability(resp)
599
+ if p >= 0:
600
+ votes.append(p); rpt[mn]=f"{p}%"
601
+ else:
602
+ # 디버그: think 제거 ν›„ 응닡 끝뢀뢄
603
+ cleaned = re.sub(r'<think>.*?</think>', '', resp, flags=re.S).strip()
604
+ tail = cleaned[-60:].replace('\n',' ') if len(cleaned) > 60 else cleaned.replace('\n',' ')
605
+ rpt[mn]=f"νŒŒμ‹±μ‹€νŒ¨({tail[:40]})"
606
+ else: rpt[mn]=f"ERR:{err[:30] if err else '?'}"
607
  if votes: return {"score":int(sum(votes)/len(votes)),"detail":rpt}
608
  return {"score":-1,"detail":rpt}
609