muni's picture
Add TinyTroupe
82a7a28
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)