Spaces:
Sleeping
Sleeping
import os, json, requests | |
import gradio as gr | |
from dotenv import load_dotenv | |
import httpx | |
import time | |
# ํ๊ฒฝ ๋ณ์ ๋ก๋ | |
load_dotenv(os.path.join(os.path.dirname(__file__), "..", "backend", ".env"), override=True) | |
# Vercel ๋ฐฑ์๋ URL | |
BACKEND = os.getenv('BACKEND_URL', 'https://personamate-kimddols-projects.vercel.app') | |
async def fetch_data_fn(): | |
try: | |
async with httpx.AsyncClient() as client: | |
res = await client.get(f"{BACKEND}/fetch_data", timeout=60) | |
res.raise_for_status() | |
return res.json() | |
except Exception as e: | |
return {"error": str(e)} | |
async def run_recommendations(yt, sns, mbti): | |
try: | |
payload = { | |
"youtube_subscriptions": [s.strip() for s in yt.splitlines() if s.strip()], | |
"sns_keywords": [s.strip() for s in sns.splitlines() if s.strip()], | |
"mbti": mbti | |
} | |
async with httpx.AsyncClient() as client: | |
res = await client.post(f"{BACKEND}/youtube/recommendations", json=payload, timeout=120) | |
res.raise_for_status() | |
data = res.json() | |
except Exception as e: | |
return "<h3>์ถ์ฒ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค.</h3>", f"API ํธ์ถ ์คํจ: {e}", None | |
recommendations_data = data.get("recommendations", {}) | |
youtube_recs = recommendations_data.get("youtube", []) | |
summary_reason = recommendations_data.get("summary_reason", "์ถ์ฒ ์ฌ์ ๋ฅผ ์์ฑํ์ง ๋ชปํ์ต๋๋ค.") | |
if not youtube_recs: | |
return "<h3>์ถ์ฒ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค.</h3>", summary_reason, None | |
table_html = "<table><thead><tr><th>์ฑ๋ ์ด๋ฆ</th><th>์ฌ์ดํธ ์ฃผ์</th></tr></thead><tbody>" | |
for c in youtube_recs: | |
url = c.get("url", "") | |
name = c.get("name", "") | |
table_html += f'<tr><td>{name}</td><td><a href="{url}" target="_blank">{url}</a></td></tr>' | |
table_html += "</tbody></table>" | |
# Store the necessary data for export/email | |
state_data = { | |
"recommendations": {"youtube": youtube_recs}, | |
"summary_reason": summary_reason | |
} | |
return table_html, summary_reason, state_data | |
async def export_file(file_type, recommendations_state): | |
if not recommendations_state: | |
return None, "๋จผ์ ์ถ์ฒ์ ์คํํด์ฃผ์ธ์." | |
endpoint = f"{BACKEND}/youtube/recommendations/export/{file_type}" | |
try: | |
# The payload is already in the correct format in recommendations_state | |
async with httpx.AsyncClient() as client: | |
res = await client.post(endpoint, json=recommendations_state, timeout=60) | |
res.raise_for_status() | |
file_path = f"/tmp/recommendations_{int(time.time())}.{file_type}" | |
with open(file_path, "wb") as f: | |
f.write(res.content) | |
return file_path, f"{file_type.upper()} ํ์ผ ์์ฑ ์๋ฃ" | |
except Exception as e: | |
return None, f"ํ์ผ ์์ฑ ์คํจ: {e}" | |
async def send_email_fn(recipient_email, recommendations_state): | |
if not recommendations_state: | |
return "๋จผ์ ์ถ์ฒ์ ์คํํด์ฃผ์ธ์." | |
if not recipient_email: | |
return "์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์." | |
endpoint = f"{BACKEND}/youtube/recommendations/email" | |
payload = { | |
"recipient_email": recipient_email, | |
"recommendations": recommendations_state.get("recommendations", {}), | |
"summary_reason": recommendations_state.get("summary_reason", "") | |
} | |
try: | |
async with httpx.AsyncClient() as client: | |
res = await client.post(endpoint, json=payload, timeout=60) | |
res.raise_for_status() | |
return "์ด๋ฉ์ผ ์ ์ก ์ฑ๊ณต!" | |
except Exception as e: | |
return f"์ด๋ฉ์ผ ์ ์ก ์คํจ: {e}" | |
with gr.Blocks(title='PersonaMate Pro (OAuth + Simplified UI)') as demo: | |
recommendations_state = gr.State() | |
gr.Markdown('## PersonaMate Pro โ OAuth ์์ง + ์ถ์ฒ UI') | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown('### 1) OAuth ๋ก๊ทธ์ธ') | |
gr.HTML(f'<a href="{BACKEND}/oauth/google/start" target="_blank">Google (YouTube) ๋ก๊ทธ์ธ</a>') | |
with gr.Column(scale=2): | |
gr.Markdown('### 2) ์๋ ์์ง') | |
fetch_btn = gr.Button('๋ด ๊ณ์ ์์ ๋ฐ์ดํฐ ์์ง') | |
fetch_result = gr.JSON(label="์์ง๋ ๋ฐ์ดํฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown('### 3) ์ ๋ ฅ/MBTI') | |
yt_text = gr.Textbox(lines=6, label='์ ํ๋ธ ๊ตฌ๋ (์์ง/์๋)') | |
sns_text = gr.Textbox(lines=6, label='SNS ํค์๋/๊ณ์ ') | |
mbti = gr.Dropdown( | |
choices=['ISTJ','ISFJ','INFJ','INTJ','ISTP','ISFP','INFP','INTP','ESTP','ESFP','ENFP','ENTP','ESTJ','ESFJ','ENFJ','ENTJ'], | |
value='ENFP', | |
label='MBTI' | |
) | |
run_btn = gr.Button('๋ถ์ & ์ถ์ฒ ์คํ', variant='primary') | |
with gr.Column(scale=3): | |
gr.Markdown('### 4) ์ถ์ฒ ๊ฒฐ๊ณผ') | |
result_html = gr.HTML(label="์ถ์ฒ ๊ฒฐ๊ณผ") | |
gr.Markdown('### 5) ์ถ์ฒ ์ฌ์ ') | |
summary_output = gr.Markdown(label="์ถ์ฒ ์ฌ์ ์์ฝ") | |
with gr.Row(): | |
gr.Markdown('### 6) ๊ฒฐ๊ณผ ์ ์ฅ ๋ฐ ๊ณต์ ') | |
with gr.Row(): | |
with gr.Column(scale=1): | |
html_btn = gr.Button("HTML ์ ์ฅ") | |
pdf_btn = gr.Button("PDF ์ ์ฅ") | |
download_file = gr.File(label="๋ค์ด๋ก๋") | |
with gr.Column(scale=2): | |
email_input = gr.Textbox(label="์ด๋ฉ์ผ ์ฃผ์", placeholder="๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ์ด๋ฉ์ผ์ ์ ๋ ฅํ์ธ์...") | |
email_btn = gr.Button("์ด๋ฉ์ผ๋ก ๋ณด๋ด๊ธฐ") | |
status_output = gr.Textbox(label="์ํ", interactive=False) | |
fetch_btn.click(fetch_data_fn, inputs=[], outputs=[fetch_result]) | |
run_btn.click(run_recommendations, [yt_text, sns_text, mbti], [result_html, summary_output, recommendations_state]) | |
html_btn.click(export_file, inputs=[gr.State("html"), recommendations_state], outputs=[download_file, status_output]) | |
pdf_btn.click(export_file, inputs=[gr.State("pdf"), recommendations_state], outputs=[download_file, status_output]) | |
email_btn.click(send_email_fn, inputs=[email_input, recommendations_state], outputs=[status_output]) | |
if __name__ == '__main__': | |
demo.launch() | |