Spaces:
Runtime error
Runtime error
import sys | |
import os | |
import gradio as gr | |
#from dotenv import load_dotenv | |
# ํ์ฌ ๋๋ ํ ๋ฆฌ๋ฅผ Python ๊ฒฝ๋ก์ ์ถ๊ฐ | |
current_dir = os.path.dirname(os.path.abspath(__file__)) | |
sys.path.append(current_dir) | |
# TinyTroupe ํจํค์ง ๊ฒฝ๋ก ์ถ๊ฐ | |
#tinytroupe_path = os.path.join(current_dir, 'TinyTroupe') | |
#sys.path.append(tinytroupe_path) | |
from TinyTroupe.wellfood_marketing.wellfood_persona_analysis import WellFoodPersona, ResultsExtractor, generate_marketing_report | |
from TinyTroupe.tinytroupe.agent import TinyPerson | |
import time | |
# Load environment variables | |
#load_dotenv() | |
# OpenAI API ํค๋ Hugging Face Space์ Secrets์์ ์๋์ผ๋ก ๋ก๋๋จ | |
def analyze_single_persona(age_group, gender, product_description, progress=gr.Progress()): | |
"""๋จ์ผ ํ๋ฅด์๋์ ๋ํ ์ ํ ๋ถ์ ์ํ""" | |
# ํ๋ฅด์๋ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ | |
persona_info = WellFoodPersona.PERSONAS[age_group][gender] | |
# ํ๋ฅด์๋ ๊ธฐ๋ณธ ์ ๋ณด ํฌ๋งทํ | |
base_info = f"""## {persona_info['display_name']}์ ์ ํ ํ๊ฐ | |
### ํ๋ฅด์๋ ์ ๋ณด | |
- ์ง์ : {persona_info['occupation']} | |
- ๊ด์ฌ์ฌ: {', '.join(persona_info['interests'])} | |
- ๋ผ์ดํ์คํ์ผ: {persona_info['lifestyle']} | |
- ์ฃผ์ ๊ณ ๋ฏผ์ : {', '.join(persona_info['pain_points'])} | |
### ์ ํ ๋ถ์ ๊ณผ์ | |
""" | |
current_content = base_info | |
# ๋ถ์ ์์์ ํ์ | |
progress(0.1, desc=f"{persona_info['display_name']} ํ๋ฅด์๋ ์ด๊ธฐํ ์ค...") | |
yield current_content, None | |
# ๊ธฐ์กด ํ๋ฅด์๋๊ฐ ์๋์ง ํ์ธ | |
existing_persona = None | |
if hasattr(TinyPerson, '_instances'): | |
for instance in TinyPerson._instances: | |
if instance.name == persona_info['name']: | |
existing_persona = instance | |
break | |
# ๊ธฐ์กด ํ๋ฅด์๋๊ฐ ์์ ๋๋ง ์๋ก ์์ฑ | |
if existing_persona is None: | |
persona = WellFoodPersona(age_group, gender) | |
else: | |
persona = WellFoodPersona.__new__(WellFoodPersona) | |
persona.persona = existing_persona | |
persona.age_group = age_group | |
persona.gender = gender | |
progress(0.2, desc=f"{persona_info['display_name']} ์๋ต ์์ฑ ์์...") | |
current_content += f"\n๐ค {persona_info['display_name']}์ด(๊ฐ) ์๊ฐํ๊ณ ์์ต๋๋ค...\n" | |
yield current_content, None | |
# ํ๋ฅด์๋์ ์๋ต ์ฒ๋ฆฌ | |
response = persona.analyze_product(product_description) | |
progress(0.8, desc=f"{persona_info['display_name']} ๊ฒฐ๊ณผ ์ถ์ถ ์ค...") | |
current_content += f"\n๐ฌ {persona_info['display_name']}์ด(๊ฐ) ์๊ฒฌ์ ์ ์ํ๊ณ ์์ต๋๋ค...\n" | |
yield current_content, None | |
# ResultsExtractor๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ์กฐํ๋ ๊ฒฐ๊ณผ ์ถ์ถ | |
extractor = ResultsExtractor() | |
res = extractor.extract_results_from_agent( | |
persona.persona, | |
extraction_objective="์ ํ ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ถ์ถํฉ๋๋ค. ๊ฐ ํ๋์ ํด๋นํ๋ ๋ด์ฉ์ ์ถ์ถํ์ธ์.", | |
situation=product_description, | |
fields=["first_impression", "purchase_intention", "usage_scenario", "price_evaluation", "improvement_points"], | |
fields_hints={ | |
"first_impression": "์ ํ์ ๋ํ ์ฒซ์ธ์์ ํ๊ธ๋ก ์์ฑ", | |
"purchase_intention": "๊ตฌ๋งค ์ํฅ ์ ์(1-10)์ ๊ทธ ์ด์ ๋ฅผ ํฌํจํ๋ ๊ฐ์ฒด", | |
"usage_scenario": "์ฃผ๋ ๊ตฌ๋งค ๋๊ธฐ๋ ์ฌ์ฉ ์ํฉ์ ํ๊ธ๋ก ์์ฑ", | |
"price_evaluation": "๊ฐ๊ฒฉ ์ ์ ์ฑ์ ๋ํ ํ๊ฐ๋ฅผ ํ๊ธ๋ก ์์ฑ", | |
"improvement_points": "๊ฐ์ ๋์์ผ๋ฉด ํ๋ ์ ์ ํ๊ธ๋ก ์์ฑ" | |
}, | |
verbose=True | |
) | |
progress(1.0, desc=f"{persona_info['display_name']} ๋ถ์ ์๋ฃ") | |
# ์ต์ข ๊ฒฐ๊ณผ ํฌ๋งทํ | |
final_result = f"""## {persona_info['display_name']}์ ์ ํ ํ๊ฐ | |
### ํ๋ฅด์๋ ์ ๋ณด | |
- ์ง์ : {persona_info['occupation']} | |
- ๊ด์ฌ์ฌ: {', '.join(persona_info['interests'])} | |
- ๋ผ์ดํ์คํ์ผ: {persona_info['lifestyle']} | |
- ์ฃผ์ ๊ณ ๋ฏผ์ : {', '.join(persona_info['pain_points'])} | |
### ์ต์ข ํ๊ฐ ๊ฒฐ๊ณผ | |
1. ์ฒซ์ธ์: {res['first_impression']} | |
2. ๊ตฌ๋งค์ํฅ: {res['purchase_intention']['score']}/10 | |
์ด์ : {res['purchase_intention']['reason']} | |
3. ์ฌ์ฉ์ํฉ: {res['usage_scenario']} | |
4. ๊ฐ๊ฒฉํ๊ฐ: {res['price_evaluation']} | |
5. ๊ฐ์ ์ : {res['improvement_points']} | |
""" | |
yield final_result, res | |
def process_input(product_description, selected_personas, generate_report, product_name, progress=gr.Progress()): | |
"""์ ๋ ฅ ์ฒ๋ฆฌ ๋ฐ ๊ฒฐ๊ณผ ์์ฑ""" | |
all_results = [] | |
selected_persona_info = [] # ์ ํ๋ ํ๋ฅด์๋ ์ ๋ณด ์ ์ฅ | |
persona_responses = "" | |
marketing_report = "" | |
current_analysis = "" # ํ์ฌ ์งํ ์ค์ธ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅ | |
# ๋ถ์ ์์ ์ํ ํ์ | |
progress(0, desc="ํ๋ฅด์๋ ๋ถ์์ ์์ํฉ๋๋ค...") | |
yield persona_responses, marketing_report, gr.update(value="๋ถ์ ์ค...", interactive=False) | |
# ์ ํ๋ ํ๋ฅด์๋๋ค์ ๋ํ ๋ถ์ ์ํ | |
for i, persona_str in enumerate(selected_personas, 1): | |
age, gender = persona_str.split(':')[0].strip().split('_') | |
persona_name = persona_str.split(':')[1].strip() | |
# ๊ฐ๋ณ ํ๋ฅด์๋ ๋ถ์ | |
for result, res in analyze_single_persona(age, gender, product_description, progress): | |
if res: # ์ต์ข ๊ฒฐ๊ณผ์ธ ๊ฒฝ์ฐ | |
persona_responses = result + "\n\n" + "-"*50 + "\n\n" + persona_responses | |
all_results.append(res) | |
selected_persona_info.append({ | |
'age': age, | |
'gender': gender, | |
'info': WellFoodPersona.PERSONAS[age][gender] | |
}) | |
else: # ์ค๊ฐ ๊ฒฐ๊ณผ์ธ ๊ฒฝ์ฐ | |
current_analysis = result | |
yield current_analysis + "\n\n" + persona_responses, marketing_report, gr.update(value="๋ถ์ ์ค...", interactive=False) | |
time.sleep(0.1) # ํ๋ฉด ์ ๋ฐ์ดํธ๋ฅผ ์ํ ์งง์ ๋๊ธฐ | |
# ๋ง์ผํ ๋ฆฌํฌํธ ์์ฑ | |
if generate_report and all_results: | |
progress(0.9, desc="๋ง์ผํ ๋ฆฌํฌํธ ์์ฑ ์ค...") | |
marketing_report = generate_marketing_report(all_results, selected_persona_info, product_name) | |
# ์๋ฃ ํ์ | |
progress(1.0, desc="๋ถ์์ด ์๋ฃ๋์์ต๋๋ค!") | |
yield persona_responses, marketing_report, gr.update(value="๋ถ์ ์์", interactive=True) | |
def create_demo(): | |
"""Gradio ๋ฐ๋ชจ ์ธํฐํ์ด์ค ์์ฑ""" | |
# ์ ํ ์ค๋ช ์์ | |
example_name = "์ ๋ก ํ๋ ์ธ ์๊ฑฐํธ" | |
example_features = """๋ฌด๊ฐ๋น ์์ ํ๋ ์ธ ์๊ฑฐํธ: ์ฒจ๊ฐ๋ฌผ์ด๋ ์ธ๊ณต ๊ฐ๋ฏธ๋ฃ ์์ด, ์๊ฑฐํธ ๋ณธ์ฐ์ ๊น๋ํ๊ณ ์ฐ๋ปํ ๋ง์ ์ ์ง | |
๊ณ ๋์ถ ์ ์ฐ๊ท ํจ์ : ์ํ์ ์ฅ ๊ฑด๊ฐ์ ๋์์ ์ฃผ๋ ๋ค์ํ ์ ์ฐ๊ท ๊ท ์ฃผ๋ฅผ ํจ์ ํ์ฌ, ๊ฑด๊ฐ ์ฆ์ง ํจ๊ณผ ์ ๊ณต | |
๊ณ ๋จ๋ฐฑ ์ ์ง๋ฐฉ: ๊ท ํ ์กํ ๋จ๋ฐฑ์ง ๊ณต๊ธ๊ณผ ๋ฎ์ ์ง๋ฐฉ ํจ๋์ผ๋ก, ๋ค์ด์ดํธ ๋ฐ ๊ฑด๊ฐ ๊ด๋ฆฌ์ ์ต์ ํ | |
์ ์ ํ ํ์ง ์์ ์ฌ์ฉ: ์ง์ญ ์ ๊ธฐ๋ ์ฐ์ ๋ฅผ ์์ ํ์ฌ ์ฌ์ฉ, ์ ์ ๋์ ์์ ์ฑ์ ๊ทน๋ํ | |
ํด๋์ฑ๊ณผ ๊ฐํธํจ: ์ํฌ์ฅ ํํ๋ก ์ธ์ ์ด๋์๋ ๊ฐํธํ๊ฒ ์ญ์ทจ ๊ฐ๋ฅ | |
๊ฐ๊ฒฉ: ๊ฐ๋น 2,900์ | |
์ ํต๊ธฐํ: ์ ์กฐ์ผ๋ก๋ถํฐ 15์ผ (๋์ฅ ๋ณด๊ด)""" | |
example_composition = """์ ๋ก ํ๋ ์ธ ์๊ฑฐํธ (150g): | |
โ ๊ณ ๋์ถ ํ๋ ์ธ ์๊ฑฐํธ, ๋ฌด๊ฐ๋น ๋ฐ ๋ฌด์ฒจ๊ฐ ์ํ๋ก ๋ณธ์ฐ์ ๋ง์ ์ฆ๊ธธ ์ ์๋๋ก ์ ์ | |
์ต์ ์ถ๊ฐ ํฉ: | |
์ ์ ๊ณผ์ผ ํ ํ ํฉ (20g): ๋ธ๋ฃจ๋ฒ ๋ฆฌ, ๋ธ๊ธฐ ๋ฑ ๊ณ์ ๊ณผ์ผ ์ ํ ๊ฐ๋ฅ (๋ณ๋ ๊ตฌ๋งค ์ต์ ) | |
๊ฑด๊ณผ์ผ/๊ฒฌ๊ณผ๋ฅ ๋ฏน์ค (15g): ์๊ฑฐํธ์ ํจ๊ป ๊ณ๋ค์ฌ ์์ ๋ฐ ์๊ฐ ๋ณด๊ฐ""" | |
# ํ๋ฅด์๋ ์ ํ ์ต์ ์์ฑ | |
def get_persona_choices(): | |
"""ํ์ฌ ํ๋ฅด์๋ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์ ํ ์ต์ ์์ฑ""" | |
persona_choices = [] | |
persona_display = {} | |
for age in ['20', '30', '40']: | |
for gender in ['M', 'F']: | |
persona_info = WellFoodPersona.PERSONAS[age][gender] | |
choice_key = f"{age}_{gender}" | |
persona_choices.append(choice_key) | |
persona_display[choice_key] = persona_info['display_name'] | |
return [f"{k}: {v}" for k, v in persona_display.items()] | |
def update_persona_info(age, gender, name, occupation, interests, lifestyle, pain_points): | |
"""ํ๋ฅด์๋ ์ ๋ณด ์ ๋ฐ์ดํธ""" | |
if age and gender: | |
WellFoodPersona.PERSONAS[age][gender].update({ | |
'name': name, | |
'occupation': occupation, | |
'interests': [i.strip() for i in interests.split(',')], | |
'lifestyle': lifestyle, | |
'pain_points': [p.strip() for p in pain_points.split(',')], | |
'display_name': f"{name} ({age}๋ {'๋จ์ฑ' if gender == 'M' else '์ฌ์ฑ'}, {occupation})" | |
}) | |
# ํ๋ฅด์๋ ์ ํ ์ต์ ์ ๋ฐ์ดํธ | |
updated_choices = get_persona_choices() | |
return ( | |
f"ํ๋ฅด์๋ ์ ๋ณด๊ฐ ์ ๋ฐ์ดํธ๋์์ต๋๋ค: {name}", | |
gr.update(choices=updated_choices, value=[]), # choices์ value ๋ชจ๋ ์ ๋ฐ์ดํธ | |
gr.update(choices=updated_choices, value=[]) # choices์ value ๋ชจ๋ ์ ๋ฐ์ดํธ | |
) | |
return "์ฐ๋ น๋์ ์ฑ๋ณ์ ์ ํํด์ฃผ์ธ์.", None, None | |
def load_persona_info(age, gender): | |
"""์ ํ๋ ํ๋ฅด์๋ ์ ๋ณด ๋ก๋""" | |
if age and gender: | |
info = WellFoodPersona.PERSONAS[age][gender] | |
return ( | |
info['name'], | |
info['occupation'], | |
', '.join(info['interests']), | |
info['lifestyle'], | |
', '.join(info['pain_points']) | |
) | |
return "", "", "", "", "" | |
# ํ๋ฅด์๋ ์ ํ ์ต์ ์ ์ํ(state)๋ก ๊ด๋ฆฌ | |
persona_choices = gr.State(value=get_persona_choices()) | |
with gr.Blocks(title="์ฐํธ๋ ํ๋ฅด์๋ ๋ถ์ ๋ฐ๋ชจ") as demo: | |
with gr.Tab("์ ํ ๋ถ์"): | |
gr.Markdown("# ์ฐํธ๋ ํ๋ฅด์๋ ๋ถ์ ๋ฐ๋ชจ") | |
gr.Markdown("๋ถ์ ๋ฐฉ๋ฒ: ์ ํ ์ ๋ณด ์ ๋ ฅ -> ๋ถ์ ํ๋ฅด์๋ ์ ํ -> ๋ถ์ ์์") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# ์ ํ ์ ๋ณด๋ฅผ ๊ตฌ์กฐํ๋ ํํ๋ก ์ ๋ ฅ๋ฐ๊ธฐ | |
product_name = gr.Textbox( | |
label="์ ํ๋ช ", | |
placeholder="์: ๋ฐ์ผ๋ฆฌ ๋ฐธ๋ฐ์ค ๋์๋ฝ", | |
value=example_name | |
) | |
product_features = gr.Textbox( | |
label="์ ํ ํน์ง", | |
placeholder="๊ฐ๊ฒฉ, ์ ํต๊ธฐํ ๋ฑ ์ ํ์ ์ฃผ์ ํน์ง์ ์ ๋ ฅํ์ธ์", | |
lines=6, | |
value=example_features | |
) | |
product_composition = gr.Textbox( | |
label="์ ํ ๊ตฌ์ฑ", | |
placeholder="์ ํ์ ๊ตฌ์ฑ๊ณผ ์ฉ๋์ ์ ๋ ฅํ์ธ์", | |
lines=4, | |
value=example_composition | |
) | |
personas = gr.CheckboxGroup( | |
choices=get_persona_choices(), | |
label="๋ถ์ํ ํ๋ฅด์๋ ์ ํ", | |
value=get_persona_choices(), | |
info="๋ถ์ํ๊ณ ์ถ์ ํ๋ฅด์๋๋ฅผ ๋ชจ๋ ์ ํํ์ธ์. \nํ๋ฅด์๋๋ฅผ ์์ ํ๊ณ ์ถ์ผ์๋ค๋ฉด ์๋จ ํ๋ฅด์๋ ์ค์ ํญ์์ ์์ ํ ์ ์์ต๋๋ค." | |
) | |
generate_report = gr.Checkbox( | |
label="๋ง์ผํ ๋ฆฌํฌํธ ์์ฑ", | |
value=True, | |
info="์ ํ๋ ํ๋ฅด์๋๋ค์ ๋ชจ๋ ๋ถ์์ด ๋๋๋ฉด, ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ข ํฉํ ๋ง์ผํ ๋ฆฌํฌํธ๋ฅผ ์์ฑํฉ๋๋ค." | |
) | |
submit_btn = gr.Button("๋ถ์ ์์", variant="primary") | |
with gr.Column(scale=2): | |
with gr.Tab("ํ๋ฅด์๋ ๋ถ์"): | |
persona_output = gr.Markdown() | |
with gr.Tab("๋ง์ผํ ๋ฆฌํฌํธ"): | |
marketing_output = gr.Markdown() | |
with gr.Tab("ํ๋ฅด์๋ ์ค์ "): | |
gr.Markdown("# ํ๋ฅด์๋ ์ ๋ณด ์ค์ ") | |
with gr.Row(): | |
age_select = gr.Dropdown( | |
choices=['20', '30', '40'], | |
label="์ฐ๋ น๋", | |
value='20' | |
) | |
gender_select = gr.Dropdown( | |
choices=[('๋จ์ฑ', 'M'), ('์ฌ์ฑ', 'F')], | |
label="์ฑ๋ณ", | |
value='M' | |
) | |
# ์ด๊ธฐ๊ฐ ์ค์ ์ ์ํด ๊ธฐ๋ณธ ํ๋ฅด์๋ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ | |
initial_info = WellFoodPersona.PERSONAS['20']['M'] | |
name_input = gr.Textbox( | |
label="์ด๋ฆ", | |
value=initial_info['name'] | |
) | |
occupation_input = gr.Textbox( | |
label="์ง์ ", | |
value=initial_info['occupation'] | |
) | |
interests_input = gr.Textbox( | |
label="๊ด์ฌ์ฌ", | |
placeholder="์ผํ(,)๋ก ๊ตฌ๋ถํ์ฌ ์ ๋ ฅํ์ธ์", | |
value=', '.join(initial_info['interests']) | |
) | |
lifestyle_input = gr.Textbox( | |
label="๋ผ์ดํ์คํ์ผ", | |
value=initial_info['lifestyle'] | |
) | |
pain_points_input = gr.Textbox( | |
label="์ฃผ์ ๊ณ ๋ฏผ์ ", | |
placeholder="์ผํ(,)๋ก ๊ตฌ๋ถํ์ฌ ์ ๋ ฅํ์ธ์", | |
value=', '.join(initial_info['pain_points']) | |
) | |
update_btn = gr.Button("ํ๋ฅด์๋ ์ ๋ณด ์ ๋ฐ์ดํธ") | |
update_result = gr.Markdown() | |
# ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ฐ๊ฒฐ | |
age_select.change( | |
load_persona_info, | |
inputs=[age_select, gender_select], | |
outputs=[name_input, occupation_input, interests_input, lifestyle_input, pain_points_input] | |
) | |
gender_select.change( | |
load_persona_info, | |
inputs=[age_select, gender_select], | |
outputs=[name_input, occupation_input, interests_input, lifestyle_input, pain_points_input] | |
) | |
# ์ ๋ฐ์ดํธ ๋ฒํผ ํด๋ฆญ ์ ํ๋ฅด์๋ ์ ๋ณด ์ ๋ฐ์ดํธ ๋ฐ ์ ํ ์ต์ ๊ฐฑ์ | |
update_btn.click( | |
update_persona_info, | |
inputs=[age_select, gender_select, name_input, occupation_input, | |
interests_input, lifestyle_input, pain_points_input], | |
outputs=[update_result, personas, personas] | |
) | |
# ์ ํ ์ ๋ณด๋ฅผ ์กฐํฉํ์ฌ ์ ์ฒด ์ค๋ช ์์ฑ | |
def combine_product_info(name, features, composition): | |
return f"""์ฐํธ๋์ ์ ์ ํ "{name}" | |
ํน์ง: | |
{features} | |
๊ตฌ์ฑ: | |
{composition}""" | |
# process_input์ ๊ฐ์ธ๋ ์๋ก์ด ํจ์ ์ถ๊ฐ | |
def process_input_wrapper(name, features, comp, personas, gen_report, progress=gr.Progress()): | |
"""process_input ํจ์๋ฅผ ๊ฐ์ธ์ ์ ๋๋ ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ํจ์""" | |
combined_description = combine_product_info(name, features, comp) | |
# ์ ๋๋ ์ดํฐ์ ๋ชจ๋ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ yield | |
for result in process_input(combined_description, personas, gen_report, name, progress): | |
yield result | |
# submit ๋ฒํผ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์ | |
submit_btn.click( | |
fn=process_input_wrapper, | |
inputs=[product_name, product_features, product_composition, personas, generate_report], | |
outputs=[persona_output, marketing_output, submit_btn], | |
api_name="analyze" | |
) | |
return demo | |
if __name__ == "__main__": | |
demo = create_demo() | |
demo.queue().launch(share=True) |