aiqcamp commited on
Commit
de65ede
·
verified ·
1 Parent(s): 9be8a74

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -424
app.py DELETED
@@ -1,424 +0,0 @@
1
-
2
- import os
3
- import gradio as gr
4
- import random
5
- import time
6
- import logging
7
- from typing import Iterator
8
-
9
- import google.generativeai as genai
10
-
11
- logging.basicConfig(
12
- level=logging.INFO,
13
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
14
- handlers=[
15
- logging.FileHandler("api_debug.log"),
16
- logging.StreamHandler()
17
- ]
18
- )
19
- logger = logging.getLogger("idea_generator")
20
-
21
- # ====== Gemini API 설정 ======
22
- GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
23
- genai.configure(api_key=GEMINI_API_KEY)
24
-
25
- # ====== 사용할 Gemini 모델 ======
26
- model = genai.GenerativeModel("gemini-2.0-flash-thinking-exp-01-21")
27
-
28
- # 슬래시("/")로 구분된 변환 문자열에서 한 옵션만 선택
29
- def choose_alternative(transformation):
30
- if "/" not in transformation:
31
- return transformation
32
- parts = transformation.split("/")
33
- if len(parts) != 2:
34
- return random.choice([part.strip() for part in parts])
35
- left = parts[0].strip()
36
- right = parts[1].strip()
37
- if " " in left:
38
- tokens = left.split(" ", 1)
39
- prefix = tokens[0]
40
- if not right.startswith(prefix):
41
- option1 = left
42
- option2 = prefix + " " + right
43
- else:
44
- option1 = left
45
- option2 = right
46
- return random.choice([option1, option2])
47
- else:
48
- return random.choice([left, right])
49
-
50
-
51
-
52
- ##############################################################################
53
- # 카테고리 사전
54
- # (아래 예시에서는 모든 카테고리를 포함시켰지만, 필요에 따라 범위를 조정하세요.)
55
- ##############################################################################
56
- physical_transformation_categories = {
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
- ],
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
- "전자 흐름 방향 변화", "전기적 공명", "전기적 차폐/노출", "자기 차폐/노출",
127
- "자기장 방향 정렬"
128
- ],
129
-
130
- "화학적 변화": [
131
- "표면 코팅 변화", "물질 성분 변화", "화학 반응 변화", "촉매 작용 시작/중단",
132
- "빛에 의한 화학 반응", "전기에 의한 화학 반응", "단분자막 형성", "분자 수준 계산 변화",
133
- "자연 모방 표면 변화", "환경 반응형 물질 변화", "주기적 화학 반응", "산화", "환원",
134
- "고분자화", "물 분해", "화합", "방사선 영향", "산-염기 반응", "중화 반응",
135
- "이온화", "화학적 흡착/탈착", "촉매 효율 변화", "효소 활성 변화", "발색 반응",
136
- "pH 변화", "화학적 평형 이동", "결합 형성/분해", "용해도 변화"
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
- "호르몬 분비", "신경 반응", "유전적 발현", "적응/진화", "생체리듬 변화",
169
- "재생/치유", "노화/성숙", "생체 모방 ��화", "바이오필름 형성", "생물학적 분해",
170
- "효소 활성화/비활성화", "생물학적 신호 전달", "스트레스 반응", "체온 조절",
171
- "생물학적 시계 변화", "세포외 기질 변화", "생체 역학적 반응", "세포 운동성",
172
- "세포 극성 변화", "영양 상태 변화"
173
- ],
174
-
175
- "환경 상호작용": [
176
- "온도 반응", "습도 반응", "기압 반응", "중력 반응", "자기장 반응",
177
- "빛 반응", "소리 반응", "화학 물질 감지", "기계적 자극 감지", "전기 자극 반응",
178
- "방사선 반응", "진동 감지", "pH 반응", "용매 반응", "기체 교환",
179
- "환경 오염 반응", "날씨 반응", "계절 변화 반응", "일주기 반응", "생태계 상호작용",
180
- "공생/경쟁 반응", "포식/피식 관계", "군집 형성", "영역 설정", "이주/정착 패턴"
181
- ],
182
-
183
- "센서 기능": [
184
- "시각 센서/감지", "청각 센서/감지", "촉각 센서/감지", "미각 센서/감지", "후각 센서/감지",
185
- "온도 센서/감지", "습도 센서/감지", "압력 센서/감지", "가속도 센서/감지", "회전 센서/감지",
186
- "근접 센서/감지", "위치 센서/감지", "운동 센서/감지", "가스 센서/감지", "적외선 센서/감지",
187
- "자외선 센서/감지", "방사선 센서/감지", "자기장 센서/감지", "전기장 센서/감지", "화학물질 센서/감지",
188
- "생체신호 센서/감지", "진동 센서/감지", "소음 센서/감지", "빛 세기 센서/감지", "빛 파장 센서/감지",
189
- "기울기 센서/감지", "pH 센서/감지", "전류 센서/감지", "전압 센서/감지", "이미지 센서/감지",
190
- "거리 센서/감지", "깊이 센서/감지", "중력 센서/감지", "속도 센서/감지", "흐름 센서/감지",
191
- "수위 센서/감지", "탁도 센서/감지", "염도 센서/감지", "금속 감지", "압전 센서/감지",
192
- "광전 센서/감지", "열전대 센서/감지", "홀 효과 센서/감지", "초음파 센서/감지", "레이더 센서/감지",
193
- "라이다 센서/감지", "터치 센서/감지", "제스처 센서/감지", "심박 센서/감지", "혈압 센서/감지"
194
- ]
195
- }
196
-
197
-
198
-
199
- # ====== Gemini 스트리밍 API 함수 ======
200
- def query_gemini_api_stream(prompt: str) -> Iterator[str]:
201
- """
202
- Gemini 2.0 Flash 모델에서 Thinking(사고 과정) + Response(최종 답변)를
203
- stream=True로 받아, chunk 단위로 yield.
204
- """
205
- # 대화 이력 없이 단순 호출
206
- chat = model.start_chat(history=[])
207
- response = chat.send_message(prompt, stream=True)
208
-
209
- thought_buffer = ""
210
- response_buffer = ""
211
- thinking_complete = False
212
-
213
- for chunk in response:
214
- parts = chunk.candidates[0].content.parts
215
-
216
- if len(parts) == 2 and not thinking_complete:
217
- # 첫 번째 part: Thinking
218
- thought_buffer += parts[0].text
219
- yield f"[Thinking Chunk] {parts[0].text}"
220
-
221
- # 두 번째 part: Response
222
- response_buffer = parts[1].text
223
- yield f"[Response Start] {parts[1].text}"
224
-
225
- thinking_complete = True
226
- elif thinking_complete:
227
- # 이미 응답 단계에 있음
228
- current_chunk = parts[0].text
229
- response_buffer += current_chunk
230
- yield current_chunk
231
- else:
232
- # 아직 Thinking 단계
233
- current_chunk = parts[0].text
234
- thought_buffer += current_chunk
235
- yield f"[Thinking Chunk] {current_chunk}"
236
-
237
- # 마지막에 전체 최종 응답
238
- yield f"\n[Final Response]\n{response_buffer}"
239
-
240
-
241
- # ====== 설명 확장 함수 (스트리밍) ======
242
- def enhance_with_llm_stream(base_description, obj_name, category) -> Iterator[str]:
243
- prompt = f"""
244
- 다음은 '{obj_name}'의 '{category}' 관련 간단한 설명입니다:
245
- "{base_description}"
246
- 위 내용을 보다 구체화하여,
247
- 1) 창의적인 모델/컨셉/형상의 변화에 대한 이해,
248
- 2) 혁신 포인트와 기능성 등을 중심으로
249
- 3~4문장의 아이디어로 확장해 주세요.
250
- """
251
- for chunk in query_gemini_api_stream(prompt):
252
- yield chunk
253
-
254
-
255
- # ====== 단일 키워드(오브젝트)에 대한 아이디어 생성 ======
256
- def generate_single_object_transformations(obj):
257
- results = {}
258
- for category, transformations in physical_transformation_categories.items():
259
- transformation = choose_alternative(random.choice(transformations))
260
- base_description = f"{obj}이(가) {transformation} 현상을 보인다"
261
- results[category] = {"base": base_description, "enhanced": ""}
262
- return results
263
-
264
- # ====== 2개 오브젝트 상호작용 ======
265
- def generate_two_objects_interaction(obj1, obj2):
266
- results = {}
267
- for category, transformations in physical_transformation_categories.items():
268
- transformation = choose_alternative(random.choice(transformations))
269
- template = random.choice([
270
- "{obj1}이(가) {obj2}에 결합하여 {change}가 발생했다",
271
- "{obj1}과(와) {obj2}이(가) 충돌하면서 {change}가 일어났다"
272
- ])
273
- base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
274
- results[category] = {"base": base_description, "enhanced": ""}
275
- return results
276
-
277
- # ====== 3개 오브젝트 상호작용 ======
278
- def generate_three_objects_interaction(obj1, obj2, obj3):
279
- results = {}
280
- for category, transformations in physical_transformation_categories.items():
281
- transformation = choose_alternative(random.choice(transformations))
282
- template = random.choice([
283
- "{obj1}, {obj2}, {obj3}이(가) 삼각형 구조로 결합하여 {change}가 발생했다",
284
- "{obj1}이(가) {obj2}와(과) {obj3} 사이에서 매개체 역할을 하며 {change}를 촉진했다"
285
- ])
286
- base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
287
- results[category] = {"base": base_description, "enhanced": ""}
288
- return results
289
-
290
-
291
- def generate_transformations(text1, text2=None, text3=None):
292
- if text2 and text3:
293
- results = generate_three_objects_interaction(text1, text2, text3)
294
- objects = [text1, text2, text3]
295
- elif text2:
296
- results = generate_two_objects_interaction(text1, text2)
297
- objects = [text1, text2]
298
- else:
299
- results = generate_single_object_transformations(text1)
300
- objects = [text1]
301
- return results, objects
302
-
303
-
304
- # ====== 스트리밍으로 각 카테고리를 순회하며 Thinking + Response 표시 ======
305
- def process_inputs_stream(text1, text2, text3) -> Iterator[list]:
306
- """
307
- Gradio 3.27+ 이상에서만 stream=True로 실시간 업데이트 가능.
308
- 메시지는 [{'role': 'assistant', 'content': ...}, ...] 형태로 반환.
309
- """
310
- # 1) 입력값 검증
311
- yield [{"role": "assistant", "content": "입력값 확인 중..."}]
312
- time.sleep(0.3)
313
-
314
- text1 = text1.strip() if text1 else None
315
- text2 = text2.strip() if text2 else None
316
- text3 = text3.strip() if text3 else None
317
- if not text1:
318
- yield [{"role": "assistant", "content": "오류: 최소 하나의 키워드를 입력해주세요."}]
319
- return
320
-
321
- # 2) 아이디어 생성
322
- yield [{"role": "assistant", "content": "창의적인 모델/컨셉/형상 변화 아이디어 생성 중... (카테고리별 분석)"}]
323
- time.sleep(0.3)
324
- results, objects = generate_transformations(text1, text2, text3)
325
-
326
- obj_name = " 및 ".join([obj for obj in objects if obj])
327
-
328
- # 카테고리별 스트리밍
329
- for i, (category, info) in enumerate(results.items(), start=1):
330
- base_desc = info["base"]
331
- yield [{
332
- "role": "assistant",
333
- "content": f"**[{i}/{len(results)}] 카테고리:** {category}\n\n기본 아이디어: {base_desc}\n\nThinking + Response 스트리밍 시작..."
334
- }]
335
- time.sleep(0.5)
336
-
337
- thinking_text = ""
338
- response_text = ""
339
- thinking_done = False
340
-
341
- for chunk in enhance_with_llm_stream(base_desc, obj_name, category):
342
- if chunk.startswith("[Thinking Chunk]"):
343
- # Thinking 단계
344
- thinking_text += chunk.replace("[Thinking Chunk]", "")
345
- yield [{"role": "assistant", "content": f"**[Thinking]**\n{thinking_text}"}]
346
-
347
- elif chunk.startswith("[Response Start]"):
348
- # Response 시작
349
- thinking_done = True
350
- partial = chunk.replace("[Response Start]", "")
351
- response_text += partial
352
- yield [{"role": "assistant", "content": f"**[Response 시작]**\n{partial}"}]
353
-
354
- elif chunk.startswith("[Final Response]"):
355
- # 최종 응답
356
- final = chunk.replace("[Final Response]", "")
357
- response_text += f"\n{final}"
358
- yield [{"role": "assistant", "content": f"**[최종 Response]**\n{response_text.strip()}"}]
359
-
360
- else:
361
- # 일반 응답 스트리밍
362
- if thinking_done:
363
- response_text += chunk
364
- yield [{"role": "assistant", "content": f"**[응답 진행]**\n{response_text}"}]
365
- else:
366
- thinking_text += chunk
367
- yield [{"role": "assistant", "content": f"**[Thinking]**\n{thinking_text}"}]
368
-
369
- info["enhanced"] = response_text
370
-
371
- # 완료 알림
372
- yield [{"role": "assistant", "content": "**모든 카테고리에 대한 스트리밍이 완료되었습니다!**"}]
373
-
374
-
375
- ##############################################################################
376
- # Gradio UI (Chatbot: type='messages')
377
- ##############################################################################
378
- with gr.Blocks(title="Gemini Flash Thinking (Stream)", theme=gr.themes.Soft(primary_hue="teal")) as demo:
379
- gr.Markdown("# 🚀 키워드 기반 창의적 변화 아이디어 (Gemini 2.0 Flash Thinking, Streaming)\n"+
380
- "키워드 1~3개를 입력하면, **카테고리별**로 'Thinking'과 'Response'가 실시간 스트리밍됩니다.")
381
-
382
- chatbot = gr.Chatbot(
383
- label="카테고리별 스트리밍",
384
- type="messages", # OpenAI 스타일 {"role":"assistant", "content":...} 포맷
385
- render_markdown=True
386
- )
387
-
388
- with gr.Row():
389
- with gr.Column(scale=1):
390
- text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 자동차")
391
- text_input2 = gr.Textbox(label="키워드 2 (선택)", placeholder="예: 로봇")
392
- text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 인공지능")
393
- submit_button = gr.Button("아이디어 생성하기")
394
- clear_button = gr.Button("대화 지우기")
395
-
396
- with gr.Column(scale=2):
397
- pass
398
-
399
- def clear_chat():
400
- return []
401
-
402
- # 예시
403
- examples = [
404
- ["자동차", "", ""],
405
- ["스마트폰", "인공지능", ""],
406
- ["드론", "인공지능", ""],
407
- ["운동화", "웨어러블", "건강"],
408
- ]
409
- gr.Examples(examples=examples, inputs=[text_input1, text_input2, text_input3])
410
-
411
- submit_button.click(
412
- fn=process_inputs_stream,
413
- inputs=[text_input1, text_input2, text_input3],
414
- outputs=chatbot,
415
- stream=True # 최신 Gradio(3.27+)에서만 지원
416
- )
417
-
418
- clear_button.click(
419
- fn=clear_chat,
420
- outputs=chatbot
421
- )
422
-
423
- if __name__ == "__main__":
424
- demo.launch(debug=True)