Naming / app.py
openfree's picture
Update app.py
6766497 verified
raw
history blame
61.1 kB
"""
THEORIAโ„ข - Theory-driven Naming AI
===================================
ํŠน๋ณ„ํ•œ 15๊ฐœ์˜ ์ด๋ก ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋„ค์ด๋ฐ AI
Theory-driven Naming AI with 15 Specialized Theories
-----------------------------------
"""
import os
import json
import gradio as gr
import openai
from openai import OpenAI
from datetime import datetime
from typing import List, Dict, Tuple, Optional
import random
import time
# OpenAI ํด๋ผ์ด์–ธํŠธ
if not os.getenv("OPENAI_API_KEY"):
raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
client = OpenAI()
# ์–ธ์–ด๋ณ„ ํ…์ŠคํŠธ ์ •์˜
TEXTS = {
"en": {
"title": "THEORIAโ„ข",
"subtitle": "Theory-driven Naming AI with 15 Specialized Theories",
"description": "Generate innovative brand names using 15 cognitive and creative theories",
"industry_label": "๐Ÿญ Industry",
"industry_placeholder": "e.g., cafe, fitness, education, beauty...",
"keywords_label": "๐Ÿ”‘ Keywords",
"keywords_placeholder": "premium, comfortable, urban, eco-friendly...",
"keywords_info": "Core values or characteristics the brand should embody",
"generate_button": "Generate with {theory}",
"language_label": "๐ŸŒ Language",
"progress_message": "Generating innovative names using {theory}...",
"error_message": "โŒ Error in {theory}: {error}",
"input_required": "โš ๏ธ Please enter both industry and keywords.",
"evaluation_labels": {
"creativity": "Creativity",
"memorability": "Memorability",
"relevance": "Relevance"
}
},
"ko": {
"title": "THEORIAโ„ข",
"subtitle": "ํŠน๋ณ„ํ•œ 15๊ฐœ์˜ ์ด๋ก ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋„ค์ด๋ฐ AI",
"description": "15๊ฐ€์ง€ ์ธ์ง€ ๋ฐ ์ฐฝ์˜ ์ด๋ก ์„ ํ™œ์šฉํ•œ ํ˜์‹ ์ ์ธ ๋ธŒ๋žœ๋“œ๋ช… ์ƒ์„ฑ",
"industry_label": "๐Ÿญ ์—…์ข…",
"industry_placeholder": "์˜ˆ: ์นดํŽ˜, ํ”ผํŠธ๋‹ˆ์Šค, ๊ต์œก, ๋ทฐํ‹ฐ...",
"keywords_label": "๐Ÿ”‘ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ",
"keywords_placeholder": "ํ”„๋ฆฌ๋ฏธ์—„, ํŽธ์•ˆํ•œ, ๋„์‹œ์ ์ธ, ์นœํ™˜๊ฒฝ...",
"keywords_info": "๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค",
"generate_button": "{theory}๋กœ ์ƒ์„ฑ",
"language_label": "๐ŸŒ ์–ธ์–ด",
"progress_message": "{theory}๋ฅผ ํ™œ์šฉํ•ด ํ˜์‹ ์ ์ธ ์ด๋ฆ„์„ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค...",
"error_message": "โŒ {theory} ์˜ค๋ฅ˜: {error}",
"input_required": "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.",
"evaluation_labels": {
"creativity": "์ฐฝ์˜์„ฑ",
"memorability": "๊ธฐ์–ต์„ฑ",
"relevance": "๊ด€๋ จ์„ฑ"
}
}
}
# ์ด๋ก ๋ณ„ ์„ค๋ช… (์˜์–ด/ํ•œ๊ตญ์–ด)
THEORY_DESCRIPTIONS = {
"en": {
"square": "Creates a semantic square structure where 4 words are connected by meaningful relationships. Hidden diagonal connections create 'aha!' moments.",
"blending": "Blends two or more concepts to create new meaning. Like Netflix (Net+Flix), it births innovative concepts.",
"sound": "Utilizes associations between phonemes and meaning. 'i,e' convey lightness and speed, 'o,u' convey weight and slowness.",
"linguistic": "Creates global brands considering linguistic thought differences. Reflects cultural nuances and localization strategies.",
"archetype": "Leverages Jung's 12 universal archetypes. Creates unconscious emotional connections like Hero (Nike) or Creator (Apple).",
"jobs": "Focuses on the 'job' customers are trying to get done. Integrates functional, emotional, and social needs.",
"scamper": "Uses 7 creative techniques (Substitute, Combine, Adapt, Modify, Put to other use, Eliminate, Reverse) for innovation.",
"design": "Pursues human-centered innovation. Finds the intersection of desirability (human), feasibility (technical), and viability (business).",
"biomimicry": "Creates nature-inspired brands. Applies 3.8 billion years of evolutionary wisdom to branding.",
"cognitive": "Creates brands that minimize cognitive processing. Uses 1-3 syllables for instant recognition and recall.",
"vonrestorff": "Creates unique, memorable brands. Intentionally violates category conventions for 30x better recall.",
"network": "Creates brands that maximize network value. Designs structures where value increases with more users.",
"memetics": "Creates culturally replicable and evolving brands. Embeds viral elements that spread naturally like memes.",
"color": "Creates brands using color associations and emotions. Applies color psychology: red (passion), blue (trust), green (nature).",
"gestalt": "Creates brands using perception principles. Designs holistic brand experiences where the whole exceeds the sum of parts."
},
"ko": {
"square": "4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ณ€์˜ ์ˆจ๊ฒจ์ง„ ์—ฐ๊ฒฐ์ด '์•„ํ•˜!' ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
"blending": "๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฐœ๋…์„ ํ˜ผํ•ฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์˜๋ฏธ๋ฅผ ์ฐฝ์ถœํ•ฉ๋‹ˆ๋‹ค. Netflix(Net+Flix)์ฒ˜๋Ÿผ ํ˜์‹ ์ ์ธ ๊ฐœ๋…์„ ํƒ„์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.",
"sound": "์Œ์†Œ์™€ ์˜๋ฏธ ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. 'i,e'๋Š” ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๋А๋‚Œ, 'o,u'๋Š” ๋ฌด๊ฒ๊ณ  ๋А๋ฆฐ ๋А๋‚Œ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.",
"linguistic": "์–ธ์–ด๋ณ„ ์‚ฌ๊ณ ๋ฐฉ์‹ ์ฐจ์ด๋ฅผ ๊ณ ๋ คํ•œ ๊ธ€๋กœ๋ฒŒ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฌธํ™”์  ๋‰˜์•™์Šค์™€ ํ˜„์ง€ํ™” ์ „๋žต์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.",
"archetype": "Jung์˜ 12๊ฐ€์ง€ ๋ณดํŽธ์  ์›ํ˜•์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. Hero(Nike), Creator(Apple)์ฒ˜๋Ÿผ ๋ฌด์˜์‹์  ๊ฐ์ • ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
"jobs": "๊ณ ๊ฐ์ด ํ•ด๊ฒฐํ•˜๋ ค๋Š” '์ผ'์— ์ดˆ์ ์„ ๋งž์ถฅ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ , ๊ฐ์ •์ , ์‚ฌํšŒ์  ์ฐจ์›์˜ ๋‹ˆ์ฆˆ๋ฅผ ํ†ตํ•ฉ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.",
"scamper": "7๊ฐ€์ง€ ์ฐฝ์˜์  ๊ธฐ๋ฒ•(๋Œ€์ฒด, ๊ฒฐํ•ฉ, ์ ์‘, ์ˆ˜์ •, ์šฉ๋„๋ณ€๊ฒฝ, ์ œ๊ฑฐ, ์—ญ์ „)์œผ๋กœ ํ˜์‹ ์ ์ธ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
"design": "์ธ๊ฐ„ ์ค‘์‹ฌ ํ˜์‹ ์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋žŒ์งํ•จ(์ธ๊ฐ„), ์‹คํ˜„๊ฐ€๋Šฅ์„ฑ(๊ธฐ์ˆ ), ์ƒ์กด๊ฐ€๋Šฅ์„ฑ(๋น„์ฆˆ๋‹ˆ์Šค)์˜ ๊ต์ง‘ํ•ฉ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.",
"biomimicry": "์ž์—ฐ์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 38์–ต๋…„ ์ง„ํ™”์˜ ์ง€ํ˜œ๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
"cognitive": "์ธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 1-3์Œ์ ˆ์˜ ์‰ฌ์šด ๋ฐœ์Œ์œผ๋กœ ์ฆ‰๊ฐ์  ์ธ์‹๊ณผ ๊ธฐ์–ต์„ ๋•์Šต๋‹ˆ๋‹ค.",
"vonrestorff": "๋…ํŠนํ•˜๊ณ  ๊ธฐ์–ต์— ๋‚จ๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ๊ด€์Šต์„ ์˜๋„์ ์œผ๋กœ ์œ„๋ฐ˜ํ•˜์—ฌ 30๋ฐฐ ๋” ์ž˜ ๊ธฐ์–ต๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.",
"network": "๋„คํŠธ์›Œํฌ ๊ฐ€์น˜๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๊ฐ€์น˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.",
"memetics": "๋ฌธํ™”์ ์œผ๋กœ ๋ณต์ œ๋˜๊ณ  ์ง„ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฐˆ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํผ์ ธ๋‚˜๊ฐ€๋Š” ๋ฐ”์ด๋Ÿด ์š”์†Œ๋ฅผ ๋‚ด์žฌํ™”ํ•ฉ๋‹ˆ๋‹ค.",
"color": "์ƒ‰์ƒ ์—ฐ์ƒ๊ณผ ๊ฐ์ •์„ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋นจ๊ฐ•(์—ด์ •), ํŒŒ๋ž‘(์‹ ๋ขฐ), ์ดˆ๋ก(์ž์—ฐ) ๋“ฑ ์ƒ‰์ƒ ์‹ฌ๋ฆฌ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
"gestalt": "์ง€๊ฐ ์›๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ „์ฒด๊ฐ€ ๋ถ€๋ถ„์˜ ํ•ฉ๋ณด๋‹ค ํฌ๋‹ค๋Š” ์›์น™์œผ๋กœ ํ†ตํ•ฉ์  ๋ธŒ๋žœ๋“œ ๊ฒฝํ—˜์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค."
}
}
# ํ†ต์ผ๋œ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ (์˜์–ด)
UNIFIED_BASE_PROMPT_EN = """
You are a {theory_name} expert. {theory_description}
Based on the user input (industry/keywords), generate an array in the following unified JSON format:
{{
"brands": [
{{
"core": {{
"brand_name": "Brand Name",
"slogan": "Slogan",
"core_value": "Core Value",
"target_emotion": "Target Emotion",
"brand_personality": "Brand Personality"
}},
"visual": {{
"primary_color": "#HEX",
"color_meaning": "Color Meaning",
"visual_concept": "Visual Concept",
"typography_style": "Typography Style"
}},
"linguistic": {{
"pronunciation": "Pronunciation Guide",
"etymology": "Etymology/Structure",
"global_adaptability": "Global Adaptability",
"memorable_factor": "Memorability Factor"
}},
"strategic": {{
"differentiation": "Differentiation Point",
"market_positioning": "Market Positioning",
"growth_potential": "Growth Potential",
"implementation_ease": "Implementation Ease"
}},
"theory_specific": {{
{theory_specific_fields}
}},
"evaluation": {{
"creativity_score": 0-10,
"memorability_score": 0-10,
"relevance_score": 0-10,
"overall_effectiveness": "Overall effectiveness description"
}}
}}
]
}}
Return valid JSON format and fill all fields.
Include theory-specific characteristics in the theory_specific section while maintaining the unified structure.
All content should be in English.
"""
# ํ†ต์ผ๋œ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ (ํ•œ๊ตญ์–ด)
UNIFIED_BASE_PROMPT_KO = """
๋‹น์‹ ์€ {theory_name} ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. {theory_description}
์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ†ต์ผ๋œ JSON ํ˜•์‹์˜ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
{{
"brands": [
{{
"core": {{
"brand_name": "ํ•œ๊ธ€ ๋ธŒ๋žœ๋“œ๋ช…",
"slogan": "์Šฌ๋กœ๊ฑด",
"core_value": "ํ•ต์‹ฌ ๊ฐ€์น˜",
"target_emotion": "๋ชฉํ‘œ ๊ฐ์ •",
"brand_personality": "๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ"
}},
"visual": {{
"primary_color": "#HEX์ฝ”๋“œ",
"color_meaning": "์ƒ‰์ƒ ์˜๋ฏธ",
"visual_concept": "์‹œ๊ฐ์  ์ปจ์…‰",
"typography_style": "ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ์Šคํƒ€์ผ"
}},
"linguistic": {{
"pronunciation": "ํ•œ๊ธ€ ๋ฐœ์Œ ๊ฐ€์ด๋“œ",
"etymology": "์–ด์›/๊ตฌ์„ฑ (์˜์–ด๋ช… ํฌํ•จ)",
"global_adaptability": "์˜์–ด ๋ธŒ๋žœ๋“œ๋ช… (์˜ˆ: Mother's Garden)",
"memorable_factor": "๊ธฐ์–ต ์šฉ์ด์„ฑ ์š”์†Œ"
}},
"strategic": {{
"differentiation": "์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ",
"market_positioning": "์‹œ์žฅ ํฌ์ง€์…”๋‹",
"growth_potential": "์„ฑ์žฅ ์ž ์žฌ๋ ฅ",
"implementation_ease": "์‹คํ–‰ ์šฉ์ด์„ฑ"
}},
"theory_specific": {{
{theory_specific_fields}
}},
"evaluation": {{
"creativity_score": 0-10,
"memorability_score": 0-10,
"relevance_score": 0-10,
"overall_effectiveness": "์ „์ฒด์ ์ธ ํšจ๊ณผ์„ฑ ์„ค๋ช…"
}}
}}
]
}}
์ค‘์š”:
1. brand_name์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ธ€๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
2. linguistic > global_adaptability์—๋Š” ๋ฐ˜๋“œ์‹œ ์˜์–ด ๋ธŒ๋žœ๋“œ๋ช…์„ ํฌํ•จํ•˜์„ธ์š”.
3. ์˜์–ด๋ช…์€ ํ•œ๊ธ€๋ช…์˜ ์˜๋ฏธ๋ฅผ ์ž˜ ์ „๋‹ฌํ•˜๋˜, ๊ธ€๋กœ๋ฒŒํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ด๋ฆ„์œผ๋กœ ๋งŒ๋“œ์„ธ์š”.
4. ๋ชจ๋“  ํ•„๋“œ๋ฅผ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜๋˜, ์˜์–ด ๋ธŒ๋žœ๋“œ๋ช…๋งŒ ์˜์–ด๋กœ ํ‘œ๊ธฐํ•˜์„ธ์š”.
"""
# ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ์ •์˜ (์˜์–ด)
THEORY_SPECIFIC_FIELDS_EN = {
"square": """
"tl": "Top Left",
"tr": "Top Right",
"bl": "Bottom Left",
"br": "Bottom Right",
"top_edge": "Top Relationship",
"bottom_edge": "Bottom Relationship",
"left_edge": "Left Relationship",
"right_edge": "Right Relationship",
"diagonal_insight": "Diagonal Insight"
""",
"blending": """
"input_space1": "First Concept",
"input_space2": "Second Concept",
"generic_space": "Common Structure",
"blended_space": "Blended New Meaning",
"emergent_properties": "Emergent Properties",
"blend_ratio": "Blend Ratio"
""",
"sound": """
"phonetic_analysis": "Phonetic Analysis",
"sound_meaning": "Sound Meaning",
"vowel_consonant_ratio": "Vowel/Consonant Ratio",
"phoneme_emotion_map": "Phoneme-Emotion Mapping",
"cross_linguistic_sound": "Cross-linguistic Sound Consistency"
""",
"linguistic": """
"korean_adaptation": "Korean Adaptation",
"english_meaning": "English Meaning",
"cultural_considerations": "Cultural Considerations",
"avoid_meanings": "Meanings to Avoid",
"localization_strategy": "Localization Strategy"
""",
"archetype": """
"archetype": "Selected Archetype",
"archetype_traits": "Archetype Traits",
"shadow_side": "Shadow Side",
"mythology_reference": "Mythological Reference",
"customer_journey": "Customer Journey Connection"
""",
"jobs": """
"functional_job": "Functional Job",
"emotional_job": "Emotional Job",
"social_job": "Social Job",
"job_statement": "Core Job Statement",
"outcome_metrics": "Outcome Metrics"
""",
"scamper": """
"scamper_technique": "Technique Used",
"original_concept": "Original Concept",
"transformation": "Transformation Process",
"innovation_type": "Innovation Type",
"disruption_level": "Disruption Level"
""",
"design": """
"user_insight": "User Insight",
"pain_point": "Pain Point Solved",
"desirability": "Desirability (Human)",
"feasibility": "Feasibility (Technical)",
"viability": "Viability (Business)"
""",
"biomimicry": """
"natural_inspiration": "Natural Inspiration",
"biomimetic_principle": "Biomimetic Principle",
"form_function": "Form and Function",
"sustainability_aspect": "Sustainability Aspect",
"adaptation_strategy": "Adaptation Strategy"
""",
"cognitive": """
"syllable_count": "Syllable Count",
"processing_ease": "Processing Ease Score",
"memory_hooks": "Memory Hooks",
"cognitive_fluency": "Cognitive Fluency",
"attention_span_fit": "Attention Span Fit"
""",
"vonrestorff": """
"category_norm": "Category Norm",
"deviation_strategy": "Deviation Strategy",
"uniqueness_factors": "Uniqueness Factors",
"attention_triggers": "Attention Triggers",
"isolation_effect": "Isolation Effect Usage"
""",
"network": """
"network_type": "Network Type",
"viral_coefficient": "Viral Coefficient",
"sharing_ease": "Sharing Ease",
"community_aspect": "Community Aspect",
"network_value": "Network Value"
""",
"memetics": """
"meme_structure": "Meme Structure",
"replication_ease": "Replication Ease",
"mutation_potential": "Mutation Potential",
"cultural_fitness": "Cultural Fitness",
"transmission_channels": "Transmission Channels"
""",
"color": """
"color_palette": "Color Palette",
"emotional_response": "Emotional Response",
"cultural_associations": "Cultural Associations",
"industry_alignment": "Industry Alignment",
"color_accessibility": "Color Accessibility"
""",
"gestalt": """
"gestalt_principle": "Principle Used",
"visual_structure": "Visual Structure",
"perceptual_grouping": "Perceptual Grouping",
"figure_ground": "Figure-Ground Relationship",
"closure_effect": "Closure Effect"
"""
}
# ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ์ •์˜ (ํ•œ๊ตญ์–ด)
THEORY_SPECIFIC_FIELDS_KO = {
"square": """
"tl": "์™ผ์ชฝ์ƒ๋‹จ",
"tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ",
"bl": "์™ผ์ชฝํ•˜๋‹จ",
"br": "์˜ค๋ฅธ์ชฝํ•˜๋‹จ",
"top_edge": "์ƒ๋‹จ ๊ด€๊ณ„",
"bottom_edge": "ํ•˜๋‹จ ๊ด€๊ณ„",
"left_edge": "์™ผ์ชฝ ๊ด€๊ณ„",
"right_edge": "์˜ค๋ฅธ์ชฝ ๊ด€๊ณ„",
"diagonal_insight": "๋Œ€๊ฐ์„  ํ†ต์ฐฐ"
""",
"blending": """
"input_space1": "์ฒซ ๋ฒˆ์งธ ๊ฐœ๋…",
"input_space2": "๋‘ ๋ฒˆ์งธ ๊ฐœ๋…",
"generic_space": "๊ณตํ†ต ๊ตฌ์กฐ",
"blended_space": "ํ˜ผํ•ฉ๋œ ์ƒˆ๋กœ์šด ์˜๋ฏธ",
"emergent_properties": "์ฐฝ๋ฐœ์  ์†์„ฑ๋“ค",
"blend_ratio": "ํ˜ผํ•ฉ ๋น„์œจ"
""",
"sound": """
"phonetic_analysis": "์Œ์„ฑ ๋ถ„์„",
"sound_meaning": "์Œํ–ฅ์ด ์ „๋‹ฌํ•˜๋Š” ์˜๋ฏธ",
"vowel_consonant_ratio": "๋ชจ์Œ/์ž์Œ ๋น„์œจ",
"phoneme_emotion_map": "์Œ์†Œ-๊ฐ์ • ๋งคํ•‘",
"cross_linguistic_sound": "์–ธ์–ด๊ฐ„ ์Œํ–ฅ ์ผ๊ด€์„ฑ"
""",
"linguistic": """
"korean_adaptation": "ํ•œ๊ตญ์–ด ์ ์‘",
"english_meaning": "์˜์–ด ๋ธŒ๋žœ๋“œ๋ช…",
"cultural_considerations": "๋ฌธํ™”์  ๊ณ ๋ ค์‚ฌํ•ญ",
"avoid_meanings": "ํ”ผํ•ด์•ผ ํ•  ์˜๋ฏธ๋“ค",
"localization_strategy": "ํ˜„์ง€ํ™” ์ „๋žต"
""",
"archetype": """
"archetype": "์„ ํƒ๋œ ์›ํ˜•",
"archetype_traits": "์›ํ˜•์˜ ํŠน์ง•๋“ค",
"shadow_side": "๊ทธ๋ฆผ์ž ์ธก๋ฉด",
"mythology_reference": "์‹ ํ™”์  ์ฐธ์กฐ",
"customer_journey": "๊ณ ๊ฐ ์—ฌ์ • ์—ฐ๊ฒฐ"
""",
"jobs": """
"functional_job": "๊ธฐ๋Šฅ์  ์ผ",
"emotional_job": "๊ฐ์ •์  ์ผ",
"social_job": "์‚ฌํšŒ์  ์ผ",
"job_statement": "ํ•ต์‹ฌ Job ๋ฌธ์žฅ",
"outcome_metrics": "์„ฑ๊ณผ ์ง€ํ‘œ"
""",
"scamper": """
"scamper_technique": "์‚ฌ์šฉ๋œ ๊ธฐ๋ฒ•",
"original_concept": "์›๋ž˜ ๊ฐœ๋…",
"transformation": "๋ณ€ํ˜• ๊ณผ์ •",
"innovation_type": "ํ˜์‹  ์œ ํ˜•",
"disruption_level": "ํŒŒ๊ดด์  ํ˜์‹  ์ˆ˜์ค€"
""",
"design": """
"user_insight": "์‚ฌ์šฉ์ž ํ†ต์ฐฐ",
"pain_point": "ํ•ด๊ฒฐํ•˜๋Š” ๋ฌธ์ œ์ ",
"desirability": "๋ฐ”๋žŒ์งํ•จ (์ธ๊ฐ„)",
"feasibility": "์‹คํ˜„๊ฐ€๋Šฅ์„ฑ (๊ธฐ์ˆ )",
"viability": "์ƒ์กด๊ฐ€๋Šฅ์„ฑ (๋น„์ฆˆ๋‹ˆ์Šค)"
""",
"biomimicry": """
"natural_inspiration": "์ž์—ฐ์  ์˜๊ฐ์›",
"biomimetic_principle": "์ƒ์ฒด๋ชจ๋ฐฉ ์›๋ฆฌ",
"form_function": "ํ˜•ํƒœ์™€ ๊ธฐ๋Šฅ",
"sustainability_aspect": "์ง€์†๊ฐ€๋Šฅ์„ฑ ์ธก๋ฉด",
"adaptation_strategy": "์ ์‘ ์ „๋žต"
""",
"cognitive": """
"syllable_count": "์Œ์ ˆ ์ˆ˜",
"processing_ease": "์ฒ˜๋ฆฌ ์šฉ์ด์„ฑ ์ ์ˆ˜",
"memory_hooks": "๊ธฐ์–ต ๊ณ ๋ฆฌ",
"cognitive_fluency": "์ธ์ง€์  ์œ ์ฐฝ์„ฑ",
"attention_span_fit": "์ฃผ์˜๋ ฅ ์ ํ•ฉ๋„"
""",
"vonrestorff": """
"category_norm": "์นดํ…Œ๊ณ ๋ฆฌ ํ‘œ์ค€",
"deviation_strategy": "์ผํƒˆ ์ „๋žต",
"uniqueness_factors": "๋…ํŠน์„ฑ ์š”์†Œ๋“ค",
"attention_triggers": "์ฃผ์˜ ํŠธ๋ฆฌ๊ฑฐ",
"isolation_effect": "๊ณ ๋ฆฝ ํšจ๊ณผ ํ™œ์šฉ"
""",
"network": """
"network_type": "๋„คํŠธ์›Œํฌ ์œ ํ˜•",
"viral_coefficient": "๋ฐ”์ด๋Ÿด ๊ณ„์ˆ˜",
"sharing_ease": "๊ณต์œ  ์šฉ์ด์„ฑ",
"community_aspect": "์ปค๋ฎค๋‹ˆํ‹ฐ ์ธก๋ฉด",
"network_value": "๋„คํŠธ์›Œํฌ ๊ฐ€์น˜"
""",
"memetics": """
"meme_structure": "๋ฐˆ ๊ตฌ์กฐ",
"replication_ease": "๋ณต์ œ ์šฉ์ด์„ฑ",
"mutation_potential": "๋ณ€์ด ์ž ์žฌ๋ ฅ",
"cultural_fitness": "๋ฌธํ™”์  ์ ํ•ฉ๋„",
"transmission_channels": "์ „๋‹ฌ ์ฑ„๋„"
""",
"color": """
"color_palette": "์ƒ‰์ƒ ํŒ”๋ ˆํŠธ",
"emotional_response": "๊ฐ์ •์  ๋ฐ˜์‘",
"cultural_associations": "๋ฌธํ™”์  ์—ฐ์ƒ",
"industry_alignment": "์—…์ข… ์ •๋ ฌ",
"color_accessibility": "์ƒ‰์ƒ ์ ‘๊ทผ์„ฑ"
""",
"gestalt": """
"gestalt_principle": "ํ™œ์šฉ ์›์น™",
"visual_structure": "์‹œ๊ฐ์  ๊ตฌ์กฐ",
"perceptual_grouping": "์ง€๊ฐ์  ๊ทธ๋ฃนํ™”",
"figure_ground": "์ „๊ฒฝ-๋ฐฐ๊ฒฝ ๊ด€๊ณ„",
"closure_effect": "ํ์‡„ ํšจ๊ณผ"
"""
}
def create_theory_prompt(theory: str, language: str) -> str:
"""๊ฐ ์ด๋ก ๋ณ„ ํ†ต์ผ๋œ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ"""
theory_names = {
"en": {
"square": "Square Theory",
"blending": "Conceptual Blending Theory",
"sound": "Sound Symbolism",
"linguistic": "Linguistic Relativity",
"archetype": "Jung's Archetype Theory",
"jobs": "Jobs-to-be-Done Theory",
"scamper": "SCAMPER Method",
"design": "IDEO's Design Thinking",
"biomimicry": "Biomimicry",
"cognitive": "Cognitive Load Theory",
"vonrestorff": "Von Restorff Effect",
"network": "Network Effects",
"memetics": "Memetics",
"color": "Color Psychology",
"gestalt": "Gestalt Theory"
},
"ko": {
"square": "Square Theory",
"blending": "Conceptual Blending Theory",
"sound": "Sound Symbolism",
"linguistic": "Linguistic Relativity",
"archetype": "Jung์˜ Archetype Theory",
"jobs": "Jobs-to-be-Done Theory",
"scamper": "SCAMPER Method",
"design": "IDEO์˜ Design Thinking",
"biomimicry": "Biomimicry",
"cognitive": "Cognitive Load Theory",
"vonrestorff": "Von Restorff Effect",
"network": "Network Effects",
"memetics": "Memetics",
"color": "Color Psychology",
"gestalt": "Gestalt Theory"
}
}
base_prompt = UNIFIED_BASE_PROMPT_EN if language == "en" else UNIFIED_BASE_PROMPT_KO
theory_specific_fields = THEORY_SPECIFIC_FIELDS_EN if language == "en" else THEORY_SPECIFIC_FIELDS_KO
return base_prompt.format(
theory_name=theory_names[language][theory],
theory_description=THEORY_DESCRIPTIONS[language][theory],
theory_specific_fields=theory_specific_fields[theory]
)
def generate_by_theory(industry: str, keywords: str, theory: str, language: str, count: int = 3) -> Tuple[str, str, gr.update]:
"""ํŠน์ • ์ด๋ก ์œผ๋กœ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
texts = TEXTS[language]
if not industry or not keywords:
return texts["input_required"], "", gr.update(visible=False)
prompt = create_theory_prompt(theory, language)
if language == "en":
user_input = f"""Industry: {industry}
Keywords: {keywords}
Generate {count} brands with the above information.
Each brand should have a unified structure, with theory-specific characteristics in the theory_specific section."""
else:
user_input = f"""์—…์ข…: {industry}
ํ‚ค์›Œ๋“œ: {keywords}
์œ„ ์ •๋ณด๋กœ {count}๊ฐœ์˜ ๋ธŒ๋žœ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
๊ฐ ๋ธŒ๋žœ๋“œ๋Š” ํ†ต์ผ๋œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋˜, theory_specific ์„น์…˜์—๋Š” {theory} ์ด๋ก ์˜ ํŠน์„ฑ์„ ๋ฐ˜์˜ํ•˜์„ธ์š”.
์ค‘์š”: linguistic > global_adaptability ํ•„๋“œ์— ๋ฐ˜๋“œ์‹œ ์˜์–ด ๋ธŒ๋žœ๋“œ๋ช…์„ ํฌํ•จํ•˜์„ธ์š”."""
try:
# ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ํ‘œ์‹œ
theory_names = {
"square": "Square Theory",
"blending": "Conceptual Blending",
"sound": "Sound Symbolism",
"linguistic": "Linguistic Relativity",
"archetype": "Archetype Theory",
"jobs": "Jobs-to-be-Done",
"scamper": "SCAMPER Method",
"design": "Design Thinking",
"biomimicry": "Biomimicry",
"cognitive": "Cognitive Load Theory",
"vonrestorff": "Von Restorff Effect",
"network": "Network Effects",
"memetics": "Memetics",
"color": "Color Psychology",
"gestalt": "Gestalt Principles"
}
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": user_input}
],
temperature=0.8,
max_tokens=2000,
response_format={"type": "json_object"}
)
content = response.choices[0].message.content
data = json.loads(content)
# ์‘๋‹ต ์ •๊ทœํ™”
if "brands" in data:
results = data["brands"]
else:
results = [data]
if not isinstance(results, list):
results = [results]
# ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ
markdown = generate_unified_markdown(theory, results, industry, keywords, language)
# HTML ์‹œ๊ฐํ™” ์ƒ์„ฑ
html = generate_unified_visualization(theory, results, language)
return markdown, html, gr.update(visible=False)
except Exception as e:
error_msg = texts["error_message"].format(theory=theory_names[theory], error=str(e))
print(error_msg)
return error_msg, "", gr.update(visible=False)
def generate_unified_markdown(theory: str, results: List[Dict], industry: str, keywords: str, language: str) -> str:
"""ํ†ต์ผ๋œ ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ"""
theory_names = {
"square": "Square Theory",
"blending": "Conceptual Blending",
"sound": "Sound Symbolism",
"linguistic": "Linguistic Relativity",
"archetype": "Archetype Theory",
"jobs": "Jobs-to-be-Done",
"scamper": "SCAMPER Method",
"design": "Design Thinking",
"biomimicry": "Biomimicry",
"cognitive": "Cognitive Load Theory",
"vonrestorff": "Von Restorff Effect",
"network": "Network Effects",
"memetics": "Memetics",
"color": "Color Psychology",
"gestalt": "Gestalt Principles"
}
theory_icons = {
"square": "๐ŸŸฆ", "blending": "๐Ÿ”€", "sound": "๐Ÿ”Š", "linguistic": "๐ŸŒ",
"archetype": "๐ŸŽญ", "jobs": "โœ…", "scamper": "๐Ÿ”ง", "design": "๐Ÿ’ญ",
"biomimicry": "๐ŸŒฟ", "cognitive": "๐Ÿง ", "vonrestorff": "โšก", "network": "๐ŸŒ",
"memetics": "๐Ÿงฌ", "color": "๐ŸŽจ", "gestalt": "๐Ÿ‘๏ธ"
}
texts = TEXTS[language]
if language == "en":
markdown = f"""# {theory_icons[theory]} {theory_names[theory]}
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
<h3 style="margin: 0 0 10px 0;">Theory Overview</h3>
<p style="margin: 0; line-height: 1.6;">{THEORY_DESCRIPTIONS[language][theory]}</p>
</div>
**Industry**: {industry} | **Keywords**: {keywords}
*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
---
"""
else:
markdown = f"""# {theory_icons[theory]} {theory_names[theory]}
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
<h3 style="margin: 0 0 10px 0;">์ด๋ก  ๊ฐœ์š”</h3>
<p style="margin: 0; line-height: 1.6;">{THEORY_DESCRIPTIONS[language][theory]}</p>
</div>
**์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}
*์ƒ์„ฑ ์‹œ๊ฐ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
---
"""
for idx, result in enumerate(results, 1):
core = result.get('core', {})
visual = result.get('visual', {})
linguistic = result.get('linguistic', {})
strategic = result.get('strategic', {})
theory_specific = result.get('theory_specific', {})
evaluation = result.get('evaluation', {})
brand_name = core.get('brand_name', 'N/A')
slogan = core.get('slogan', 'N/A')
# ํ•œ๊ธ€์ผ ๊ฒฝ์šฐ ์˜์–ด ํ‘œํ˜„ ์ถ”๊ฐ€
if language == "ko":
# ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์˜์–ด๋ช… ์ฐพ๊ธฐ
english_name = None
# 1. linguistic theory์˜ ๊ฒฝ์šฐ theory_specific์—์„œ ์ฐพ๊ธฐ
if theory == "linguistic" and 'english_meaning' in theory_specific:
english_name = theory_specific.get('english_meaning', '')
# 2. global_adaptability์—์„œ ์ฐพ๊ธฐ
if not english_name or english_name == 'N/A':
english_name = linguistic.get('global_adaptability', '')
# 3. etymology์—์„œ ์˜์–ด ์ถ”์ถœ
if not english_name or english_name == 'N/A':
etymology = linguistic.get('etymology', '')
if etymology and '์˜์–ด' in etymology and ':' in etymology:
# "์˜์–ด: Brand Name" ํ˜•์‹์—์„œ ์ถ”์ถœ
parts = etymology.split(':')
for i, part in enumerate(parts):
if '์˜์–ด' in part and i + 1 < len(parts):
english_name = parts[i + 1].strip().split(',')[0].strip()
break
# ์˜์–ด๋ช…์ด ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ถ”๊ฐ€
if english_name and english_name != 'N/A' and english_name != brand_name:
# ๊ธธ์ด๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๊ฑฐ๋‚˜ ์„ค๋ช…์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ ์ •๋ฆฌ
if len(english_name) > 50 or '(' in english_name or ',' in english_name:
english_name = english_name.split('(')[0].split(',')[0].strip()
# ์˜์–ด๋ช…์ด ์‹ค์ œ๋กœ ์˜์–ด์ธ์ง€ ๊ฐ„๋‹จํžˆ ํ™•์ธ (ํ•œ๊ธ€์ด ํฌํ•จ๋˜์ง€ ์•Š์•˜๋Š”์ง€)
if not any(ord(char) >= 0xAC00 and ord(char) <= 0xD7A3 for char in english_name):
brand_display = f"{brand_name} / {english_name}"
else:
brand_display = brand_name
else:
brand_display = brand_name
else:
brand_display = brand_name
markdown += f"\n## {idx}. {brand_display}\n"
if language == "en":
markdown += f"""**Slogan**: *"{slogan}"*
### ๐Ÿ“ Core Information
- **Core Value**: {core.get('core_value', 'N/A')}
- **Target Emotion**: {core.get('target_emotion', 'N/A')}
- **Brand Personality**: {core.get('brand_personality', 'N/A')}
### ๐ŸŽจ Visual Concept
- **Primary Color**: {visual.get('primary_color', '#000000')} - {visual.get('color_meaning', 'N/A')}
- **Visual Concept**: {visual.get('visual_concept', 'N/A')}
- **Typography**: {visual.get('typography_style', 'N/A')}
### ๐Ÿ—ฃ๏ธ Linguistic Features
- **Pronunciation**: {linguistic.get('pronunciation', 'N/A')}
- **Etymology**: {linguistic.get('etymology', 'N/A')}
- **Global Adaptability**: {linguistic.get('global_adaptability', 'N/A')}
### ๐ŸŽฏ Strategic Value
- **Differentiation**: {strategic.get('differentiation', 'N/A')}
- **Market Positioning**: {strategic.get('market_positioning', 'N/A')}
- **Growth Potential**: {strategic.get('growth_potential', 'N/A')}
"""
else:
markdown += f"""**์Šฌ๋กœ๊ฑด**: *"{slogan}"*
### ๐Ÿ“ ํ•ต์‹ฌ ์ •๋ณด
- **ํ•ต์‹ฌ ๊ฐ€์น˜**: {core.get('core_value', 'N/A')}
- **๋ชฉํ‘œ ๊ฐ์ •**: {core.get('target_emotion', 'N/A')}
- **๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ**: {core.get('brand_personality', 'N/A')}
### ๐ŸŽจ ์‹œ๊ฐ์  ์ปจ์…‰
- **์ฃผ์š” ์ƒ‰์ƒ**: {visual.get('primary_color', '#000000')} - {visual.get('color_meaning', 'N/A')}
- **๋น„์ฃผ์–ผ ์ปจ์…‰**: {visual.get('visual_concept', 'N/A')}
- **ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ**: {visual.get('typography_style', 'N/A')}
### ๐Ÿ—ฃ๏ธ ์–ธ์–ด์  ํŠน์„ฑ
- **๋ฐœ์Œ**: {linguistic.get('pronunciation', 'N/A')}
- **์–ด์›/๊ตฌ์„ฑ**: {linguistic.get('etymology', 'N/A')}
- **๊ธ€๋กœ๋ฒŒ ์ ์‘์„ฑ**: {linguistic.get('global_adaptability', 'N/A')}
### ๐ŸŽฏ ์ „๋žต์  ๊ฐ€์น˜
- **์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ**: {strategic.get('differentiation', 'N/A')}
- **์‹œ์žฅ ํฌ์ง€์…”๋‹**: {strategic.get('market_positioning', 'N/A')}
- **์„ฑ์žฅ ์ž ์žฌ๋ ฅ**: {strategic.get('growth_potential', 'N/A')}
"""
# ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ์ •๋ณด
if theory_specific:
theory_header = f"### ๐Ÿ’ก {theory_names[theory]} " + ("Features" if language == "en" else "ํŠน์„ฑ") + "\n"
markdown += theory_header
for key, value in theory_specific.items():
display_key = key.replace('_', ' ').title()
markdown += f"- **{display_key}**: {value}\n"
# ํ‰๊ฐ€ ์ ์ˆ˜
eval_labels = texts["evaluation_labels"]
if language == "en":
markdown += f"""
### ๐Ÿ“Š Evaluation
- **{eval_labels['creativity']}**: {'โญ' * int(evaluation.get('creativity_score', 0))} ({evaluation.get('creativity_score', 0)}/10)
- **{eval_labels['memorability']}**: {'โญ' * int(evaluation.get('memorability_score', 0))} ({evaluation.get('memorability_score', 0)}/10)
- **{eval_labels['relevance']}**: {'โญ' * int(evaluation.get('relevance_score', 0))} ({evaluation.get('relevance_score', 0)}/10)
๐Ÿ’ฌ **Overall Assessment**: {evaluation.get('overall_effectiveness', 'N/A')}
"""
else:
markdown += f"""
### ๐Ÿ“Š ํ‰๊ฐ€
- **{eval_labels['creativity']}**: {'โญ' * int(evaluation.get('creativity_score', 0))} ({evaluation.get('creativity_score', 0)}/10)
- **{eval_labels['memorability']}**: {'โญ' * int(evaluation.get('memorability_score', 0))} ({evaluation.get('memorability_score', 0)}/10)
- **{eval_labels['relevance']}**: {'โญ' * int(evaluation.get('relevance_score', 0))} ({evaluation.get('relevance_score', 0)}/10)
๐Ÿ’ฌ **์ „์ฒด ํ‰๊ฐ€**: {evaluation.get('overall_effectiveness', 'N/A')}
"""
markdown += "\n---\n"
return markdown
def generate_unified_visualization(theory: str, results: List[Dict], language: str) -> str:
"""ํ†ต์ผ๋œ ์‹œ๊ฐํ™” ์ƒ์„ฑ"""
texts = TEXTS[language]
eval_labels = texts["evaluation_labels"]
html_parts = []
for idx, result in enumerate(results, 1):
core = result.get('core', {})
visual = result.get('visual', {})
linguistic = result.get('linguistic', {})
strategic = result.get('strategic', {})
theory_specific = result.get('theory_specific', {})
evaluation = result.get('evaluation', {})
brand_name = core.get('brand_name', 'Brand')
slogan = core.get('slogan', '')
primary_color = visual.get('primary_color', '#667eea')
# ํ•œ๊ธ€์ผ ๊ฒฝ์šฐ ์˜์–ด ํ‘œํ˜„ ์ถ”๊ฐ€
if language == "ko":
# ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์˜์–ด๋ช… ์ฐพ๊ธฐ
english_name = None
# 1. linguistic theory์˜ ๊ฒฝ์šฐ theory_specific์—์„œ ์ฐพ๊ธฐ
if theory == "linguistic" and 'english_meaning' in theory_specific:
english_name = theory_specific.get('english_meaning', '')
# 2. global_adaptability์—์„œ ์ฐพ๊ธฐ
if not english_name or english_name == 'N/A':
english_name = linguistic.get('global_adaptability', '')
# 3. etymology์—์„œ ์˜์–ด ์ถ”์ถœ
if not english_name or english_name == 'N/A':
etymology = linguistic.get('etymology', '')
if etymology and '์˜์–ด' in etymology and ':' in etymology:
# "์˜์–ด: Brand Name" ํ˜•์‹์—์„œ ์ถ”์ถœ
parts = etymology.split(':')
for i, part in enumerate(parts):
if '์˜์–ด' in part and i + 1 < len(parts):
english_name = parts[i + 1].strip().split(',')[0].strip()
break
# ์˜์–ด๋ช…์ด ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ถ”๊ฐ€
if english_name and english_name != 'N/A' and english_name != brand_name:
# ๊ธธ์ด๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๊ฑฐ๋‚˜ ์„ค๋ช…์ด ํฌํ•จ๋œ ๊ฒฝ์šฐ ์ •๋ฆฌ
if len(english_name) > 50 or '(' in english_name or ',' in english_name:
english_name = english_name.split('(')[0].split(',')[0].strip()
# ์˜์–ด๋ช…์ด ์‹ค์ œ๋กœ ์˜์–ด์ธ์ง€ ๊ฐ„๋‹จํžˆ ํ™•์ธ (ํ•œ๊ธ€์ด ํฌํ•จ๋˜์ง€ ์•Š์•˜๋Š”์ง€)
if not any(ord(char) >= 0xAC00 and ord(char) <= 0xD7A3 for char in english_name):
brand_display = f"{brand_name} / {english_name}"
else:
brand_display = brand_name
else:
brand_display = brand_name
else:
brand_display = brand_name
# ์–ธ์–ด๋ณ„ ๋ผ๋ฒจ
if language == "en":
labels = {
"core_value": "Core Value",
"target_emotion": "Target Emotion",
"differentiation": "Differentiation",
"pronunciation": "Pronunciation"
}
else:
labels = {
"core_value": "ํ•ต์‹ฌ ๊ฐ€์น˜",
"target_emotion": "๋ชฉํ‘œ ๊ฐ์ •",
"differentiation": "์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ",
"pronunciation": "๋ฐœ์Œ ๊ฐ€์ด๋“œ"
}
# ํ†ต์ผ๋œ ์นด๋“œ ๋ ˆ์ด์•„์›ƒ
html = f"""
<div style="max-width: 800px; margin: 30px auto; font-family: -apple-system, sans-serif;">
<div style="background: white; border-radius: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.1); overflow: hidden;">
<!-- ํ—ค๋” -->
<div style="background: linear-gradient(135deg, {primary_color} 0%, #2c3e50 100%); padding: 40px; color: white;">
<h2 style="margin: 0 0 10px 0; font-size: 2.5em;">{brand_display}</h2>
<p style="margin: 0; font-style: italic; font-size: 1.2em; opacity: 0.9;">"{slogan}"</p>
</div>
<!-- ๋ณธ๋ฌธ -->
<div style="padding: 40px;">
<!-- ํ‰๊ฐ€ ์ ์ˆ˜ -->
<div style="display: flex; justify-content: space-around; margin-bottom: 30px;">
<div style="text-align: center;">
<div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
{evaluation.get('creativity_score', 0)}/10
</div>
<div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['creativity']}</div>
</div>
<div style="text-align: center;">
<div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
{evaluation.get('memorability_score', 0)}/10
</div>
<div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['memorability']}</div>
</div>
<div style="text-align: center;">
<div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
{evaluation.get('relevance_score', 0)}/10
</div>
<div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['relevance']}</div>
</div>
</div>
<!-- ํ•ต์‹ฌ ์ •๋ณด ๊ทธ๋ฆฌ๋“œ -->
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px;">
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['core_value']}</h4>
<p style="margin: 0; color: #555;">{core.get('core_value', 'N/A')}</p>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['target_emotion']}</h4>
<p style="margin: 0; color: #555;">{core.get('target_emotion', 'N/A')}</p>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['differentiation']}</h4>
<p style="margin: 0; color: #555;">{strategic.get('differentiation', 'N/A')}</p>
</div>
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['pronunciation']}</h4>
<p style="margin: 0; color: #555;">{linguistic.get('pronunciation', 'N/A')}</p>
</div>
</div>
"""
# ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ์‹œ๊ฐํ™” ์ถ”๊ฐ€
if theory == "square" and all(k in theory_specific for k in ['tl', 'tr', 'bl', 'br']):
html += visualize_square_specific(theory_specific, primary_color)
elif theory == "blending" and 'input_space1' in theory_specific:
html += visualize_blending_specific(theory_specific, primary_color)
elif theory == "color" and 'color_palette' in theory_specific:
html += visualize_color_specific(theory_specific, primary_color)
else:
# ๊ธฐ๋ณธ ์ด๋ก  ํŠน์„ฑ ํ‘œ์‹œ
theory_header = "Theory Features" if language == "en" else "์ด๋ก  ํŠน์„ฑ"
html += f"""
<div style="background: linear-gradient(135deg, {primary_color}15 0%, {primary_color}05 100%); padding: 25px; border-radius: 15px; margin-top: 20px;">
<h4 style="margin: 0 0 15px 0; color: {primary_color};">{theory_header}</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
"""
for key, value in theory_specific.items():
display_key = key.replace('_', ' ').title()
html += f"""
<div>
<strong style="color: #555;">{display_key}:</strong><br>
<span style="color: #777;">{value}</span>
</div>
"""
html += """
</div>
</div>
"""
# ์ „์ฒด ํ‰๊ฐ€
overall_header = "Overall Assessment" if language == "en" else "์ „์ฒด ํ‰๊ฐ€"
html += f"""
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-top: 20px;">
<h4 style="margin: 0 0 10px 0; color: {primary_color};">{overall_header}</h4>
<p style="margin: 0; color: #555; line-height: 1.6;">{evaluation.get('overall_effectiveness', 'N/A')}</p>
</div>
</div>
</div>
</div>
"""
html_parts.append(html)
return "\n".join(html_parts)
def visualize_square_specific(theory_specific: Dict, primary_color: str) -> str:
"""Square Theory ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
return f"""
<div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
<h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Square Structure</h4>
<div style="position: relative; width: 100%; max-width: 400px; height: 300px; margin: 0 auto;">
<div style="position: absolute; top: 0; left: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
{theory_specific.get('tl', '?')}
</div>
<div style="position: absolute; top: 0; right: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
{theory_specific.get('tr', '?')}
</div>
<div style="position: absolute; bottom: 0; left: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
{theory_specific.get('bl', '?')}
</div>
<div style="position: absolute; bottom: 0; right: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
{theory_specific.get('br', '?')}
</div>
<!-- ์—ฐ๊ฒฐ์„ ๊ณผ ๊ด€๊ณ„ ํ‘œ์‹œ -->
<div style="position: absolute; top: 25px; left: 50%; transform: translateX(-50%); color: #7f8c8d; font-size: 0.9em;">
{theory_specific.get('top_edge', '')}
</div>
<div style="position: absolute; bottom: 25px; left: 50%; transform: translateX(-50%); color: #7f8c8d; font-size: 0.9em;">
{theory_specific.get('bottom_edge', '')}
</div>
<div style="position: absolute; top: 50%; left: 25px; transform: translateY(-50%) rotate(-90deg); color: #7f8c8d; font-size: 0.9em;">
{theory_specific.get('left_edge', '')}
</div>
<div style="position: absolute; top: 50%; right: 25px; transform: translateY(-50%) rotate(90deg); color: #7f8c8d; font-size: 0.9em;">
{theory_specific.get('right_edge', '')}
</div>
</div>
</div>
"""
def visualize_blending_specific(theory_specific: Dict, primary_color: str) -> str:
"""Conceptual Blending ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
return f"""
<div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
<h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Concept Blending</h4>
<div style="display: flex; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap;">
<div style="text-align: center; padding: 20px; background: white; color: {primary_color}; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<div>
<strong>Input 1</strong><br>
<span style="font-size: 0.9em;">{theory_specific.get('input_space1', '')}</span>
</div>
</div>
<div style="font-size: 2em; color: {primary_color};">+</div>
<div style="text-align: center; padding: 20px; background: white; color: {primary_color}; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<div>
<strong>Input 2</strong><br>
<span style="font-size: 0.9em;">{theory_specific.get('input_space2', '')}</span>
</div>
</div>
<div style="font-size: 2em; color: {primary_color};">=</div>
<div style="text-align: center; padding: 20px; background: {primary_color}; color: white; border-radius: 20px; min-width: 150px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<strong>Blend</strong><br>
<span style="font-size: 0.95em;">{theory_specific.get('blended_space', '')}</span>
</div>
</div>
</div>
"""
def visualize_color_specific(theory_specific: Dict, primary_color: str) -> str:
"""Color Psychology ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
palette = theory_specific.get('color_palette', primary_color)
colors = palette.split(',') if ',' in palette else [primary_color]
html = f"""
<div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
<h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Color Palette</h4>
<div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
"""
for color in colors[:5]: # ์ตœ๋Œ€ 5๊ฐœ ์ƒ‰์ƒ๋งŒ ํ‘œ์‹œ
color = color.strip()
html += f"""
<div style="width: 80px; height: 80px; background: {color}; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);"></div>
"""
html += """
</div>
</div>
"""
return html
# Gradio UI
with gr.Blocks(
title="THEORIAโ„ข - Theory-driven Naming AI",
theme=gr.themes.Soft(),
css="""
.gradio-container {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 1400px !important;
}
/* ํƒญ ๋„ค๋น„๊ฒŒ์ด์…˜ ์Šคํƒ€์ผ ๊ฐœ์„  */
.tab-nav {
display: grid !important;
grid-template-columns: repeat(5, 1fr) !important;
gap: 8px !important;
padding: 15px !important;
background: #f8f9fa !important;
border-radius: 10px !important;
margin-bottom: 20px !important;
}
.tab-nav button {
font-size: 0.8em !important;
padding: 10px 8px !important;
white-space: normal !important;
line-height: 1.3 !important;
height: auto !important;
min-height: 50px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
border-radius: 8px !important;
transition: all 0.3s ease !important;
}
.tab-nav button:hover {
transform: translateY(-2px) !important;
box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
}
.tab-nav button.selected {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important;
font-weight: 600 !important;
}
/* ๋ชจ๋ฐ”์ผ ๋ฐ˜์‘ํ˜• */
@media (max-width: 768px) {
.tab-nav {
grid-template-columns: repeat(3, 1fr) !important;
}
}
@media (max-width: 480px) {
.tab-nav {
grid-template-columns: repeat(2, 1fr) !important;
}
}
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; }
100% { opacity: 0.6; }
}
.progress-bar {
animation: pulse 1.5s ease-in-out infinite;
}
"""
) as demo:
# ์–ธ์–ด ์ƒํƒœ ๊ด€๋ฆฌ
current_language = gr.State(value="en")
def update_ui_language(language):
"""UI ์–ธ์–ด ์—…๋ฐ์ดํŠธ"""
texts = TEXTS[language]
return (
language, # current_language state update
# Title section update
gr.update(value=f"""
<div style="text-align: center; padding: 30px 0;">
<h1 style="font-size: 3em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
{texts['title']}
</h1>
<p style="font-size: 1.4em; color: #7f8c8d; font-weight: 500;">{texts['subtitle']}</p>
<p style="font-size: 1.1em; color: #95a5a6; margin-top: 10px;">{texts['description']}</p>
</div>
"""),
gr.update(label=texts['industry_label'], placeholder=texts['industry_placeholder']),
gr.update(label=texts['keywords_label'], placeholder=texts['keywords_placeholder'], info=texts['keywords_info']),
)
# ํ—ค๋”
title_section = gr.Markdown("""
<div style="text-align: center; padding: 30px 0;">
<h1 style="font-size: 3em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
THEORIAโ„ข
</h1>
<p style="font-size: 1.4em; color: #7f8c8d; font-weight: 500;">Theory-driven Naming AI with 15 Specialized Theories</p>
<p style="font-size: 1.1em; color: #95a5a6; margin-top: 10px;">Generate innovative brand names using 15 cognitive and creative theories</p>
</div>
""")
with gr.Row():
with gr.Column(scale=1, min_width=250):
gr.Markdown("""
<div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
<h3 style="margin-top: 0; color: #2c3e50;">๐Ÿ“ Brand Information</h3>
</div>
""")
# ์–ธ์–ด ์„ ํƒ
language_selector = gr.Radio(
choices=[("English", "en"), ("ํ•œ๊ตญ์–ด", "ko")],
value="en",
label="๐ŸŒ Language",
info="Select output language"
)
industry_input = gr.Textbox(
label="๐Ÿญ Industry",
placeholder="e.g., cafe, fitness, education, beauty...",
value="์นดํŽ˜/์ปคํ”ผ์ˆ"
)
keywords_input = gr.Textbox(
label="๐Ÿ”‘ Keywords",
placeholder="premium, comfortable, urban, eco-friendly...",
info="Core values or characteristics the brand should embody",
lines=2
)
# ์–ธ์–ด ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
language_selector.change(
update_ui_language,
inputs=[language_selector],
outputs=[current_language, title_section, industry_input, keywords_input]
)
gr.Markdown("""
<div style="background: #e3f2fd; padding: 15px; border-radius: 8px; margin-top: 20px;">
<h4 style="margin-top: 0; color: #1976d2;">๐ŸŽฏ 15 Theories</h4>
<p style="margin: 10px 0; font-size: 0.9em;">Each theory offers unique approach:</p>
<ul style="margin: 5px 0; padding-left: 20px; font-size: 0.8em; line-height: 1.4;">
<li><strong>Cognitive</strong>: Square, Sound, Cognitive, Gestalt</li>
<li><strong>Creative</strong>: Blending, SCAMPER, Biomimicry</li>
<li><strong>Strategic</strong>: Jobs-to-be-Done, Design</li>
<li><strong>Cultural</strong>: Archetype, Linguistic, Memetics</li>
<li><strong>Distinctive</strong>: Von Restorff, Color, Network</li>
</ul>
</div>
<div style="background: #fff3cd; padding: 15px; border-radius: 8px; margin-top: 15px;">
<h4 style="margin-top: 0; color: #856404;">๐Ÿ’ก Tips</h4>
<ul style="margin: 5px 0; padding-left: 20px; font-size: 0.8em; line-height: 1.4;">
<li>Try multiple theories</li>
<li>Compare results</li>
<li>Combine insights</li>
</ul>
</div>
""")
with gr.Column(scale=4):
# 15๊ฐœ ํƒญ์„ 3๊ฐœ ํ–‰์œผ๋กœ ๊ตฌ์„ฑ
gr.Markdown("""
<div style="background: #f8f9fa; padding: 15px; border-radius: 10px; margin-bottom: 20px;">
<h3 style="margin: 0; color: #2c3e50; text-align: center;">Select a Theory to Generate Names</h3>
</div>
""")
# 15๊ฐœ ํƒญ ์ƒ์„ฑ
with gr.Tabs(elem_classes="tab-nav"):
theories = [
("๐ŸŸฆ Square Theory", "square"),
("๐Ÿ”€ Conceptual Blending", "blending"),
("๐Ÿ”Š Sound Symbolism", "sound"),
("๐ŸŒ Linguistic Relativity", "linguistic"),
("๐ŸŽญ Archetype Theory", "archetype"),
("โœ… Jobs-to-be-Done", "jobs"),
("๐Ÿ”ง SCAMPER Method", "scamper"),
("๐Ÿ’ญ Design Thinking", "design"),
("๐ŸŒฟ Biomimicry", "biomimicry"),
("๐Ÿง  Cognitive Load", "cognitive"),
("โšก Von Restorff Effect", "vonrestorff"),
("๐ŸŒ Network Effects", "network"),
("๐Ÿงฌ Memetics", "memetics"),
("๐ŸŽจ Color Psychology", "color"),
("๐Ÿ‘๏ธ Gestalt Principles", "gestalt")
]
for tab_name, theory_key in theories:
with gr.Tab(tab_name):
with gr.Column():
# ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฉ”์‹œ์ง€
progress_msg = gr.Markdown(
visible=False
)
with gr.Row():
btn = gr.Button(
f"Generate with {tab_name}",
variant="primary",
size="lg",
elem_id=f"btn_{theory_key}"
)
output = gr.Markdown()
visual = gr.HTML()
def show_progress(industry, keywords, theory, language, tab_name):
"""ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ํ‘œ์‹œ"""
if not industry or not keywords:
return "", "", gr.update(visible=False)
texts = TEXTS[language]
progress_text = texts["progress_message"].format(theory=tab_name)
progress_html = f"""
<div style="text-align: center; padding: 20px; background: #f0f8ff; border-radius: 10px; margin: 10px 0;">
<div class="progress-bar" style="font-size: 1.2em; color: #1976d2;">
{progress_text}
</div>
<div style="margin-top: 10px;">
<div style="width: 100%; background: #e0e0e0; border-radius: 5px; overflow: hidden;">
<div style="width: 100%; height: 4px; background: linear-gradient(90deg, #1976d2 0%, #42a5f5 50%, #1976d2 100%); animation: slide 1.5s linear infinite;"></div>
</div>
</div>
</div>
<style>
@keyframes slide {{
0% {{ transform: translateX(-100%); }}
100% {{ transform: translateX(100%); }}
}}
</style>
"""
return "", "", gr.update(visible=True, value=progress_html)
def generate_and_hide_progress(industry, keywords, theory, language):
"""์ƒ์„ฑ ํ›„ ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ์ˆจ๊น€"""
result_md, result_html, _ = generate_by_theory(industry, keywords, theory, language)
return result_md, result_html, gr.update(visible=False)
# ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ํ‘œ์‹œ
btn.click(
lambda i, k, l, t=theory_key, n=tab_name: show_progress(i, k, t, l, n),
inputs=[industry_input, keywords_input, current_language],
outputs=[output, visual, progress_msg]
).then(
# ์‹ค์ œ ์ƒ์„ฑ ์ž‘์—…
lambda i, k, l, t=theory_key: generate_and_hide_progress(i, k, t, l),
inputs=[industry_input, keywords_input, current_language],
outputs=[output, visual, progress_msg]
)
gr.Markdown("""
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; border-radius: 15px; margin-top: 40px;">
<h3 style="margin-top: 0; text-align: center;">๐Ÿ† Why THEORIAโ„ข?</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 25px; margin-top: 25px;">
<div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0;">๐Ÿงช Scientific Foundation</h4>
<p style="margin: 0; font-size: 0.95em;">Based on proven cognitive and creative theories from psychology, linguistics, and design</p>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0;">๐ŸŽฏ Multi-dimensional Approach</h4>
<p style="margin: 0; font-size: 0.95em;">15 different perspectives ensure you find the perfect name for your brand</p>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0;">๐Ÿ“Š Unified Evaluation</h4>
<p style="margin: 0; font-size: 0.95em;">Consistent scoring system allows easy comparison across all theories</p>
</div>
<div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
<h4 style="margin: 0 0 10px 0;">๐ŸŒ Global Ready</h4>
<p style="margin: 0; font-size: 0.95em;">Multilingual support and cultural considerations built into every theory</p>
</div>
</div>
<div style="text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.2);">
<p style="margin: 0; font-size: 0.9em; opacity: 0.8;">
THEORIAโ„ข - Where Science Meets Creativity in Brand Naming
</p>
</div>
</div>
""")
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False
)