Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -14,20 +14,27 @@ BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search"
|
|
14 |
IMAGE_API_URL = "http://211.233.58.201:7896"
|
15 |
MAX_TOKENS = 7_999
|
16 |
|
17 |
-
# λΈλ‘κ·Έ ν
νλ¦Ώ λ° μ€νμΌ μ μ
|
18 |
BLOG_TEMPLATES = {
|
19 |
-
"standard": "
|
20 |
-
"tutorial": "λ¨κ³λ³ νν 리μΌ
|
21 |
-
"review": "μ ν/μλΉμ€
|
22 |
-
"storytelling": "
|
23 |
-
"seo_optimized": "
|
24 |
}
|
25 |
|
26 |
BLOG_TONES = {
|
27 |
-
"professional": "μ λ¬Έμ μ΄κ³ 곡μμ μΈ
|
28 |
-
"casual": "μΉκ·Όνκ³ λν체
|
29 |
-
"humorous": "
|
30 |
-
"storytelling": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
# ββββββββββββββββββββββββββββββββ λ‘κΉ
ββββββββββββββββββββββββββββββββββββββ
|
@@ -155,7 +162,7 @@ def get_system_prompt(template="standard", tone="professional", word_count=1750)
|
|
155 |
return final_prompt
|
156 |
|
157 |
# ββββββββββββββββββββββββββββββββ Brave Search API βββββββββββββββββββββββββ
|
158 |
-
def brave_search(query: str, count: int =
|
159 |
"""
|
160 |
Brave Web Search API νΈμΆ β list[dict]
|
161 |
λ°ν νλ: index, title, link, snippet, displayed_link
|
@@ -168,7 +175,7 @@ def brave_search(query: str, count: int = 5):
|
|
168 |
"Accept-Encoding": "gzip",
|
169 |
"X-Subscription-Token": BRAVE_KEY
|
170 |
}
|
171 |
-
params = {"q": query, "count": str(count)}
|
172 |
|
173 |
for attempt in range(3): # μ΅λ 3λ² μ¬μλ
|
174 |
try:
|
@@ -185,7 +192,7 @@ def brave_search(query: str, count: int = 5):
|
|
185 |
raise ValueError("κ²μ κ²°κ³Όκ° μμ΅λλ€")
|
186 |
|
187 |
arts = []
|
188 |
-
for i, res in enumerate(raw[:count], 1):
|
189 |
url = res.get("url", res.get("link", ""))
|
190 |
host = re.sub(r"https?://(www\.)?", "", url).split("/")[0]
|
191 |
arts.append({
|
@@ -221,7 +228,7 @@ def mock_results(query: str) -> str:
|
|
221 |
def do_web_search(query: str) -> str:
|
222 |
"""μΉ κ²μ μν λ° κ²°κ³Ό ν¬λ§·ν
"""
|
223 |
try:
|
224 |
-
arts = brave_search(query,
|
225 |
if not arts:
|
226 |
logging.warning("κ²μ κ²°κ³Ό μμ, λ체 μ½ν
μΈ μ¬μ©")
|
227 |
return mock_results(query)
|
@@ -271,7 +278,7 @@ def keywords(text: str, top=5):
|
|
271 |
|
272 |
# ββββββββββββββββββββββββββββββββ Streamlit UI ββββββββββββββββββββββββββββ
|
273 |
def ginigen_app():
|
274 |
-
st.title("
|
275 |
|
276 |
# μΈμ
κΈ°λ³Έκ°
|
277 |
defaults = dict(
|
@@ -294,17 +301,31 @@ def ginigen_app():
|
|
294 |
# λΈλ‘κ·Έ ν
νλ¦Ώ λ° μ€νμΌ μ ν
|
295 |
sb.subheader("λΈλ‘κ·Έ μ€νμΌ μ€μ ")
|
296 |
sb.selectbox("λΈλ‘κ·Έ ν
νλ¦Ώ", options=list(BLOG_TEMPLATES.keys()),
|
297 |
-
format_func=lambda x: x
|
298 |
key="blog_template")
|
299 |
|
300 |
sb.selectbox("λΈλ‘κ·Έ ν€", options=list(BLOG_TONES.keys()),
|
301 |
-
format_func=lambda x: x
|
302 |
key="blog_tone")
|
303 |
|
304 |
sb.slider("λΈλ‘κ·Έ κΈΈμ΄ (λ¨μ΄ μ)", 800, 3000, 1750, key="word_count")
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
sb.subheader("κΈ°ν μ€μ ")
|
307 |
-
sb.toggle("μλ μ μ₯",
|
308 |
sb.toggle("μ΄λ―Έμ§ μλ μμ±", key="generate_image")
|
309 |
|
310 |
# μΉ κ²μ ν κΈ (λͺ¨λν°λ§μ μν΄ μ μ§νλ κΈ°λ³Έκ°μ False)
|
@@ -322,7 +343,7 @@ def ginigen_app():
|
|
322 |
title = title.group(1).strip() if title else "blog"
|
323 |
sb.subheader("μ΅κ·Ό λΈλ‘κ·Έ λ€μ΄λ‘λ")
|
324 |
c1, c2 = sb.columns(2)
|
325 |
-
c1.download_button("
|
326 |
file_name=f"{title}.md", mime="text/markdown")
|
327 |
c2.download_button("HTML", md_to_html(latest_blog, title),
|
328 |
file_name=f"{title}.html", mime="text/html")
|
@@ -350,8 +371,16 @@ def ginigen_app():
|
|
350 |
if "image" in m:
|
351 |
st.image(m["image"], caption=m.get("image_caption", ""))
|
352 |
|
353 |
-
# ββ μ¬μ©μ μ
λ ₯
|
354 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
355 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
356 |
with st.chat_message("user"): st.markdown(prompt)
|
357 |
|
@@ -400,7 +429,7 @@ def ginigen_app():
|
|
400 |
# λ³Έλ¬Έ λ€μ΄λ‘λ λ²νΌ (MD / HTML)
|
401 |
st.subheader("μ΄ λΈλ‘κ·Έ λ€μ΄λ‘λ")
|
402 |
b1, b2 = st.columns(2)
|
403 |
-
b1.download_button("
|
404 |
file_name=f"{prompt[:30]}.md", mime="text/markdown")
|
405 |
b2.download_button("HTML", md_to_html(answer, prompt[:30]),
|
406 |
file_name=f"{prompt[:30]}.html", mime="text/html")
|
|
|
14 |
IMAGE_API_URL = "http://211.233.58.201:7896"
|
15 |
MAX_TOKENS = 7_999
|
16 |
|
17 |
+
# λΈλ‘κ·Έ ν
νλ¦Ώ λ° μ€νμΌ μ μ (νκΈν)
|
18 |
BLOG_TEMPLATES = {
|
19 |
+
"standard": "νμ€ 8λ¨κ³ νλ μμν¬ λΈλ‘κ·Έ",
|
20 |
+
"tutorial": "λ¨κ³λ³ νν λ¦¬μΌ νμ",
|
21 |
+
"review": "μ ν/μλΉμ€ 리뷰 νμ",
|
22 |
+
"storytelling": "μ€ν 리ν
λ§ νμ",
|
23 |
+
"seo_optimized": "SEO μ΅μ ν λΈλ‘κ·Έ"
|
24 |
}
|
25 |
|
26 |
BLOG_TONES = {
|
27 |
+
"professional": "μ λ¬Έμ μ΄κ³ 곡μμ μΈ ν€",
|
28 |
+
"casual": "μΉκ·Όνκ³ λν체 μ€μ¬ ν€",
|
29 |
+
"humorous": "μ λ¨Έλ¬μ€ν μ κ·Ό",
|
30 |
+
"storytelling": "μ΄μΌκΈ° μ€μ¬μ μ κ·Ό"
|
31 |
+
}
|
32 |
+
|
33 |
+
# μμ λΈλ‘κ·Έ μ£Όμ
|
34 |
+
EXAMPLE_TOPICS = {
|
35 |
+
"example1": "2025λ
λ°λ λΆλμ° μΈκΈ μ λ: μΌλ° κ°μ μ λ―ΈμΉλ μν₯κ³Ό μ μΈ μ λ΅",
|
36 |
+
"example2": "2025λ
μ¬λ¦ μ κ΅ μ§μλ³ λν μΆμ μ΄μ 리μ μ¨μ λͺ
μ μΆμ²",
|
37 |
+
"example3": "2025λ
μ£Όλͺ©ν΄μΌ ν μ μ±μ₯ μ°μ
ν¬μ κ°μ΄λ: μΈκ³΅μ§λ₯ κ΄λ ¨ λ°κ΅΄ μ λ΅"
|
38 |
}
|
39 |
|
40 |
# ββββββββββββββββββββββββββββββββ λ‘κΉ
ββββββββββββββββββββββββββββββββββββββ
|
|
|
162 |
return final_prompt
|
163 |
|
164 |
# ββββββββββββββββββββββββββββββββ Brave Search API βββββββββββββββββββββββββ
|
165 |
+
def brave_search(query: str, count: int = 20): # κΈ°λ³Έκ°μ 20μΌλ‘ λ³κ²½
|
166 |
"""
|
167 |
Brave Web Search API νΈμΆ β list[dict]
|
168 |
λ°ν νλ: index, title, link, snippet, displayed_link
|
|
|
175 |
"Accept-Encoding": "gzip",
|
176 |
"X-Subscription-Token": BRAVE_KEY
|
177 |
}
|
178 |
+
params = {"q": query, "count": str(count)} # μΉ΄μ΄νΈ νλΌλ―Έν° μ λ¬
|
179 |
|
180 |
for attempt in range(3): # μ΅λ 3λ² μ¬μλ
|
181 |
try:
|
|
|
192 |
raise ValueError("κ²μ κ²°κ³Όκ° μμ΅λλ€")
|
193 |
|
194 |
arts = []
|
195 |
+
for i, res in enumerate(raw[:count], 1): # countλ§νΌ λ°λ³΅
|
196 |
url = res.get("url", res.get("link", ""))
|
197 |
host = re.sub(r"https?://(www\.)?", "", url).split("/")[0]
|
198 |
arts.append({
|
|
|
228 |
def do_web_search(query: str) -> str:
|
229 |
"""μΉ κ²μ μν λ° κ²°κ³Ό ν¬λ§·ν
"""
|
230 |
try:
|
231 |
+
arts = brave_search(query, 20) # μ¬κΈ°λ 20μΌλ‘ λ³κ²½
|
232 |
if not arts:
|
233 |
logging.warning("κ²μ κ²°κ³Ό μμ, λ체 μ½ν
μΈ μ¬μ©")
|
234 |
return mock_results(query)
|
|
|
278 |
|
279 |
# ββββββββββββββββββββββββββββββββ Streamlit UI ββββββββββββββββββββββββββββ
|
280 |
def ginigen_app():
|
281 |
+
st.title("μ§λμ λΈλ‘κ·Έ")
|
282 |
|
283 |
# μΈμ
κΈ°λ³Έκ°
|
284 |
defaults = dict(
|
|
|
301 |
# λΈλ‘κ·Έ ν
νλ¦Ώ λ° μ€νμΌ μ ν
|
302 |
sb.subheader("λΈλ‘κ·Έ μ€νμΌ μ€μ ")
|
303 |
sb.selectbox("λΈλ‘κ·Έ ν
νλ¦Ώ", options=list(BLOG_TEMPLATES.keys()),
|
304 |
+
format_func=lambda x: BLOG_TEMPLATES[x],
|
305 |
key="blog_template")
|
306 |
|
307 |
sb.selectbox("λΈλ‘κ·Έ ν€", options=list(BLOG_TONES.keys()),
|
308 |
+
format_func=lambda x: BLOG_TONES[x],
|
309 |
key="blog_tone")
|
310 |
|
311 |
sb.slider("λΈλ‘κ·Έ κΈΈμ΄ (λ¨μ΄ μ)", 800, 3000, 1750, key="word_count")
|
312 |
|
313 |
+
# μμ μ£Όμ μ ν
|
314 |
+
sb.subheader("μμ μ£Όμ ")
|
315 |
+
if sb.button("μλ°μ€ν¬λ¦½νΈ νλ μμν¬ λΉκ΅", key="example1"):
|
316 |
+
st.session_state.example_topic = EXAMPLE_TOPICS["example1"]
|
317 |
+
st.experimental_rerun()
|
318 |
+
|
319 |
+
if sb.button("μ΄λ³΄μλ₯Ό μν μ£Όμ ν¬μ κ°μ΄λ", key="example2"):
|
320 |
+
st.session_state.example_topic = EXAMPLE_TOPICS["example2"]
|
321 |
+
st.experimental_rerun()
|
322 |
+
|
323 |
+
if sb.button("ν¨κ³Όμ μΈ μκ° κ΄λ¦¬ μ λ΅", key="example3"):
|
324 |
+
st.session_state.example_topic = EXAMPLE_TOPICS["example3"]
|
325 |
+
st.experimental_rerun()
|
326 |
+
|
327 |
sb.subheader("κΈ°ν μ€μ ")
|
328 |
+
sb.toggle("μλ μ μ₯", key="auto_save")
|
329 |
sb.toggle("μ΄λ―Έμ§ μλ μμ±", key="generate_image")
|
330 |
|
331 |
# μΉ κ²μ ν κΈ (λͺ¨λν°λ§μ μν΄ μ μ§νλ κΈ°λ³Έκ°μ False)
|
|
|
343 |
title = title.group(1).strip() if title else "blog"
|
344 |
sb.subheader("μ΅κ·Ό λΈλ‘κ·Έ λ€μ΄λ‘λ")
|
345 |
c1, c2 = sb.columns(2)
|
346 |
+
c1.download_button("λ§ν¬λ€μ΄", latest_blog,
|
347 |
file_name=f"{title}.md", mime="text/markdown")
|
348 |
c2.download_button("HTML", md_to_html(latest_blog, title),
|
349 |
file_name=f"{title}.html", mime="text/html")
|
|
|
371 |
if "image" in m:
|
372 |
st.image(m["image"], caption=m.get("image_caption", ""))
|
373 |
|
374 |
+
# ββ μ¬μ©μ μ
λ ₯ λλ μμ μ£Όμ μ²λ¦¬
|
375 |
+
prompt = st.chat_input("무μμ λμλ릴κΉμ?")
|
376 |
+
|
377 |
+
# μμ μ£Όμ κ° μ νλμμΌλ©΄ μ²λ¦¬
|
378 |
+
if hasattr(st.session_state, 'example_topic') and st.session_state.example_topic:
|
379 |
+
prompt = st.session_state.example_topic
|
380 |
+
# μ²λ¦¬ ν μμ μ£Όμ μ΄κΈ°ν
|
381 |
+
del st.session_state.example_topic
|
382 |
+
|
383 |
+
if prompt:
|
384 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
385 |
with st.chat_message("user"): st.markdown(prompt)
|
386 |
|
|
|
429 |
# λ³Έλ¬Έ λ€μ΄λ‘λ λ²νΌ (MD / HTML)
|
430 |
st.subheader("μ΄ λΈλ‘κ·Έ λ€μ΄λ‘λ")
|
431 |
b1, b2 = st.columns(2)
|
432 |
+
b1.download_button("λ§ν¬λ€μ΄", answer,
|
433 |
file_name=f"{prompt[:30]}.md", mime="text/markdown")
|
434 |
b2.download_button("HTML", md_to_html(answer, prompt[:30]),
|
435 |
file_name=f"{prompt[:30]}.html", mime="text/html")
|