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