Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +250 -167
src/streamlit_app.py
CHANGED
@@ -1,11 +1,9 @@
|
|
1 |
-
#
|
2 |
-
#
|
3 |
|
4 |
import streamlit as st
|
5 |
import pandas as pd
|
6 |
import numpy as np
|
7 |
-
from sentence_transformers import SentenceTransformer
|
8 |
-
from sklearn.metrics.pairwise import cosine_similarity
|
9 |
import pickle
|
10 |
import google.generativeai as genai
|
11 |
import time
|
@@ -13,6 +11,11 @@ import json
|
|
13 |
import os
|
14 |
from datetime import datetime
|
15 |
|
|
|
|
|
|
|
|
|
|
|
16 |
# ํ์ด์ง ์ค์
|
17 |
st.set_page_config(
|
18 |
page_title="AI ์นดํผ๋ผ์ดํฐ | RAG ๊ธฐ๋ฐ ๊ด๊ณ ์นดํผ ์์ฑ",
|
@@ -23,7 +26,7 @@ st.set_page_config(
|
|
23 |
|
24 |
# ์ ๋ชฉ ๋ฐ ์ค๋ช
|
25 |
st.title("โจ AI ์นดํผ๋ผ์ดํฐ")
|
26 |
-
st.markdown("### ๐ฏ 37,
|
27 |
st.markdown("---")
|
28 |
|
29 |
# ์ฌ์ด๋๋ฐ ์ค์
|
@@ -33,59 +36,123 @@ st.sidebar.header("๐๏ธ ์นดํผ ์์ฑ ์ค์ ")
|
|
33 |
default_api_key = os.getenv("GEMINI_API_KEY", "")
|
34 |
|
35 |
api_key = st.sidebar.text_input(
|
36 |
-
"๐ Gemini API ํค",
|
37 |
value=default_api_key,
|
38 |
type="password",
|
39 |
-
help="
|
40 |
)
|
41 |
|
42 |
if not api_key:
|
43 |
st.warning("โ ๏ธ Gemini API ํค๋ฅผ ์
๋ ฅํด์ฃผ์ธ์")
|
44 |
-
st.info("๐ก
|
45 |
st.stop()
|
46 |
|
47 |
-
# ์์คํ
์ด๊ธฐํ (์บ์ฑ)
|
48 |
-
@st.cache_resource
|
49 |
def load_system():
|
50 |
-
"""์์คํ
์ปดํฌ๋ํธ ๋ก๋ฉ
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
df = pd.read_excel('๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx')
|
63 |
-
|
64 |
-
|
65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
with open('copy_embeddings.pkl', 'rb') as f:
|
67 |
embeddings_data = pickle.load(f)
|
68 |
embeddings = embeddings_data['embeddings']
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
# ์์คํ
๋ก๋ฉ
|
81 |
with st.spinner("๐ AI ์นดํผ๋ผ์ดํฐ ์์คํ
์ด๊ธฐํ ์ค..."):
|
82 |
model, embedding_model, df, embeddings = load_system()
|
83 |
|
84 |
-
if model is None:
|
85 |
-
st.error("โ ์์คํ
์ ๋ก๋ฉํ ์ ์์ต๋๋ค.")
|
86 |
st.stop()
|
87 |
|
88 |
-
|
|
|
89 |
|
90 |
# ์นดํ
๊ณ ๋ฆฌ ์ ํ
|
91 |
categories = ['์ ์ฒด'] + sorted(df['์นดํ
๊ณ ๋ฆฌ'].unique().tolist())
|
@@ -98,14 +165,14 @@ selected_category = st.sidebar.selectbox(
|
|
98 |
# ํ๊ฒ ๊ณ ๊ฐ ์ค์
|
99 |
target_audience = st.sidebar.selectbox(
|
100 |
"๐ฏ ํ๊ฒ ๊ณ ๊ฐ",
|
101 |
-
['
|
102 |
-
|
103 |
)
|
104 |
|
105 |
# ๋ธ๋๋ ํค์ค๋งค๋
|
106 |
brand_tone = st.sidebar.selectbox(
|
107 |
"๐จ ๋ธ๋๋ ํค",
|
108 |
-
['
|
109 |
help="์ํ๋ ๋ธ๋๋ ์ด๋ฏธ์ง๋ฅผ ์ ํํ์ธ์"
|
110 |
)
|
111 |
|
@@ -136,37 +203,28 @@ if input_method == "์ง์ ์
๋ ฅ":
|
|
136 |
else:
|
137 |
# ํ
ํ๋ฆฟ ์ ํ
|
138 |
templates = {
|
139 |
-
"์ ์ ํ ๋ฐ์นญ": "
|
140 |
-
"ํ ์ธ ์ด๋ฒคํธ": "{์นดํ
๊ณ ๋ฆฌ}
|
141 |
"๋ธ๋๋ ์ฌ๋ก๊ฑด": "{์นดํ
๊ณ ๋ฆฌ} ๋ธ๋๋์ ๋ํ ์ฌ๋ก๊ฑด",
|
142 |
-
"์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ": "{
|
143 |
"์์ฆ ํ์ ": "{์์ฆ} ํ์ {์นดํ
๊ณ ๋ฆฌ} ํน๋ณ ์๋์
์นดํผ"
|
144 |
}
|
145 |
-
|
146 |
selected_template = st.selectbox("ํ
ํ๋ฆฟ ์ ํ:", list(templates.keys()))
|
147 |
-
|
148 |
-
# ํ
ํ๋ฆฟ ์ปค์คํฐ๋ง์ด์ง
|
149 |
col1, col2 = st.columns(2)
|
150 |
with col1:
|
151 |
-
template_target = st.text_input("ํ๊ฒ ๊ณ ๊ฐ:", value=target_audience)
|
152 |
-
with col2:
|
153 |
template_category = st.text_input("์ ํ/์๋น์ค:", value="")
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
)
|
165 |
-
else:
|
166 |
-
user_request = templates[selected_template].format(
|
167 |
-
ํ๊ฒ=template_target, ์นดํ
๊ณ ๋ฆฌ=template_category
|
168 |
-
)
|
169 |
-
|
170 |
st.text_area("์์ฑ๋ ์์ฒญ:", value=user_request, height=80, disabled=True)
|
171 |
|
172 |
# ๊ณ ๊ธ ์ต์
|
@@ -174,81 +232,85 @@ with st.expander("๐ง ๊ณ ๊ธ ์ต์
"):
|
|
174 |
col1, col2 = st.columns(2)
|
175 |
with col1:
|
176 |
num_concepts = st.slider("์์ฑํ ์ปจ์
์:", 1, 5, 3)
|
177 |
-
exclude_brand = st.text_input("์ ์ธํ ๋ธ๋๋:", placeholder="๊ฒฝ์์ฌ ๋ธ๋๋๋ช
")
|
178 |
-
with col2:
|
179 |
min_similarity = st.slider("์ต์ ์ ์ฌ๋:", 0.0, 1.0, 0.3, 0.1)
|
|
|
180 |
show_references = st.checkbox("์ฐธ๊ณ ์นดํผ ๋ณด๊ธฐ", value=True)
|
|
|
181 |
|
182 |
-
# ์นดํผ ์์ฑ ํจ์
|
183 |
-
def
|
184 |
-
"""
|
185 |
-
|
186 |
if not user_request.strip():
|
187 |
st.error("โ ์นดํผ ์์ฒญ์ ์
๋ ฅํด์ฃผ์ธ์")
|
188 |
return None
|
189 |
-
|
190 |
# ์งํ ์ํฉ ํ์
|
191 |
progress_bar = st.progress(0)
|
192 |
status_text = st.empty()
|
193 |
-
|
194 |
-
# 1๋จ๊ณ: ๊ฒ์
|
195 |
-
status_text.text("๐
|
196 |
progress_bar.progress(20)
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
252 |
๋น์ ์ ํ๊ตญ์ ์ ๋ฌธ ๊ด๊ณ ์นดํผ๋ผ์ดํฐ์
๋๋ค.
|
253 |
|
254 |
**์์ฒญ์ฌํญ:** {user_request}
|
@@ -256,7 +318,7 @@ def generate_copy_web(user_request, category, target, tone, creative, num_concep
|
|
256 |
**๋ธ๋๋ ํค:** {tone}
|
257 |
**์ฐฝ์์ฑ ์์ค:** {creative}
|
258 |
|
259 |
-
**์ฐธ๊ณ
|
260 |
{references_text}
|
261 |
|
262 |
**์์ฑ ๊ฐ์ด๋๋ผ์ธ:**
|
@@ -270,7 +332,7 @@ def generate_copy_web(user_request, category, target, tone, creative, num_concep
|
|
270 |
1. [์นดํผ1]
|
271 |
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
272 |
|
273 |
-
2. [์นดํผ2]
|
274 |
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
275 |
|
276 |
3. [์นดํผ3]
|
@@ -278,19 +340,23 @@ def generate_copy_web(user_request, category, target, tone, creative, num_concep
|
|
278 |
|
279 |
**์ถ์ฒ ์นดํผ:** ์ ์ค ๊ฐ์ฅ ์ถ์ฒํ๋ ์นดํผ์ ์ด์
|
280 |
"""
|
281 |
-
|
282 |
-
try:
|
283 |
response = model.generate_content(prompt)
|
284 |
progress_bar.progress(100)
|
285 |
status_text.text("โ
์๋ฃ!")
|
286 |
-
|
287 |
time.sleep(0.5)
|
288 |
progress_bar.empty()
|
289 |
status_text.empty()
|
290 |
-
|
291 |
return {
|
292 |
'references': reference_copies,
|
293 |
'generated_content': response.text,
|
|
|
|
|
|
|
|
|
|
|
294 |
'settings': {
|
295 |
'category': category,
|
296 |
'target': target,
|
@@ -298,19 +364,21 @@ def generate_copy_web(user_request, category, target, tone, creative, num_concep
|
|
298 |
'creative': creative
|
299 |
}
|
300 |
}
|
301 |
-
|
302 |
except Exception as e:
|
303 |
st.error(f"โ ์นดํผ ์์ฑ ์คํจ: {e}")
|
|
|
|
|
304 |
return None
|
305 |
|
306 |
# ์์ฑ ๋ฒํผ
|
307 |
if st.button("๐ ์นดํผ ์์ฑํ๊ธฐ", type="primary", use_container_width=True):
|
308 |
-
|
309 |
if not user_request or not user_request.strip():
|
310 |
st.error("โ ์นดํผ ์์ฒญ์ ์
๋ ฅํด์ฃผ์ธ์")
|
311 |
else:
|
312 |
-
# ์นดํผ ์์ฑ
|
313 |
-
result =
|
314 |
user_request=user_request,
|
315 |
category=selected_category,
|
316 |
target=target_audience,
|
@@ -318,33 +386,38 @@ if st.button("๐ ์นดํผ ์์ฑํ๊ธฐ", type="primary", use_container_width=Tru
|
|
318 |
creative=creative_level,
|
319 |
num_concepts=num_concepts
|
320 |
)
|
321 |
-
|
322 |
if result:
|
323 |
# ๊ฒฐ๊ณผ ํ์
|
324 |
st.markdown("## ๐ ์์ฑ๋ ์นดํผ")
|
325 |
st.markdown("---")
|
326 |
-
|
|
|
|
|
|
|
|
|
327 |
# ์ฐธ๊ณ ์นดํผ ํ์
|
328 |
if show_references and result['references']:
|
329 |
-
with st.expander("๐
|
330 |
for i, ref in enumerate(result['references'], 1):
|
331 |
st.markdown(f"**{i}.** \"{ref['copy']}\"")
|
332 |
-
st.markdown(f" - ๋ธ๋๋: {ref['brand']}")
|
333 |
st.markdown(f" - ์ ์ฌ๋: {ref['similarity']:.3f}")
|
334 |
st.markdown("")
|
335 |
-
|
336 |
# ์์ฑ๋ ์นดํผ ํ์
|
337 |
st.markdown("### โจ AI๊ฐ ์์ฑํ ์นดํผ:")
|
338 |
st.markdown(result['generated_content'])
|
339 |
-
|
340 |
# ๊ฒฐ๊ณผ ๋ค์ด๋ก๋
|
341 |
result_json = json.dumps({
|
342 |
'timestamp': datetime.now().isoformat(),
|
343 |
'request': user_request,
|
344 |
'settings': result['settings'],
|
|
|
345 |
'generated_content': result['generated_content']
|
346 |
}, ensure_ascii=False, indent=2)
|
347 |
-
|
348 |
st.download_button(
|
349 |
label="๐พ ๊ฒฐ๊ณผ ๋ค์ด๋ก๋ (JSON)",
|
350 |
data=result_json,
|
@@ -352,35 +425,42 @@ if st.button("๐ ์นดํผ ์์ฑํ๊ธฐ", type="primary", use_container_width=Tru
|
|
352 |
mime="application/json"
|
353 |
)
|
354 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
355 |
# ์ฌ์ฉ๋ฒ ๊ฐ์ด๋
|
356 |
-
with st.expander("๐ก ์ฌ์ฉ๋ฒ ๊ฐ์ด๋"):
|
357 |
st.markdown("""
|
358 |
### ๐ฏ ํจ๊ณผ์ ์ธ ์ฌ์ฉ๋ฒ
|
359 |
-
|
360 |
**1. ๊ตฌ์ฒด์ ์ธ ์์ฒญํ๊ธฐ:**
|
361 |
- โ "์นดํผ ์จ์ค"
|
362 |
- โ
"30๋ ์ง์ฅ ์ฌ์ฑ์ฉ ํ๋ฆฌ๋ฏธ์ ์คํจ์ผ์ด ์ ์ ํ ๋ฐ์นญ ์นดํผ"
|
363 |
-
|
364 |
-
**2.
|
365 |
-
-
|
366 |
-
|
|
|
|
|
367 |
**3. ์ฐฝ์์ฑ ์กฐ์ :**
|
368 |
- **๋ณด์์ **: ์์ ํ ํด๋ผ์ด์ธํธ, ๊ฒ์ฆ๋ ์ ๊ทผ
|
369 |
- **๊ท ํ**: ์ผ๋ฐ์ ์ธ ํ๋ก์ ํธ (์ถ์ฒ!)
|
370 |
- **์ฐฝ์์ **: ํ์ ์ ๋ธ๋๋, ํ๊ฒฉ์ ์บ ํ์ธ
|
371 |
-
|
372 |
-
**4.
|
373 |
-
-
|
|
|
|
|
374 |
""")
|
375 |
|
376 |
-
# ์์คํ
์ ๋ณด (์ฌ์ด๋๋ฐ ํ๋จ)
|
377 |
-
st.sidebar.markdown("---")
|
378 |
-
st.sidebar.markdown("### ๐ ์์คํ
์ ๋ณด")
|
379 |
-
st.sidebar.markdown(f"**๋ฐ์ดํฐ**: {len(df):,}๊ฐ ์นดํผ")
|
380 |
-
st.sidebar.markdown(f"**์นดํ
๊ณ ๋ฆฌ**: {df['์นดํ
๊ณ ๋ฆฌ'].nunique()}๊ฐ")
|
381 |
-
st.sidebar.markdown(f"**๋ธ๋๋**: {df['๋ธ๋๋'].nunique()}๊ฐ")
|
382 |
-
st.sidebar.markdown("**ํธ์คํ
**: ๐ค Hugging Face")
|
383 |
-
|
384 |
# ํธํฐ
|
385 |
st.markdown("---")
|
386 |
st.markdown(
|
@@ -388,6 +468,9 @@ st.markdown(
|
|
388 |
"RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ
powered by Korean SBERT + Gemini AI"
|
389 |
)
|
390 |
|
391 |
-
#
|
392 |
-
if os.getenv("
|
393 |
-
st.markdown("
|
|
|
|
|
|
|
|
1 |
+
# ์์ ์ ์ธ AI ์นดํผ๋ผ์ดํฐ - ์๋ฒ ๋ฉ ๊ธฐ๋ฐ RAG ์์คํ
|
2 |
+
# Hugging Face Spaces ํ๊ฒฝ ์ต์ ํ ๋ฒ์
|
3 |
|
4 |
import streamlit as st
|
5 |
import pandas as pd
|
6 |
import numpy as np
|
|
|
|
|
7 |
import pickle
|
8 |
import google.generativeai as genai
|
9 |
import time
|
|
|
11 |
import os
|
12 |
from datetime import datetime
|
13 |
|
14 |
+
# ํ๊ฒฝ ์ค์ (๊ถํ ๋ฌธ์ ํด๊ฒฐ)
|
15 |
+
os.environ['STREAMLIT_BROWSER_GATHER_USAGE_STATS'] = 'false'
|
16 |
+
os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers'
|
17 |
+
os.environ['SENTENCE_TRANSFORMERS_HOME'] = '/tmp/sentence_transformers'
|
18 |
+
|
19 |
# ํ์ด์ง ์ค์
|
20 |
st.set_page_config(
|
21 |
page_title="AI ์นดํผ๋ผ์ดํฐ | RAG ๊ธฐ๋ฐ ๊ด๊ณ ์นดํผ ์์ฑ",
|
|
|
26 |
|
27 |
# ์ ๋ชฉ ๋ฐ ์ค๋ช
|
28 |
st.title("โจ AI ์นดํผ๋ผ์ดํฐ")
|
29 |
+
st.markdown("### ๐ฏ 37,671๊ฐ ์ค์ ๊ด๊ณ ์นดํผ ๋ฐ์ดํฐ ๊ธฐ๋ฐ RAG ์์คํ
")
|
30 |
st.markdown("---")
|
31 |
|
32 |
# ์ฌ์ด๋๋ฐ ์ค์
|
|
|
36 |
default_api_key = os.getenv("GEMINI_API_KEY", "")
|
37 |
|
38 |
api_key = st.sidebar.text_input(
|
39 |
+
"๐ Gemini API ํค",
|
40 |
value=default_api_key,
|
41 |
type="password",
|
42 |
+
help="ํ๊ฒฝ๋ณ์์ GEMINI_API_KEY๋ก ์ค์ ํ๋ฉด ์๋ ์
๋ ฅ๋ฉ๋๋ค"
|
43 |
)
|
44 |
|
45 |
if not api_key:
|
46 |
st.warning("โ ๏ธ Gemini API ํค๋ฅผ ์
๋ ฅํด์ฃผ์ธ์")
|
47 |
+
st.info("๐ก Settings โ Repository secrets์์ GEMINI_API_KEY๋ฅผ ์ค์ ํ์ธ์")
|
48 |
st.stop()
|
49 |
|
50 |
+
# ์์คํ
์ด๊ธฐํ (์บ์ฑ) - ์๋ฒ ๋ฉ ํ์!
|
51 |
+
@st.cache_resource(show_spinner=False)
|
52 |
def load_system():
|
53 |
+
"""์์คํ
์ปดํฌ๋ํธ ๋ก๋ฉ - ์๋ฒ ๋ฉ ๊ธฐ๋ฐ RAG ์์คํ
"""
|
54 |
+
|
55 |
+
progress_container = st.container()
|
56 |
+
|
57 |
+
with progress_container:
|
58 |
+
# ์ ์ฒด ์งํ๋ฅ
|
59 |
+
total_progress = st.progress(0)
|
60 |
+
status_text = st.empty()
|
61 |
+
|
62 |
+
# 1๋จ๊ณ: API ์ค์ (10%)
|
63 |
+
status_text.text("๐ Gemini API ์ด๊ธฐํ ์ค...")
|
64 |
+
try:
|
65 |
+
genai.configure(api_key=api_key)
|
66 |
+
model = genai.GenerativeModel('gemini-2.0-flash')
|
67 |
+
total_progress.progress(10)
|
68 |
+
st.success("โ
Gemini API ์ค์ ์๋ฃ")
|
69 |
+
except Exception as e:
|
70 |
+
st.error(f"โ Gemini API ์ค์ ์คํจ: {e}")
|
71 |
+
return None, None, None, None
|
72 |
+
|
73 |
+
# 2๋จ๊ณ: ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ (40%)
|
74 |
+
status_text.text("๐ค ํ๊ตญ์ด ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์ค... (1-2๋ถ ์์)")
|
75 |
+
embedding_model = None
|
76 |
+
|
77 |
+
# ์์ ์ ์ธ ๋ชจ๋ธ ๋ก๋ฉ ์ ๋ต
|
78 |
+
try:
|
79 |
+
# ๋จผ์ ์บ์ ๋๋ ํ ๋ฆฌ ์์ฑ
|
80 |
+
os.makedirs('/tmp/sentence_transformers', exist_ok=True)
|
81 |
+
os.makedirs('/tmp/transformers', exist_ok=True)
|
82 |
+
|
83 |
+
# sentence-transformers ์ํฌํธ๋ฅผ ํจ์ ๋ด์์
|
84 |
+
from sentence_transformers import SentenceTransformer
|
85 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
86 |
+
|
87 |
+
# ํ๊ตญ์ด ๋ชจ๋ธ ๋ก๋ฉ ์๋
|
88 |
+
embedding_model = SentenceTransformer('jhgan/ko-sbert-nli',
|
89 |
+
cache_folder='/tmp/sentence_transformers')
|
90 |
+
total_progress.progress(40)
|
91 |
+
st.success("โ
ํ๊ตญ์ด ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ")
|
92 |
+
|
93 |
+
except Exception as e:
|
94 |
+
st.error(f"โ ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์คํจ: {e}")
|
95 |
+
st.error("๐จ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์์ด๋ RAG ์์คํ
์ด ์๋ํ ์ ์์ต๋๋ค!")
|
96 |
+
return None, None, None, None
|
97 |
+
|
98 |
+
# 3๋จ๊ณ: ๋ฐ์ดํฐ ๋ก๋ (60%)
|
99 |
+
status_text.text("๐ ์นดํผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ก๋ฉ ์ค...")
|
100 |
+
try:
|
101 |
df = pd.read_excel('๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx')
|
102 |
+
total_progress.progress(60)
|
103 |
+
st.success(f"โ
๋ฐ์ดํฐ ๋ก๋ฉ ์๋ฃ: {len(df):,}๊ฐ ์นดํผ")
|
104 |
+
except Exception as e:
|
105 |
+
st.error(f"โ ๋ฐ์ดํฐ ๋ก๋ฉ ์คํจ: {e}")
|
106 |
+
return None, None, None, None
|
107 |
+
|
108 |
+
# 4๋จ๊ณ: ์๋ฒ ๋ฉ ๋ฐ์ดํฐ ๋ก๋ (90%) - ์ด๊ฒ ํต์ฌ!
|
109 |
+
status_text.text("๐ ๋ฒกํฐ ์๋ฒ ๋ฉ ๋ก๋ฉ ์ค... (RAG ์์คํ
ํต์ฌ)")
|
110 |
+
try:
|
111 |
with open('copy_embeddings.pkl', 'rb') as f:
|
112 |
embeddings_data = pickle.load(f)
|
113 |
embeddings = embeddings_data['embeddings']
|
114 |
+
total_progress.progress(90)
|
115 |
+
st.success(f"โ
์๋ฒ ๋ฉ ๋ก๋ฉ ์๋ฃ: {embeddings.shape[0]:,}๊ฐ ร {embeddings.shape[1]}์ฐจ์")
|
116 |
+
except Exception as e:
|
117 |
+
st.error(f"โ ์๋ฒ ๋ฉ ๋ก๋ฉ ์คํจ: {e}")
|
118 |
+
st.error("๐จ ์๋ฒ ๋ฉ ์์ด๋ ์๋ฏธ์ ๊ฒ์์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค!")
|
119 |
+
return None, None, None, None
|
120 |
+
|
121 |
+
# 5๋จ๊ณ: ์ต์ข
๊ฒ์ฆ (100%)
|
122 |
+
status_text.text("โจ ์์คํ
๊ฒ์ฆ ์ค...")
|
123 |
+
if model and embedding_model and df is not None and embeddings is not None:
|
124 |
+
total_progress.progress(100)
|
125 |
+
status_text.text("๐ RAG ์์คํ
๋ก๋ฉ ์๋ฃ!")
|
126 |
+
|
127 |
+
# ์ฑ๊ณต ๋ฉ์์ง
|
128 |
+
success_col1, success_col2, success_col3 = st.columns(3)
|
129 |
+
with success_col1:
|
130 |
+
st.metric("์นดํผ ๋ฐ์ดํฐ", f"{len(df):,}๊ฐ")
|
131 |
+
with success_col2:
|
132 |
+
st.metric("์๋ฒ ๋ฉ ์ฐจ์", f"{embeddings.shape[1]}D")
|
133 |
+
with success_col3:
|
134 |
+
st.metric("๊ฒ์ ์์ง", "Korean SBERT")
|
135 |
+
|
136 |
+
# ์งํ๋ฅ ๋ฐ ์ ๊ฑฐ
|
137 |
+
time.sleep(1)
|
138 |
+
total_progress.empty()
|
139 |
+
status_text.empty()
|
140 |
+
|
141 |
+
return model, embedding_model, df, embeddings
|
142 |
+
else:
|
143 |
+
st.error("โ ์์คํ
๋ก๋ฉ ์คํจ: ํ์ ๊ตฌ์ฑ์์ ๋๋ฝ")
|
144 |
+
return None, None, None, None
|
145 |
|
146 |
# ์์คํ
๋ก๋ฉ
|
147 |
with st.spinner("๐ AI ์นดํผ๋ผ์ดํฐ ์์คํ
์ด๊ธฐํ ์ค..."):
|
148 |
model, embedding_model, df, embeddings = load_system()
|
149 |
|
150 |
+
if model is None or embedding_model is None or df is None or embeddings is None:
|
151 |
+
st.error("โ ์์คํ
์ ๋ก๋ฉํ ์ ์์ต๋๋ค. ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํ๊ฑฐ๋ ๊ด๋ฆฌ์์๊ฒ ๋ฌธ์ํ์ธ์.")
|
152 |
st.stop()
|
153 |
|
154 |
+
# ์ฌ์ด๋๋ฐ ์ค์ (์์คํ
๋ก๋ฉ ์ฑ๊ณต ํ)
|
155 |
+
st.sidebar.success("๐ RAG ์์คํ
์ค๋น ์๋ฃ!")
|
156 |
|
157 |
# ์นดํ
๊ณ ๋ฆฌ ์ ํ
|
158 |
categories = ['์ ์ฒด'] + sorted(df['์นดํ
๊ณ ๋ฆฌ'].unique().tolist())
|
|
|
165 |
# ํ๊ฒ ๊ณ ๊ฐ ์ค์
|
166 |
target_audience = st.sidebar.selectbox(
|
167 |
"๐ฏ ํ๊ฒ ๊ณ ๊ฐ",
|
168 |
+
['20๋', '30๋', '์ผ๋ฐ', '10๋', '40๋', '50๋+', '๋จ์ฑ', '์ฌ์ฑ', '์ง์ฅ์ธ', 'ํ์', '์ฃผ๋ถ'],
|
169 |
+
help="ํ๊ฒ ๊ณ ๊ฐ์ ๋ง๋ ํค์ค๋งค๋๋ก ์นดํผ๋ฅผ ์์ฑํฉ๋๋ค"
|
170 |
)
|
171 |
|
172 |
# ๋ธ๋๋ ํค์ค๋งค๋
|
173 |
brand_tone = st.sidebar.selectbox(
|
174 |
"๐จ ๋ธ๋๋ ํค",
|
175 |
+
['์ธ๋ จ๋', '์น๊ทผํ', '๊ณ ๊ธ์ค๋ฌ์ด', 'ํ๊ธฐ์ฐฌ', '์ ๋ขฐํ ์ ์๋', '์ ์', '๋ฐ๋ปํ', '์ ๋ฌธ์ ์ธ'],
|
176 |
help="์ํ๋ ๋ธ๋๋ ์ด๋ฏธ์ง๋ฅผ ์ ํํ์ธ์"
|
177 |
)
|
178 |
|
|
|
203 |
else:
|
204 |
# ํ
ํ๋ฆฟ ์ ํ
|
205 |
templates = {
|
206 |
+
"์ ์ ํ ๋ฐ์นญ": "๋์ {์นดํ
๊ณ ๋ฆฌ} ์ ์ ํ ๋ฐ์นญ ์นดํผ",
|
207 |
+
"ํ ์ธ ์ด๋ฒคํธ": "{์นดํ
๊ณ ๋ฆฌ} ํ ์ธ ์ด๋ฒคํธ ํ๋ก๋ชจ์
์นดํผ",
|
208 |
"๋ธ๋๋ ์ฌ๋ก๊ฑด": "{์นดํ
๊ณ ๋ฆฌ} ๋ธ๋๋์ ๋ํ ์ฌ๋ก๊ฑด",
|
209 |
+
"์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ": "{์๋น์ค๋ช
} ์ ๋ฒ์ ์ถ์ ์นดํผ",
|
210 |
"์์ฆ ํ์ ": "{์์ฆ} ํ์ {์นดํ
๊ณ ๋ฆฌ} ํน๋ณ ์๋์
์นดํผ"
|
211 |
}
|
212 |
+
|
213 |
selected_template = st.selectbox("ํ
ํ๋ฆฟ ์ ํ:", list(templates.keys()))
|
214 |
+
|
|
|
215 |
col1, col2 = st.columns(2)
|
216 |
with col1:
|
|
|
|
|
217 |
template_category = st.text_input("์ ํ/์๋น์ค:", value="")
|
218 |
+
with col2:
|
219 |
+
if selected_template == "์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ":
|
220 |
+
service_name = st.text_input("์๋น์ค๋ช
:", placeholder="์: ๋ฐฐ๋ฌ์ฑ, ๊ธ์ต์ฑ")
|
221 |
+
user_request = templates[selected_template].format(์๋น์ค๋ช
=service_name)
|
222 |
+
elif selected_template == "์์ฆ ํ์ ":
|
223 |
+
season = st.selectbox("์์ฆ:", ["๋ด", "์ฌ๋ฆ", "๊ฐ์", "๊ฒจ์ธ", "ํฌ๋ฆฌ์ค๋ง์ค", "์ ๋
"])
|
224 |
+
user_request = templates[selected_template].format(์์ฆ=season, ์นดํ
๊ณ ๋ฆฌ=template_category)
|
225 |
+
else:
|
226 |
+
user_request = templates[selected_template].format(์นดํ
๊ณ ๋ฆฌ=template_category)
|
227 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
st.text_area("์์ฑ๋ ์์ฒญ:", value=user_request, height=80, disabled=True)
|
229 |
|
230 |
# ๊ณ ๊ธ ์ต์
|
|
|
232 |
col1, col2 = st.columns(2)
|
233 |
with col1:
|
234 |
num_concepts = st.slider("์์ฑํ ์ปจ์
์:", 1, 5, 3)
|
|
|
|
|
235 |
min_similarity = st.slider("์ต์ ์ ์ฌ๋:", 0.0, 1.0, 0.3, 0.1)
|
236 |
+
with col2:
|
237 |
show_references = st.checkbox("์ฐธ๊ณ ์นดํผ ๋ณด๊ธฐ", value=True)
|
238 |
+
num_references = st.slider("์ฐธ๊ณ ์นดํผ ์:", 3, 10, 5)
|
239 |
|
240 |
+
# RAG ์นดํผ ์์ฑ ํจ์ (์๋ฒ ๋ฉ ๊ธฐ๋ฐ ํ์!)
|
241 |
+
def generate_copy_with_rag(user_request, category, target, tone, creative, num_concepts):
|
242 |
+
"""RAG ๊ธฐ๋ฐ ์นดํผ ์์ฑ - ์๋ฒ ๋ฉ ํ์ ์ฌ์ฉ"""
|
243 |
+
|
244 |
if not user_request.strip():
|
245 |
st.error("โ ์นดํผ ์์ฒญ์ ์
๋ ฅํด์ฃผ์ธ์")
|
246 |
return None
|
247 |
+
|
248 |
# ์งํ ์ํฉ ํ์
|
249 |
progress_bar = st.progress(0)
|
250 |
status_text = st.empty()
|
251 |
+
|
252 |
+
# 1๋จ๊ณ: ์๋ฏธ์ ๊ฒ์ (์๋ฒ ๋ฉ ๊ธฐ๋ฐ)
|
253 |
+
status_text.text("๐ ์๋ฏธ์ ๊ฒ์ ์ค... (RAG ํต์ฌ ๊ธฐ๋ฅ)")
|
254 |
progress_bar.progress(20)
|
255 |
+
|
256 |
+
try:
|
257 |
+
# ๊ฒ์ ์ฟผ๋ฆฌ ์์ฑ ๋ฐ ์๋ฒ ๋ฉ
|
258 |
+
search_query = f"{user_request} {target} ๊ด๊ณ ์นดํผ"
|
259 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
260 |
+
query_embedding = embedding_model.encode([search_query])
|
261 |
+
|
262 |
+
# ์นดํ
๊ณ ๋ฆฌ ํํฐ๋ง
|
263 |
+
if category != '์ ์ฒด':
|
264 |
+
filtered_df = df[df['์นดํ
๊ณ ๋ฆฌ'] == category]
|
265 |
+
else:
|
266 |
+
filtered_df = df
|
267 |
+
|
268 |
+
progress_bar.progress(40)
|
269 |
+
|
270 |
+
# ์ ์ฌ๋ ๊ณ์ฐ (์๋ฒ ๋ฉ์ ํต์ฌ!)
|
271 |
+
filtered_indices = filtered_df.index.tolist()
|
272 |
+
filtered_embeddings = embeddings[filtered_indices]
|
273 |
+
similarities = cosine_similarity(query_embedding, filtered_embeddings)[0]
|
274 |
+
|
275 |
+
# ์์ ์ฐธ๊ณ ์นดํผ ์ ๋ณ
|
276 |
+
top_indices = np.argsort(similarities)[::-1][:num_references]
|
277 |
+
|
278 |
+
reference_copies = []
|
279 |
+
for idx in top_indices:
|
280 |
+
original_idx = filtered_indices[idx]
|
281 |
+
row = df.iloc[original_idx]
|
282 |
+
if similarities[idx] >= min_similarity:
|
283 |
+
reference_copies.append({
|
284 |
+
'copy': row['์นดํผ ๋ด์ฉ'],
|
285 |
+
'brand': row['๋ธ๋๋'],
|
286 |
+
'similarity': similarities[idx]
|
287 |
+
})
|
288 |
+
|
289 |
+
progress_bar.progress(60)
|
290 |
+
|
291 |
+
if not reference_copies:
|
292 |
+
st.warning(f"โ ๏ธ ์ ์ฌ๋ {min_similarity} ์ด์์ธ ์ฐธ๊ณ ์นดํผ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค. ์ ์ฌ๋๋ฅผ ๋ฎ์ถฐ๋ณด์ธ์.")
|
293 |
+
progress_bar.empty()
|
294 |
+
status_text.empty()
|
295 |
+
return None
|
296 |
+
|
297 |
+
# 2๋จ๊ณ: AI ์นดํผ ์์ฑ
|
298 |
+
status_text.text("๐ค AI ์นดํผ ์์ฑ ์ค...")
|
299 |
+
progress_bar.progress(80)
|
300 |
+
|
301 |
+
# ํ๋กฌํํธ ์์ฑ
|
302 |
+
references_text = "\n".join([
|
303 |
+
f"{i}. \"{ref['copy']}\" - {ref['brand']} (์ ์ฌ๋: {ref['similarity']:.3f})"
|
304 |
+
for i, ref in enumerate(reference_copies, 1)
|
305 |
+
])
|
306 |
+
|
307 |
+
creativity_guidance = {
|
308 |
+
"๋ณด์์ ": "์์ ํ๊ณ ๊ฒ์ฆ๋ ํํ์ ์ฌ์ฉํ์ฌ",
|
309 |
+
"๊ท ํ": "์ฐฝ์์ ์ด๋ฉด์๋ ์ ์ ํ ์์ค์์",
|
310 |
+
"์ฐฝ์์ ": "๋
์ฐฝ์ ์ด๊ณ ํ์ ์ ์ธ ํํ์ผ๋ก"
|
311 |
+
}
|
312 |
+
|
313 |
+
prompt = f"""
|
314 |
๋น์ ์ ํ๊ตญ์ ์ ๋ฌธ ๊ด๊ณ ์นดํผ๋ผ์ดํฐ์
๋๋ค.
|
315 |
|
316 |
**์์ฒญ์ฌํญ:** {user_request}
|
|
|
318 |
**๋ธ๋๋ ํค:** {tone}
|
319 |
**์ฐฝ์์ฑ ์์ค:** {creative}
|
320 |
|
321 |
+
**์ฐธ๊ณ ์นดํผ๋ค (์๋ฏธ์ ์ ์ฌ๋ ๊ธฐ๋ฐ ์ ๋ณ):**
|
322 |
{references_text}
|
323 |
|
324 |
**์์ฑ ๊ฐ์ด๋๋ผ์ธ:**
|
|
|
332 |
1. [์นดํผ1]
|
333 |
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
334 |
|
335 |
+
2. [์นดํผ2]
|
336 |
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
337 |
|
338 |
3. [์นดํผ3]
|
|
|
340 |
|
341 |
**์ถ์ฒ ์นดํผ:** ์ ์ค ๊ฐ์ฅ ์ถ์ฒํ๋ ์นดํผ์ ์ด์
|
342 |
"""
|
343 |
+
|
|
|
344 |
response = model.generate_content(prompt)
|
345 |
progress_bar.progress(100)
|
346 |
status_text.text("โ
์๋ฃ!")
|
347 |
+
|
348 |
time.sleep(0.5)
|
349 |
progress_bar.empty()
|
350 |
status_text.empty()
|
351 |
+
|
352 |
return {
|
353 |
'references': reference_copies,
|
354 |
'generated_content': response.text,
|
355 |
+
'search_info': {
|
356 |
+
'query': search_query,
|
357 |
+
'total_candidates': len(filtered_df),
|
358 |
+
'selected_references': len(reference_copies)
|
359 |
+
},
|
360 |
'settings': {
|
361 |
'category': category,
|
362 |
'target': target,
|
|
|
364 |
'creative': creative
|
365 |
}
|
366 |
}
|
367 |
+
|
368 |
except Exception as e:
|
369 |
st.error(f"โ ์นดํผ ์์ฑ ์คํจ: {e}")
|
370 |
+
progress_bar.empty()
|
371 |
+
status_text.empty()
|
372 |
return None
|
373 |
|
374 |
# ์์ฑ ๋ฒํผ
|
375 |
if st.button("๐ ์นดํผ ์์ฑํ๊ธฐ", type="primary", use_container_width=True):
|
376 |
+
|
377 |
if not user_request or not user_request.strip():
|
378 |
st.error("โ ์นดํผ ์์ฒญ์ ์
๋ ฅํด์ฃผ์ธ์")
|
379 |
else:
|
380 |
+
# RAG ์นดํผ ์์ฑ
|
381 |
+
result = generate_copy_with_rag(
|
382 |
user_request=user_request,
|
383 |
category=selected_category,
|
384 |
target=target_audience,
|
|
|
386 |
creative=creative_level,
|
387 |
num_concepts=num_concepts
|
388 |
)
|
389 |
+
|
390 |
if result:
|
391 |
# ๊ฒฐ๊ณผ ํ์
|
392 |
st.markdown("## ๐ ์์ฑ๋ ์นดํผ")
|
393 |
st.markdown("---")
|
394 |
+
|
395 |
+
# ๊ฒ์ ์ ๋ณด ํ์
|
396 |
+
st.info(f"๐ **๊ฒ์ ์ ๋ณด**: {result['search_info']['total_candidates']:,}๊ฐ ํ๋ณด์์ "
|
397 |
+
f"{result['search_info']['selected_references']}๊ฐ ์ฐธ๊ณ ์นดํผ ์ ๋ณ")
|
398 |
+
|
399 |
# ์ฐธ๊ณ ์นดํผ ํ์
|
400 |
if show_references and result['references']:
|
401 |
+
with st.expander("๐ ๏ฟฝ๏ฟฝ๏ฟฝ๊ณ ํ ์นดํผ๋ค (์๋ฏธ์ ์ ์ฌ๋ ๊ธฐ๋ฐ ์ ๋ณ)"):
|
402 |
for i, ref in enumerate(result['references'], 1):
|
403 |
st.markdown(f"**{i}.** \"{ref['copy']}\"")
|
404 |
+
st.markdown(f" - ๋ธ๋๋: {ref['brand']}")
|
405 |
st.markdown(f" - ์ ์ฌ๋: {ref['similarity']:.3f}")
|
406 |
st.markdown("")
|
407 |
+
|
408 |
# ์์ฑ๋ ์นดํผ ํ์
|
409 |
st.markdown("### โจ AI๊ฐ ์์ฑํ ์นดํผ:")
|
410 |
st.markdown(result['generated_content'])
|
411 |
+
|
412 |
# ๊ฒฐ๊ณผ ๋ค์ด๋ก๋
|
413 |
result_json = json.dumps({
|
414 |
'timestamp': datetime.now().isoformat(),
|
415 |
'request': user_request,
|
416 |
'settings': result['settings'],
|
417 |
+
'search_info': result['search_info'],
|
418 |
'generated_content': result['generated_content']
|
419 |
}, ensure_ascii=False, indent=2)
|
420 |
+
|
421 |
st.download_button(
|
422 |
label="๐พ ๊ฒฐ๊ณผ ๋ค์ด๋ก๋ (JSON)",
|
423 |
data=result_json,
|
|
|
425 |
mime="application/json"
|
426 |
)
|
427 |
|
428 |
+
# ์์คํ
์ ๋ณด (์ฌ์ด๋๋ฐ ํ๋จ)
|
429 |
+
st.sidebar.markdown("---")
|
430 |
+
st.sidebar.markdown("### ๐ RAG ์์คํ
์ ๋ณด")
|
431 |
+
if df is not None and embeddings is not None:
|
432 |
+
st.sidebar.markdown(f"**์นดํผ ๋ฐ์ดํฐ**: {len(df):,}๊ฐ")
|
433 |
+
st.sidebar.markdown(f"**์นดํ
๊ณ ๋ฆฌ**: {df['์นดํ
๊ณ ๋ฆฌ'].nunique()}๊ฐ")
|
434 |
+
st.sidebar.markdown(f"**๋ธ๋๋**: {df['๋ธ๋๋'].nunique()}๊ฐ")
|
435 |
+
st.sidebar.markdown(f"**์๋ฒ ๋ฉ**: {embeddings.shape[1]}์ฐจ์")
|
436 |
+
st.sidebar.markdown("**๊ฒ์ ์์ง**: Korean SBERT")
|
437 |
+
st.sidebar.markdown("**ํธ์คํ
**: ๐ค Hugging Face")
|
438 |
+
|
439 |
# ์ฌ์ฉ๋ฒ ๊ฐ์ด๋
|
440 |
+
with st.expander("๐ก RAG ์์คํ
์ฌ์ฉ๋ฒ ๊ฐ์ด๋"):
|
441 |
st.markdown("""
|
442 |
### ๐ฏ ํจ๊ณผ์ ์ธ ์ฌ์ฉ๋ฒ
|
443 |
+
|
444 |
**1. ๊ตฌ์ฒด์ ์ธ ์์ฒญํ๊ธฐ:**
|
445 |
- โ "์นดํผ ์จ์ค"
|
446 |
- โ
"30๋ ์ง์ฅ ์ฌ์ฑ์ฉ ํ๋ฆฌ๋ฏธ์ ์คํจ์ผ์ด ์ ์ ํ ๋ฐ์นญ ์นดํผ"
|
447 |
+
|
448 |
+
**2. RAG ์์คํ
์ ์ฅ์ :**
|
449 |
+
- ๐ง **์๋ฏธ์ ๊ฒ์**: ํค์๋๋ฟ๋ง ์๋๋ผ ์๋ฏธ๊น์ง ์ดํด
|
450 |
+
- ๐ฏ **๋ฌธ๋งฅ ๋งค์นญ**: ํ๊ฒ๊ณผ ์ํฉ์ ๋ง๋ ์นดํผ ์๋ ์ ๋ณ
|
451 |
+
- ๐ **๋ฐ์ดํฐ ๊ธฐ๋ฐ**: 37,671๊ฐ ์ค์ ์นดํผ์์ ํ์ตํ ํจํด
|
452 |
+
|
453 |
**3. ์ฐฝ์์ฑ ์กฐ์ :**
|
454 |
- **๋ณด์์ **: ์์ ํ ํด๋ผ์ด์ธํธ, ๊ฒ์ฆ๋ ์ ๊ทผ
|
455 |
- **๊ท ํ**: ์ผ๋ฐ์ ์ธ ํ๋ก์ ํธ (์ถ์ฒ!)
|
456 |
- **์ฐฝ์์ **: ํ์ ์ ๋ธ๋๋, ํ๊ฒฉ์ ์บ ํ์ธ
|
457 |
+
|
458 |
+
**4. ์ฐธ๊ณ ์นดํผ ํ์ฉ:**
|
459 |
+
- ์์ฑ๋ ์นดํผ์ ์ฐธ๊ณ ์นดํผ๋ฅผ ๋น๊ต ๋ถ์
|
460 |
+
- ํธ๋ ๋์ ํจํด ํ์
๊ฐ๋ฅ
|
461 |
+
- ๊ฒฝ์์ฌ ๋ถ์ ์๋ฃ๋ก ํ์ฉ
|
462 |
""")
|
463 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
# ํธํฐ
|
465 |
st.markdown("---")
|
466 |
st.markdown(
|
|
|
468 |
"RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ
powered by Korean SBERT + Gemini AI"
|
469 |
)
|
470 |
|
471 |
+
# ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง (๊ฐ๋ฐ์์ฉ)
|
472 |
+
if os.getenv("DEBUG_MODE"):
|
473 |
+
st.sidebar.markdown("### ๐ง ๋๋ฒ๊ทธ ์ ๋ณด")
|
474 |
+
if 'embeddings' in locals():
|
475 |
+
st.sidebar.write(f"์๋ฒ ๋ฉ ๋ฉ๋ชจ๋ฆฌ: {embeddings.nbytes / (1024*1024):.1f}MB")
|
476 |
+
st.sidebar.write(f"Streamlit ๋ฒ์ : {st.__version__}")
|