Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- .gitattributes +1 -0
- app.py +393 -0
- copy_embeddings.pkl +3 -0
- ๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx filter=lfs diff=lfs merge=lfs -text
|
app.py
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces์ฉ app.py
|
| 2 |
+
# ์๋ณธ streamlit_app.py์์ ํ๊ฒฝ๋ณ์ ์ฒ๋ฆฌ๋ง ๊ฐ์
|
| 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
|
| 12 |
+
import json
|
| 13 |
+
import os
|
| 14 |
+
from datetime import datetime
|
| 15 |
+
|
| 16 |
+
# ํ์ด์ง ์ค์
|
| 17 |
+
st.set_page_config(
|
| 18 |
+
page_title="AI ์นดํผ๋ผ์ดํฐ | RAG ๊ธฐ๋ฐ ๊ด๊ณ ์นดํผ ์์ฑ",
|
| 19 |
+
page_icon="โจ",
|
| 20 |
+
layout="wide",
|
| 21 |
+
initial_sidebar_state="expanded"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# ์ ๋ชฉ ๋ฐ ์ค๋ช
|
| 25 |
+
st.title("โจ AI ์นดํผ๋ผ์ดํฐ")
|
| 26 |
+
st.markdown("### ๐ฏ 37,000๊ฐ ์ค์ ๊ด๊ณ ์นดํผ ๋ฐ์ดํฐ ๊ธฐ๋ฐ RAG ์์คํ
")
|
| 27 |
+
st.markdown("---")
|
| 28 |
+
|
| 29 |
+
# ์ฌ์ด๋๋ฐ ์ค์
|
| 30 |
+
st.sidebar.header("๐๏ธ ์นดํผ ์์ฑ ์ค์ ")
|
| 31 |
+
|
| 32 |
+
# API ํค ์
๋ ฅ (ํ๊ฒฝ๋ณ์ ์ฐ์ ์ฌ์ฉ)
|
| 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="https://makersuite.google.com/app/apikey ์์ ๋ฐ๊ธ\nํ๊ฒฝ๋ณ์์ GEMINI_API_KEY๋ก ์ค์ ํ๋ฉด ์๋ ์
๋ ฅ๋ฉ๋๋ค"
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
if not api_key:
|
| 43 |
+
st.warning("โ ๏ธ Gemini API ํค๋ฅผ ์
๋ ฅํด์ฃผ์ธ์")
|
| 44 |
+
st.info("๐ก Hugging Face Spaces ๊ด๋ฆฌ์๋ผ๋ฉด Settings โ Repository secrets์์ GEMINI_API_KEY๋ฅผ ์ค์ ํ์ธ์")
|
| 45 |
+
st.stop()
|
| 46 |
+
|
| 47 |
+
# ์์คํ
์ด๊ธฐํ (์บ์ฑ)
|
| 48 |
+
@st.cache_resource
|
| 49 |
+
def load_system():
|
| 50 |
+
"""์์คํ
์ปดํฌ๋ํธ ๋ก๋ฉ (ํ ๋ฒ๋ง ์คํ)"""
|
| 51 |
+
try:
|
| 52 |
+
# API ์ค์
|
| 53 |
+
genai.configure(api_key=api_key)
|
| 54 |
+
model = genai.GenerativeModel('gemini-1.5-flash')
|
| 55 |
+
|
| 56 |
+
# ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ก๋
|
| 57 |
+
with st.spinner("๐ค Korean SBERT ๋ชจ๋ธ ๋ก๋ฉ ์ค... (์ต์ด 1-2๋ถ ์์)"):
|
| 58 |
+
embedding_model = SentenceTransformer('jhgan/ko-sbert-nli')
|
| 59 |
+
|
| 60 |
+
# ๋ฐ์ดํฐ ๋ก๋
|
| 61 |
+
with st.spinner("๐ ์นดํผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ก๋ฉ ์ค..."):
|
| 62 |
+
df = pd.read_excel('๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx')
|
| 63 |
+
|
| 64 |
+
# ์๋ฒ ๋ฉ ๋ก๋
|
| 65 |
+
with st.spinner("๐ ๋ฒกํฐ ์๋ฒ ๋ฉ ๋ก๋ฉ ์ค..."):
|
| 66 |
+
with open('copy_embeddings.pkl', 'rb') as f:
|
| 67 |
+
embeddings_data = pickle.load(f)
|
| 68 |
+
embeddings = embeddings_data['embeddings']
|
| 69 |
+
|
| 70 |
+
return model, embedding_model, df, embeddings
|
| 71 |
+
except FileNotFoundError as e:
|
| 72 |
+
st.error(f"โ ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค: {e}")
|
| 73 |
+
st.error("ํ์ํ ํ์ผ๋ค์ด ์ฌ๋ฐ๋ฅธ ์์น์ ์๋์ง ํ์ธํด์ฃผ์ธ์:")
|
| 74 |
+
st.code("- ๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx\n- copy_embeddings.pkl")
|
| 75 |
+
return None, None, None, None
|
| 76 |
+
except Exception as e:
|
| 77 |
+
st.error(f"โ ์์คํ
๋ก๋ฉ ์คํจ: {e}")
|
| 78 |
+
return None, None, None, None
|
| 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 |
+
st.success(f"โ
์์คํ
๋ก๋ฉ ์๋ฃ: {len(df):,}๊ฐ ์นดํผ ๋ฐ์ดํฐ๋ฒ ์ด์ค")
|
| 89 |
+
|
| 90 |
+
# ์นดํ
๊ณ ๋ฆฌ ์ ํ
|
| 91 |
+
categories = ['์ ์ฒด'] + sorted(df['์นดํ
๊ณ ๋ฆฌ'].unique().tolist())
|
| 92 |
+
selected_category = st.sidebar.selectbox(
|
| 93 |
+
"๐ ์นดํ
๊ณ ๋ฆฌ",
|
| 94 |
+
categories,
|
| 95 |
+
help="ํน์ ์นดํ
๊ณ ๋ฆฌ๋ก ๊ฒ์์ ์ ํํ ์ ์์ต๋๋ค"
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
# ํ๊ฒ ๊ณ ๊ฐ ์ค์
|
| 99 |
+
target_audience = st.sidebar.selectbox(
|
| 100 |
+
"๐ฏ ํ๊ฒ ๊ณ ๊ฐ",
|
| 101 |
+
['์ผ๋ฐ', '10๋', '20๋', '30๋', '40๋', '50๋+', '๋จ์ฑ', '์ฌ์ฑ', '์ง์ฅ์ธ', 'ํ์', '์ฃผ๋ถ'],
|
| 102 |
+
index=2 # 20๋ ๊ธฐ๋ณธ ์ ํ
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
# ๋ธ๋๋ ํค์ค๋งค๋
|
| 106 |
+
brand_tone = st.sidebar.selectbox(
|
| 107 |
+
"๐จ ๋ธ๋๋ ํค",
|
| 108 |
+
['์น๊ทผํ', '์ธ๋ จ๋', '๊ณ ๊ธ์ค๋ฌ์ด', 'ํ๊ธฐ์ฐฌ', '์ ๋ขฐํ ์ ์๋', '์ ์', '๋ฐ๋ปํ', '์ ๋ฌธ์ ์ธ'],
|
| 109 |
+
help="์ํ๋ ๋ธ๋๋ ์ด๋ฏธ์ง๋ฅผ ์ ํํ์ธ์"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
# ์ฐฝ์์ฑ ์์ค
|
| 113 |
+
creative_level = st.sidebar.select_slider(
|
| 114 |
+
"๐ง ์ฐฝ์์ฑ ์์ค",
|
| 115 |
+
options=['๋ณด์์ ', '๊ท ํ', '์ฐฝ์์ '],
|
| 116 |
+
value='๊ท ํ',
|
| 117 |
+
help="๋ณด์์ : ์์ ํ ํํ, ์ฐฝ์์ : ๋
์ฐฝ์ ํํ"
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
# ๋ฉ์ธ ์
๋ ฅ ์์ญ
|
| 121 |
+
st.markdown("## ๐ญ ์ด๋ค ์นดํผ๋ฅผ ๋ง๋ค๊ณ ์ถ์ผ์ ๊ฐ์?")
|
| 122 |
+
|
| 123 |
+
# ์
๋ ฅ ๋ฐฉ์ ์ ํ
|
| 124 |
+
input_method = st.radio(
|
| 125 |
+
"์
๋ ฅ ๋ฐฉ์ ์ ํ:",
|
| 126 |
+
["์ง์ ์
๋ ฅ", "ํ
ํ๋ฆฟ ์ ํ"],
|
| 127 |
+
horizontal=True
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
if input_method == "์ง์ ์
๋ ฅ":
|
| 131 |
+
user_request = st.text_area(
|
| 132 |
+
"์นดํผ ์์ฒญ์ ์์ธํ ์์ฑํด์ฃผ์ธ์:",
|
| 133 |
+
placeholder="์: 30๋ ์ง์ฅ ์ฌ์ฑ์ฉ ํ๋ฆฌ๋ฏธ์ ์คํจ์ผ์ด ์ ์ ํ ๋ฐ์นญ ์นดํผ",
|
| 134 |
+
height=100
|
| 135 |
+
)
|
| 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 |
+
if selected_template == "์ฑ/์๋น์ค ๋ฆฌ๋ด์ผ":
|
| 156 |
+
service_name = st.text_input("์๋น์ค๋ช
:", placeholder="์: ๋ฐฐ๋ฌ์ฑ, ๊ธ์ต์ฑ")
|
| 157 |
+
user_request = templates[selected_template].format(
|
| 158 |
+
ํ๊ฒ=template_target, ์๋น์ค๋ช
=service_name
|
| 159 |
+
)
|
| 160 |
+
elif selected_template == "์์ฆ ํ์ ":
|
| 161 |
+
season = st.selectbox("์์ฆ:", ["๋ด", "์ฌ๋ฆ", "๊ฐ์", "๊ฒจ์ธ", "ํฌ๋ฆฌ์ค๋ง์ค", "์ ๋
"])
|
| 162 |
+
user_request = templates[selected_template].format(
|
| 163 |
+
์์ฆ=season, ์นดํ
๊ณ ๋ฆฌ=template_category
|
| 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 |
+
# ๊ณ ๊ธ ์ต์
|
| 173 |
+
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 generate_copy_web(user_request, category, target, tone, creative, num_concepts):
|
| 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 |
+
search_query = f"{user_request} {target} ๊ด๊ณ ์นดํผ"
|
| 200 |
+
query_embedding = embedding_model.encode([search_query])
|
| 201 |
+
|
| 202 |
+
# ์นดํ
๊ณ ๋ฆฌ ํํฐ๋ง
|
| 203 |
+
if category != '์ ์ฒด':
|
| 204 |
+
filtered_df = df[df['์นดํ
๊ณ ๋ฆฌ'] == category]
|
| 205 |
+
else:
|
| 206 |
+
filtered_df = df
|
| 207 |
+
|
| 208 |
+
progress_bar.progress(40)
|
| 209 |
+
|
| 210 |
+
# ์ ์ฌ๋ ๊ณ์ฐ
|
| 211 |
+
filtered_indices = filtered_df.index.tolist()
|
| 212 |
+
filtered_embeddings = embeddings[filtered_indices]
|
| 213 |
+
similarities = cosine_similarity(query_embedding, filtered_embeddings)[0]
|
| 214 |
+
|
| 215 |
+
# ์์ 5๊ฐ ์ ๋ณ
|
| 216 |
+
top_indices = np.argsort(similarities)[::-1][:5]
|
| 217 |
+
|
| 218 |
+
reference_copies = []
|
| 219 |
+
for idx in top_indices:
|
| 220 |
+
original_idx = filtered_indices[idx]
|
| 221 |
+
row = df.iloc[original_idx]
|
| 222 |
+
if similarities[idx] >= min_similarity:
|
| 223 |
+
reference_copies.append({
|
| 224 |
+
'copy': row['์นดํผ ๋ด์ฉ'],
|
| 225 |
+
'brand': row['๋ธ๋๋'],
|
| 226 |
+
'similarity': similarities[idx]
|
| 227 |
+
})
|
| 228 |
+
|
| 229 |
+
progress_bar.progress(60)
|
| 230 |
+
|
| 231 |
+
if not reference_copies:
|
| 232 |
+
st.warning(f"โ ๏ธ ์ ์ฌ๋ {min_similarity} ์ด์์ธ ์ฐธ๊ณ ์นดํผ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.")
|
| 233 |
+
return None
|
| 234 |
+
|
| 235 |
+
# 2๋จ๊ณ: ์นดํผ ์์ฑ
|
| 236 |
+
status_text.text("๐ค AI ์นดํผ ์์ฑ ์ค...")
|
| 237 |
+
progress_bar.progress(80)
|
| 238 |
+
|
| 239 |
+
# ํ๋กฌํํธ ์์ฑ
|
| 240 |
+
references_text = "\n".join([
|
| 241 |
+
f"{i}. \"{ref['copy']}\" - {ref['brand']}"
|
| 242 |
+
for i, ref in enumerate(reference_copies, 1)
|
| 243 |
+
])
|
| 244 |
+
|
| 245 |
+
creativity_guidance = {
|
| 246 |
+
"๋ณด์์ ": "์์ ํ๊ณ ๊ฒ์ฆ๋ ํํ์ ์ฌ์ฉํ์ฌ",
|
| 247 |
+
"๊ท ํ": "์ฐฝ์์ ์ด๋ฉด์๋ ์ ์ ํ ์์ค์์",
|
| 248 |
+
"์ฐฝ์์ ": "๋
์ฐฝ์ ์ด๊ณ ํ์ ์ ์ธ ํํ์ผ๋ก"
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
prompt = f"""
|
| 252 |
+
๋น์ ์ ํ๊ตญ์ ์ ๋ฌธ ๊ด๊ณ ์นดํผ๋ผ์ดํฐ์
๋๋ค.
|
| 253 |
+
|
| 254 |
+
**์์ฒญ์ฌํญ:** {user_request}
|
| 255 |
+
**ํ๊ฒ ๊ณ ๊ฐ:** {target}
|
| 256 |
+
**๋ธ๋๋ ํค:** {tone}
|
| 257 |
+
**์ฐฝ์์ฑ ์์ค:** {creative}
|
| 258 |
+
|
| 259 |
+
**์ฐธ๊ณ ์นดํผ๋ค:**
|
| 260 |
+
{references_text}
|
| 261 |
+
|
| 262 |
+
**์์ฑ ๊ฐ์ด๋๋ผ์ธ:**
|
| 263 |
+
1. ์ ์ฐธ๊ณ ์นดํผ๋ค์ ์คํ์ผ๊ณผ ํค์ ๋ถ์ํ์ฌ ์ ์ฌํ ๋๋์ผ๋ก ์์ฑ
|
| 264 |
+
2. {creativity_guidance[creative]} ์๋ก์ด ์นดํผ {num_concepts}๊ฐ๋ฅผ ์์ฑ
|
| 265 |
+
3. ๊ฐ ์นดํผ๋ ํ๊ตญ์ด๋ก ์์ฐ์ค๋ฝ๊ณ ๋งค๋ ฅ์ ์ด์ด์ผ ํจ
|
| 266 |
+
4. {target}์๊ฒ ์ดํํ ์ ์๋ ํํ ์ฌ์ฉ
|
| 267 |
+
5. {tone} ํค์ค๋งค๋ ์ ์ง
|
| 268 |
+
|
| 269 |
+
**์ถ๋ ฅ ํ์:**
|
| 270 |
+
1. [์นดํผ1]
|
| 271 |
+
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
| 272 |
+
|
| 273 |
+
2. [์นดํผ2]
|
| 274 |
+
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
| 275 |
+
|
| 276 |
+
3. [์นดํผ3]
|
| 277 |
+
- ์ค๋ช
: ์ ์ด ์นดํผ๊ฐ ํจ๊ณผ์ ์ธ์ง ๊ฐ๋จํ ์ค๋ช
|
| 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,
|
| 297 |
+
'tone': tone,
|
| 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 = generate_copy_web(
|
| 314 |
+
user_request=user_request,
|
| 315 |
+
category=selected_category,
|
| 316 |
+
target=target_audience,
|
| 317 |
+
tone=brand_tone,
|
| 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,
|
| 351 |
+
file_name=f"copy_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
|
| 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 |
+
- ์ปจ์
์๋ฅผ 3-5๊ฐ๋ก ์ค์ ํด์ ๋ค์ํ ์ต์
ํ๋ณด
|
| 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(
|
| 387 |
+
"๐ก **AI ์นดํผ๋ผ์ดํฐ** | 37,671๊ฐ ์ค์ ๊ด๊ณ ์นดํผ ๋ฐ์ดํฐ ๊ธฐ๋ฐ | "
|
| 388 |
+
"RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ์์คํ
powered by Korean SBERT + Gemini AI"
|
| 389 |
+
)
|
| 390 |
+
|
| 391 |
+
# Hugging Face ์ ์ฉ ์ ๋ณด
|
| 392 |
+
if os.getenv("SPACE_ID"): # Hugging Face Spaces์์๋ง ํ์
|
| 393 |
+
st.markdown("๐ **Powered by Hugging Face Spaces** | ์์ ๋ฌด๋ฃ AI ํ๋ซํผ")
|
copy_embeddings.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4e0f35715ecca21180ae89582ec91b9c55fd22650ae5a1eb5e213c6d7b9e636f
|
| 3 |
+
size 115725584
|
๊ด๊ณ ์นดํผ๋ฐ์ดํฐ_๋ธ๋๋์ถ์ถ์๋ฃ.xlsx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d38360acd129b9d8ec065a0231c42a0029f5ed6718d397d049f3601065d001d7
|
| 3 |
+
size 3584205
|