Spaces:
Sleeping
Sleeping
# ์์ ์ ์ธ AI ์นดํผ๋ผ์ดํฐ - ์๋ฒ ๋ฉ ๊ธฐ๋ฐ RAG ์์คํ | |
# Hugging Face Spaces ํ๊ฒฝ ์ต์ ํ ๋ฒ์ | |
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import pickle | |
import google.generativeai as genai | |
import time | |
import json | |
import os | |
from datetime import datetime | |
# ํ๊ฒฝ ์ค์ (๊ถํ ๋ฌธ์ ํด๊ฒฐ) | |
os.environ['STREAMLIT_BROWSER_GATHER_USAGE_STATS'] = 'false' | |
os.environ['TRANSFORMERS_CACHE'] = '/tmp/transformers' | |
os.environ['SENTENCE_TRANSFORMERS_HOME'] = '/tmp/sentence_transformers' | |
# ํ์ด์ง ์ค์ | |
st.set_page_config( | |
page_title="AI ์นดํผ๋ผ์ดํฐ | RAG ๊ธฐ๋ฐ ๊ด๊ณ ์นดํผ ์์ฑ", | |
page_icon="โจ", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# ์ ๋ชฉ ๋ฐ ์ค๋ช | |
st.title("โจ AI ์นดํผ๋ผ์ดํฐ") | |
st.markdown("### ๐ฏ 37,671๊ฐ ์ค์ ๊ด๊ณ ์นดํผ ๋ฐ์ดํฐ ๊ธฐ๋ฐ RAG ์์คํ ") | |
st.markdown("---") | |
# ์ฌ์ด๋๋ฐ ์ค์ | |
st.sidebar.header("๐๏ธ ์นดํผ ์์ฑ ์ค์ ") | |
# API ํค ์ ๋ ฅ (ํ๊ฒฝ๋ณ์ ์ฐ์ ์ฌ์ฉ) | |
default_api_key = os.getenv("GEMINI_API_KEY", "") | |
api_key = st.sidebar.text_input( | |
"๐ Gemini API ํค", | |
value=default_api_key, | |
type="password", | |
help="ํ๊ฒฝ๋ณ์์ GEMINI_API_KEY๋ก ์ค์ ํ๋ฉด ์๋ ์ ๋ ฅ๋ฉ๋๋ค" | |
) | |
if not api_key: | |
st.warning("โ ๏ธ Gemini API ํค๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์") | |
st.info("๐ก Settings โ Repository secrets์์ GEMINI_API_KEY๋ฅผ ์ค์ ํ์ธ์") | |
st.stop() | |
# ์์คํ ์ด๊ธฐํ (์บ์ฑ) - ์๋ฒ ๋ฉ ํ์! | |
def load_system(): | |
"""์์คํ ์ปดํฌ๋ํธ ๋ก๋ฉ - ์๋ฒ ๋ฉ ๊ธฐ๋ฐ RAG ์์คํ """ | |
progress_container = st.container() | |
with progress_container: | |
# ์ ์ฒด ์งํ๋ฅ | |
total_progress = st.progress(0) | |
status_text = st.empty() | |
# 1๋จ๊ณ: API ์ค์ (10%) | |
status_text.text("๐ Gemini API ์ด๊ธฐํ ์ค...") | |
try: | |
genai.configure(api_key=api_key) | |
model = genai.GenerativeModel('gemini-2.0-flash') | |
total_progress.progress(10) | |
st.success("โ Gemini API ์ค์ ์๋ฃ") | |
except Exception as e: | |
st.error(f"โ Gemini API ์ค์ ์คํจ: {e}") | |
return None, None, None, None | |
# 2๋จ๊ณ: ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ (40%) | |
status_text.text("๐ค ํ๊ตญ์ด ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์ค... (1-2๋ถ ์์)") | |
embedding_model = None | |
# ์์ ์ ์ธ ๋ชจ๋ธ ๋ก๋ฉ ์ ๋ต | |
try: | |
# ๋จผ์ ์บ์ ๋๋ ํ ๋ฆฌ ์์ฑ | |
os.makedirs('/tmp/sentence_transformers', exist_ok=True) | |
os.makedirs('/tmp/transformers', exist_ok=True) | |
# sentence-transformers ์ํฌํธ๋ฅผ ํจ์ ๋ด์์ | |
from sentence_transformers import SentenceTransformer | |
from sklearn.metrics.pairwise import cosine_similarity | |
# ํ๊ตญ์ด ๋ชจ๋ธ ๋ก๋ฉ ์๋ | |
embedding_model = SentenceTransformer('jhgan/ko-sbert-nli', | |
cache_folder='/tmp/sentence_transformers') | |
total_progress.progress(40) | |
st.success("โ ํ๊ตญ์ด ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์๋ฃ") | |
except Exception as e: | |
st.error(f"โ ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋ฉ ์คํจ: {e}") | |
st.error("๐จ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์์ด๋ RAG ์์คํ ์ด ์๋ํ ์ ์์ต๋๋ค!") | |
return None, None, None, None | |
# 3๋จ๊ณ: ๋ฐ์ดํฐ ๋ก๋ (60%) | |
status_text.text("๐ ์นดํผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ก๋ฉ ์ค...") | |
try: | |
df = pd.read_excel('๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx') | |
total_progress.progress(60) | |
st.success(f"โ ๋ฐ์ดํฐ ๋ก๋ฉ ์๋ฃ: {len(df):,}๊ฐ ์นดํผ") | |
except Exception as e: | |
st.error(f"โ ๋ฐ์ดํฐ ๋ก๋ฉ ์คํจ: {e}") | |
return None, None, None, None | |
# 4๋จ๊ณ: ์๋ฒ ๋ฉ ๋ฐ์ดํฐ ๋ก๋ (90%) - ์ด๊ฒ ํต์ฌ! | |
status_text.text("๐ ๋ฒกํฐ ์๋ฒ ๋ฉ ๋ก๋ฉ ์ค... (RAG ์์คํ ํต์ฌ)") | |
try: | |
with open('copy_embeddings.pkl', 'rb') as f: | |
embeddings_data = pickle.load(f) | |
embeddings = embeddings_data['embeddings'] | |
total_progress.progress(90) | |
st.success(f"โ ์๋ฒ ๋ฉ ๋ก๋ฉ ์๋ฃ: {embeddings.shape[0]:,}๊ฐ ร {embeddings.shape[1]}์ฐจ์") | |
except Exception as e: | |
st.error(f"โ ์๋ฒ ๋ฉ ๋ก๋ฉ ์คํจ: {e}") | |
st.error("๐จ ์๋ฒ ๋ฉ ์์ด๋ ์๋ฏธ์ ๊ฒ์์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค!") | |
return None, None, None, None | |
# 5๋จ๊ณ: ์ต์ข ๊ฒ์ฆ (100%) | |
status_text.text("โจ ์์คํ ๊ฒ์ฆ ์ค...") | |
if model and embedding_model and df is not None and embeddings is not None: | |
total_progress.progress(100) | |
status_text.text("๐ RAG ์์คํ ๋ก๋ฉ ์๋ฃ!") | |
# ์ฑ๊ณต ๋ฉ์์ง | |
success_col1, success_col2, success_col3 = st.columns(3) | |
with success_col1: | |
st.metric("์นดํผ ๋ฐ์ดํฐ", f"{len(df):,}๊ฐ") | |
with success_col2: | |
st.metric("์๋ฒ ๋ฉ ์ฐจ์", f"{embeddings.shape[1]}D") | |
with success_col3: | |
st.metric("๊ฒ์ ์์ง", "Korean SBERT") | |
# ์งํ๋ฅ ๋ฐ ์ ๊ฑฐ | |
time.sleep(1) | |
total_progress.empty() | |
status_text.empty() | |
return model, embedding_model, df, embeddings | |
else: | |
st.error("โ ์์คํ ๋ก๋ฉ ์คํจ: ํ์ ๊ตฌ์ฑ์์ ๋๋ฝ") | |
return None, None, None, None | |
# ์์คํ ๋ก๋ฉ | |
with st.spinner("๐ AI ์นดํผ๋ผ์ดํฐ ์์คํ ์ด๊ธฐํ ์ค..."): | |
model, embedding_model, df, embeddings = load_system() | |
if model is None or embedding_model is None or df is None or embeddings is None: | |
st.error("โ ์์คํ ์ ๋ก๋ฉํ ์ ์์ต๋๋ค. ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํ๊ฑฐ๋ ๊ด๋ฆฌ์์๊ฒ ๋ฌธ์ํ์ธ์.") | |
st.stop() | |
# ์ฌ์ด๋๋ฐ ์ค์ (์์คํ ๋ก๋ฉ ์ฑ๊ณต ํ) | |
st.sidebar.success("๐ RAG ์์คํ ์ค๋น ์๋ฃ!") | |
# ์นดํ ๊ณ ๋ฆฌ ์ ํ | |
categories = ['์ ์ฒด'] + sorted(df['์นดํ ๊ณ ๋ฆฌ'].unique().tolist()) | |
selected_category = st.sidebar.selectbox( | |
"๐ ์นดํ ๊ณ ๋ฆฌ", | |
categories, | |
help="ํน์ ์นดํ ๊ณ ๋ฆฌ๋ก ๊ฒ์์ ์ ํํ ์ ์์ต๋๋ค" | |
) | |
# ํ๊ฒ ๊ณ ๊ฐ ์ค์ | |
target_audience = st.sidebar.selectbox( | |
"๐ฏ ํ๊ฒ ๊ณ ๊ฐ", | |
['20๋', '30๋', '์ผ๋ฐ', '10๋', '40๋', '50๋+', '๋จ์ฑ', '์ฌ์ฑ', '์ง์ฅ์ธ', 'ํ์', '์ฃผ๋ถ'], | |
help="ํ๊ฒ ๊ณ ๊ฐ์ ๋ง๋ ํค์ค๋งค๋๋ก ์นดํผ๋ฅผ ์์ฑํฉ๋๋ค" | |
) | |
# ๋ธ๋๋ ํค์ค๋งค๋ | |
brand_tone = st.sidebar.selectbox( | |
"๐จ ๋ธ๋๋ ํค", | |
['์ธ๋ จ๋', '์น๊ทผํ', '๊ณ ๊ธ์ค๋ฌ์ด', 'ํ๊ธฐ์ฐฌ', '์ ๋ขฐํ ์ ์๋', '์ ์', '๋ฐ๋ปํ', '์ ๋ฌธ์ ์ธ'], | |
help="์ํ๋ ๋ธ๋๋ ์ด๋ฏธ์ง๋ฅผ ์ ํํ์ธ์" | |
) | |
# ์ฐฝ์์ฑ ์์ค | |
creative_level = st.sidebar.select_slider( | |
"๐ง ์ฐฝ์์ฑ ์์ค", | |
options=['๋ณด์์ ', '๊ท ํ', '์ฐฝ์์ '], | |
value='๊ท ํ', | |
help="๋ณด์์ : ์์ ํ ํํ, ์ฐฝ์์ : ๋ ์ฐฝ์ ํํ" | |
) | |
# ๋ฉ์ธ ์ ๋ ฅ ์์ญ | |
st.markdown("## ๐ญ ์ด๋ค ์นดํผ๋ฅผ ๋ง๋ค๊ณ ์ถ์ผ์ ๊ฐ์?") | |
# ์ ๋ ฅ ๋ฐฉ์ ์ ํ | |
input_method = st.radio( | |
"์ ๋ ฅ ๋ฐฉ์ ์ ํ:", | |
["์ง์ ์ ๋ ฅ", "ํ ํ๋ฆฟ ์ ํ"], | |
horizontal=True | |
) | |
if input_method == "์ง์ ์ ๋ ฅ": | |
user_request = st.text_area( | |
"์นดํผ ์์ฒญ์ ์์ธํ ์์ฑํด์ฃผ์ธ์:", | |
placeholder="์: 30๋ ์ง์ฅ ์ฌ์ฑ์ฉ ํ๋ฆฌ๋ฏธ์ ์คํจ์ผ์ด ์ ์ ํ ๋ฐ์นญ ์นดํผ", | |
height=100 | |
) | |
else: | |
# ํ ํ๋ฆฟ ์ ํ | |
templates = { | |
"์ ์ ํ ๋ฐ์นญ": "๋์ {์นดํ ๊ณ ๋ฆฌ} ์ ์ ํ ๋ฐ์นญ ์นดํผ", | |
"ํ ์ธ ์ด๋ฒคํธ": "{์นดํ ๊ณ ๋ฆฌ} ํ ์ธ ์ด๋ฒคํธ ํ๋ก๋ชจ์ ์นดํผ", | |
"๋ธ๋๋ ์ฌ๋ก๊ฑด": "{์นดํ ๊ณ ๋ฆฌ} ๋ธ๋๋์ ๋ํ ์ฌ๋ก๊ฑด", | |
"์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ": "{์๋น์ค๋ช } ์ ๋ฒ์ ์ถ์ ์นดํผ", | |
"์์ฆ ํ์ ": "{์์ฆ} ํ์ {์นดํ ๊ณ ๋ฆฌ} ํน๋ณ ์๋์ ์นดํผ" | |
} | |
selected_template = st.selectbox("ํ ํ๋ฆฟ ์ ํ:", list(templates.keys())) | |
col1, col2 = st.columns(2) | |
with col1: | |
template_category = st.text_input("์ ํ/์๋น์ค:", value="") | |
with col2: | |
if selected_template == "์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ": | |
service_name = st.text_input("์๋น์ค๋ช :", placeholder="์: ๋ฐฐ๋ฌ์ฑ, ๊ธ์ต์ฑ") | |
user_request = templates[selected_template].format(์๋น์ค๋ช =service_name) | |
elif selected_template == "์์ฆ ํ์ ": | |
season = st.selectbox("์์ฆ:", ["๋ด", "์ฌ๋ฆ", "๊ฐ์", "๊ฒจ์ธ", "ํฌ๋ฆฌ์ค๋ง์ค", "์ ๋ "]) | |
user_request = templates[selected_template].format(์์ฆ=season, ์นดํ ๊ณ ๋ฆฌ=template_category) | |
else: | |
user_request = templates[selected_template].format(์นดํ ๊ณ ๋ฆฌ=template_category) | |
st.text_area("์์ฑ๋ ์์ฒญ:", value=user_request, height=80, disabled=True) | |
# ๊ณ ๊ธ ์ต์ | |
with st.expander("๐ง ๊ณ ๊ธ ์ต์ "): | |
col1, col2 = st.columns(2) | |
with col1: | |
num_concepts = st.slider("์์ฑํ ์ปจ์ ์:", 1, 5, 3) | |
min_similarity = st.slider("์ต์ ์ ์ฌ๋:", 0.0, 1.0, 0.3, 0.1) | |
with col2: | |
show_references = st.checkbox("์ฐธ๊ณ ์นดํผ ๋ณด๊ธฐ", value=True) | |
num_references = st.slider("์ฐธ๊ณ ์นดํผ ์:", 3, 10, 5) | |
# RAG ์นดํผ ์์ฑ ํจ์ (์๋ฒ ๋ฉ ๊ธฐ๋ฐ ํ์!) | |
def generate_copy_with_rag(user_request, category, target, tone, creative, num_concepts): | |
"""RAG ๊ธฐ๋ฐ ์นดํผ ์์ฑ - ์๋ฒ ๋ฉ ํ์ ์ฌ์ฉ""" | |
if not user_request.strip(): | |
st.error("โ ์นดํผ ์์ฒญ์ ์ ๋ ฅํด์ฃผ์ธ์") | |
return None | |
# ์งํ ์ํฉ ํ์ | |
progress_bar = st.progress(0) | |
status_text = st.empty() | |
# 1๋จ๊ณ: ์๋ฏธ์ ๊ฒ์ (์๋ฒ ๋ฉ ๊ธฐ๋ฐ) | |
status_text.text("๐ ์๋ฏธ์ ๊ฒ์ ์ค... (RAG ํต์ฌ ๊ธฐ๋ฅ)") | |
progress_bar.progress(20) | |
try: | |
# ๊ฒ์ ์ฟผ๋ฆฌ ์์ฑ ๋ฐ ์๋ฒ ๋ฉ | |
search_query = f"{user_request} {target} ๊ด๊ณ ์นดํผ" | |
from sklearn.metrics.pairwise import cosine_similarity | |
query_embedding = embedding_model.encode([search_query]) | |
# ์นดํ ๊ณ ๋ฆฌ ํํฐ๋ง | |
if category != '์ ์ฒด': | |
filtered_df = df[df['์นดํ ๊ณ ๋ฆฌ'] == category] | |
else: | |
filtered_df = df | |
progress_bar.progress(40) | |
# ์ ์ฌ๋ ๊ณ์ฐ (์๋ฒ ๋ฉ์ ํต์ฌ!) | |
filtered_indices = filtered_df.index.tolist() | |
filtered_embeddings = embeddings[filtered_indices] | |
similarities = cosine_similarity(query_embedding, filtered_embeddings)[0] | |
# ์์ ์ฐธ๊ณ ์นดํผ ์ ๋ณ | |
top_indices = np.argsort(similarities)[::-1][:num_references] | |
reference_copies = [] | |
for idx in top_indices: | |
original_idx = filtered_indices[idx] | |
row = df.iloc[original_idx] | |
if similarities[idx] >= min_similarity: | |
reference_copies.append({ | |
'copy': row['์นดํผ ๋ด์ฉ'], | |
'brand': row['๋ธ๋๋'], | |
'similarity': similarities[idx] | |
}) | |
progress_bar.progress(60) | |
if not reference_copies: | |
st.warning(f"โ ๏ธ ์ ์ฌ๋ {min_similarity} ์ด์์ธ ์ฐธ๊ณ ์นดํผ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค. ์ ์ฌ๋๋ฅผ ๋ฎ์ถฐ๋ณด์ธ์.") | |
progress_bar.empty() | |
status_text.empty() | |
return None | |
# 2๋จ๊ณ: AI ์นดํผ ์์ฑ | |
status_text.text("๐ค AI ์นดํผ ์์ฑ ์ค...") | |
progress_bar.progress(80) | |
# ํ๋กฌํํธ ์์ฑ | |
references_text = "\n".join([ | |
f"{i}. \"{ref['copy']}\" - {ref['brand']} (์ ์ฌ๋: {ref['similarity']:.3f})" | |
for i, ref in enumerate(reference_copies, 1) | |
]) | |
creativity_guidance = { | |
"๋ณด์์ ": "์์ ํ๊ณ ๊ฒ์ฆ๋ ํํ์ ์ฌ์ฉํ์ฌ", | |
"๊ท ํ": "์ฐฝ์์ ์ด๋ฉด์๋ ์ ์ ํ ์์ค์์", | |
"์ฐฝ์์ ": "๋ ์ฐฝ์ ์ด๊ณ ํ์ ์ ์ธ ํํ์ผ๋ก" | |
} | |
prompt = f""" | |
๋น์ ์ ํ๊ตญ์ ์ ๋ฌธ ๊ด๊ณ ์นดํผ๋ผ์ดํฐ์ ๋๋ค. | |
**์์ฒญ์ฌํญ:** {user_request} | |
**ํ๊ฒ ๊ณ ๊ฐ:** {target} | |
**๋ธ๋๋ ํค:** {tone} | |
**์ฐฝ์์ฑ ์์ค:** {creative} | |
**์ฐธ๊ณ ์นดํผ๋ค (์๋ฏธ์ ์ ์ฌ๋ ๊ธฐ๋ฐ ์ ๋ณ):** | |
{references_text} | |
**์์ฑ ๊ฐ์ด๋๋ผ์ธ:** | |
1. ์ ์ฐธ๊ณ ์นดํผ๋ค์ ์คํ์ผ๊ณผ ํค์ ๋ถ์ํ์ฌ ์ ์ฌํ ๋๋์ผ๋ก ์์ฑ | |
2. {creativity_guidance[creative]} ์๋ก์ด ์นดํผ {num_concepts}๊ฐ๋ฅผ ์์ฑ | |
3. ๊ฐ ์นดํผ๋ ํ๊ตญ์ด๋ก ์์ฐ์ค๋ฝ๊ณ ๋งค๋ ฅ์ ์ด์ด์ผ ํจ | |
4. {target}์๊ฒ ์ดํํ ์ ์๋ ํํ ์ฌ์ฉ | |
5. {tone} ํค์ค๋งค๋ ์ ์ง | |
**์ถ๋ ฅ ํ์:** | |
1. [์นดํผ1] | |
- ์ค๋ช : ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช | |
2. [์นดํผ2] | |
- ์ค๋ช : ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช | |
3. [์นดํผ3] | |
- ์ค๋ช : ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช | |
**์ถ์ฒ ์นดํผ:** ์ ์ค ๊ฐ์ฅ ์ถ์ฒํ๋ ์นดํผ์ ์ด์ | |
""" | |
response = model.generate_content(prompt) | |
progress_bar.progress(100) | |
status_text.text("โ ์๋ฃ!") | |
time.sleep(0.5) | |
progress_bar.empty() | |
status_text.empty() | |
return { | |
'references': reference_copies, | |
'generated_content': response.text, | |
'search_info': { | |
'query': search_query, | |
'total_candidates': len(filtered_df), | |
'selected_references': len(reference_copies) | |
}, | |
'settings': { | |
'category': category, | |
'target': target, | |
'tone': tone, | |
'creative': creative | |
} | |
} | |
except Exception as e: | |
st.error(f"โ ์นดํผ ์์ฑ ์คํจ: {e}") | |
progress_bar.empty() | |
status_text.empty() | |
return None | |
# ์์ฑ ๋ฒํผ | |
if st.button("๐ ์นดํผ ์์ฑํ๊ธฐ", type="primary", use_container_width=True): | |
if not user_request or not user_request.strip(): | |
st.error("โ ์นดํผ ์์ฒญ์ ์ ๋ ฅํด์ฃผ์ธ์") | |
else: | |
# RAG ์นดํผ ์์ฑ | |
result = generate_copy_with_rag( | |
user_request=user_request, | |
category=selected_category, | |
target=target_audience, | |
tone=brand_tone, | |
creative=creative_level, | |
num_concepts=num_concepts | |
) | |
if result: | |
# ๊ฒฐ๊ณผ ํ์ | |
st.markdown("## ๐ ์์ฑ๋ ์นดํผ") | |
st.markdown("---") | |
# ๊ฒ์ ์ ๋ณด ํ์ | |
st.info(f"๐ **๊ฒ์ ์ ๋ณด**: {result['search_info']['total_candidates']:,}๊ฐ ํ๋ณด์์ " | |
f"{result['search_info']['selected_references']}๊ฐ ์ฐธ๊ณ ์นดํผ ์ ๋ณ") | |
# ์ฐธ๊ณ ์นดํผ ํ์ | |
if show_references and result['references']: | |
with st.expander("๐ ์ฐธ๊ณ ํ ์นดํผ๋ค (์๋ฏธ์ ์ ์ฌ๋ ๊ธฐ๋ฐ ์ ๋ณ)"): | |
for i, ref in enumerate(result['references'], 1): | |
st.markdown(f"**{i}.** \"{ref['copy']}\"") | |
st.markdown(f" - ๋ธ๋๋: {ref['brand']}") | |
st.markdown(f" - ์ ์ฌ๋: {ref['similarity']:.3f}") | |
st.markdown("") | |
# ์์ฑ๋ ์นดํผ ํ์ | |
st.markdown("### โจ AI๊ฐ ์์ฑํ ์นดํผ:") | |
st.markdown(result['generated_content']) | |
# ๊ฒฐ๊ณผ ๋ค์ด๋ก๋ | |
result_json = json.dumps({ | |
'timestamp': datetime.now().isoformat(), | |
'request': user_request, | |
'settings': result['settings'], | |
'search_info': result['search_info'], | |
'generated_content': result['generated_content'] | |
}, ensure_ascii=False, indent=2) | |
st.download_button( | |
label="๐พ ๊ฒฐ๊ณผ ๋ค์ด๋ก๋ (JSON)", | |
data=result_json, | |
file_name=f"copy_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", | |
mime="application/json" | |
) | |
# ์์คํ ์ ๋ณด (์ฌ์ด๋๋ฐ ํ๋จ) | |
st.sidebar.markdown("---") | |
st.sidebar.markdown("### ๐ RAG ์์คํ ์ ๋ณด") | |
if df is not None and embeddings is not None: | |
st.sidebar.markdown(f"**์นดํผ ๋ฐ์ดํฐ**: {len(df):,}๊ฐ") | |
st.sidebar.markdown(f"**์นดํ ๊ณ ๋ฆฌ**: {df['์นดํ ๊ณ ๋ฆฌ'].nunique()}๊ฐ") | |
st.sidebar.markdown(f"**๋ธ๋๋**: {df['๋ธ๋๋'].nunique()}๊ฐ") | |
st.sidebar.markdown(f"**์๋ฒ ๋ฉ**: {embeddings.shape[1]}์ฐจ์") | |
st.sidebar.markdown("**๊ฒ์ ์์ง**: Korean SBERT") | |
st.sidebar.markdown("**ํธ์คํ **: ๐ค Hugging Face") | |
# ์ฌ์ฉ๋ฒ ๊ฐ์ด๋ | |
with st.expander("๐ก RAG ์์คํ ์ฌ์ฉ๋ฒ ๊ฐ์ด๋"): | |
st.markdown(""" | |
### ๐ฏ ํจ๊ณผ์ ์ธ ์ฌ์ฉ๋ฒ | |
**1. ๊ตฌ์ฒด์ ์ธ ์์ฒญํ๊ธฐ:** | |
- โ "์นดํผ ์จ์ค" | |
- โ "30๋ ์ง์ฅ ์ฌ์ฑ์ฉ ํ๋ฆฌ๋ฏธ์ ์คํจ์ผ์ด ์ ์ ํ ๋ฐ์นญ ์นดํผ" | |
**2. RAG ์์คํ ์ ์ฅ์ :** | |
- ๐ง **์๋ฏธ์ ๊ฒ์**: ํค์๋๋ฟ๋ง ์๋๋ผ ์๋ฏธ๊น์ง ์ดํด | |
- ๐ฏ **๋ฌธ๋งฅ ๋งค์นญ**: ํ๊ฒ๊ณผ ์ํฉ์ ๋ง๋ ์นดํผ ์๋ ์ ๋ณ | |
- ๐ **๋ฐ์ดํฐ ๊ธฐ๋ฐ**: 37,671๊ฐ ์ค์ ์นดํผ์์ ํ์ตํ ํจํด | |
**3. ์ฐฝ์์ฑ ์กฐ์ :** | |
- **๋ณด์์ **: ์์ ํ ํด๋ผ์ด์ธํธ, ๊ฒ์ฆ๋ ์ ๊ทผ | |
- **๊ท ํ**: ์ผ๋ฐ์ ์ธ ํ๋ก์ ํธ (์ถ์ฒ!) | |
- **์ฐฝ์์ **: ํ์ ์ ๋ธ๋๋, ํ๊ฒฉ์ ์บ ํ์ธ | |
**4. ์ฐธ๊ณ ์นดํผ ํ์ฉ:** | |
- ์์ฑ๋ ์นดํผ์ ์ฐธ๊ณ ์นดํผ๋ฅผ ๋น๊ต ๋ถ์ | |
- ํธ๋ ๋์ ํจํด ํ์ ๊ฐ๋ฅ | |
- ๊ฒฝ์์ฌ ๋ถ์ ์๋ฃ๋ก ํ์ฉ | |
""") | |
# ํธํฐ | |
st.markdown("---") | |
st.markdown( | |
"๐ก **AI ์นดํผ๋ผ์ดํฐ** | 37,671๊ฐ ์ค์ ๊ด๊ณ ์นดํผ ๋ฐ์ดํฐ ๊ธฐ๋ฐ | " | |
"RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ powered by Korean SBERT + Gemini AI" | |
) | |
# ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง (๊ฐ๋ฐ์์ฉ) | |
if os.getenv("DEBUG_MODE"): | |
st.sidebar.markdown("### ๐ง ๋๋ฒ๊ทธ ์ ๋ณด") | |
if 'embeddings' in locals(): | |
st.sidebar.write(f"์๋ฒ ๋ฉ ๋ฉ๋ชจ๋ฆฌ: {embeddings.nbytes / (1024*1024):.1f}MB") | |
st.sidebar.write(f"Streamlit ๋ฒ์ : {st.__version__}") | |