coconut / src /pipeline /text_processor.py
alohaboy
docs: Update report note text to emphasize medical validation
fa59ba6
# echolalia_assistant/src/pipeline/text_processor.py
"""
gradio_app.py의 process_text 함수를 위한 래퍼
새로운 3단계 Phase 파이프라인을 사용하여 기존 인터페이스와 호환
"""
from __future__ import annotations
from typing import Tuple, Optional
from .coconut_pipeline import run_full_analysis
from .models import UtteranceAnalysisRequest
def process_text_with_pipeline(
text: str,
context_situation: str,
situation: str = "기타",
profile_id: Optional[int] = None,
analysis_mode: str = "detailed"
) -> Tuple[bool, str, str, str, str, str, str]:
"""
새로운 3단계 Phase 파이프라인을 사용하여 텍스트 분석
Returns:
(is_echo, confidence_html, quick_summary_text, three_step_text, detailed_report, save_message, analysis_id)
analysis_id는 Optional[int]이지만 Tuple에서는 None을 반환
"""
# UtteranceAnalysisRequest 생성
user_id = str(profile_id) if profile_id else "anonymous"
# 대화 로그 구성 (간단한 형태)
dialogue_log = [
{"speaker": "caregiver", "utterance": context_situation or "상황 설명 없음"},
{"speaker": "child", "utterance": text}
]
req = UtteranceAnalysisRequest(
user_id=user_id,
context_description=context_situation or situation,
dialogue_log=dialogue_log,
)
# 파이프라인 실행
try:
result = run_full_analysis(req)
# 결과 파싱
is_echo = result.echolalia_detection.is_echolalia
# 신뢰도 계산 (반향어 감지 결과 기반)
# YJ 파이프라인 결과를 기반으로 더 세밀한 신뢰도 계산
if is_echo:
# 반향어가 탐지된 경우
# type, completeness, functional을 종합적으로 고려
type_weight = {
'immediate': 0.9, # 즉각적 반향어는 높은 신뢰도
'delayed': 0.7, # 지연 반향어는 중간 신뢰도
'mixed': 0.6, # 혼합은 낮은 신뢰도
'uncertain': 0.4 # 불확실은 더 낮은 신뢰도
}
completeness_weight = {
'full': 1.0,
'partial': 0.7,
'transformed': 0.5
}
# 기본 신뢰도 (type 기반)
base_confidence = type_weight.get(result.echolalia_detection.type, 0.5)
# completeness 조정
completeness_mult = completeness_weight.get(result.echolalia_detection.completeness, 0.7)
# functional 여부 조정
functional_bonus = 0.1 if result.echolalia_detection.functional else 0.0
# 최종 신뢰도 계산 (0.3 ~ 0.9 범위)
confidence = min(0.9, max(0.3, base_confidence * completeness_mult + functional_bonus))
else:
# 반향어가 아닌 경우 낮은 신뢰도
confidence = 0.2
# 기존 형식으로 변환
confidence_html = _generate_confidence_html(is_echo, confidence * 100)
quick_summary_text = _generate_quick_summary(result, text)
three_step_text = "" # 3단계 변환 제안 제거
detailed_report = _generate_detailed_report(
result, analysis_mode, text, context_situation, situation, profile_id, None
)
save_message = "분석 결과가 프로필에 저장되었습니다." if profile_id else "프로필을 선택하면 분석 결과가 자동으로 저장됩니다."
analysis_id = None # TODO: DB에 저장하고 ID 반환
return (is_echo, confidence_html, quick_summary_text, three_step_text, detailed_report, save_message, analysis_id)
except Exception as e:
# 오류 발생 시 기본값 반환
import traceback
error_trace = traceback.format_exc()
print(f"❌ process_text_with_pipeline 에러: {e}")
print(f"에러 상세:\n{error_trace}")
error_html = f"<div style='background: #fee; border: 2px solid #f44; border-radius: 8px; padding: 20px; margin: 15px 0; text-align: center;'><h3>❌ 분석 오류</h3><p>{str(e)}</p></div>"
return (False, error_html, "", "", "", f"분석 중 오류가 발생했습니다: {str(e)}", None) # 7개 반환값
def _generate_confidence_html(is_echo: bool, confidence: float) -> str:
"""신뢰도 HTML 생성"""
if confidence >= 70:
color = "#ef4444"
bg_color = "#fee2e2"
icon = "⚠️"
urgency = "관찰 필요"
elif confidence >= 40:
color = "#f59e0b"
bg_color = "#fef3c7"
icon = "📊"
urgency = "지속 관찰"
else:
color = "#10b981"
bg_color = "#d1fae5"
icon = "✅"
urgency = "양호"
return f"""
<div style='background: {bg_color}; border: 2px solid {color}; border-radius: 12px; padding: 20px; margin: 15px 0; text-align: center;'>
<div style='font-size: 48px; margin-bottom: 10px;'>{icon}</div>
<h2 style='color: {color}; margin: 5px 0;'>{confidence:.0f}%</h2>
<p style='color: {color}; font-size: 1.2rem; margin: 5px 0;'><strong>{urgency}</strong></p>
</div>
"""
def _generate_quick_summary(result, text: str) -> str:
"""빠른 요약 생성"""
is_echo = result.echolalia_detection.is_echolalia
primary_interpretation = result.meaning_inference.primary_interpretation
if is_echo:
return f"""
### ⚠️ 분석 결과 요약
**아이의 말**: "{text}"
{primary_interpretation}
"""
else:
return f"""
### ✅ 분석 결과 요약
**아이의 말**: "{text}"
정상적인 의사소통 패턴으로 보입니다. 🎉
"""
def _translate_echolalia_tag(tag: str) -> str:
"""반향어 기능 태그를 한국어로 변환"""
tag_map = {
"FILLING_TURN": "대화 차례 채우기",
"SAYING_YES": "동의 표현",
"LABELING_PRACTICE": "명명 연습",
"SELF_SOOTHING_ROUTINE": "자기 진정 루틴",
"STIMMING_VERBAL": "구어적 자극 행동",
"SOUND_PLEASURE": "소리 즐기기",
"LANGUAGE_PROCESSING_OUTLOUD": "언어 처리 발화",
"SITUATION_SCRIPT_REPLAY": "상황 스크립트 재현",
"COMMUNICATION_ATTEMPT": "의사소통 시도",
"ANXIETY_DEFENSE": "불안 방어",
}
return tag_map.get(tag, tag)
def _translate_relative_level(level: str) -> str:
"""발달 수준을 한국어로 변환"""
level_map = {
"strength": "강점 영역",
"age_appropriate": "또래 수준",
"age_appropriate_or_mild_delay": "또래 수준 (약간의 지연 가능)",
"developing": "발달 진행 중",
"emerging": "발달 시작 단계",
"needs_more_observation": "추가 관찰 필요",
}
return level_map.get(level, level)
def _generate_detailed_report(result, analysis_mode: str, text: str = "", context_situation: str = "",
situation: str = "기타", profile_id: int = None, analysis_id: int = None) -> str:
"""
상세 보고서 생성 - 새로운 파이프라인 결과만 사용하여 "아이의 말에 담긴 마음" 형식으로 생성
"""
if analysis_mode == "quick":
return ""
# 새로운 파이프라인 결과를 기반으로 "아이의 말에 담긴 마음" 형식의 보고서 생성
is_echo = result.echolalia_detection.is_echolalia
# 1️⃣ 아이의 언어 성향 분석 (Personal Profile) - 파이프라인 결과 기반
profile_info = ""
if result.development_profile.age_reference:
age_years = result.development_profile.age_reference // 12
age_months = result.development_profile.age_reference % 12
profile_info = f"""
**👶 기본 정보**
- **나이**: {age_years}{age_months}개월
- **반향어 경향**: {'높은 경향' if is_echo else '낮은 경향'} ({result.echolalia_detection.type or '미확인'})
"""
# 반향어 유형 및 기능 분석
echo_type_kr = {
'immediate': '즉시 반향어',
'delayed': '지연 반향어',
'mixed': '혼합형',
'uncertain': '불확실'
}.get(result.echolalia_detection.type, '미확인')
primary_function = ""
if result.meaning_inference.echolalia_functions:
top_function = result.meaning_inference.echolalia_functions[0]
function_tag_kr = _translate_echolalia_tag(top_function.tag)
primary_function = f"""
**🧠 언어 지도 (Language Map)**
아이는 **{echo_type_kr}**를 주로 사용하며,
반복 언어를 통해 **{function_tag_kr}** 기능을 하고 있습니다.
{top_function.caregiver_explanation}
**💡 언어 특성 이해**
- **사회적 상호작용**: {echo_type_kr}를 통한 의사소통 시도
- **언어적 유연성**: 반복을 통한 안정감 추구
- **감정 표현**: 반복 언어를 통한 내적 상태 전달
"""
personal_profile = f"""
### 1️⃣ 아이의 언어 성향 분석 (Personal Profile)
{profile_info}
{primary_function}
"""
# 2️⃣ 입력 발화 및 대화 분석 (Context & Function) - 파이프라인 결과 기반
context_interpretation = ""
if result.echolalia_detection.evidence:
if result.echolalia_detection.functional:
context_interpretation = "**상황과 잘 맞는 발화**입니다. 아이가 현재 상황을 이해하고 적절하게 반응하고 있습니다."
else:
context_interpretation = "**부분적으로 상황과 연관된 발화**입니다. 아이가 상황의 일부를 이해하고 있지만 완전한 연결은 어려워 보입니다."
else:
context_interpretation = "**상황과 무관한 발화**일 가능성이 높습니다. 아이가 이전에 들은 말을 현재 상황과 연결하지 못하고 있습니다."
function_type = "**의미 전달**" if result.echolalia_detection.functional else "**단순 모방**"
function_desc = "아이가 명확한 의미를 전달하려고 시도하고 있습니다." if result.echolalia_detection.functional else "아이가 이전에 들은 말을 그대로 반복하고 있습니다."
context_function_analysis = f"""
### 2️⃣ 입력 발화 및 대화 분석 (Context & Function)
**🗣️ 발화 내용**: "{text}"
**📍 맥락 분석**
- **상황**: {situation}
- **상황 설명**: {context_situation if context_situation else '제공되지 않음'}
{context_interpretation}
**🔍 기능 분석**
- **발화 유형**: {function_type}
- **설명**: {function_desc}
**💭 구체적 해석**
{result.meaning_inference.primary_interpretation}
**반향어 기능 분석**:
"""
for func in result.meaning_inference.echolalia_functions:
function_tag_kr = _translate_echolalia_tag(func.tag)
context_function_analysis += f"- **{function_tag_kr}** (신뢰도: {func.confidence:.1%}): {func.caregiver_explanation}\n"
# 3️⃣ 보완 방향 (Alternative & Strategy) - 파이프라인 결과 기반
caregiver_response = f"""
**🧡 보호자 반응 방식**
✅ **해야 할 것**
"""
for response in result.parent_guide.immediate_response:
caregiver_response += f"- {response}\n"
caregiver_response += f"""
**💬 아이를 위한 대안 발화 모델링**
"""
for utterance in result.parent_guide.modeling_utterance:
caregiver_response += f"- {utterance}\n"
caregiver_response += f"""
**🎯 장기 지원 팁**
"""
for tip in result.parent_guide.long_term_tips:
caregiver_response += f"- {tip}\n"
alternative_strategy = f"""
### 3️⃣ 보완 방향 (Alternative & Strategy)
{caregiver_response}
**📚 발달 영역별 평가 및 지원 방향**
"""
for domain, domain_profile in result.development_profile.domains.items():
domain_name_kr = {
'pragmatics': '화용론',
'semantics': '의미론',
'morphosyntax': '형태통사론',
'communicative_function': '의사소통 기능'
}.get(domain, domain)
level_kr = _translate_relative_level(domain_profile.relative_level)
alternative_strategy += f"""
**{domain_name_kr}**
- **수준**: {level_kr}
- **요약**: {domain_profile.summary}
- **참고사항**: {domain_profile.notes or '없음'}
"""
if result.development_profile.safety_note:
alternative_strategy += f"\n**안전 참고사항**: {result.development_profile.safety_note}\n"
# 최종 보고서 조립
report = f"""## 🌟 아이의 말에 담긴 마음 - 3단계 분석 보고서
**📌 참고사항**: 이 보고서는 coconut AI가 의학 자문을 통해 검증한 고유 데이터베이스를 기반으로 생성되었습니다.
{personal_profile}
{context_function_analysis}
{alternative_strategy}
---
*이 보고서는 공감적 접근을 바탕으로 한 AI 분석 시스템을 통해 생성되었습니다. 정확한 진단을 위해서는 전문가와의 상담을 권장합니다.*"""
return report