File size: 5,957 Bytes
cb245e5
226a535
cb245e5
 
226a535
cb245e5
 
 
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226a535
cb245e5
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
226a535
cb245e5
 
 
 
 
226a535
cb245e5
 
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
226a535
cb245e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226a535
cb245e5
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
# ν•„μš”ν•œ 라이브러리λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€.
import gradio as gr
import google.generativeai as genai
import os

# --- Hugging Face Spaces의 Secrets λ˜λŠ” 둜컬 ν™˜κ²½λ³€μˆ˜μ—μ„œ API ν‚€λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. ---
# 이 앱을 Spaces에 배포할 λ•ŒλŠ” 'Settings' -> 'Repository secrets'에
# 'GEMINI_API_KEY'λΌλŠ” μ΄λ¦„μœΌλ‘œ ν‚€λ₯Ό μ €μž₯ν•΄μ•Ό ν•©λ‹ˆλ‹€.
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")

# --- UI 및 챗봇 μ„€λͺ… ---
# Gradio Blocksλ₯Ό μ‚¬μš©ν•˜μ—¬ μ’€ 더 μœ μ—°ν•œ UIλ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€.
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue")) as demo:
    gr.Markdown(
        """
        # β™ŠοΈ Gemini API 챗봇 (Secrets μ‚¬μš©)
        Google Gemini APIλ₯Ό μ‚¬μš©ν•˜λŠ” μ±—λ΄‡μž…λ‹ˆλ‹€. 
        Hugging Face Spaces의 'Settings' 탭에 μžˆλŠ” 'Repository secrets'에 `GEMINI_API_KEY`κ°€ μ„€μ •λ˜μ–΄ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.
        [API ν‚€ λ°œκΈ‰λ°›κΈ°](https://aistudio.google.com/app/apikey)
        """
    )
    
    # API ν‚€κ°€ μ„€μ •λ˜μ—ˆλŠ”μ§€ ν™•μΈν•˜κ³  μ•ˆλ‚΄ λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€.
    if not GEMINI_API_KEY:
        gr.Warning("⚠️ Gemini API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. Hugging Face Spaces의 'Repository secrets'에 GEMINI_API_KEYλ₯Ό μΆ”κ°€ν•΄μ£Όμ„Έμš”.")

    # Gradio 챗봇 UI μ»΄ν¬λ„ŒνŠΈ
    chatbot = gr.Chatbot(label="Gemini 챗봇", height=600)

    with gr.Row():
        # μ‚¬μš©μž λ©”μ‹œμ§€ μž…λ ₯λž€
        msg = gr.Textbox(
            label="λ©”μ‹œμ§€ μž…λ ₯",
            placeholder="무엇이든 λ¬Όμ–΄λ³΄μ„Έμš”...",
            container=False,
            scale=7,
        )
        # 전솑 λ²„νŠΌ
        submit_button = gr.Button("전솑", variant="primary", scale=1)

    with gr.Accordion("κ³ κΈ‰ μ„€μ •", open=False):
        # LLM의 역할을 μ •μ˜ν•˜λŠ” μ‹œμŠ€ν…œ λ©”μ‹œμ§€
        system_message = gr.Textbox(
            value="You are a helpful and friendly chatbot.", label="μ‹œμŠ€ν…œ λ©”μ‹œμ§€"
        )
        # λͺ¨λΈμ˜ μ°½μ˜μ„±μ„ μ‘°μ ˆν•˜λŠ” μŠ¬λΌμ΄λ”
        temperature = gr.Slider(
            minimum=0.0, maximum=1.0, value=0.7, step=0.1, label="Temperature"
        )
        # 생성할 μ΅œλŒ€ 토큰 수λ₯Ό μ‘°μ ˆν•˜λŠ” μŠ¬λΌμ΄λ”
        max_tokens = gr.Slider(
            minimum=1, maximum=4096, value=1024, step=1, label="Max new tokens"
        )

    # --- Gemini API 호좜 ν•¨μˆ˜ ---
    def respond(message, chat_history, system_prompt, temp, max_output_tokens):
        # ν™˜κ²½λ³€μˆ˜μ—μ„œ κ°€μ Έμ˜¨ API ν‚€κ°€ μ—†μœΌλ©΄ μ•ˆλ‚΄ λ©”μ‹œμ§€λ₯Ό λ„μ›λ‹ˆλ‹€.
        if not GEMINI_API_KEY:
            yield "Google API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. κ΄€λ¦¬μžμ—κ²Œ λ¬Έμ˜ν•˜μ„Έμš”."
            return

        try:
            # API ν‚€λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.
            genai.configure(api_key=GEMINI_API_KEY)
        except Exception as e:
            yield f"API ν‚€ 섀정에 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {e}"
            return
        
        # μ‚¬μš©ν•  λͺ¨λΈκ³Ό μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈλ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.
        model = genai.GenerativeModel(
            model_name='gemini-2.0-flash', # μ΅œμ‹  Flash λͺ¨λΈ μ‚¬μš©
            system_instruction=system_prompt
        )

        # Gradio의 λŒ€ν™” 기둝을 Gemini APIκ°€ 이해할 수 μžˆλŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€.
        gemini_history = []
        for user_msg, model_msg in chat_history:
            if user_msg:
                gemini_history.append({"role": "user", "parts": [user_msg]})
            if model_msg:
                gemini_history.append({"role": "model", "parts": [model_msg]})
            
        # 이전 λŒ€ν™” 기둝을 λ°”νƒ•μœΌλ‘œ μ±„νŒ… μ„Έμ…˜μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.
        chat = model.start_chat(history=gemini_history)

        # λͺ¨λΈ 생성 κ΄€λ ¨ 섀정을 κ΅¬μ„±ν•©λ‹ˆλ‹€.
        generation_config = genai.types.GenerationConfig(
            temperature=temp,
            max_output_tokens=int(max_output_tokens),
        )

        try:
            # 슀트리밍 λ°©μ‹μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό 보내고 응닡을 λ°›μŠ΅λ‹ˆλ‹€.
            response = chat.send_message(
                message, 
                stream=True, 
                generation_config=generation_config
            )

            # 슀트리밍 응닡을 μ‹€μ‹œκ°„μœΌλ‘œ UI에 ν‘œμ‹œν•©λ‹ˆλ‹€.
            full_response = ""
            for chunk in response:
                if hasattr(chunk, 'text'):
                    full_response += chunk.text
                    yield full_response

        except Exception as e:
            # API 호좜 쀑 μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ UI에 ν‘œμ‹œν•©λ‹ˆλ‹€.
            yield f"응닡 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {e}"

    # --- Gradio 이벀트 λ¦¬μŠ€λ„ˆ ---
    # μ‚¬μš©μžκ°€ λ©”μ‹œμ§€λ₯Ό μž…λ ₯ν•˜κ³  '전솑' λ²„νŠΌμ„ λˆ„λ₯΄κ±°λ‚˜ μ—”ν„°λ₯Ό 쳀을 λ•Œ 싀행될 둜직
    def on_submit(message, chat_history, system_prompt, temp, max_output_tokens):
        # λŒ€ν™” 기둝에 μ‚¬μš©μž λ©”μ‹œμ§€λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
        chat_history.append((message, None))
        # 슀트리밍 응닡을 μœ„ν•΄ 빈 λ¬Έμžμ—΄λ‘œ 응닡을 μ‹œμž‘ν•©λ‹ˆλ‹€.
        bot_response_stream = respond(message, chat_history, system_prompt, temp, max_output_tokens)
        
        # 슀트리밍 응닡을 UI에 μ—…λ°μ΄νŠΈν•©λ‹ˆλ‹€.
        for partial_response in bot_response_stream:
            chat_history[-1] = (message, partial_response)
            yield "", chat_history
    
    # λ©”μ‹œμ§€ 전솑(λ²„νŠΌ 클릭 λ˜λŠ” μ—”ν„°) μ‹œ on_submit ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.
    # UIμ—μ„œ API ν‚€ μž…λ ₯λž€μ΄ μ œκ±°λ˜μ—ˆμœΌλ―€λ‘œ, μž…λ ₯(inputs) λ¦¬μŠ€νŠΈμ—μ„œλ„ μ œμ™Έν•©λ‹ˆλ‹€.
    msg.submit(
        on_submit, 
        [msg, chatbot, system_message, temperature, max_tokens], 
        [msg, chatbot]
    )
    submit_button.click(
        on_submit, 
        [msg, chatbot, system_message, temperature, max_tokens], 
        [msg, chatbot]
    )

# μŠ€ν¬λ¦½νŠΈκ°€ 직접 싀행될 λ•Œ Gradio 앱을 μ‹€ν–‰ν•©λ‹ˆλ‹€.
if __name__ == "__main__":
    demo.launch(debug=True)