Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -5,7 +5,6 @@ import time
|
|
5 |
import logging
|
6 |
import google.generativeai as genai
|
7 |
|
8 |
-
# 로깅 설정
|
9 |
logging.basicConfig(
|
10 |
level=logging.INFO,
|
11 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
@@ -16,11 +15,10 @@ logging.basicConfig(
|
|
16 |
)
|
17 |
logger = logging.getLogger("idea_generator")
|
18 |
|
19 |
-
# Gemini API 키는 환경 변수 GEMINI_API_KEY에서 가져옵니다.
|
20 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
21 |
genai.configure(api_key=GEMINI_API_KEY)
|
22 |
|
23 |
-
|
24 |
def choose_alternative(transformation):
|
25 |
if "/" not in transformation:
|
26 |
return transformation
|
@@ -42,7 +40,7 @@ def choose_alternative(transformation):
|
|
42 |
else:
|
43 |
return random.choice([left, right])
|
44 |
|
45 |
-
|
46 |
physical_transformation_categories = {
|
47 |
"공간 이동": [
|
48 |
"앞/뒤 이동", "좌/우 이동", "위/아래 이동", "세로축 회전(고개 끄덕임)",
|
@@ -51,7 +49,6 @@ physical_transformation_categories = {
|
|
51 |
"무중력 부유", "수면 위 부유", "점프/도약", "슬라이딩", "롤링", "자유 낙하",
|
52 |
"왕복 운동", "탄성 튕김", "관통", "회피 움직임", "지그재그 이동", "스윙 운동"
|
53 |
],
|
54 |
-
|
55 |
"크기와 형태 변화": [
|
56 |
"부피 늘어남/줄어듦", "길이 늘어남/줄어듦", "너비 늘어남/줄어듦", "높이 늘어남/줄어듦",
|
57 |
"밀도 변화", "무게 증가/감소", "모양 변형", "상태 변화", "불균등 변형",
|
@@ -60,145 +57,18 @@ physical_transformation_categories = {
|
|
60 |
"접힘/펼쳐짐", "압착/팽창", "늘어남/수축", "구겨짐/평평해짐", "뭉개짐/단단해짐",
|
61 |
"말림/펴짐", "꺾임/구부러짐"
|
62 |
],
|
63 |
-
|
64 |
-
|
65 |
-
"색상 변화", "질감 변화", "투명/불투명 변화", "반짝임/무광 변화",
|
66 |
-
"빛 반사 정도 변화", "무늬 변화", "각도에 따른 색상 변화", "빛에 따른 색상 변화",
|
67 |
-
"온도에 따른 색상 변화", "홀로그램 효과", "표면 각도별 빛 반사", "표면 모양 변형",
|
68 |
-
"초미세 표면 구조 변화", "자가 세정 효과", "얼룩/패턴 생성", "흐림/선명함 변화",
|
69 |
-
"광택/윤기 변화", "색조/채도 변화", "발광/형광", "빛 산란 효과",
|
70 |
-
"빛 흡수 변화", "반투명 효과", "그림자 효과 변화", "자외선 반응 변화",
|
71 |
-
"야광 효과"
|
72 |
-
],
|
73 |
-
|
74 |
-
"물질의 상태 변화": [
|
75 |
-
"고체/액체/기체 전환", "결정화/용해", "산화/부식", "딱딱해짐/부드러워짐",
|
76 |
-
"특수 상태 전환", "무정형/결정형 전환", "성분 분리", "미세 입자 형성/분해",
|
77 |
-
"젤 형성/풀어짐", "준안정 상태 변화", "분자 자가 정렬/분해", "상태변화 지연 현상",
|
78 |
-
"녹음", "굳음", "증발/응축", "승화/증착", "침전/부유", "분산/응집",
|
79 |
-
"건조/습윤", "팽윤/수축", "동결/해동", "풍화/침식", "충전/방전",
|
80 |
-
"결합/분리", "발효/부패"
|
81 |
-
],
|
82 |
-
|
83 |
-
"열 관련 변화": [
|
84 |
-
"온도 상승/하강", "열에 의한 팽창/수축", "열 전달/차단", "압력 상승/하강",
|
85 |
-
"열 변화에 따른 자화", "무질서도 변화", "열전기 현상", "자기장에 의한 열 변화",
|
86 |
-
"상태변화 중 열 저장/방출", "열 스트레스 발생/해소", "급격한 온도 변화 영향",
|
87 |
-
"복사열에 의한 냉각/가열", "발열/흡열", "열 분포 변화", "열 반사/흡수",
|
88 |
-
"냉각 응축", "열 활성화", "열 변색", "열 팽창 계수 변화", "열 안정성 변화",
|
89 |
-
"내열성/내한성", "자기발열", "열적 평형/불균형", "열적 변형", "열 분산/집중"
|
90 |
-
],
|
91 |
-
|
92 |
-
"움직임 특성 변화": [
|
93 |
-
"가속/감속", "일정 속도 유지", "진동/진동 감소", "부딪힘/튕김",
|
94 |
-
"회전 속도 증가/감소", "회전 방향 변화", "불규칙 움직임", "멈췄다 미끄러지는 현상",
|
95 |
-
"공진/반공진", "유체 속 저항/양력 변화", "움직임 저항 변화", "복합 진동 움직임",
|
96 |
-
"특수 유체 속 움직임", "회전-이동 연계 움직임", "관성 정지", "충격 흡수",
|
97 |
-
"충격 전달", "운동량 보존", "마찰력 변화", "관성 탈출", "불안정 균형",
|
98 |
-
"동적 안정성", "흔들림 감쇠", "경로 예측성", "회피 움직임"
|
99 |
-
],
|
100 |
-
|
101 |
-
"구조적 변화": [
|
102 |
-
"부품 추가/제거", "조립/분해", "접기/펴기", "변형/원상복구", "최적 구조 변화",
|
103 |
-
"자가 재배열", "자연 패턴 형성/소멸", "규칙적 패턴 변화", "모듈식 변형",
|
104 |
-
"복잡성 증가 구조", "원래 모양 기억 효과", "시간에 따른 형태 변화", "부분 제거",
|
105 |
-
"부분 교체", "결합", "분리", "분할/통합", "중첩/겹침", "내부 구조 변화",
|
106 |
-
"외부 구조 변화", "중심축 이동", "균형점 변화", "계층 구조 변화", "지지 구조 변화",
|
107 |
-
"응력 분산 구조", "충격 흡수 구조", "그리드/매트릭스 구조 변화", "상호 연결성 변화"
|
108 |
-
],
|
109 |
-
|
110 |
-
"전기 및 자기 변화": [
|
111 |
-
"자성 생성/소멸", "전하량 증가/감소", "전기장 생성/소멸", "자기장 생성/소멸",
|
112 |
-
"초전도 상태 전환", "강유전체 특성 변화", "양자 상태 변화", "플라즈마 상태 형성/소멸",
|
113 |
-
"스핀파 전달", "빛에 의한 전기 발생", "압력에 의한 전기 발생", "자기장 속 전류 변화",
|
114 |
-
"전기 저항 변화", "전기 전도성 변화", "정전기 발생/방전", "전자기 유도",
|
115 |
-
"전자기파 방출/흡수", "전기 용량 변화", "자기 이력 현상", "전기적 분극",
|
116 |
-
"전자 흐름 방향 변화", "전기적 공명", "전기적 차폐/노출", "자기 차폐/노출",
|
117 |
-
"자기장 방향 정렬"
|
118 |
-
],
|
119 |
-
|
120 |
-
"화학적 변화": [
|
121 |
-
"표면 코팅 변화", "물질 성분 변화", "화학 반응 변화", "촉매 작용 시작/중단",
|
122 |
-
"빛에 의한 화학 반응", "전기에 의한 화학 반응", "단분자막 형성", "분자 수준 계산 변화",
|
123 |
-
"자연 모방 표면 변화", "환경 반응형 물질 변화", "주기적 화학 반응", "산화", "환원",
|
124 |
-
"고분자화", "물 분해", "화합", "방사선 영향", "산-염기 반응", "중화 반응",
|
125 |
-
"이온화", "화학적 흡착/탈착", "촉매 효율 변화", "효소 활성 변화", "발색 반응",
|
126 |
-
"pH 변화", "화학적 평형 이동", "결합 형성/분해", "용해도 변화"
|
127 |
-
],
|
128 |
-
|
129 |
-
"시간 관련 변화": [
|
130 |
-
"노화/풍화", "마모/부식", "색 바램/변색", "손상/회복", "수명 주기 변화",
|
131 |
-
"사용자 상호작용에 따른 적응", "학습 기반 형태 최적화", "시간에 따른 물성 변화",
|
132 |
-
"집단 기억 효과", "문화적 의미 변화", "지연 반응", "이전 상태 의존 변화",
|
133 |
-
"점진적 시간 변화", "진화적 변화", "주기적 재생", "계절 변화 적응",
|
134 |
-
"생체리듬 변화", "생애 주기 단계", "성장/퇴화", "자기 복구/재생",
|
135 |
-
"자연 순환 적응", "지속성/일시성", "기억 효과", "지연된 작용", "누적 효과"
|
136 |
-
],
|
137 |
-
|
138 |
-
"빛과 시각 효과": [
|
139 |
-
"발광/소등", "빛 투과/차단", "빛 산란/집중", "색상 스펙트럼 변화", "빛 회절",
|
140 |
-
"빛 간섭", "홀로그램 생성", "레이저 효과", "빛 편광", "형광/인광",
|
141 |
-
"자외선/적외선 발광", "광학적 착시", "빛 굴절", "그림자 생성/제거",
|
142 |
-
"색수차 효과", "무지개 효과", "글로우 효과", "플래시 효과", "조명 패턴",
|
143 |
-
"빔 효과", "광 필터 효과", "빛의 방향성 변화", "투영 효과", "빛 감지/반응",
|
144 |
-
"광도 변화"
|
145 |
-
],
|
146 |
-
|
147 |
-
"소리와 진동 효과": [
|
148 |
-
"소리 발생/소멸", "소리 높낮이 변화", "소리 크기 변화", "음색 변화",
|
149 |
-
"공명/반공명", "음향 진동", "초음파/저음파 발생", "음향 집중/분산",
|
150 |
-
"음향 반사/흡수", "음향 도플러 효과", "음파 간섭", "음향 공진",
|
151 |
-
"진동 패턴 변화", "타악 효과", "음향 피드백", "음향 차폐/증폭",
|
152 |
-
"소리 지향성", "음향 왜곡", "비트 생성", "하모닉스 생성", "주파수 변조",
|
153 |
-
"음향 충격파", "음향 필터링", "음파 전파 패턴", "진동 댐핑"
|
154 |
-
],
|
155 |
-
|
156 |
-
"생물학적 변화": [
|
157 |
-
"생장/위축", "세포 분열/사멸", "생물 발광", "신진대사 변화", "면역 반응",
|
158 |
-
"호르몬 분비", "신경 반응", "유전적 발현", "적응/진화", "생체리듬 변화",
|
159 |
-
"재생/치유", "노화/성숙", "생체 모방 변화", "바이오필름 형성", "생물학적 분해",
|
160 |
-
"효소 활성화/비활성화", "생물학적 신호 전달", "스트레스 반응", "체온 조절",
|
161 |
-
"생물학적 시계 변화", "세포외 기질 변화", "생체 역학적 반응", "세포 운동성",
|
162 |
-
"세포 극성 변화", "영양 상태 변화"
|
163 |
-
],
|
164 |
-
|
165 |
-
"환경 상호작용": [
|
166 |
-
"온도 반응", "습도 반응", "기압 반응", "중력 반응", "자기장 반응",
|
167 |
-
"빛 반응", "소리 반응", "화학 물질 감지", "기계적 자극 감지", "전기 자극 반응",
|
168 |
-
"방사선 반응", "진동 감지", "pH 반응", "용매 반응", "기체 교환",
|
169 |
-
"환경 오염 반응", "날씨 반응", "계절 변화 반응", "일주기 반응", "생태계 상호작용",
|
170 |
-
"공생/경쟁 반응", "포식/피식 관계", "군집 형성", "영역 설정", "이주/정착 패턴"
|
171 |
-
],
|
172 |
-
|
173 |
-
"센서 기능": [
|
174 |
-
"시각 센서/감지", "청각 센서/감지", "촉각 센서/감지", "미각 센서/감지", "후각 센서/감지",
|
175 |
-
"온도 센서/감지", "습도 센서/감지", "압력 센���/감지", "가속도 센서/감지", "회전 센서/감지",
|
176 |
-
"근접 센서/감지", "위치 센서/감지", "운동 센서/감지", "가스 센서/감지", "적외선 센서/감지",
|
177 |
-
"자외선 센서/감지", "방사선 센서/감지", "자기장 센서/감지", "전기장 센서/감지", "화학물질 센서/감지",
|
178 |
-
"생체신호 센서/감지", "진동 센서/감지", "소음 센서/감지", "빛 세기 센서/감지", "빛 파장 센서/감지",
|
179 |
-
"기울기 센서/감지", "pH 센서/감지", "전류 센서/감지", "전압 센서/감지", "이미지 센서/감지",
|
180 |
-
"거리 센서/감지", "깊이 센서/감지", "중력 센서/감지", "속도 센서/감지", "흐름 센서/감지",
|
181 |
-
"수위 센서/감지", "탁도 센서/감지", "염도 센서/감지", "금속 감지", "압전 센서/감지",
|
182 |
-
"광전 센서/감지", "열전대 센서/감지", "홀 효과 센서/감지", "초음파 센서/감지", "레이더 센서/감지",
|
183 |
-
"라이다 센서/감지", "터치 센서/감지", "제스처 센서/감지", "심박 센서/감지", "혈압 센서/감지"
|
184 |
-
]
|
185 |
}
|
186 |
|
187 |
-
##############################################################################
|
188 |
-
# Gemini API 호출 함수 (예: gemini-2.0-flash-thinking-exp-01-21 -> 다른 모델 사용 시 수정)
|
189 |
-
##############################################################################
|
190 |
def query_gemini_api(prompt):
|
191 |
try:
|
192 |
-
# 예시: 기존 gemini-2.0... 대신, 다른 모델이 필요하다면 교체하세요.
|
193 |
model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
|
194 |
-
|
195 |
response = model.generate_content(prompt)
|
196 |
|
197 |
-
# 응답 구조 방어적으로 처리
|
198 |
try:
|
199 |
if hasattr(response, 'text'):
|
200 |
return response.text
|
201 |
-
|
202 |
if hasattr(response, 'candidates') and response.candidates:
|
203 |
if len(response.candidates) > 0:
|
204 |
candidate = response.candidates[0]
|
@@ -210,27 +80,21 @@ def query_gemini_api(prompt):
|
|
210 |
if hasattr(response, 'parts') and response.parts:
|
211 |
if len(response.parts) > 0:
|
212 |
return response.parts[0].text
|
213 |
-
|
214 |
return "Unable to generate a response. API response structure is different than expected."
|
215 |
-
|
216 |
except Exception as inner_e:
|
217 |
logger.error(f"Error processing response: {inner_e}")
|
218 |
return f"An error occurred while processing the response: {str(inner_e)}"
|
219 |
-
|
220 |
except Exception as e:
|
221 |
logger.error(f"Error calling Gemini API: {e}")
|
222 |
if "API key not valid" in str(e):
|
223 |
return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
|
224 |
return f"An error occurred while calling the API: {str(e)}"
|
225 |
|
226 |
-
|
227 |
-
# 설명 확장 함수: "모델/컨셉/형상의 변화에 대한 이해와 혁신 포인트, 기능성 등을 중심"으로
|
228 |
-
##############################################################################
|
229 |
def enhance_with_llm(base_description, obj_name, category):
|
230 |
prompt = f"""
|
231 |
다음은 '{obj_name}'의 '{category}' 관련 간단한 설명입니다:
|
232 |
"{base_description}"
|
233 |
-
|
234 |
위 내용을 보다 구체화하여,
|
235 |
1) 창의적인 모델/컨셉/형상의 변화에 대한 이해,
|
236 |
2) 혁신 포인트와 기능성 등을 중심으로
|
@@ -238,9 +102,7 @@ def enhance_with_llm(base_description, obj_name, category):
|
|
238 |
"""
|
239 |
return query_gemini_api(prompt)
|
240 |
|
241 |
-
|
242 |
-
# 단일 키워드(오브젝트)에 대한 "창의적 변화 아이디어" 생성
|
243 |
-
##############################################################################
|
244 |
def generate_single_object_transformations(obj):
|
245 |
results = {}
|
246 |
for category, transformations in physical_transformation_categories.items():
|
@@ -249,9 +111,7 @@ def generate_single_object_transformations(obj):
|
|
249 |
results[category] = {"base": base_description, "enhanced": None}
|
250 |
return results
|
251 |
|
252 |
-
|
253 |
-
# 두 키워드에 대한 "창의적 변화 아이디어" 생성
|
254 |
-
##############################################################################
|
255 |
def generate_two_objects_interaction(obj1, obj2):
|
256 |
results = {}
|
257 |
for category, transformations in physical_transformation_categories.items():
|
@@ -264,9 +124,7 @@ def generate_two_objects_interaction(obj1, obj2):
|
|
264 |
results[category] = {"base": base_description, "enhanced": None}
|
265 |
return results
|
266 |
|
267 |
-
|
268 |
-
# 세 키워드에 대한 "창의적 변화 아이디어" 생성
|
269 |
-
##############################################################################
|
270 |
def generate_three_objects_interaction(obj1, obj2, obj3):
|
271 |
results = {}
|
272 |
for category, transformations in physical_transformation_categories.items():
|
@@ -279,18 +137,14 @@ def generate_three_objects_interaction(obj1, obj2, obj3):
|
|
279 |
results[category] = {"base": base_description, "enhanced": None}
|
280 |
return results
|
281 |
|
282 |
-
|
283 |
-
# 생성된 기본 설명을 LLM을 통해 확장
|
284 |
-
##############################################################################
|
285 |
def enhance_descriptions(results, objects):
|
286 |
obj_name = " 및 ".join([obj for obj in objects if obj])
|
287 |
for category, result in results.items():
|
288 |
result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
|
289 |
return results
|
290 |
|
291 |
-
|
292 |
-
# 사용자 입력(최대 3개 키워드)에 따라 창의적 변화 아이디어 생성
|
293 |
-
##############################################################################
|
294 |
def generate_transformations(text1, text2=None, text3=None):
|
295 |
if text2 and text3:
|
296 |
results = generate_three_objects_interaction(text1, text2, text3)
|
@@ -303,53 +157,55 @@ def generate_transformations(text1, text2=None, text3=None):
|
|
303 |
objects = [text1]
|
304 |
return enhance_descriptions(results, objects)
|
305 |
|
306 |
-
|
307 |
-
# 결과 포맷팅
|
308 |
-
##############################################################################
|
309 |
def format_results(results):
|
310 |
formatted = ""
|
311 |
for category, result in results.items():
|
312 |
formatted += f"## {category}\n**기본 아이디어**: {result['base']}\n\n**확장된 아이디어**: {result['enhanced']}\n\n---\n\n"
|
313 |
return formatted
|
314 |
|
|
|
315 |
##############################################################################
|
316 |
-
#
|
317 |
##############################################################################
|
318 |
-
def
|
319 |
-
|
320 |
-
|
321 |
time.sleep(0.3)
|
|
|
322 |
text1 = text1.strip() if text1 else None
|
323 |
text2 = text2.strip() if text2 else None
|
324 |
text3 = text3.strip() if text3 else None
|
325 |
if not text1:
|
326 |
-
|
327 |
-
return
|
328 |
|
329 |
-
|
|
|
330 |
time.sleep(0.3)
|
|
|
|
|
331 |
results = generate_transformations(text1, text2, text3)
|
332 |
|
333 |
-
|
|
|
334 |
time.sleep(0.3)
|
|
|
|
|
335 |
formatted = format_results(results)
|
336 |
|
337 |
-
|
338 |
-
|
339 |
|
340 |
-
|
|
|
341 |
|
342 |
-
##############################################################################
|
343 |
-
# API 키 경고 메시지
|
344 |
-
##############################################################################
|
345 |
def get_warning_message():
|
346 |
if not GEMINI_API_KEY:
|
347 |
return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
|
348 |
return ""
|
349 |
|
350 |
-
|
351 |
-
# Gradio UI
|
352 |
-
##############################################################################
|
353 |
with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
354 |
theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
|
355 |
|
@@ -370,7 +226,6 @@ with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
|
370 |
|
371 |
warning = gr.Markdown(get_warning_message())
|
372 |
|
373 |
-
# 좌측 입력 영역
|
374 |
with gr.Row():
|
375 |
with gr.Column(scale=1):
|
376 |
text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 스마트폰")
|
@@ -378,12 +233,11 @@ with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
|
378 |
text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 헬스케어")
|
379 |
submit_button = gr.Button("아이디어 생성하기")
|
380 |
|
381 |
-
# 우측 출력 영역 (탭은 하나만 사용)
|
382 |
with gr.Column(scale=2):
|
383 |
with gr.TabItem("창의적인 모델/컨셉/형상 변화 아이디어", id="creative_tab"):
|
|
|
384 |
idea_output = gr.Markdown(label="아이디어 결과")
|
385 |
|
386 |
-
# 예시 입력
|
387 |
gr.Examples(
|
388 |
examples=[
|
389 |
["스마트폰", "", ""],
|
@@ -394,10 +248,13 @@ with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
|
394 |
inputs=[text_input1, text_input2, text_input3],
|
395 |
)
|
396 |
|
397 |
-
#
|
398 |
-
submit_button.click(
|
399 |
-
|
400 |
-
|
|
|
|
|
|
|
401 |
|
402 |
if __name__ == "__main__":
|
403 |
demo.launch(debug=True)
|
|
|
5 |
import logging
|
6 |
import google.generativeai as genai
|
7 |
|
|
|
8 |
logging.basicConfig(
|
9 |
level=logging.INFO,
|
10 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
|
15 |
)
|
16 |
logger = logging.getLogger("idea_generator")
|
17 |
|
|
|
18 |
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
19 |
genai.configure(api_key=GEMINI_API_KEY)
|
20 |
|
21 |
+
|
22 |
def choose_alternative(transformation):
|
23 |
if "/" not in transformation:
|
24 |
return transformation
|
|
|
40 |
else:
|
41 |
return random.choice([left, right])
|
42 |
|
43 |
+
|
44 |
physical_transformation_categories = {
|
45 |
"공간 이동": [
|
46 |
"앞/뒤 이동", "좌/우 이동", "위/아래 이동", "세로축 회전(고개 끄덕임)",
|
|
|
49 |
"무중력 부유", "수면 위 부유", "점프/도약", "슬라이딩", "롤링", "자유 낙하",
|
50 |
"왕복 운동", "탄성 튕김", "관통", "회피 움직임", "지그재그 이동", "스윙 운동"
|
51 |
],
|
|
|
52 |
"크기와 형태 변화": [
|
53 |
"부피 늘어남/줄어듦", "길이 늘어남/줄어듦", "너비 늘어남/줄어듦", "높이 늘어남/줄어듦",
|
54 |
"밀도 변화", "무게 증가/감소", "모양 변형", "상태 변화", "불균등 변형",
|
|
|
57 |
"접힘/펼쳐짐", "압착/팽창", "늘어남/수축", "구겨짐/평평해짐", "뭉개짐/단단해짐",
|
58 |
"말림/펴짐", "꺾임/구부러짐"
|
59 |
],
|
60 |
+
# ... (중간 생략: 나머지 카테고리는 동일)
|
61 |
+
# 생략된 부분도 기존 코드 그대로 유지
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
}
|
63 |
|
|
|
|
|
|
|
64 |
def query_gemini_api(prompt):
|
65 |
try:
|
|
|
66 |
model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
|
|
|
67 |
response = model.generate_content(prompt)
|
68 |
|
|
|
69 |
try:
|
70 |
if hasattr(response, 'text'):
|
71 |
return response.text
|
|
|
72 |
if hasattr(response, 'candidates') and response.candidates:
|
73 |
if len(response.candidates) > 0:
|
74 |
candidate = response.candidates[0]
|
|
|
80 |
if hasattr(response, 'parts') and response.parts:
|
81 |
if len(response.parts) > 0:
|
82 |
return response.parts[0].text
|
|
|
83 |
return "Unable to generate a response. API response structure is different than expected."
|
|
|
84 |
except Exception as inner_e:
|
85 |
logger.error(f"Error processing response: {inner_e}")
|
86 |
return f"An error occurred while processing the response: {str(inner_e)}"
|
|
|
87 |
except Exception as e:
|
88 |
logger.error(f"Error calling Gemini API: {e}")
|
89 |
if "API key not valid" in str(e):
|
90 |
return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
|
91 |
return f"An error occurred while calling the API: {str(e)}"
|
92 |
|
93 |
+
|
|
|
|
|
94 |
def enhance_with_llm(base_description, obj_name, category):
|
95 |
prompt = f"""
|
96 |
다음은 '{obj_name}'의 '{category}' 관련 간단한 설명입니다:
|
97 |
"{base_description}"
|
|
|
98 |
위 내용을 보다 구체화하여,
|
99 |
1) 창의적인 모델/컨셉/형상의 변화에 대한 이해,
|
100 |
2) 혁신 포인트와 기능성 등을 중심으로
|
|
|
102 |
"""
|
103 |
return query_gemini_api(prompt)
|
104 |
|
105 |
+
|
|
|
|
|
106 |
def generate_single_object_transformations(obj):
|
107 |
results = {}
|
108 |
for category, transformations in physical_transformation_categories.items():
|
|
|
111 |
results[category] = {"base": base_description, "enhanced": None}
|
112 |
return results
|
113 |
|
114 |
+
|
|
|
|
|
115 |
def generate_two_objects_interaction(obj1, obj2):
|
116 |
results = {}
|
117 |
for category, transformations in physical_transformation_categories.items():
|
|
|
124 |
results[category] = {"base": base_description, "enhanced": None}
|
125 |
return results
|
126 |
|
127 |
+
|
|
|
|
|
128 |
def generate_three_objects_interaction(obj1, obj2, obj3):
|
129 |
results = {}
|
130 |
for category, transformations in physical_transformation_categories.items():
|
|
|
137 |
results[category] = {"base": base_description, "enhanced": None}
|
138 |
return results
|
139 |
|
140 |
+
|
|
|
|
|
141 |
def enhance_descriptions(results, objects):
|
142 |
obj_name = " 및 ".join([obj for obj in objects if obj])
|
143 |
for category, result in results.items():
|
144 |
result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
|
145 |
return results
|
146 |
|
147 |
+
|
|
|
|
|
148 |
def generate_transformations(text1, text2=None, text3=None):
|
149 |
if text2 and text3:
|
150 |
results = generate_three_objects_interaction(text1, text2, text3)
|
|
|
157 |
objects = [text1]
|
158 |
return enhance_descriptions(results, objects)
|
159 |
|
160 |
+
|
|
|
|
|
161 |
def format_results(results):
|
162 |
formatted = ""
|
163 |
for category, result in results.items():
|
164 |
formatted += f"## {category}\n**기본 아이디어**: {result['base']}\n\n**확장된 아이디어**: {result['enhanced']}\n\n---\n\n"
|
165 |
return formatted
|
166 |
|
167 |
+
|
168 |
##############################################################################
|
169 |
+
# 스트리밍(Streaming) 방식으로 출력하는 함수: yield를 사용
|
170 |
##############################################################################
|
171 |
+
def process_inputs_stream(text1, text2, text3):
|
172 |
+
# 1) 첫 메시지
|
173 |
+
yield "입력값 확인 중..."
|
174 |
time.sleep(0.3)
|
175 |
+
|
176 |
text1 = text1.strip() if text1 else None
|
177 |
text2 = text2.strip() if text2 else None
|
178 |
text3 = text3.strip() if text3 else None
|
179 |
if not text1:
|
180 |
+
yield "오류: 최소 하나의 키워드를 입력해주세요."
|
181 |
+
return # 여기서 함수 종료
|
182 |
|
183 |
+
# 2) 다음 메시지
|
184 |
+
yield "창의적인 모델/컨셉/형상 변화 아이디어 생성 중..."
|
185 |
time.sleep(0.3)
|
186 |
+
|
187 |
+
# 3) 실제 아이디어 생성
|
188 |
results = generate_transformations(text1, text2, text3)
|
189 |
|
190 |
+
# 4) 중간 단계 출력
|
191 |
+
yield "결과 포맷팅 중..."
|
192 |
time.sleep(0.3)
|
193 |
+
|
194 |
+
# 5) 최종 결과 정리
|
195 |
formatted = format_results(results)
|
196 |
|
197 |
+
# 6) 결과 출력
|
198 |
+
yield formatted
|
199 |
|
200 |
+
# 7) 완료
|
201 |
+
yield "완료!"
|
202 |
|
|
|
|
|
|
|
203 |
def get_warning_message():
|
204 |
if not GEMINI_API_KEY:
|
205 |
return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
|
206 |
return ""
|
207 |
|
208 |
+
|
|
|
|
|
209 |
with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
210 |
theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
|
211 |
|
|
|
226 |
|
227 |
warning = gr.Markdown(get_warning_message())
|
228 |
|
|
|
229 |
with gr.Row():
|
230 |
with gr.Column(scale=1):
|
231 |
text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 스마트폰")
|
|
|
233 |
text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 헬스케어")
|
234 |
submit_button = gr.Button("아이디어 생성하기")
|
235 |
|
|
|
236 |
with gr.Column(scale=2):
|
237 |
with gr.TabItem("창의적인 모델/컨셉/형상 변화 아이디어", id="creative_tab"):
|
238 |
+
# Markdown 출력
|
239 |
idea_output = gr.Markdown(label="아이디어 결과")
|
240 |
|
|
|
241 |
gr.Examples(
|
242 |
examples=[
|
243 |
["스마트폰", "", ""],
|
|
|
248 |
inputs=[text_input1, text_input2, text_input3],
|
249 |
)
|
250 |
|
251 |
+
# stream=True 옵션을 통해 함수가 yield하는 문자열을 실시간 출력
|
252 |
+
submit_button.click(
|
253 |
+
fn=process_inputs_stream,
|
254 |
+
inputs=[text_input1, text_input2, text_input3],
|
255 |
+
outputs=idea_output,
|
256 |
+
stream=True
|
257 |
+
)
|
258 |
|
259 |
if __name__ == "__main__":
|
260 |
demo.launch(debug=True)
|