|
36 | 36 | openai_client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY) |
37 | 37 |
|
38 | 38 | # Content quality patterns |
39 | | -_MEANINGFUL_CHAR_PATTERN = re.compile(r'[가-힣a-zA-Z0-9]') |
40 | 39 | _HANGUL_JAMO_ONLY_PATTERN = re.compile(r'^[ㄱ-ㅎㅏ-ㅣ\s.,!?~ㅋㅎㅠㅜ]+$') |
| 40 | +_REPEATED_CHAR_PATTERN = re.compile(r'(.)\1{3,}') # 같은 문자 4번 이상 반복 |
41 | 41 | _MIN_CONTENT_LENGTH = 20 # 본문 최소 글자수 기준 |
42 | 42 |
|
43 | 43 |
|
@@ -421,23 +421,28 @@ def _calculate_content_quality(experience: Experience) -> float: |
421 | 421 |
|
422 | 422 | combined = " ".join(content_parts) |
423 | 423 |
|
| 424 | + total_chars = len(combined.replace(" ", "")) |
| 425 | + if total_chars == 0: |
| 426 | + return 0.1 |
| 427 | + |
424 | 428 | # 자모만으로 이루어진 텍스트 (ㅋㅋㅋ, ㅎㅎㅎ 등) |
425 | 429 | if _HANGUL_JAMO_ONLY_PATTERN.match(combined): |
426 | 430 | return 0.1 |
427 | 431 |
|
428 | | - # 의미 있는 문자 비율 (완성된 한글, 영문, 숫자) |
429 | | - meaningful_chars = len(_MEANINGFUL_CHAR_PATTERN.findall(combined)) |
430 | | - total_chars = len(combined.replace(" ", "")) |
431 | | - |
432 | | - if total_chars == 0: |
| 432 | + # 같은 문자 반복 패턴 (aaaa, ㅋㅋㅋㅋ 등) |
| 433 | + if _REPEATED_CHAR_PATTERN.search(combined): |
433 | 434 | return 0.1 |
434 | 435 |
|
435 | | - quality_ratio = meaningful_chars / total_chars |
| 436 | + # 문자 다양성이 극단적으로 낮으면 쓰레기 입력 (abcabc, 123123 등) |
| 437 | + unique_ratio = len(set(combined.replace(" ", ""))) / total_chars |
| 438 | + if unique_ratio < 0.2: |
| 439 | + return 0.1 |
436 | 440 |
|
437 | | - # 최소 글자수 기준 미만이면 감점 |
438 | | - length_factor = min(len(combined) / _MIN_CONTENT_LENGTH, 1.0) |
| 441 | + # 최소 글자수 미만이면 소폭 감점, 그 외는 정상 |
| 442 | + if total_chars < _MIN_CONTENT_LENGTH: |
| 443 | + return 0.7 |
439 | 444 |
|
440 | | - return min(quality_ratio * length_factor, 1.0) |
| 445 | + return 1.0 |
441 | 446 |
|
442 | 447 |
|
443 | 448 | def _calculate_category_matching_score(experience_category: str, question_category: str | None) -> float: |
|
0 commit comments