ginipick commited on
Commit
4298a84
ยท
verified ยท
1 Parent(s): e27c21b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -8
app.py CHANGED
@@ -2,19 +2,27 @@ import os
2
  import streamlit as st
3
  import json
4
  import anthropic
 
 
 
 
 
 
 
 
5
 
6
  # API ์„ค์ •
7
  api_key = os.environ.get("API_KEY")
8
  client = anthropic.Anthropic(api_key=api_key)
9
 
 
 
 
10
  # ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜ ์„ค์ • (Claude-3 Sonnet์˜ ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜)
11
  MAX_TOKENS = 7999
12
 
13
  def get_system_prompt():
14
-
15
  return """
16
-
17
-
18
  ๋‹น์‹ ์€ ์ „๋ฌธ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ธ”๋กœ๊ทธ ๊ธ€ ์ž‘์„ฑ ์š”์ฒญ์— ๋Œ€ํ•ด ๋‹ค์Œ์˜ 8๋‹จ๊ณ„ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ฒ ์ €ํžˆ ๋”ฐ๋ฅด๋˜, ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ๋งค๋ ฅ์ ์ธ ๊ธ€์ด ๋˜๋„๋ก ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
19
 
20
  ๋…์ž ์—ฐ๊ฒฐ ๋‹จ๊ณ„ 1.1. ๊ณต๊ฐ๋Œ€ ํ˜•์„ฑ์„ ์œ„ํ•œ ์นœ๊ทผํ•œ ์ธ์‚ฌ 1.2. ๋…์ž์˜ ์‹ค์ œ ๊ณ ๋ฏผ์„ ๋ฐ˜์˜ํ•œ ๋„์ž… ์งˆ๋ฌธ 1.3. ์ฃผ์ œ์— ๋Œ€ํ•œ ์ฆ‰๊ฐ์  ๊ด€์‹ฌ ์œ ๋„
@@ -36,10 +44,69 @@ def get_system_prompt():
36
  ์ž‘์„ฑ ์‹œ ์ค€์ˆ˜์‚ฌํ•ญ 9.1. ๊ธ€์ž ์ˆ˜: 1500-2000์ž ๋‚ด์™ธ 9.2. ๋ฌธ๋‹จ ๊ธธ์ด: 3-4๋ฌธ์žฅ ์ด๋‚ด 9.3. ์‹œ๊ฐ์  ๊ตฌ๋ถ„: ์†Œ์ œ๋ชฉ, ๊ตฌ๋ถ„์„ , ๋ฒˆํ˜ธ ๋ชฉ๋ก ํ™œ์šฉ 9.4. ํ†ค์•ค๋งค๋„ˆ: ์นœ๊ทผํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ๋Œ€ํ™”์ฒด 9.5. ๋ฐ์ดํ„ฐ: ๋ชจ๋“  ์ •๋ณด์˜ ์ถœ์ฒ˜ ๋ช…์‹œ 9.6. ๊ฐ€๋…์„ฑ: ๋ช…ํ™•ํ•œ ๋‹จ๋ฝ ๊ตฌ๋ถ„๊ณผ ๊ฐ•์กฐ์  ์‚ฌ์šฉ
37
 
38
  ์ด๋Ÿฌํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์š”์ฒญ๋ฐ›์€ ์ฃผ์ œ์— ๋Œ€ํ•ด ์ฒด๊ณ„์ ์ด๊ณ  ๋งค๋ ฅ์ ์ธ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
39
-
40
  """
41
 
 
 
 
 
 
 
 
 
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  def chatbot_interface():
45
  st.title("Ginigen Blog")
@@ -47,13 +114,22 @@ def chatbot_interface():
47
  # ๋ชจ๋ธ ๊ณ ์ • ์„ค์ •
48
  if "ai_model" not in st.session_state:
49
  st.session_state["ai_model"] = "claude-3-7-sonnet-20250219"
 
50
  # ์„ธ์…˜ ์ƒํƒœ ์ดˆ๊ธฐํ™”
51
  if "messages" not in st.session_state:
52
  st.session_state.messages = []
53
-
54
  # ์ž๋™ ์ €์žฅ ๊ธฐ๋Šฅ
55
  if "auto_save" not in st.session_state:
56
  st.session_state.auto_save = True
 
 
 
 
 
 
 
 
57
 
58
  # ๋Œ€ํ™” ๊ธฐ๋ก ๊ด€๋ฆฌ (์‚ฌ์ด๋“œ๋ฐ”)
59
  st.sidebar.title("๋Œ€ํ™” ๊ธฐ๋ก ๊ด€๋ฆฌ")
@@ -61,6 +137,24 @@ def chatbot_interface():
61
  # ์ž๋™ ์ €์žฅ ํ† ๊ธ€
62
  st.session_state.auto_save = st.sidebar.toggle("์ž๋™ ์ €์žฅ", value=st.session_state.auto_save)
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  # ๋Œ€ํ™” ๊ธฐ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
65
  uploaded_file = st.sidebar.file_uploader("๋Œ€ํ™” ๊ธฐ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ", type=['json'])
66
  if uploaded_file is not None:
@@ -85,6 +179,9 @@ def chatbot_interface():
85
  for message in st.session_state.messages:
86
  with st.chat_message(message["role"]):
87
  st.markdown(message["content"])
 
 
 
88
 
89
  # ์‚ฌ์šฉ์ž ์ž…๋ ฅ
90
  if prompt := st.chat_input("๋ฌด์—‡์„ ๋„์™€๋“œ๋ฆด๊นŒ์š”?"):
@@ -110,19 +207,67 @@ def chatbot_interface():
110
 
111
  message_placeholder.markdown(full_response)
112
 
113
- st.session_state.messages.append({"role": "assistant", "content": full_response})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  # ์ž๋™ ์ €์žฅ ๊ธฐ๋Šฅ
116
  if st.session_state.auto_save:
117
  try:
 
 
 
 
 
 
118
  with open('chat_history_auto_save.json', 'w', encoding='utf-8') as f:
119
- json.dump(st.session_state.messages, f, ensure_ascii=False, indent=4)
120
  except Exception as e:
121
  st.sidebar.error(f"์ž๋™ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
122
 
123
  # ๋Œ€ํ™” ๊ธฐ๋ก ๋‹ค์šด๋กœ๋“œ
124
  if st.sidebar.button("๋Œ€ํ™” ๊ธฐ๋ก ๋‹ค์šด๋กœ๋“œ"):
125
- json_history = json.dumps(st.session_state.messages, indent=4, ensure_ascii=False)
 
 
 
 
 
 
126
  st.sidebar.download_button(
127
  label="๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅํ•˜๊ธฐ",
128
  data=json_history,
@@ -134,4 +279,11 @@ def main():
134
  chatbot_interface()
135
 
136
  if __name__ == "__main__":
 
 
 
 
 
 
 
137
  main()
 
2
  import streamlit as st
3
  import json
4
  import anthropic
5
+ import requests
6
+ import logging
7
+ from gradio_client import Client
8
+
9
+ # ๋กœ๊น… ์„ค์ •
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(levelname)s - %(message)s')
13
 
14
  # API ์„ค์ •
15
  api_key = os.environ.get("API_KEY")
16
  client = anthropic.Anthropic(api_key=api_key)
17
 
18
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ API URL
19
+ IMAGE_API_URL = "http://211.233.58.201:7896"
20
+
21
  # ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜ ์„ค์ • (Claude-3 Sonnet์˜ ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜)
22
  MAX_TOKENS = 7999
23
 
24
  def get_system_prompt():
 
25
  return """
 
 
26
  ๋‹น์‹ ์€ ์ „๋ฌธ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ธ”๋กœ๊ทธ ๊ธ€ ์ž‘์„ฑ ์š”์ฒญ์— ๋Œ€ํ•ด ๋‹ค์Œ์˜ 8๋‹จ๊ณ„ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ฒ ์ €ํžˆ ๋”ฐ๋ฅด๋˜, ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ๋งค๋ ฅ์ ์ธ ๊ธ€์ด ๋˜๋„๋ก ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
27
 
28
  ๋…์ž ์—ฐ๊ฒฐ ๋‹จ๊ณ„ 1.1. ๊ณต๊ฐ๋Œ€ ํ˜•์„ฑ์„ ์œ„ํ•œ ์นœ๊ทผํ•œ ์ธ์‚ฌ 1.2. ๋…์ž์˜ ์‹ค์ œ ๊ณ ๋ฏผ์„ ๋ฐ˜์˜ํ•œ ๋„์ž… ์งˆ๋ฌธ 1.3. ์ฃผ์ œ์— ๋Œ€ํ•œ ์ฆ‰๊ฐ์  ๊ด€์‹ฌ ์œ ๋„
 
44
  ์ž‘์„ฑ ์‹œ ์ค€์ˆ˜์‚ฌํ•ญ 9.1. ๊ธ€์ž ์ˆ˜: 1500-2000์ž ๋‚ด์™ธ 9.2. ๋ฌธ๋‹จ ๊ธธ์ด: 3-4๋ฌธ์žฅ ์ด๋‚ด 9.3. ์‹œ๊ฐ์  ๊ตฌ๋ถ„: ์†Œ์ œ๋ชฉ, ๊ตฌ๋ถ„์„ , ๋ฒˆํ˜ธ ๋ชฉ๋ก ํ™œ์šฉ 9.4. ํ†ค์•ค๋งค๋„ˆ: ์นœ๊ทผํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ๋Œ€ํ™”์ฒด 9.5. ๋ฐ์ดํ„ฐ: ๋ชจ๋“  ์ •๋ณด์˜ ์ถœ์ฒ˜ ๋ช…์‹œ 9.6. ๊ฐ€๋…์„ฑ: ๋ช…ํ™•ํ•œ ๋‹จ๋ฝ ๊ตฌ๋ถ„๊ณผ ๊ฐ•์กฐ์  ์‚ฌ์šฉ
45
 
46
  ์ด๋Ÿฌํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์š”์ฒญ๋ฐ›์€ ์ฃผ์ œ์— ๋Œ€ํ•ด ์ฒด๊ณ„์ ์ด๊ณ  ๋งค๋ ฅ์ ์ธ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
 
47
  """
48
 
49
+ def test_image_api_connection():
50
+ """์ด๋ฏธ์ง€ API ์„œ๋ฒ„ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ"""
51
+ try:
52
+ client = Client(IMAGE_API_URL)
53
+ return "์ด๋ฏธ์ง€ API ์—ฐ๊ฒฐ ์„ฑ๊ณต: ์ •์ƒ ์ž‘๋™ ์ค‘"
54
+ except Exception as e:
55
+ logging.error(f"์ด๋ฏธ์ง€ API ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ์‹คํŒจ: {e}")
56
+ return f"์ด๋ฏธ์ง€ API ์—ฐ๊ฒฐ ์‹คํŒจ: {e}"
57
 
58
+ def generate_image(prompt, width=768, height=768, guidance=3.5, inference_steps=30, seed=3):
59
+ """์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜"""
60
+ if not prompt:
61
+ return None, "์˜ค๋ฅ˜: ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”"
62
+
63
+ try:
64
+ client = Client(IMAGE_API_URL)
65
+ result = client.predict(
66
+ prompt=prompt,
67
+ width=int(width),
68
+ height=int(height),
69
+ guidance=float(guidance),
70
+ inference_steps=int(inference_steps),
71
+ seed=int(seed),
72
+ do_img2img=False,
73
+ init_image=None,
74
+ image2image_strength=0.8,
75
+ resize_img=True,
76
+ api_name="/generate_image"
77
+ )
78
+ logging.info(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ฑ๊ณต: {result[1]}")
79
+ return result[0], f"์‚ฌ์šฉ๋œ ์‹œ๋“œ: {result[1]}"
80
+ except Exception as e:
81
+ logging.error(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ: {str(e)}")
82
+ return None, f"์˜ค๋ฅ˜: {str(e)}"
83
+
84
+ def extract_image_prompt(blog_content, blog_topic):
85
+ """๋ธ”๋กœ๊ทธ ๋‚ด์šฉ์—์„œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ์ถ”์ถœ"""
86
+ image_prompt_system = f"""
87
+ ๋‹ค์Œ์€ '{blog_topic}'์— ๊ด€ํ•œ ๋ธ”๋กœ๊ทธ ๊ธ€์ž…๋‹ˆ๋‹ค. ์ด ๋ธ”๋กœ๊ทธ ๊ธ€์˜ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ์ ˆํ•œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ
88
+ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”. ํ”„๋กฌํ”„ํŠธ๋Š” ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๊ณ , ๊ตฌ์ฒด์ ์ธ ์‹œ๊ฐ์  ์š”์†Œ๋ฅผ ๋‹ด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
89
+ ํ”„๋กฌํ”„ํŠธ๋งŒ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”(๋‹ค๋ฅธ ์„ค๋ช… ์—†์ด).
90
+
91
+ ์˜ˆ์‹œ ํ˜•์‹:
92
+ "A professional photo of [subject], [specific details], [atmosphere], [lighting], [perspective], high quality, detailed"
93
+ """
94
+
95
+ try:
96
+ response = client.messages.create(
97
+ model="claude-3-7-sonnet-20250219",
98
+ max_tokens=150,
99
+ system=image_prompt_system,
100
+ messages=[{"role": "user", "content": blog_content}]
101
+ )
102
+
103
+ # ์‘๋‹ต์—์„œ ํ”„๋กฌํ”„ํŠธ ์ถ”์ถœ
104
+ image_prompt = response.content[0].text.strip()
105
+ logging.info(f"์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ: {image_prompt}")
106
+ return image_prompt
107
+ except Exception as e:
108
+ logging.error(f"์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {e}")
109
+ return f"A professional photo related to {blog_topic}, detailed, high quality"
110
 
111
  def chatbot_interface():
112
  st.title("Ginigen Blog")
 
114
  # ๋ชจ๋ธ ๊ณ ์ • ์„ค์ •
115
  if "ai_model" not in st.session_state:
116
  st.session_state["ai_model"] = "claude-3-7-sonnet-20250219"
117
+
118
  # ์„ธ์…˜ ์ƒํƒœ ์ดˆ๊ธฐํ™”
119
  if "messages" not in st.session_state:
120
  st.session_state.messages = []
121
+
122
  # ์ž๋™ ์ €์žฅ ๊ธฐ๋Šฅ
123
  if "auto_save" not in st.session_state:
124
  st.session_state.auto_save = True
125
+
126
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ† ๊ธ€
127
+ if "generate_image" not in st.session_state:
128
+ st.session_state.generate_image = False
129
+
130
+ # ์ด๋ฏธ์ง€ API ์ƒํƒœ
131
+ if "image_api_status" not in st.session_state:
132
+ st.session_state.image_api_status = test_image_api_connection()
133
 
134
  # ๋Œ€ํ™” ๊ธฐ๋ก ๊ด€๋ฆฌ (์‚ฌ์ด๋“œ๋ฐ”)
135
  st.sidebar.title("๋Œ€ํ™” ๊ธฐ๋ก ๊ด€๋ฆฌ")
 
137
  # ์ž๋™ ์ €์žฅ ํ† ๊ธ€
138
  st.session_state.auto_save = st.sidebar.toggle("์ž๋™ ์ €์žฅ", value=st.session_state.auto_save)
139
 
140
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ† ๊ธ€
141
+ st.session_state.generate_image = st.sidebar.toggle("๋ธ”๋กœ๊ทธ ๊ธ€ ์ž‘์„ฑ ํ›„ ์ด๋ฏธ์ง€ ์ž๋™ ์ƒ์„ฑ", value=st.session_state.generate_image)
142
+
143
+ # ์ด๋ฏธ์ง€ API ์ƒํƒœ ํ‘œ์‹œ
144
+ st.sidebar.text(st.session_state.image_api_status)
145
+
146
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ค์ • (ํ† ๊ธ€์ด ์ผœ์ ธ ์žˆ์„ ๋•Œ๋งŒ ํ‘œ์‹œ)
147
+ if st.session_state.generate_image:
148
+ st.sidebar.subheader("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ค์ •")
149
+ width = st.sidebar.slider("๋„ˆ๋น„", 256, 1024, 768, 64)
150
+ height = st.sidebar.slider("๋†’์ด", 256, 1024, 768, 64)
151
+ guidance = st.sidebar.slider("๊ฐ€์ด๋˜์Šค ์Šค์ผ€์ผ", 1.0, 20.0, 3.5, 0.1)
152
+ inference_steps = st.sidebar.slider("์ธํผ๋Ÿฐ์Šค ์Šคํ…", 1, 50, 30, 1)
153
+ seed = st.sidebar.number_input("์‹œ๋“œ", value=3, min_value=0, step=1)
154
+ else:
155
+ # ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
156
+ width, height, guidance, inference_steps, seed = 768, 768, 3.5, 30, 3
157
+
158
  # ๋Œ€ํ™” ๊ธฐ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
159
  uploaded_file = st.sidebar.file_uploader("๋Œ€ํ™” ๊ธฐ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ", type=['json'])
160
  if uploaded_file is not None:
 
179
  for message in st.session_state.messages:
180
  with st.chat_message(message["role"]):
181
  st.markdown(message["content"])
182
+ # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ‘œ์‹œ
183
+ if "image" in message:
184
+ st.image(message["image"], caption=message.get("image_caption", "์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€"))
185
 
186
  # ์‚ฌ์šฉ์ž ์ž…๋ ฅ
187
  if prompt := st.chat_input("๋ฌด์—‡์„ ๋„์™€๋“œ๋ฆด๊นŒ์š”?"):
 
207
 
208
  message_placeholder.markdown(full_response)
209
 
210
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์˜ต์…˜์ด ์ผœ์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ
211
+ if st.session_state.generate_image:
212
+ with st.spinner("๋ธ”๋กœ๊ทธ์— ๋งž๋Š” ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘..."):
213
+ # ์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ
214
+ image_prompt = extract_image_prompt(full_response, prompt)
215
+
216
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ
217
+ image, image_caption = generate_image(
218
+ image_prompt,
219
+ width=width,
220
+ height=height,
221
+ guidance=guidance,
222
+ inference_steps=inference_steps,
223
+ seed=seed
224
+ )
225
+
226
+ if image:
227
+ st.image(image, caption=image_caption)
228
+ # ์ด๋ฏธ์ง€ ์ •๋ณด๋ฅผ ์‘๋‹ต์— ํฌํ•จ
229
+ st.session_state.messages.append({
230
+ "role": "assistant",
231
+ "content": full_response,
232
+ "image": image,
233
+ "image_caption": image_caption
234
+ })
235
+ else:
236
+ st.error(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ: {image_caption}")
237
+ st.session_state.messages.append({
238
+ "role": "assistant",
239
+ "content": full_response
240
+ })
241
+ else:
242
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์—†์ด ์‘๋‹ต๋งŒ ์ €์žฅ
243
+ st.session_state.messages.append({
244
+ "role": "assistant",
245
+ "content": full_response
246
+ })
247
 
248
  # ์ž๋™ ์ €์žฅ ๊ธฐ๋Šฅ
249
  if st.session_state.auto_save:
250
  try:
251
+ # ์ด๋ฏธ์ง€ ์ •๋ณด๋Š” ์ €์žฅํ•˜์ง€ ์•Š์Œ (JSON์—๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ €์žฅํ•  ์ˆ˜ ์—†์Œ)
252
+ save_messages = []
253
+ for msg in st.session_state.messages:
254
+ save_msg = {"role": msg["role"], "content": msg["content"]}
255
+ save_messages.append(save_msg)
256
+
257
  with open('chat_history_auto_save.json', 'w', encoding='utf-8') as f:
258
+ json.dump(save_messages, f, ensure_ascii=False, indent=4)
259
  except Exception as e:
260
  st.sidebar.error(f"์ž๋™ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
261
 
262
  # ๋Œ€ํ™” ๊ธฐ๋ก ๋‹ค์šด๋กœ๋“œ
263
  if st.sidebar.button("๋Œ€ํ™” ๊ธฐ๋ก ๋‹ค์šด๋กœ๋“œ"):
264
+ # ์ด๋ฏธ์ง€ ์ •๋ณด๋Š” ์ €์žฅํ•˜์ง€ ์•Š์Œ
265
+ save_messages = []
266
+ for msg in st.session_state.messages:
267
+ save_msg = {"role": msg["role"], "content": msg["content"]}
268
+ save_messages.append(save_msg)
269
+
270
+ json_history = json.dumps(save_messages, indent=4, ensure_ascii=False)
271
  st.sidebar.download_button(
272
  label="๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅํ•˜๊ธฐ",
273
  data=json_history,
 
279
  chatbot_interface()
280
 
281
  if __name__ == "__main__":
282
+ # requirements.txt ํŒŒ์ผ ์ƒ์„ฑ
283
+ with open("requirements.txt", "w") as f:
284
+ f.write("streamlit>=1.31.0\n")
285
+ f.write("anthropic>=0.18.1\n")
286
+ f.write("gradio-client>=1.8.0\n")
287
+ f.write("requests>=2.32.3\n")
288
+
289
  main()