File size: 13,191 Bytes
caf53ab fa59ba6 caf53ab | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | # 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
|