| import os |
| import requests |
| import re |
| import random |
| from datetime import datetime, timedelta |
| from typing import Union |
| from fastapi import APIRouter, Request |
| from fastapi.responses import JSONResponse, HTMLResponse |
| from fastapi.templating import Jinja2Templates |
| from pydantic import BaseModel |
| from google import genai |
|
|
| router = APIRouter() |
| templates = Jinja2Templates(directory="templates") |
|
|
| |
| GEMINI_API_KEYS = [] |
| default_key = os.environ.get("GEMINI_API_KEY") |
| if default_key: GEMINI_API_KEYS.append(default_key) |
| for i in range(1, 11): |
| key = os.environ.get(f"GEMINI_API_KEY{i}") |
| if key and key not in GEMINI_API_KEYS: GEMINI_API_KEYS.append(key) |
|
|
| SLACK_WEBHOOK_URL = os.environ.get("SLACK_WEBHOOK_URL") |
|
|
| def send_slack_message(message): |
| if not SLACK_WEBHOOK_URL: return |
| try: requests.post(SLACK_WEBHOOK_URL, json={"text": message}) |
| except: pass |
|
|
| class SajuRequest(BaseModel): |
| year: Union[str, int] |
| month: Union[str, int] |
| day: Union[str, int] |
| time: Union[str, int] = "์๊ฐ ๋ชจ๋ฆ" |
|
|
| @router.get("/saju", response_class=HTMLResponse) |
| async def main_saju(request: Request): |
| return templates.TemplateResponse("main_saju.html", {"request": request}) |
|
|
| @router.post("/analyze") |
| def analyze_saju(req: SajuRequest): |
| req_year = str(req.year) |
| req_month = str(req.month) |
| req_day = str(req.day) |
| req_time = str(req.time) |
|
|
| candidate_models = [ |
| "gemini-3-flash-preview", |
| "gemini-3-pro-preview", |
| "gemini-flash-latest" |
| ] |
| |
| birth_info = f"{req_year}๋
{req_month}์ {req_day}์ผ ({req_time})" |
| korea_now = datetime.now() + timedelta(hours=9) |
| today_date = korea_now.strftime("%Y๋
%m์ %d์ผ") |
| |
| prompt = f""" |
| ๋น์ ์ ํธ๋ ๋ํ 'ํผ์ค๋ ์ฌ์ฃผ ํจ์
๋๋ ํฐ' Theo์
๋๋ค. |
| |
| [์ฌ์ฉ์ ์ ๋ณด] |
| - ์๋
์์ผ: {birth_info} (์๋ ฅ/Solar Calendar ๊ธฐ์ค) |
| - ์์ฒญ์ฌํญ: ์ ์๋ ฅ ๋ ์ง๋ฅผ ๋ฐํ์ผ๋ก ์ ํํ ์ฌ์ฃผ๋ฅผ ๋ถ์ํ์ธ์. |
| |
| [ํ์ฌ ์์ ] |
| - ์ค๋ ๋ ์ง: {today_date} |
| |
| [์ถ๋ ฅ ๊ฐ์ด๋] |
| 1. **์ค์: ๋ชจ๋ ๊ฐ์กฐ(Bold) ์ฒ๋ฆฌ๋ ๋งํฌ๋ค์ด(**)์ด ์๋ HTML `<b>` ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ธ์.** |
| 2. ์ธ์ฌ๋ง: ๋ฐ๋์ `<div class="greeting">` ํ๊ทธ๋ก ๊ฐ์ธ์ ์์ฑํ์ธ์. |
| 3. ์๊ฐ ์๋ต: ์๊ธฐ์๊ฐ๋ ํ์ง ๋ง์ธ์. |
| 4. ํ์: ๋ชจ๋ ์น์
('์ค๋์ ์ฌ์ฃผ ๋ถ์', '์ค๋์ ํ์ด ์ปฌ๋ฌ', '์ค๋์ ํ์ด ๋ฒํธ', '์ค๋์ ์ถ์ฒ ์ฝ๋', '์ค๋์ ๋ง์โผผ๊ฐ์ง')์ <details><summary>... [๋ณด๊ธฐ]</summary></details> ํ๊ทธ๋ก ๊ฐ์ธ์ ์ ์ด๋์ธ์. |
| 5. **(ํ์)** '์ค๋์ ํ์ด ๋ฒํธ' ์น์
์ ์ถ๊ฐํ์ฌ 1๋ถํฐ 45 ์ฌ์ด์ ๊ฒน์น์ง ์๋ ์ซ์ 6๊ฐ๋ฅผ ์ถ์ฒํด ์ฃผ์ธ์. |
| 6. **(์์คํ
ํ์ฑ์ฉ - ๋งค์ฐ ์ค์)** ๋ฐฑ์๋ ์์คํ
ํ์ฑ์ ์ํด ์๋ต ํ
์คํธ ๋งจ ๋ง์ง๋ง ์ค์ ๋ฐ๋์ ์๋์ ๊ฐ์ ํ์์ HTML ์ฃผ์์ ์ถ๊ฐํ์ธ์. (์ซ์๋ ์ผํ๋ก ๊ตฌ๋ถ) |
| 7. ํค์ค๋งค๋: ์ ๋ฌธ์ ์ด๊ณ ์ฐ์ํ ์ด์กฐ. |
| """ |
|
|
| last_error = None |
| |
| if not GEMINI_API_KEYS: |
| return JSONResponse(content={'result': "<div class='greeting'>์๋ฒ์ API ํค๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.</div>"}) |
|
|
| send_slack_message(f"๐ฎ [Theo] ๋ถ์ ์์ฒญ: {birth_info}") |
|
|
| for key_idx, current_key in enumerate(GEMINI_API_KEYS): |
| key_alias = f"KEY_{key_idx+1}" |
| |
| try: |
| client = genai.Client(api_key=current_key) |
| except Exception: |
| continue |
|
|
| for model_name in candidate_models: |
| try: |
| response = client.models.generate_content( |
| model=model_name, |
| contents=prompt |
| ) |
| |
| if response.text: |
| send_slack_message(f"โ
[์ฑ๊ณต] {key_alias} / {model_name}") |
| |
| |
| |
| |
| text_result = response.text |
| lucky_numbers = [] |
| |
| |
| match = re.search(r'', text_result) |
| if match: |
| try: |
| num_str = match.group(1) |
| |
| lucky_numbers = [int(n.strip()) for n in num_str.split(',') if n.strip().isdigit()] |
| lucky_numbers = [n for n in lucky_numbers if 1 <= n <= 45] |
| lucky_numbers = list(set(lucky_numbers)) |
| except Exception: |
| pass |
| |
| |
| |
| while len(lucky_numbers) < 6: |
| rand_num = random.randint(1, 45) |
| if rand_num not in lucky_numbers: |
| lucky_numbers.append(rand_num) |
| |
| |
| lucky_numbers = lucky_numbers[:6] |
| lucky_numbers.sort() |
|
|
| |
| |
| text_result = re.sub(r'', '', text_result).strip() |
| |
|
|
| |
| return {"result": text_result, "luckyNumbers": lucky_numbers} |
| |
| except Exception as e: |
| last_error = e |
| continue |
|
|
| error_msg = str(last_error) |
|
|
| send_slack_message(f"๐จ [์ ์ฒด ์คํจ] ์๋ฌ: {error_msg}") |
| |
| return JSONResponse(content={ |
| 'result': f"<div class='greeting'>์ฃ์กํฉ๋๋ค. ์ ์์ด ์ํํ์ง ์์ต๋๋ค.<br><span style='font-size:0.8rem; color:#999'>({error_msg})</span></div>" |
| }) |