File size: 5,934 Bytes
81678dc
2c2a4ee
81678dc
46f9aa4
09849b4
fa6dca9
81678dc
2f46d2c
ea0f5b7
81678dc
6ff35fe
273e879
 
2c2a4ee
273e879
 
 
 
 
09849b4
81678dc
273e879
81678dc
 
 
6ff35fe
81678dc
 
 
09849b4
 
81678dc
 
4c2b05c
81678dc
 
 
 
 
 
09849b4
81678dc
 
4c2b05c
09849b4
2f46d2c
09849b4
 
 
 
 
 
2f46d2c
273e879
 
 
fa6dca9
06a87e5
fa6dca9
 
 
273e879
09849b4
 
fa6dca9
09849b4
 
fa6dca9
 
288a085
273e879
 
fa6dca9
06a87e5
 
fa6dca9
273e879
09849b4
 
06a87e5
09849b4
 
06a87e5
fa6dca9
288a085
06a87e5
273e879
fa6dca9
06a87e5
 
fa6dca9
273e879
09849b4
 
06a87e5
09849b4
 
06a87e5
fa6dca9
2f46d2c
09849b4
273e879
2f46d2c
 
09849b4
c6e608a
81678dc
 
2c2a4ee
ea0f5b7
81678dc
 
 
6ff35fe
81678dc
 
2f46d2c
2c2a4ee
 
 
46f9aa4
09849b4
 
46f9aa4
09849b4
 
46f9aa4
 
 
2c2a4ee
2f46d2c
 
 
 
 
 
 
 
2c2a4ee
 
 
2f46d2c
 
77ee20a
06a87e5
 
2c2a4ee
 
06a87e5
2c2a4ee
 
06a87e5
2c2a4ee
2f46d2c
2c2a4ee
 
2f46d2c
ea0f5b7
06a87e5
81678dc
2c2a4ee
 
 
 
06a87e5
2c2a4ee
 
06a87e5
2c2a4ee
2f46d2c
2c2a4ee
 
2f46d2c
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
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Dict, Any
# utils ํด๋” ํ™•์ธ ํ•„์ˆ˜
from utils import tarot, calculations, prompts, llm 
import os
import traceback

app = FastAPI(title="AI Pantheon API")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# --- 1. ์š”์ฒญ ๋ชจ๋ธ ---
class TarotRequest(BaseModel):
    cards: List[str]
    topic: str
    query: str
    lang: str = "ํ•œ๊ตญ์–ด"

class FengShuiRequest(BaseModel):
    year: int
    gender: str
    door_dir: str  
    head_dir: str  
    query: str
    lang: str = "ํ•œ๊ตญ์–ด"

class SajuRequest(BaseModel):
    year: int
    month: int
    day: int
    hour: int
    minute: int
    calendar_type: str 
    query: str
    lang: str = "ํ•œ๊ตญ์–ด"

# --- 2. ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ๊ธฐ (๐Ÿ”ฅ ๋‹ค๊ตญ์–ด ์™„๋ฒฝ ์ง€์› ์ˆ˜์ •!) ---
def get_dynamic_persona(role_type: str, lang: str) -> Dict[str, str]:
    # ์–ธ์–ด๊ฐ’์ด ๋น„์–ด์žˆ์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์˜์–ด
    target_lang = lang if lang else "English"
    
    # ํ•œ๊ตญ์–ด ํŠนํ™” ์ฒ˜๋ฆฌ (ํ•œ๊ตญ์–ด๋Š” ๋‰˜์•™์Šค๊ฐ€ ์ค‘์š”ํ•ด์„œ ๋”ฐ๋กœ ๋บŒ)
    is_korean = any(k in target_lang for k in ["ํ•œ๊ตญ", "Korean", "ko"])
    
    prompt_text = ""
    
    if role_type == "tarot":
        if is_korean:
            prompt_text = """
            ๋‹น์‹ ์€ ํƒ€๋กœ ๋ฆฌ๋” '์—๋ฐ€๋ฆฌ'์ž…๋‹ˆ๋‹ค. 
            ์‚ฌ์šฉ์ž์˜ ๊ณ ๋ฏผ์— ๋Œ€ํ•ด ๋”ฐ๋œปํ•˜๊ณ  ์ง๊ด€์ ์ธ ํ†ต์ฐฐ๋ ฅ์„ ์ œ๊ณตํ•˜์„ธ์š”.
            ๋งํˆฌ: ๋ถ€๋“œ๋Ÿฝ๊ณ  ์‹ ๋น„๋กœ์šด ์กด๋Œ“๋ง (ํ•ด์š”์ฒด).
            """
        else:
            # ๐Ÿ”ฅ [์ˆ˜์ •] ์˜์–ด๊ฐ€ ์•„๋‹ˆ๋ผ {target_lang}์œผ๋กœ ๋‹ต๋ณ€ํ•˜๋ผ๊ณ  ์ง€์‹œ
            prompt_text = f"""
            You are 'Emily', a mysterious Tarot Reader.
            CRITICAL INSTRUCTION: You must ANSWER STRICTLY IN {target_lang}.
            Even if the user input is in another language, TRANSLATE your reading to {target_lang}.
            Tone: Mystical, soft, empathetic.
            """
            
    elif role_type == "fengshui":
        if is_korean:
            prompt_text = """
            ๋‹น์‹ ์€ ํ’์ˆ˜์ง€๋ฆฌ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ๋…ผ๋ฆฌ์ ์ด๊ณ  ์ „๋ฌธ์ ์œผ๋กœ ํ•œ๊ตญ์–ด๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”.
            """
        else:
            # ๐Ÿ”ฅ [์ˆ˜์ •] {target_lang} ์‚ฌ์šฉ
            prompt_text = f"""
            You are a Feng Shui Master.
            CRITICAL INSTRUCTION: You must ANSWER STRICTLY IN {target_lang}.
            Do NOT mention translation. Speak with authority as a Master in {target_lang}.
            Tone: Professional, logical, wise.
            """

    elif role_type == "shaman":
        if is_korean:
            prompt_text = """
            ๋‹น์‹ ์€ ๋ฌด๋‹น '์ฒœ๋ช…'์ž…๋‹ˆ๋‹ค. 
            ๊ฑฐ์นœ ๋ฐ˜๋ง(~ํ•ด๋ผ, ~๊ตฌ๋‚˜)์„ ์“ฐ๋ฉฐ ํ•œ๊ตญ์–ด๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”.
            """
        else:
            # ๐Ÿ”ฅ [์ˆ˜์ •] {target_lang} ์‚ฌ์šฉ
            prompt_text = f"""
            You are 'Shaman Cheon-Myeong'.
            CRITICAL INSTRUCTION: You must ANSWER STRICTLY IN {target_lang}.
            Speak directly to the user's soul in {target_lang}.
            Tone: Mystical, Charismatic, slightly archaic style.
            """
    else:
        prompt_text = f"Answer strictly in {target_lang}."

    return {"system_prompt": prompt_text}

# --- 3. ์—”๋“œํฌ์ธํŠธ ---

@app.get("/")
def read_root():
    return {"message": "Server is Running!"}

@app.get("/tarot/deck")
def get_tarot_deck():
    return tarot.MAJOR_ARCANA

@app.post("/tarot/read")
def read_tarot(req: TarotRequest):
    try:
        selected_cards = [card for card in tarot.MAJOR_ARCANA if card["name"] in req.cards]
        persona = get_dynamic_persona("tarot", req.lang)
        
        card_infos = []
        # ์นด๋“œ ์„ค๋ช…์€ ํ•œ๊ตญ์–ด ์•„๋‹ˆ๋ฉด ์ผ๋‹จ ์˜์–ด๋กœ ๋‚˜๊ฐ (์ถ”ํ›„ ๋ฒ ํŠธ๋‚จ์–ด DB ์žˆ์œผ๋ฉด ์—ฌ๊ธฐ๋„ ๋ถ„๊ธฐ ๊ฐ€๋Šฅ)
        is_kor = "ํ•œ๊ตญ" in req.lang or "Korean" in req.lang
        for c in selected_cards:
            desc = c.get('desc_kor') if is_kor else c.get('desc_eng') or c.get('desc')
            if not desc: desc = "No description"
            card_infos.append(f"- {c['name']}: {desc}")
            
        card_str = "\n".join(card_infos)
        
        full_query = f"""
        Topic: {req.topic}
        User Question: {req.query}
        Selected Cards:
        {card_str}
        """
        
        response = llm.get_ai_response(full_query, persona)
        return {"result": response}

    except Exception as e:
        print(traceback.format_exc())
        return {"result": f"Server Error: {str(e)}"}

@app.post("/fengshui/analyze")
def analyze_fengshui(req: FengShuiRequest):
    try:
        gender_kor = "๋‚จ์„ฑ" if req.gender in ["Male", "๋‚จ์„ฑ"] else "์—ฌ์„ฑ"
        fs_data = calculations.get_fengshui_advanced(req.year, gender_kor, req.door_dir, req.head_dir)
        
        persona = get_dynamic_persona("fengshui", req.lang)
        full_query = f"[FengShui Data]: {fs_data}\nUser Query: {req.query}"
        
        response = llm.get_ai_response(full_query, persona)
        return {"data": fs_data, "result": response}
    except Exception as e:
        return {"result": f"Error: {str(e)}"}

@app.post("/shaman/read")
def read_saju(req: SajuRequest):
    try:
        import datetime
        b_date = datetime.date(req.year, req.month, req.day)
        b_time = datetime.time(req.hour, req.minute)
        saju_data = calculations.get_ganji_full(b_date, b_time, req.calendar_type)
        
        persona = get_dynamic_persona("shaman", req.lang)
        full_query = f"[Saju Data]: {saju_data}\nUser Query: {req.query}"
        
        response = llm.get_ai_response(full_query, persona)
        return {"data": saju_data, "result": response}
    except Exception as e:
        return {"result": f"Error: {str(e)}"}