File size: 6,104 Bytes
194e37e
 
852ef5c
194e37e
 
 
4720161
194e37e
1e5561b
 
 
194e37e
1e5561b
 
 
194e37e
1e5561b
 
6b3a25b
1e5561b
 
 
 
 
6b3a25b
194e37e
1e5561b
 
4720161
 
1e5561b
4720161
 
 
 
 
 
1e5561b
194e37e
1e5561b
 
 
 
 
 
 
 
 
 
c2c3399
194e37e
4503e17
194e37e
 
 
 
 
 
4720161
194e37e
 
852ef5c
 
4720161
852ef5c
 
 
 
 
 
 
 
1e5561b
 
852ef5c
 
1e5561b
 
852ef5c
 
1e5561b
 
 
4720161
 
194e37e
1e5561b
4720161
194e37e
1e5561b
4720161
1e5561b
4720161
 
1e5561b
4720161
 
1e5561b
4720161
194e37e
1e5561b
4720161
1e5561b
4720161
 
1e5561b
4720161
 
1e5561b
4720161
194e37e
1e5561b
4720161
1e5561b
 
 
 
 
 
 
 
 
 
4720161
 
194e37e
 
 
 
 
 
 
1e5561b
194e37e
1e5561b
 
 
4720161
 
 
1e5561b
4720161
 
 
 
 
 
1e5561b
4720161
 
 
 
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
import streamlit as st
import pandas as pd
import json
from io import StringIO
from datetime import datetime
import requests
import sseclient

# νŽ˜μ΄μ§€ μ„€μ •
st.set_page_config(page_title="Solar ν”„λ‘¬ν”„νŠΈ 비ꡐ기", page_icon="🌞")
st.title("🌞 μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ 비ꡐ 챗봇")

# --- μž…λ ₯ UI ---
api_key = st.text_input("πŸ”‘ Upstage API Keyλ₯Ό μž…λ ₯ν•˜μ„Έμš” ('up_'둜 μ‹œμž‘)", type="password")
user_input = st.text_input("πŸ’¬ μ‚¬μš©μž λ©”μ‹œμ§€λ₯Ό μž…λ ₯ν•˜μ„Έμš”", "")

# --- μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ μ•ˆλ‚΄ 및 μž…λ ₯ ---
st.markdown("### 🧠 μ»€μŠ€ν…€ μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ")
st.markdown("""
**μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈλž€ λ¬΄μ—‡μΈκ°€μš”?**  
μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈλŠ” AIμ—κ²Œ λŒ€ν™”λ₯Ό μ‹œμž‘ν•˜κΈ° 전에 μ£Όμ–΄μ§€λŠ” νŠΉλ³„ν•œ μ§€μ‹œλ¬Έμž…λ‹ˆλ‹€.  
AIκ°€ μ–΄λ–€ μ—­ν• μ΄λ‚˜ 말투, μ„±κ²©μœΌλ‘œ λŒ€ν™”μ— μž„ν•΄μ•Ό ν•˜λŠ”μ§€λ₯Ό μ•Œλ €μ£ΌλŠ” 역할을 ν•©λ‹ˆλ‹€.  
예λ₯Ό λ“€μ–΄, AIμ—κ²Œ 예의 λ°”λ₯Έ λΉ„μ„œμ²˜λŸΌ ν–‰λ™ν•˜κ²Œ ν•˜κ±°λ‚˜, 창의적인 μž‘κ°€, μ—„κ²©ν•œ 문법 κ²€μ‚¬μžμ²˜λŸΌ ν–‰λ™ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.  
같은 μ§ˆλ¬Έμ΄λΌλ„ μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈμ— 따라 μ™„μ „νžˆ λ‹€λ₯Έ 응닡이 λ‚˜μ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
""")

# κΈ°λ³Έ μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈμ™€ μ‚¬μš©μž μ»€μŠ€ν…€ ν”„λ‘¬ν”„νŠΈ μž…λ ₯
custom_prompt = st.text_area("✏️ μ•„λž˜μ— μ›ν•˜λŠ” μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš”:", "You are a helpful assistant.", height=100)
default_prompt = "You are a helpful assistant."

# --- μ„Έμ…˜ μƒνƒœ μ΄ˆκΈ°ν™” ---
if "default_messages" not in st.session_state:
    st.session_state.default_messages = [{"role": "system", "content": default_prompt}]
if "custom_messages" not in st.session_state or st.session_state.custom_prompt != custom_prompt:
    st.session_state.custom_messages = [{"role": "system", "content": custom_prompt}]
    st.session_state.custom_prompt = custom_prompt

# --- Solar Pro API 호좜 ν•¨μˆ˜ ---
def solar_pro_chat(messages, api_key):
    """
    Solar Pro API에 λ©”μ‹œμ§€λ₯Ό 보내고 슀트리밍 ν˜•νƒœλ‘œ 응닡을 λ°›μ•„μ˜€λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

    Parameters:
        messages (list): μ‹œμŠ€ν…œ/μ‚¬μš©μž λ©”μ‹œμ§€ λͺ©λ‘
        api_key (str): Upstage API ν‚€

    Returns:
        generator: AI의 응닡을 슀트리밍 ν˜•νƒœλ‘œ ν•œ 쀄씩 λ°˜ν™˜
    """
    url = "https://api.upstage.ai/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Accept": "text/event-stream",
        "Content-Type": "application/json"
    }
    payload = {
        "model": "solar-pro", 
        "messages": messages,
        "stream": True
    }

    try:
        response = requests.post(url, headers=headers, json=payload, stream=True)
        response.raise_for_status()
        client = sseclient.SSEClient(response)
        for event in client.events():
            if event.data == "[DONE]":
                break
            try:
                content = json.loads(event.data)["choices"][0]["delta"].get("content", "")
                yield content
            except Exception as e:
                st.error("⚠️ 응닡 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.")
                print(f"[SSE νŒŒμ‹± 였λ₯˜] {e}")
                continue
    except requests.exceptions.RequestException as e:
        st.error("❌ API 호좜 μ‹€νŒ¨: API ν‚€λ‚˜ λ„€νŠΈμ›Œν¬ μƒνƒœλ₯Ό ν™•μΈν•΄μ£Όμ„Έμš”.")
        print(f"[API μš”μ²­ 였λ₯˜] {e}")
        return

# --- 비ꡐ μ‹€ν–‰ ---
if st.button("πŸš€ 응닡 λΉ„κ΅ν•˜κΈ°") and api_key and user_input:
    # μ‚¬μš©μž μž…λ ₯을 λ©”μ‹œμ§€μ— μΆ”κ°€
    st.session_state.default_messages.append({"role": "user", "content": user_input})
    st.session_state.custom_messages.append({"role": "user", "content": user_input})

    # 두 개의 컬럼으둜 κ²°κ³Ό λ‚˜λˆ„κΈ°
    col1, col2 = st.columns(2)

    # κΈ°λ³Έ ν”„λ‘¬ν”„νŠΈ 응닡
    with col1:
        st.subheader("πŸ”Ή κΈ°λ³Έ ν”„λ‘¬ν”„νŠΈ")
        default_response = ""
        default_area = st.empty()
        with st.spinner("κΈ°λ³Έ 응닡 생성 쀑..."):
            for chunk in solar_pro_chat(st.session_state.default_messages, api_key):
                default_response += chunk
                default_area.markdown(f"**πŸ€– 봇:** {default_response}")
        st.session_state.default_messages.append({"role": "assistant", "content": default_response})

    # μ»€μŠ€ν…€ ν”„λ‘¬ν”„νŠΈ 응닡
    with col2:
        st.subheader("πŸ”Έ μ»€μŠ€ν…€ ν”„λ‘¬ν”„νŠΈ")
        custom_response = ""
        custom_area = st.empty()
        with st.spinner("μ»€μŠ€ν…€ 응닡 생성 쀑..."):
            for chunk in solar_pro_chat(st.session_state.custom_messages, api_key):
                custom_response += chunk
                custom_area.markdown(f"**πŸ€– 봇:** {custom_response}")
        st.session_state.custom_messages.append({"role": "assistant", "content": custom_response})

# --- μ±„νŒ… λ‚΄μ—­ CSV둜 μ €μž₯ ---
def generate_csv(messages, prompt_label):
    """
    μ£Όμ–΄μ§„ λ©”μ‹œμ§€λ₯Ό CSV둜 λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

    Parameters:
        messages (list): μ‹œμŠ€ν…œ/μ‚¬μš©μž/AI λ©”μ‹œμ§€ 리슀트
        prompt_label (str): μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ ν…μŠ€νŠΈ

    Returns:
        str: CSV ν˜•μ‹μ˜ λ¬Έμžμ—΄
    """
    rows = [{"role": "system", "content": prompt_label}]
    for msg in messages:
        if msg["role"] != "system":
            rows.append(msg)
    df = pd.DataFrame(rows)
    output = StringIO()
    df.to_csv(output, index=False)
    return output.getvalue()

# ν˜„μž¬ μ‹œκ°μœΌλ‘œ 파일λͺ… 생성
now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")

# --- λ‹€μš΄λ‘œλ“œ UI ---
st.markdown("### ⬇️ μ±„νŒ… λ‚΄μ—­ λ‹€μš΄λ‘œλ“œ")
col1, col2 = st.columns(2)
with col1:
    st.download_button(
        label="κΈ°λ³Έ 응닡 λ‹€μš΄λ‘œλ“œ",
        data=generate_csv(st.session_state.default_messages, default_prompt),
        file_name=f"default_chat_{now}.csv",
        mime="text/csv",
    )
with col2:
    st.download_button(
        label="μ»€μŠ€ν…€ 응닡 λ‹€μš΄λ‘œλ“œ",
        data=generate_csv(st.session_state.custom_messages, custom_prompt),
        file_name=f"custom_chat_{now}.csv",
        mime="text/csv",
    )