"""
Persona prediction tool using LLM
"""
import os
import json
from groq import Groq
from ...db.database import get_session
from ...db.models import Persona, FGIResponse
def predict_persona(responses: list, user_id: str = None):
"""
설문 응답을 기반으로 사용자의 페르소나 예측/분석
Groq LLM을 사용하여 응답을 분석하고 페르소나 프로필 생성
:param responses: 설문 응답 리스트 [{"question_id": "q1", "answer": "답변"}]
:param user_id: 사용자 ID (선택사항)
:return: predicted_persona 정보
"""
try:
groq_api_key = os.getenv("GROQ_API_KEY")
if not groq_api_key:
return {"error": "GROQ_API_KEY 환경 변수가 설정되지 않았습니다."}
client = Groq(api_key=groq_api_key)
# 응답을 텍스트로 변환
responses_text = "\n".join([
f"Q: {resp.get('question_text', resp.get('question_id'))}\nA: {resp['answer']}"
for resp in responses
])
prompt = f"""다음은 사용자의 설문 응답입니다:
{responses_text}
이 응답을 분석하여 사용자의 페르소나를 예측해주세요.
**MBTI 스타일 성향 분석**도 포함해주세요.
다음 정보를 JSON 형식으로 반환해주세요:
{{
"age_range": "예측되는 연령대 (예: '20-30', '30-40', '40-50' 등)",
"interests": ["관심사1", "관심사2", "관심사3"],
"personality_traits": ["성격특성1", "성격특성2", "성격특성3"],
"values": ["가치관1", "가치관2", "가치관3"],
"lifestyle": "라이프스타일에 대한 간단한 설명 (한 문장)",
"mbti_type": "예측되는 MBTI 유형 (예: 'INTJ', 'ENFP' 등, 확실하지 않으면 null)",
"mbti_dimensions": {{
"E_I": "외향(E) 또는 내향(I) - 어디서 에너지를 얻는가",
"S_N": "감각(S) 또는 직관(N) - 정보를 어떻게 처리하는가",
"T_F": "사고(T) 또는 감정(F) - 결정을 어떻게 내리는가",
"J_P": "판단(J) 또는 인식(P) - 일상을 어떻게 구조화하는가"
}},
"mbti_confidence": 0-100,
"mbti_reason": "MBTI 유형 예측 근거",
"confidence": 85,
"matching_reason": "이 페르소나로 예측한 근거에 대한 간단한 설명"
}}
**MBTI 분석 가이드:**
- E(외향) vs I(내향): 사람들과 어울려서 에너지를 얻는가? 혼자 시간을 선호하는가?
- S(감각) vs N(직관): 구체적 사실과 현재에 집중하는가? 가능성과 패턴을 보는가?
- T(사고) vs F(감정): 논리와 객관성을 중시하는가? 가치와 조화를 중시하는가?
- J(판단) vs P(인식): 계획적이고 체계적인가? 유연하고 즉흥적인가?
주의:
- 모든 값은 한국어로 작성
- confidence는 0-100 사이의 숫자 (예측의 신뢰도)
- interests, personality_traits, values는 각각 3-5개 항목
- MBTI 유형이 명확하지 않으면 mbti_type을 null로 설정
- mbti_dimensions는 각 차원에 대한 설명을 포함
"""
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
max_tokens=600,
temperature=0.7
)
analysis = json.loads(response.choices[0].message.content)
matched_persona_id = None
if user_id:
with get_session() as session:
persona = session.query(Persona).filter_by(user_id=user_id).first()
if persona:
matched_persona_id = persona.id
persona.age_range = analysis.get("age_range")
persona.interests = analysis.get("interests")
persona.personality_traits = analysis.get("personality_traits")
persona.values = analysis.get("values")
persona.lifestyle = analysis.get("lifestyle")
# MBTI 정보 저장
persona.mbti_type = analysis.get("mbti_type")
persona.mbti_dimensions = analysis.get("mbti_dimensions")
persona.mbti_confidence = analysis.get("mbti_confidence")
session.commit()
return {
"predicted_persona": {
"persona_id": matched_persona_id,
"persona_profile": {
"age_range": analysis.get("age_range"),
"interests": analysis.get("interests", []),
"personality_traits": analysis.get("personality_traits", []),
"values": analysis.get("values", []),
"lifestyle": analysis.get("lifestyle", "")
},
"mbti_analysis": {
"mbti_type": analysis.get("mbti_type"),
"mbti_dimensions": analysis.get("mbti_dimensions", {}),
"mbti_confidence": analysis.get("mbti_confidence", 0),
"mbti_reason": analysis.get("mbti_reason", "")
},
"confidence": analysis.get("confidence", 0),
"matching_reason": analysis.get("matching_reason", "")
},
"matched_existing": matched_persona_id is not None,
"user_id": user_id
}
except Exception as e:
return {"error": f"페르소나 예측 중 오류 발생: {str(e)}"}