Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1,232 +1,427 @@
|
|
1 |
import os
|
2 |
import gradio as gr
|
3 |
-
|
4 |
-
|
|
|
5 |
import google.generativeai as genai
|
6 |
-
import time # Import time module for potential debugging/delay
|
7 |
|
8 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
10 |
genai.configure(api_key=GEMINI_API_KEY)
|
11 |
|
12 |
-
#
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
|
|
39 |
try:
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
#
|
44 |
-
|
45 |
-
|
46 |
-
#
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
parts
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
)
|
78 |
-
yield messages
|
79 |
-
|
80 |
-
# Start response
|
81 |
-
response_buffer = parts[1].text
|
82 |
-
print(f"\n=== Starting Response ===\n{response_buffer}")
|
83 |
-
|
84 |
-
messages.append(
|
85 |
-
ChatMessage(
|
86 |
-
role="assistant",
|
87 |
-
content=response_buffer
|
88 |
-
)
|
89 |
-
)
|
90 |
-
thinking_complete = True
|
91 |
-
|
92 |
-
elif thinking_complete:
|
93 |
-
# Stream response
|
94 |
-
response_buffer += current_chunk
|
95 |
-
print(f"\n=== Response Chunk ===\n{current_chunk}")
|
96 |
-
|
97 |
-
messages[-1] = ChatMessage(
|
98 |
-
role="assistant",
|
99 |
-
content=response_buffer
|
100 |
-
)
|
101 |
-
|
102 |
-
else:
|
103 |
-
# Stream thinking
|
104 |
-
thought_buffer += current_chunk
|
105 |
-
print(f"\n=== Thinking Chunk ===\n{current_chunk}")
|
106 |
-
|
107 |
-
messages[-1] = ChatMessage(
|
108 |
-
role="assistant",
|
109 |
-
content=thought_buffer,
|
110 |
-
metadata={"title": "⚙️ Thinking: *The thoughts produced by the model are experimental"}
|
111 |
-
)
|
112 |
-
#time.sleep(0.05) #Optional: Uncomment this line to add a slight delay for debugging/visualization of streaming. Remove for final version
|
113 |
-
|
114 |
-
yield messages
|
115 |
-
|
116 |
-
print(f"\n=== Final Response ===\n{response_buffer}")
|
117 |
-
|
118 |
except Exception as e:
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
)
|
126 |
-
|
127 |
-
|
128 |
-
def
|
129 |
-
""
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
139 |
-
|
140 |
-
<img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Faiqcamp-Gemini2-Flash-Thinking.hf.space&countColor=%23263759" />
|
141 |
-
</a>""")
|
142 |
-
|
143 |
-
|
144 |
-
chatbot = gr.Chatbot(
|
145 |
-
type="messages",
|
146 |
-
label="Gemini2.0 'Thinking' Chatbot (Streaming Output)", #Label now indicates streaming
|
147 |
-
render_markdown=True,
|
148 |
-
scale=1,
|
149 |
-
avatar_images=(None,"https://lh3.googleusercontent.com/oxz0sUBF0iYoN4VvhqWTmux-cxfD1rxuYkuFEfm1SFaseXEsjjE4Je_C_V3UQPuJ87sImQK3HfQ3RXiaRnQetjaZbjJJUkiPL5jFJ1WRl5FKJZYibUA=w214-h214-n-nu")
|
150 |
-
)
|
151 |
-
|
152 |
-
with gr.Row(equal_height=True):
|
153 |
-
input_box = gr.Textbox(
|
154 |
-
lines=1,
|
155 |
-
label="Chat Message",
|
156 |
-
placeholder="Type your message here...",
|
157 |
-
scale=4
|
158 |
-
)
|
159 |
-
|
160 |
-
clear_button = gr.Button("Clear Chat", scale=1)
|
161 |
-
|
162 |
-
# Add example prompts - removed file upload examples. Kept text focused examples.
|
163 |
-
example_prompts = [
|
164 |
-
["Write a short poem about the sunset."],
|
165 |
-
["Explain the theory of relativity in simple terms."],
|
166 |
-
["If a train leaves Chicago at 6am traveling at 60mph, and another train leaves New York at 8am traveling at 80mph, at what time will they meet?"],
|
167 |
-
["Summarize the plot of Hamlet."],
|
168 |
-
["Write a haiku about a cat."]
|
169 |
-
]
|
170 |
-
|
171 |
gr.Examples(
|
172 |
-
examples=
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
# Set up event handlers
|
180 |
-
msg_store = gr.State("") # Store for preserving user message
|
181 |
-
|
182 |
-
input_box.submit(
|
183 |
-
lambda msg: (msg, msg, ""), # Store message and clear input
|
184 |
-
inputs=[input_box],
|
185 |
-
outputs=[msg_store, input_box, input_box],
|
186 |
-
queue=False
|
187 |
-
).then(
|
188 |
-
user_message, # Add user message to chat
|
189 |
-
inputs=[msg_store, chatbot],
|
190 |
-
outputs=[input_box, chatbot],
|
191 |
-
queue=False
|
192 |
-
).then(
|
193 |
-
stream_gemini_response, # Generate and stream response
|
194 |
-
inputs=[msg_store, chatbot],
|
195 |
-
outputs=chatbot
|
196 |
)
|
|
|
|
|
|
|
|
|
197 |
|
198 |
-
clear_button.click(
|
199 |
-
lambda: ([], "", ""),
|
200 |
-
outputs=[chatbot, input_box, msg_store],
|
201 |
-
queue=False
|
202 |
-
)
|
203 |
-
|
204 |
-
gr.Markdown( # Description moved to the bottom - updated for text-only
|
205 |
-
"""
|
206 |
-
<br><br><br> <!-- Add some vertical space -->
|
207 |
-
---
|
208 |
-
### About this Chatbot
|
209 |
-
This chatbot demonstrates the experimental 'thinking' capability of the **Gemini 2.0 Flash** model.
|
210 |
-
You can observe the model's thought process as it generates responses, displayed with the "⚙️ Thinking" prefix.
|
211 |
-
|
212 |
-
**Try out the example prompts below to see Gemini in action!**
|
213 |
-
|
214 |
-
**Key Features:**
|
215 |
-
* Powered by Google's **Gemini 2.0 Flash** model.
|
216 |
-
* Shows the model's **thoughts** before the final answer (experimental feature).
|
217 |
-
* Supports **conversation history** for multi-turn chats.
|
218 |
-
* Uses **streaming** for a more interactive experience.
|
219 |
-
**Instructions:**
|
220 |
-
1. Type your message in the input box below or select an example.
|
221 |
-
2. Press Enter or click Submit to send.
|
222 |
-
3. Observe the chatbot's "Thinking" process followed by the final response.
|
223 |
-
4. Use the "Clear Chat" button to start a new conversation.
|
224 |
-
|
225 |
-
*Please note*: The 'thinking' feature is experimental and the quality of thoughts may vary.
|
226 |
-
"""
|
227 |
-
)
|
228 |
-
|
229 |
-
|
230 |
-
# Launch the interface
|
231 |
if __name__ == "__main__":
|
232 |
demo.launch(debug=True)
|
|
|
1 |
import os
|
2 |
import gradio as gr
|
3 |
+
import random
|
4 |
+
import time
|
5 |
+
import logging
|
6 |
import google.generativeai as genai
|
|
|
7 |
|
8 |
+
# Configure logging
|
9 |
+
logging.basicConfig(
|
10 |
+
level=logging.INFO,
|
11 |
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
12 |
+
handlers=[
|
13 |
+
logging.FileHandler("api_debug.log"),
|
14 |
+
logging.StreamHandler()
|
15 |
+
]
|
16 |
+
)
|
17 |
+
logger = logging.getLogger("idea_generator")
|
18 |
+
|
19 |
+
# Get Gemini API Key from environment variable
|
20 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
21 |
genai.configure(api_key=GEMINI_API_KEY)
|
22 |
|
23 |
+
# Helper function to select one option from a transformation string with a slash
|
24 |
+
def choose_alternative(transformation):
|
25 |
+
if "/" not in transformation:
|
26 |
+
return transformation
|
27 |
+
parts = transformation.split("/")
|
28 |
+
if len(parts) != 2:
|
29 |
+
return random.choice([part.strip() for part in parts])
|
30 |
+
left = parts[0].strip()
|
31 |
+
right = parts[1].strip()
|
32 |
+
if " " in left:
|
33 |
+
tokens = left.split(" ", 1)
|
34 |
+
prefix = tokens[0]
|
35 |
+
if not right.startswith(prefix):
|
36 |
+
option1 = left
|
37 |
+
option2 = prefix + " " + right
|
38 |
+
else:
|
39 |
+
option1 = left
|
40 |
+
option2 = right
|
41 |
+
return random.choice([option1, option2])
|
42 |
+
else:
|
43 |
+
return random.choice([left, right])
|
44 |
+
|
45 |
+
# Physical transformation categories and related changes
|
46 |
+
physical_transformation_categories = {
|
47 |
+
"공간적 변화": [
|
48 |
+
"전진/후진 이동", "좌/우 이동", "상승/하강", "피치 회전", "요 회전", "롤 회전",
|
49 |
+
"궤도 운동", "나선형 이동", "관성 드리프트", "자이로스코픽 세차 운동", "비대칭 회전",
|
50 |
+
"진자 운동", "탄도학적 이동", "무중력 상태에서의 부유"
|
51 |
+
],
|
52 |
+
"물리적 형상 변화": [
|
53 |
+
"부피 증가/감소", "길이 신장/수축", "너비 확장/축소", "높이 증가/감소",
|
54 |
+
"밀도 변화", "무게 증가/감소", "형태 변형", "위상 변화", "비등방성 변형",
|
55 |
+
"비선형 변형", "뒤틀림/비틀림", "수축/팽창 비율 변화", "모서리 라운딩/샤프닝",
|
56 |
+
"파단/균열 진행", "세그먼트화"
|
57 |
+
],
|
58 |
+
"표면/외관 변화": [
|
59 |
+
"색상 변화", "텍스처 변화", "투명도/불투명도 변화", "광택/무광 변화",
|
60 |
+
"반사율 변화", "패턴 변화", "이색성 효과", "광변색 효과", "열변색 효과",
|
61 |
+
"홀로그래픽 패턴 변화", "프레넬 반사", "표면 모핑", "나노구조 패턴 변화",
|
62 |
+
"자가 청소 효과"
|
63 |
+
],
|
64 |
+
"물질 상태 변화": [
|
65 |
+
"고체화/액화/기화", "결정화/용해", "산화/부식", "경화/연화", "초임계 상태 전환",
|
66 |
+
"비정질화/결정화", "상분리", "콜로이드 형성/분해", "겔화/졸화", "준안정 상태 전이",
|
67 |
+
"자기조립/분해", "상전이 히스테리시스", "융해", "응고"
|
68 |
+
],
|
69 |
+
"열역학적 변화": [
|
70 |
+
"온도 상승/냉각", "열팽창/수축", "열 전도/단열", "압력 증가/감소", "단열 자화/탈자화",
|
71 |
+
"엔트로피 변화", "열전기 효과", "자기열량 효과", "상변화 축열/방열", "열 스트레스 발생/완화",
|
72 |
+
"열충격 효과", "복사 냉각/가열"
|
73 |
+
],
|
74 |
+
"운동학적 변화": [
|
75 |
+
"가속/감속", "등속 운동", "진동/진동 감쇠", "충돌/반발", "회전 속도 증가/감소",
|
76 |
+
"각속도 변화", "카오스적 운동", "스틱-슬립 현상", "공진/반공진", "유체역학적 양력/항력 변화",
|
77 |
+
"댐핑 계수 변화", "하모닉 모션 합성", "비뉴턴 유체 거동", "회전-병진 운동 커플링"
|
78 |
+
],
|
79 |
+
"구조적 변화": [
|
80 |
+
"부품 추가/제��", "조립/분해", "접이/펼침", "변형/복원", "위상최적화 형상 변화",
|
81 |
+
"자가 재구성", "프랙탈 패턴 형성/소멸", "세포자동자 패턴 변화", "모듈식 변형",
|
82 |
+
"발현적 구조 형성", "형상 기억 효과", "4D 프린팅 구조 변화", "부분 제거", "부분 교환",
|
83 |
+
"결합", "분리"
|
84 |
+
],
|
85 |
+
"전기/자기적 변화": [
|
86 |
+
"자화/탈자화", "전하 증가/감소", "전기장 생성/소멸", "자기장 생성/소멸", "초전도 상태 전이",
|
87 |
+
"강유전/반강유전 전이", "양자 스핀 상태 변화", "플라즈마 상태 형성/소멸", "스핀파 전파",
|
88 |
+
"광전 효과", "압전 효과", "홀 효과"
|
89 |
+
],
|
90 |
+
"화학적 변화": [
|
91 |
+
"표면 코팅 변화", "물질 조성 변화", "화학 반응에 의한 변화", "촉매 활성화/비활성화",
|
92 |
+
"광화학 반응", "전기화학 반응", "자기조립 단분자막 형성", "분자컴퓨팅 변화",
|
93 |
+
"생체모방 표면 변화", "스마트 폴리머 반응", "화학적 진동 반응", "산화", "환원",
|
94 |
+
"중합", "가수분해", "융합", "방사화"
|
95 |
+
],
|
96 |
+
"시간 관련 변화": [
|
97 |
+
"노화/풍화", "마모/부식", "퇴색/변색", "손상/복구", "수명 주기 단계 변화",
|
98 |
+
"사용자 인터랙션 기반 적응", "학습기반 형상 최적화", "시간적 물성 변화", "집단 기억 효과",
|
99 |
+
"문화적 의미 변화", "시간 지연 응답", "이력 의존적 변화", "퍼지 시간 거동", "진화적 변화",
|
100 |
+
"주기적 재생/재생성"
|
101 |
+
]
|
102 |
+
}
|
103 |
+
|
104 |
+
# Marketing transformation categories
|
105 |
+
marketing_transformation_categories = {
|
106 |
+
"브랜드/아이덴티티 변화": [
|
107 |
+
"브랜드명 변경/리브랜딩", "로고 재설계/현대화", "슬로건 업데이트/변경",
|
108 |
+
"브랜드 컬러 팔레트 변경", "브랜드 보이스/톤 조정", "브랜드 포지셔닝 재정립",
|
109 |
+
"브랜드 스토리 재구성", "브랜드 아키텍처 재구성", "브랜드 퍼스널리티 진화",
|
110 |
+
"브랜드 이미지 재정립"
|
111 |
+
],
|
112 |
+
"제품/서비스 변화": [
|
113 |
+
"기능적 업그레이드/다운그레이드", "포장/패키징 재설계", "제품 사이즈/용량 조정",
|
114 |
+
"SKU 확장/축소", "맞춤형/개인화 옵션 추가", "프리미엄/베이직 라인 출시",
|
115 |
+
"한정판/시즌 에디션 출시", "콜라보레이션/크로스오버 제품", "지속가능성 개선",
|
116 |
+
"번들링/언번들링 전략 변경"
|
117 |
+
],
|
118 |
+
"가격 전략 변화": [
|
119 |
+
"프리미엄/럭셔리 가격 포지셔닝", "가격 하락/경제적 포지셔닝", "가치 기반 가격 책정",
|
120 |
+
"동적 가격 정책 도입", "멤버십/구독 모델 전환", "가격 세분화 전략",
|
121 |
+
"프로모션 가격 전략 변경", "심리적 가격 책정 적용", "번들 가격 전략 도입",
|
122 |
+
"프리미엄/이코노미 이중 전략"
|
123 |
+
],
|
124 |
+
"프로모션/커뮤니케이션 변화": [
|
125 |
+
"메시지 프레이밍 변경", "타겟 오디언스 확장/재정의", "감성적/이성적 소구점 전환",
|
126 |
+
"스토리텔링 방식 변화", "콘텐츠 마케팅 전략 조정", "크리에이티브 방향성 변경",
|
127 |
+
"광고 캠페인 재설계", "브랜드 앰배서더/인플루언서 교체", "언어/트론 조정",
|
128 |
+
"비주얼 아이덴티티 업데이트"
|
129 |
+
],
|
130 |
+
"채널/유통 변화": [
|
131 |
+
"온라인/오프라인 전략 전환", "옴니채널 통합/분리", "유통 파트너십 확장/축소",
|
132 |
+
"D2C(Direct-to-Consumer) 모델 도입", "리테일 경험 재설계", "서비스 딜리버리 방식 변경",
|
133 |
+
"팝업/이벤트 기반 유통 전략", "지역적 확장/축소", "파트너 생태계 재구성",
|
134 |
+
"디지털 마켓플레이스 전략 변화"
|
135 |
+
],
|
136 |
+
"고객 경험 변화": [
|
137 |
+
"고객 여정 재설계", "퍼스널라이제이션/맞춤화 강화", "서비스 레벨 조정",
|
138 |
+
"로열티 프로그램 재구성", "고객 참여 메커니즘 변화", "사용자 인터페이스/UX 개선",
|
139 |
+
"고객 서비스 프로토콜 변경", "피드백 루프 재설계", "자가 서비스 옵션 확장",
|
140 |
+
"체험형 마케팅 요소 강화"
|
141 |
+
],
|
142 |
+
"디지털 마케팅 변화": [
|
143 |
+
"검색 최적화(SEO) 전략 변경", "소셜 미디어 플랫폼 포트폴리오 조정", "콘텐츠 타입/포맷 다양화",
|
144 |
+
"데이터 기반 타겟팅 정교화", "마케팅 자동화 확장/조정", "디지털 광고 알고리즘 최적화",
|
145 |
+
"이메일 마케팅 전략 변화", "모바일 최적화 전략 강화", "AR/VR 마케팅 요소 통합",
|
146 |
+
"인공지능 기반 마케팅 도입"
|
147 |
+
],
|
148 |
+
"시장 포지셔닝 변화": [
|
149 |
+
"시장 세그먼트 재정의", "경쟁사 대비 포지셔닝 변경", "틈새시장/메인스트림 전략 전환",
|
150 |
+
"산업/카테고리 횡단 재포지셔닝", "지리적 타겟 시장 확장/축소", "글로벌/로컬 포지셔닝 조정",
|
151 |
+
"문화적 ���락 적응", "주요 시장 메시지 재정의", "특성 차별화 강화/변경",
|
152 |
+
"가치 제안 재구성"
|
153 |
+
],
|
154 |
+
"혁신/트렌드 반응": [
|
155 |
+
"첨단 기술 통합", "트렌드 얼리어답터/팔로워 포지셔닝", "지속가능성/친환경 전략 강화",
|
156 |
+
"사회적 책임 이니셔티브 도입", "디지털 트랜스포메이션 가속화", "헬스/웰빙 요소 강화",
|
157 |
+
"세대별 트렌드 반응 적용", "미래지향적 혁신 커뮤니케이션", "문화적 현상 연계 마케팅",
|
158 |
+
"크로스 인더스트리 혁신 적용"
|
159 |
+
],
|
160 |
+
"데이터/분석 기반 변화": [
|
161 |
+
"고객 데이터 수집 방식 변경", "예측 분석 모델 도입/강화", "A/B 테스팅 체계 구축/확장",
|
162 |
+
"소비자 인사이트 발굴 방식 변화", "마케팅 ROI 측정 프레임워크 변경", "실시간 데이터 활용 체계 구축",
|
163 |
+
"프라이버시 중심 데이터 전략", "세그먼테이션 모델 고도화", "디지털 행동 분석 체계 강화",
|
164 |
+
"통합 마케팅 데이터 대시보드 구축"
|
165 |
+
]
|
166 |
+
}
|
167 |
|
168 |
+
def query_gemini_api(prompt):
|
169 |
try:
|
170 |
+
# Use a stable model
|
171 |
+
model = genai.GenerativeModel('gemini-pro')
|
172 |
+
|
173 |
+
# Generate content with a simple approach
|
174 |
+
response = model.generate_content(prompt)
|
175 |
+
|
176 |
+
# Check the response - defensive handling
|
177 |
+
try:
|
178 |
+
# First try .text attribute
|
179 |
+
if hasattr(response, 'text'):
|
180 |
+
return response.text
|
181 |
+
|
182 |
+
# Try accessing candidates (safely)
|
183 |
+
if hasattr(response, 'candidates') and response.candidates:
|
184 |
+
if len(response.candidates) > 0:
|
185 |
+
candidate = response.candidates[0]
|
186 |
+
|
187 |
+
# Try accessing content and parts
|
188 |
+
if hasattr(candidate, 'content'):
|
189 |
+
content = candidate.content
|
190 |
+
|
191 |
+
if hasattr(content, 'parts') and content.parts:
|
192 |
+
if len(content.parts) > 0:
|
193 |
+
return content.parts[0].text
|
194 |
+
|
195 |
+
# Direct parts access attempt
|
196 |
+
if hasattr(response, 'parts') and response.parts:
|
197 |
+
if len(response.parts) > 0:
|
198 |
+
return response.parts[0].text
|
199 |
+
|
200 |
+
# Fallback if all attempts fail
|
201 |
+
return "Unable to generate a response. API response structure is different than expected."
|
202 |
+
|
203 |
+
except Exception as inner_e:
|
204 |
+
logger.error(f"Error processing response: {inner_e}")
|
205 |
+
return f"An error occurred while processing the response: {str(inner_e)}"
|
206 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
except Exception as e:
|
208 |
+
logger.error(f"Error calling Gemini API: {e}")
|
209 |
+
|
210 |
+
# Check for API key validation error
|
211 |
+
if "API key not valid" in str(e):
|
212 |
+
return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
|
213 |
+
|
214 |
+
return f"An error occurred while calling the API: {str(e)}"
|
215 |
+
|
216 |
+
# Generate enhanced descriptions without unnecessary questions or explanations
|
217 |
+
def enhance_with_llm(base_description, obj_name, category, is_marketing=False):
|
218 |
+
domain = "마케팅" if is_marketing else "물리적"
|
219 |
+
prompt = f"""다음은 '{obj_name}'의 '{domain} {category}' 관련 간단한 설명입니다:
|
220 |
+
"{base_description}"
|
221 |
+
해당 설명을 3-4문장의 창의적인 답변으로 확장하여 출력하라."""
|
222 |
+
return query_gemini_api(prompt)
|
223 |
+
|
224 |
+
# Generate physical transformations for a single object
|
225 |
+
def generate_single_object_physical_transformations(obj):
|
226 |
+
results = {}
|
227 |
+
for category, transformations in physical_transformation_categories.items():
|
228 |
+
transformation = choose_alternative(random.choice(transformations))
|
229 |
+
base_description = f"{obj}이(가) {transformation} 현상을 보인다"
|
230 |
+
results[category] = {"base": base_description, "enhanced": None}
|
231 |
+
return results
|
232 |
+
|
233 |
+
# Generate marketing transformations for a single object
|
234 |
+
def generate_single_object_marketing_transformations(obj):
|
235 |
+
results = {}
|
236 |
+
for category, transformations in marketing_transformation_categories.items():
|
237 |
+
transformation = choose_alternative(random.choice(transformations))
|
238 |
+
base_description = f"{obj}이(가) {transformation} 전략을 실행했다"
|
239 |
+
results[category] = {"base": base_description, "enhanced": None}
|
240 |
+
return results
|
241 |
+
|
242 |
+
# Generate physical transformations for two objects
|
243 |
+
def generate_two_objects_physical_interaction(obj1, obj2):
|
244 |
+
results = {}
|
245 |
+
for category, transformations in physical_transformation_categories.items():
|
246 |
+
transformation = choose_alternative(random.choice(transformations))
|
247 |
+
template = random.choice([
|
248 |
+
"{obj1}이(가) {obj2}에 결합하여 {change}가 발생했다",
|
249 |
+
"{obj1}과(와) {obj2}이(가) 충돌하면서 {change}가 일어났다"
|
250 |
+
])
|
251 |
+
base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
|
252 |
+
results[category] = {"base": base_description, "enhanced": None}
|
253 |
+
return results
|
254 |
+
|
255 |
+
# Generate marketing transformations for two objects
|
256 |
+
def generate_two_objects_marketing_interaction(obj1, obj2):
|
257 |
+
results = {}
|
258 |
+
for category, transformations in marketing_transformation_categories.items():
|
259 |
+
transformation = choose_alternative(random.choice(transformations))
|
260 |
+
template = random.choice([
|
261 |
+
"{obj1}이(가) {obj2}의 브랜드 특성을 활용하여 {change}를 진행했다",
|
262 |
+
"{obj1}과(와) {obj2}의 협업으로 {change}가 시장에 도입되었다"
|
263 |
+
])
|
264 |
+
base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
|
265 |
+
results[category] = {"base": base_description, "enhanced": None}
|
266 |
+
return results
|
267 |
+
|
268 |
+
# Generate physical transformations for three objects
|
269 |
+
def generate_three_objects_physical_interaction(obj1, obj2, obj3):
|
270 |
+
results = {}
|
271 |
+
for category, transformations in physical_transformation_categories.items():
|
272 |
+
transformation = choose_alternative(random.choice(transformations))
|
273 |
+
template = random.choice([
|
274 |
+
"{obj1}, {obj2}, {obj3}이(가) 삼각형 구조로 결합하여 {change}가 발생했다",
|
275 |
+
"{obj1}이(가) {obj2}와(과) {obj3} 사이에서 매개체 역할을 하며 {change}를 촉진했다"
|
276 |
+
])
|
277 |
+
base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
|
278 |
+
results[category] = {"base": base_description, "enhanced": None}
|
279 |
+
return results
|
280 |
+
|
281 |
+
# Generate marketing transformations for three objects
|
282 |
+
def generate_three_objects_marketing_interaction(obj1, obj2, obj3):
|
283 |
+
results = {}
|
284 |
+
for category, transformations in marketing_transformation_categories.items():
|
285 |
+
transformation = choose_alternative(random.choice(transformations))
|
286 |
+
template = random.choice([
|
287 |
+
"{obj1}, {obj2}, {obj3}이(가) 공동 마케팅으로 {change}가 시너지를 창출했다",
|
288 |
+
"{obj1}이(가) {obj2}와(과) {obj3}의 고객층을 통합하여 {change}로 새로운 시장을 창출했다"
|
289 |
+
])
|
290 |
+
base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
|
291 |
+
results[category] = {"base": base_description, "enhanced": None}
|
292 |
+
return results
|
293 |
+
|
294 |
+
# Enhance descriptions using the LLM
|
295 |
+
def enhance_descriptions(results, objects, is_marketing=False):
|
296 |
+
obj_name = " 및 ".join([obj for obj in objects if obj])
|
297 |
+
for category, result in results.items():
|
298 |
+
result["enhanced"] = enhance_with_llm(result["base"], obj_name, category, is_marketing)
|
299 |
+
return results
|
300 |
+
|
301 |
+
# Generate physical transformations based on number of objects
|
302 |
+
def generate_physical_transformations(text1, text2=None, text3=None):
|
303 |
+
if text2 and text3:
|
304 |
+
results = generate_three_objects_physical_interaction(text1, text2, text3)
|
305 |
+
objects = [text1, text2, text3]
|
306 |
+
elif text2:
|
307 |
+
results = generate_two_objects_physical_interaction(text1, text2)
|
308 |
+
objects = [text1, text2]
|
309 |
+
else:
|
310 |
+
results = generate_single_object_physical_transformations(text1)
|
311 |
+
objects = [text1]
|
312 |
+
return enhance_descriptions(results, objects, is_marketing=False)
|
313 |
+
|
314 |
+
# Generate marketing transformations based on number of objects
|
315 |
+
def generate_marketing_transformations(text1, text2=None, text3=None):
|
316 |
+
if text2 and text3:
|
317 |
+
results = generate_three_objects_marketing_interaction(text1, text2, text3)
|
318 |
+
objects = [text1, text2, text3]
|
319 |
+
elif text2:
|
320 |
+
results = generate_two_objects_marketing_interaction(text1, text2)
|
321 |
+
objects = [text1, text2]
|
322 |
+
else:
|
323 |
+
results = generate_single_object_marketing_transformations(text1)
|
324 |
+
objects = [text1]
|
325 |
+
return enhance_descriptions(results, objects, is_marketing=True)
|
326 |
+
|
327 |
+
# Format results for display
|
328 |
+
def format_results(results):
|
329 |
+
formatted = ""
|
330 |
+
for category, result in results.items():
|
331 |
+
formatted += f"## {category}\n**기본 변화**: {result['base']}\n\n**자세한 설명**: {result['enhanced']}\n\n---\n\n"
|
332 |
+
return formatted
|
333 |
+
|
334 |
+
# Process physical inputs and generate transformations
|
335 |
+
def process_physical_inputs(text1, text2, text3):
|
336 |
+
messages = []
|
337 |
+
messages.append("입력값 확인 중...")
|
338 |
+
time.sleep(0.3)
|
339 |
+
text1 = text1.strip() if text1 else None
|
340 |
+
text2 = text2.strip() if text2 else None
|
341 |
+
text3 = text3.strip() if text3 else None
|
342 |
+
if not text1:
|
343 |
+
messages.append("오류: 최소 하나의 키워드를 입력해주세요.")
|
344 |
+
return "\n\n".join(messages)
|
345 |
+
messages.append("물리적 변화 아이디어 생성 중...")
|
346 |
+
time.sleep(0.3)
|
347 |
+
results = generate_physical_transformations(text1, text2, text3)
|
348 |
+
messages.append("결과 포맷팅 중...")
|
349 |
+
time.sleep(0.3)
|
350 |
+
formatted = format_results(results)
|
351 |
+
messages.append("완료!")
|
352 |
+
messages.append(formatted)
|
353 |
+
return "\n\n".join(messages)
|
354 |
+
|
355 |
+
# Process marketing inputs and generate transformations
|
356 |
+
def process_marketing_inputs(text1, text2, text3):
|
357 |
+
messages = []
|
358 |
+
messages.append("입력값 확인 중...")
|
359 |
+
time.sleep(0.3)
|
360 |
+
text1 = text1.strip() if text1 else None
|
361 |
+
text2 = text2.strip() if text2 else None
|
362 |
+
text3 = text3.strip() if text3 else None
|
363 |
+
if not text1:
|
364 |
+
messages.append("오류: 최소 하나의 키워드를 입력해주세요.")
|
365 |
+
return "\n\n".join(messages)
|
366 |
+
messages.append("마케팅 변화 아이디어 생성 중...")
|
367 |
+
time.sleep(0.3)
|
368 |
+
results = generate_marketing_transformations(text1, text2, text3)
|
369 |
+
messages.append("결과 포맷팅 중...")
|
370 |
+
time.sleep(0.3)
|
371 |
+
formatted = format_results(results)
|
372 |
+
messages.append("완료!")
|
373 |
+
messages.append(formatted)
|
374 |
+
return "\n\n".join(messages)
|
375 |
+
|
376 |
+
# Check for API key and return warning message if needed
|
377 |
+
def get_warning_message():
|
378 |
+
if not GEMINI_API_KEY:
|
379 |
+
return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
|
380 |
+
return ""
|
381 |
+
|
382 |
+
# Create the Gradio UI
|
383 |
+
with gr.Blocks(title="키워드 기반 창의적 아이디어 생성기", theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
|
384 |
+
gr.HTML("""
|
385 |
+
<style>
|
386 |
+
body { background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Arial', sans-serif; }
|
387 |
+
.gradio-container { padding: 20px; }
|
388 |
+
h1, h2 { text-align: center; }
|
389 |
+
h1 { color: #333; }
|
390 |
+
h2 { color: #555; }
|
391 |
+
.output { background-color: #ffffff; padding: 15px; border-radius: 8px; }
|
392 |
+
.gr-button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; padding: 8px 16px; }
|
393 |
+
</style>
|
394 |
+
""")
|
395 |
+
gr.Markdown("# 🚀 키워드 기반 창의적 아이디어 생성기")
|
396 |
+
gr.Markdown("입력한 키워드를 바탕으로 창의적인 물리적/마케팅 변화 아이디어를 도출합니다. 최대 3개의 키워드를 입력할 수 있습니다.")
|
397 |
+
warning = gr.Markdown(get_warning_message())
|
398 |
+
with gr.Row():
|
399 |
+
with gr.Column(scale=1):
|
400 |
+
text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 스마트폰")
|
401 |
+
text_input2 = gr.Textbox(label="키워드 2 (선택)", placeholder="예: 인공지능")
|
402 |
+
text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 헬스케어")
|
403 |
+
submit_button = gr.Button("아이디어 생성하기")
|
404 |
+
with gr.Column(scale=2):
|
405 |
+
with gr.Tabs():
|
406 |
+
with gr.TabItem("물리적 변화 아이디어", id="physical_tab"):
|
407 |
+
physical_output = gr.Markdown(label="물리적 변화 아이디어 결과")
|
408 |
+
with gr.TabItem("마케팅 변화 아이디어", id="marketing_tab"):
|
409 |
+
marketing_output = gr.Markdown(label="마케팅 변화 아이디어 결과")
|
410 |
|
411 |
+
# Add some example combinations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
gr.Examples(
|
413 |
+
examples=[
|
414 |
+
["스마트폰", "", ""],
|
415 |
+
["커피", "책", ""],
|
416 |
+
["자동차", "로봇", "인공지능"],
|
417 |
+
["운동화", "웨어러블", "건강"],
|
418 |
+
],
|
419 |
+
inputs=[text_input1, text_input2, text_input3],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
420 |
)
|
421 |
+
|
422 |
+
# Connect the button click events to functions
|
423 |
+
submit_button.click(fn=process_physical_inputs, inputs=[text_input1, text_input2, text_input3], outputs=physical_output)
|
424 |
+
submit_button.click(fn=process_marketing_inputs, inputs=[text_input1, text_input2, text_input3], outputs=marketing_output)
|
425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
if __name__ == "__main__":
|
427 |
demo.launch(debug=True)
|