File size: 6,383 Bytes
add7d3f
6528e6f
 
c0ebd19
 
95f8d1c
c0ebd19
6528e6f
95f8d1c
c0ebd19
 
95f8d1c
c0ebd19
b97f664
c0ebd19
add7d3f
 
 
b97f664
 
 
c0ebd19
b97f664
 
 
 
 
 
c0ebd19
add7d3f
 
c0ebd19
b97f664
c0ebd19
d0c9819
6c9843d
 
 
b97f664
6c9843d
c0ebd19
e592770
c91f7f1
6c9843d
e592770
 
c91f7f1
e592770
d0c9819
6c9843d
 
 
 
 
 
 
c0ebd19
 
 
 
 
 
 
6c9843d
c0ebd19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6c9843d
 
c0ebd19
 
 
 
 
 
 
 
 
 
 
b97f664
6528e6f
 
 
 
b97f664
6528e6f
 
c0ebd19
b97f664
6528e6f
 
 
b97f664
 
 
 
 
 
 
e592770
6528e6f
 
c0ebd19
e592770
 
c0ebd19
 
 
 
 
 
 
 
 
 
 
eadc151
6528e6f
c0ebd19
 
 
 
 
6528e6f
b97f664
 
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
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()