wanda222's picture
Update app.py
1e5561b verified
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",
)