openfree commited on
Commit
af82c26
ยท
verified ยท
1 Parent(s): a7d8fec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +366 -151
app.py CHANGED
@@ -12,7 +12,7 @@ from transformers import pipeline as hf_pipeline
12
  import re
13
 
14
  ##############################################################################
15
- # 1) ZeroGPU ํ™˜๊ฒฝ ์ฒ˜๋ฆฌ + device, dtype ์„ค์ •
16
  ##############################################################################
17
  try:
18
  import zerogpu
@@ -34,7 +34,7 @@ dtype = torch.bfloat16 if device == "cuda" else torch.float32
34
  print(f"Using device: {device}, dtype: {dtype}")
35
 
36
  ##############################################################################
37
- # 2) ๋ชจ๋ธ ๋กœ๋“œ: ๋ฒˆ์—ญ ๋ชจ๋ธ, DiffusionPipeline
38
  ##############################################################################
39
  try:
40
  translator = hf_pipeline(
@@ -71,7 +71,7 @@ MAX_SEED = np.iinfo(np.int32).max
71
  MAX_IMAGE_SIZE = 2048
72
 
73
  ##############################################################################
74
- # ํ•œ๊ตญ์–ด ๊ฐ์ง€ ํ•จ์ˆ˜
75
  ##############################################################################
76
  def contains_korean(text):
77
  for char in text:
@@ -79,45 +79,39 @@ def contains_korean(text):
79
  return True
80
  return False
81
 
82
- ##############################################################################
83
- # ์ž…๋ ฅ ํ…์ŠคํŠธ ํด๋ฆฐ์ง• ํ•จ์ˆ˜: ํ•œ๊ธ€, ์˜๋ฌธ, ์ˆซ์ž, ๊ณต๋ฐฑ ๋ฐ ์ผ๋ฐ˜์ ์ธ ๋ฌธ์žฅ ๋ถ€ํ˜ธ๋งŒ ํ—ˆ์šฉ
84
- ##############################################################################
85
  def clean_input_text(text):
86
  """
87
- ํ•œ๊ธ€, ์˜๋ฌธ, ์ˆซ์ž, ๊ณต๋ฐฑ ๋ฐ . , ! ? - : ; ' " ๋“ฑ์˜ ๋ฌธ์žฅ ๋ถ€ํ˜ธ๋งŒ ๋‚จ๊ธฐ๊ณ  ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
88
- ํ•„์š”์— ๋”ฐ๋ผ ํ—ˆ์šฉํ•  ๋ฌธ์ž๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
89
  """
90
  allowed = re.compile(r'[^ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9\s\.\,\!\?\-\:\;\'\"]')
91
  cleaned_text = allowed.sub('', text)
92
  return cleaned_text
93
 
94
- ##############################################################################
95
- # ์ž…๋ ฅ ํ…์ŠคํŠธ์˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ž ๋กœ๊ทธ ํ•จ์ˆ˜ (๋””๋ฒ„๊น…์šฉ)
96
- ##############################################################################
97
  def log_unexpected_characters(text):
98
  allowed = re.compile(r'[ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9\s\.\,\!\?\-\:\;\'\"]')
99
  unexpected_chars = [char for char in text if not allowed.match(char)]
100
  if unexpected_chars:
101
- print("์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ž ๋ฐœ๊ฒฌ:", set(unexpected_chars))
102
  else:
103
- print("์ž…๋ ฅ ํ…์ŠคํŠธ์— ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ž๋Š” ์—†์Šต๋‹ˆ๋‹ค.")
104
 
105
  ##############################################################################
106
- # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜
107
  ##############################################################################
108
  def generate_design_image(prompt, seed=42, randomize_seed=True, width=1024, height=1024, num_inference_steps=4):
109
  original_prompt = prompt
110
  translated = False
111
 
112
- # ์ž…๋ ฅ ํ…์ŠคํŠธ ํด๋ฆฐ์ง• ์ ์šฉ
113
  prompt = clean_input_text(prompt)
114
 
115
- # ์‚ฌ์ „ ์ฒ˜๋ฆฌ: ์ž…๋ ฅ ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๋ฉด ๋ฏธ๋ฆฌ ์ž๋ฅด๊ธฐ (์˜ˆ: 1000์ž ์ด์ƒ์ด๋ฉด 1000์ž๋กœ ์ž˜๋ผ๋ƒ„)
116
  if len(prompt) > 1000:
117
  prompt = prompt[:1000]
118
 
119
  if contains_korean(prompt):
120
- # ๋ฒˆ์—ญ ํ˜ธ์ถœ ์‹œ max_length์™€ truncation ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ธธ์ด ์ดˆ๊ณผ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€
121
  translation = translator(prompt, max_length=400, truncation=True)
122
  prompt = translation[0]['translation_text']
123
  translated = True
@@ -138,9 +132,8 @@ def generate_design_image(prompt, seed=42, randomize_seed=True, width=1024, heig
138
 
139
  return image
140
 
141
-
142
  ##############################################################################
143
- # ๋กœ๊น… ์„ค์ •
144
  ##############################################################################
145
  logging.basicConfig(
146
  level=logging.INFO,
@@ -153,13 +146,13 @@ logging.basicConfig(
153
  logger = logging.getLogger("idea_generator")
154
 
155
  ##############################################################################
156
- # Gemini API ํ‚ค
157
  ##############################################################################
158
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
159
  genai.configure(api_key=GEMINI_API_KEY)
160
 
161
  ##############################################################################
162
- # ์„ ํƒ์  ๋ณ€ํ˜• ์„ ํƒ ํ•จ์ˆ˜
163
  ##############################################################################
164
  def choose_alternative(transformation):
165
  if "/" not in transformation:
@@ -183,8 +176,9 @@ def choose_alternative(transformation):
183
  return random.choice([left, right])
184
 
185
  ##############################################################################
186
- # ๋ฌผ๋ฆฌ์  ๋ณ€ํ™” ์นดํ…Œ๊ณ ๋ฆฌ ์‚ฌ์ „ (์ด 15๊ฐœ)
187
  ##############################################################################
 
188
  physical_transformation_categories = {
189
  "์„ผ์„œ ๊ธฐ๋Šฅ": [
190
  "์‹œ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "์ฒญ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "์ด‰๊ฐ ์„ผ์„œ/๊ฐ์ง€", "๋ฏธ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "ํ›„๊ฐ ์„ผ์„œ/๊ฐ์ง€",
@@ -214,10 +208,7 @@ physical_transformation_categories = {
214
  "๊ด‘ํƒ/์œค๊ธฐ ๋ณ€ํ™”", "์ƒ‰์กฐ/์ฑ„๋„ ๋ณ€ํ™”", "๋ฐœ๊ด‘/ํ˜•๊ด‘", "๋น› ์‚ฐ๋ž€ ํšจ๊ณผ",
215
  "๋น› ํก์ˆ˜ ๋ณ€ํ™”", "๋ฐ˜ํˆฌ๋ช… ํšจ๊ณผ", "๊ทธ๋ฆผ์ž ํšจ๊ณผ ๋ณ€ํ™”", "์ž์™ธ์„  ๋ฐ˜์‘ ๋ณ€ํ™”",
216
  "์•ผ๊ด‘ ํšจ๊ณผ"
217
- ],
218
-
219
-
220
-
221
  "๋ฌผ์งˆ์˜ ์ƒํƒœ ๋ณ€ํ™”": [
222
  "๊ณ ์ฒด/์•ก์ฒด/๊ธฐ์ฒด ์ „ํ™˜", "๊ฒฐ์ •ํ™”/์šฉํ•ด", "์‚ฐํ™”/๋ถ€์‹", "๋”ฑ๋”ฑํ•ด์ง/๋ถ€๋“œ๋Ÿฌ์›Œ์ง",
223
  "ํŠน์ˆ˜ ์ƒํƒœ ์ „ํ™˜", "๋ฌด์ •ํ˜•/๊ฒฐ์ •ํ˜• ์ „ํ™˜", "์„ฑ๋ถ„ ๋ถ„๋ฆฌ", "๋ฏธ์„ธ ์ž…์ž ํ˜•์„ฑ/๋ถ„ํ•ด",
@@ -226,7 +217,6 @@ physical_transformation_categories = {
226
  "๊ฑด์กฐ/์Šต์œค", "ํŒฝ์œค/์ˆ˜์ถ•", "๋™๊ฒฐ/ํ•ด๋™", "ํ’ํ™”/์นจ์‹", "์ถฉ์ „/๋ฐฉ์ „",
227
  "๊ฒฐํ•ฉ/๋ถ„๋ฆฌ", "๋ฐœํšจ/๋ถ€ํŒจ"
228
  ],
229
-
230
  "์›€์ง์ž„ ํŠน์„ฑ ๋ณ€ํ™”": [
231
  "๊ฐ€์†/๊ฐ์†", "์ผ์ • ์†๋„ ์œ ์ง€", "์ง„๋™/์ง„๋™ ๊ฐ์†Œ", "๋ถ€๋”ชํž˜/ํŠ•๊น€",
232
  "ํšŒ์ „ ์†๋„ ์ฆ๊ฐ€/๊ฐ์†Œ", "ํšŒ์ „ ๋ฐฉํ–ฅ ๋ณ€ํ™”", "๋ถˆ๊ทœ์น™ ์›€์ง์ž„", "๋ฉˆ์ท„๋‹ค ๋ฏธ๋„๋Ÿฌ์ง€๋Š” ํ˜„์ƒ",
@@ -299,7 +289,6 @@ physical_transformation_categories = {
299
  "์ด์˜จํ™”", "ํ™”ํ•™์  ํก์ฐฉ/ํƒˆ์ฐฉ", "์ด‰๋งค ํšจ์œจ ๋ณ€ํ™”", "ํšจ์†Œ ํ™œ์„ฑ ๋ณ€ํ™”", "๋ฐœ์ƒ‰ ๋ฐ˜์‘",
300
  "pH ๋ณ€ํ™”", "ํ™”ํ•™์  ํ‰ํ˜• ์ด๋™", "๊ฒฐํ•ฉ ํ˜•์„ฑ/๋ถ„ํ•ด", "์šฉํ•ด๋„ ๋ณ€ํ™”"
301
  ],
302
-
303
  "์ƒ๋ฌผํ•™์  ๋ณ€ํ™”": [
304
  "์ƒ์žฅ/์œ„์ถ•", "์„ธํฌ ๋ถ„์—ด/์‚ฌ๋ฉธ", "์ƒ๋ฌผ ๋ฐœ๊ด‘", "์‹ ์ง„๋Œ€์‚ฌ ๋ณ€ํ™”", "๋ฉด์—ญ ๋ฐ˜์‘",
305
  "ํ˜ธ๋ฅด๋ชฌ ๋ถ„๋น„", "์‹ ๊ฒฝ ๋ฐ˜์‘", "์œ ์ „์  ๋ฐœํ˜„", "์ ์‘/์ง„ํ™”", "์ƒ์ฒด๋ฆฌ๋“ฌ ๋ณ€ํ™”",
@@ -315,11 +304,137 @@ physical_transformation_categories = {
315
  "ํ™˜๊ฒฝ ์˜ค์—ผ ๋ฐ˜์‘", "๋‚ ์”จ ๋ฐ˜์‘", "๊ณ„์ ˆ ๋ณ€ํ™” ๋ฐ˜์‘", "์ผ์ฃผ๊ธฐ ๋ฐ˜์‘", "์ƒํƒœ๊ณ„ ์ƒํ˜ธ์ž‘์šฉ",
316
  "๊ณต์ƒ/๊ฒฝ์Ÿ ๋ฐ˜์‘", "ํฌ์‹/ํ”ผ์‹ ๊ด€๊ณ„", "๊ตฐ์ง‘ ํ˜•์„ฑ", "์˜์—ญ ์„ค์ •", "์ด์ฃผ/์ •์ฐฉ ํŒจํ„ด"
317
  ]
 
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  }
320
 
321
  ##############################################################################
322
- # Gemini API ํ˜ธ์ถœ ํ•จ์ˆ˜
323
  ##############################################################################
324
  def query_gemini_api(prompt):
325
  try:
@@ -349,7 +464,7 @@ def query_gemini_api(prompt):
349
  return f"An error occurred while calling the API: {str(e)}"
350
 
351
  ##############################################################################
352
- # ์„ค๋ช… ํ™•์žฅ ํ•จ์ˆ˜ (LLM ์ด์šฉ)
353
  ##############################################################################
354
  def enhance_with_llm(base_description, obj_name, category):
355
  prompt = f"""
@@ -362,101 +477,129 @@ def enhance_with_llm(base_description, obj_name, category):
362
  """
363
  return query_gemini_api(prompt)
364
 
 
 
 
 
 
 
 
 
 
 
 
365
  ##############################################################################
366
- # ๊ฐ ๊ฐ์ฒด์ˆ˜(1, 2, 3)์— ๋”ฐ๋ฅธ ๋ณ€ํ˜• ์•„์ด๋””์–ด ์ƒ์„ฑ
367
  ##############################################################################
368
- def generate_single_object_transformation_for_category(obj, selected_category):
369
- transformations = physical_transformation_categories.get(selected_category)
370
  if not transformations:
371
  return {}
372
  transformation = choose_alternative(random.choice(transformations))
373
- base_description = f"{obj}์ด(๊ฐ€) {transformation} ํ˜„์ƒ์„ ๋ณด์ธ๋‹ค"
 
 
 
374
  return {selected_category: {"base": base_description, "enhanced": None}}
375
 
376
- def generate_two_objects_interaction_for_category(obj1, obj2, selected_category):
377
- transformations = physical_transformation_categories.get(selected_category)
378
  if not transformations:
379
  return {}
380
  transformation = choose_alternative(random.choice(transformations))
381
- template = random.choice([
382
- "{obj1}์ด(๊ฐ€) {obj2}์— ๊ฒฐํ•ฉํ•˜์—ฌ {change}๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค",
383
- "{obj1}๊ณผ(์™€) {obj2}์ด(๊ฐ€) ์ถฉ๋Œํ•˜๋ฉด์„œ {change}๊ฐ€ ์ผ์–ด๋‚ฌ๋‹ค"
384
- ])
 
 
 
 
 
 
385
  base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
386
  return {selected_category: {"base": base_description, "enhanced": None}}
387
 
388
- def generate_three_objects_interaction_for_category(obj1, obj2, obj3, selected_category):
389
- transformations = physical_transformation_categories.get(selected_category)
390
  if not transformations:
391
  return {}
392
  transformation = choose_alternative(random.choice(transformations))
393
- template = random.choice([
394
- "{obj1}, {obj2}, {obj3}์ด(๊ฐ€) ์‚ผ๊ฐํ˜• ๊ตฌ์กฐ๋กœ ๊ฒฐํ•ฉํ•˜์—ฌ {change}๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค",
395
- "{obj1}์ด(๊ฐ€) {obj2}์™€(๊ณผ) {obj3} ์‚ฌ์ด์—์„œ ๋งค๊ฐœ์ฒด ์—ญํ• ์„ ํ•˜๋ฉฐ {change}๋ฅผ ์ด‰์ง„ํ–ˆ๋‹ค"
396
- ])
 
 
 
 
 
 
397
  base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
398
  return {selected_category: {"base": base_description, "enhanced": None}}
399
 
400
- ##############################################################################
401
- # ์ƒ์„ฑ๋œ ๊ธฐ๋ณธ ์„ค๋ช…์„ LLM์„ ํ†ตํ•ด ํ™•์žฅ (๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„)
402
- ##############################################################################
403
- def enhance_descriptions(results, objects):
404
- obj_name = " ๋ฐ ".join([obj for obj in objects if obj])
405
  for category, result in results.items():
406
- result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
 
 
 
407
  return results
408
 
409
- ##############################################################################
410
- # ์‚ฌ์šฉ์ž ์ž…๋ ฅ(์ตœ๋Œ€ 3๊ฐœ ํ‚ค์›Œ๋“œ) + ์„ ํƒ ์นดํ…Œ๊ณ ๋ฆฌ โ†’ ๋ณ€ํ™” ์•„์ด๋””์–ด ์ƒ์„ฑ
411
- ##############################################################################
412
- def generate_transformations(text1, text2, text3, selected_category):
413
  if text2 and text3:
414
- results = generate_three_objects_interaction_for_category(text1, text2, text3, selected_category)
415
  objects = [text1, text2, text3]
416
  elif text2:
417
- results = generate_two_objects_interaction_for_category(text1, text2, selected_category)
418
  objects = [text1, text2]
419
  else:
420
- results = generate_single_object_transformation_for_category(text1, selected_category)
421
  objects = [text1]
422
- return enhance_descriptions(results, objects)
423
 
424
- ##############################################################################
425
- # ๊ฒฐ๊ณผ ํฌ๋งทํŒ…
426
- ##############################################################################
427
- def format_results(results):
428
  formatted = ""
429
- for category, result in results.items():
430
- formatted += f"## {category}\n**๊ธฐ๋ณธ ์•„์ด๋””์–ด**: {result['base']}\n\n**ํ™•์žฅ๋œ ์•„์ด๋””์–ด**: {result['enhanced']}\n\n---\n\n"
 
 
 
 
431
  return formatted
432
 
433
- ##############################################################################
434
- # Gradio UI์—์„œ ํ˜ธ์ถœ๋  ํ•จ์ˆ˜ (ํ…์ŠคํŠธ ์•„์ด๋””์–ด๋งŒ ์ƒ์„ฑ)
435
- ##############################################################################
436
- def process_inputs(text1, text2, text3, selected_category, progress=gr.Progress()):
437
  text1 = text1.strip() if text1 else None
438
  text2 = text2.strip() if text2 else None
439
  text3 = text3.strip() if text3 else None
440
 
441
  if not text1:
442
- return "์˜ค๋ฅ˜: ์ตœ์†Œ ํ•˜๋‚˜์˜ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
443
 
444
- progress(0.05, desc="์•„์ด๋””์–ด ์ƒ์„ฑ ์ค€๋น„ ์ค‘...")
445
- time.sleep(0.3)
446
- progress(0.1, desc="์ฐฝ์˜์ ์ธ ์•„์ด๋””์–ด ์ƒ์„ฑ ์‹œ์ž‘...")
 
 
 
 
 
447
 
448
- results = generate_transformations(text1, text2, text3, selected_category)
449
 
450
- progress(0.8, desc="๊ฒฐ๊ณผ ํฌ๋งทํŒ… ์ค‘...")
451
- formatted = format_results(results)
452
- progress(1.0, desc="์™„๋ฃŒ!")
 
 
 
 
 
453
  return formatted
454
 
455
- ##############################################################################
456
- # ์•„์ด๋””์–ด์™€ ์ด๋ฏธ์ง€๋ฅผ ํ•จ๊ป˜ ์ƒ์„ฑํ•˜๋Š” ์ตœ์ข… ํ•จ์ˆ˜
457
- ##############################################################################
458
- def process_all(text1, text2, text3, selected_category, progress=gr.Progress()):
459
- idea_result = process_inputs(text1, text2, text3, selected_category, progress)
460
  image_result = generate_design_image(
461
  idea_result,
462
  seed=42,
@@ -468,18 +611,19 @@ def process_all(text1, text2, text3, selected_category, progress=gr.Progress()):
468
  return idea_result, image_result
469
 
470
  ##############################################################################
471
- # API ํ‚ค ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€
472
  ##############################################################################
473
- def get_warning_message():
474
  if not GEMINI_API_KEY:
475
- return "โš ๏ธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Gemini API ํ‚ค๋ฅผ ์„ค์ •ํ•˜์„ธ์š”."
476
  return ""
477
 
 
478
  ##############################################################################
479
- # Gradio UI
480
  ##############################################################################
481
  with gr.Blocks(
482
- title="ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ฐฝ์˜์  ๋ณ€ํ™” ์•„์ด๋””์–ด ๋ฐ ๋””์ž์ธ ์ƒ์„ฑ๊ธฐ",
483
  theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")
484
  ) as demo:
485
 
@@ -521,73 +665,144 @@ with gr.Blocks(
521
  </style>
522
  """)
523
 
524
- gr.Markdown("# ๐Ÿš€ ์•„์ด๋””์–ด ํŠธ๋žœ์Šคํฌ๋จธ")
525
- gr.Markdown("์ž…๋ ฅํ•œ **ํ‚ค์›Œ๋“œ**(์ตœ๋Œ€ 3๊ฐœ)์™€ **์นดํ…Œ๊ณ ๋ฆฌ**๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์ฐฝ์˜์ ์ธ ๋ชจ๋ธ/์ปจ์…‰/ํ˜•์ƒ ๋ณ€ํ™” ์•„์ด๋””์–ด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ํ™•์žฅ ์•„์ด๋””์–ด๋ฅผ ํ”„๋กฌํ”„ํŠธ๋กœ ํ•˜์—ฌ ๋””์ž์ธ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.")
526
-
527
- warning = gr.Markdown(get_warning_message())
528
-
529
- with gr.Row():
530
- with gr.Column(scale=1):
531
- text_input1 = gr.Textbox(label="ํ‚ค์›Œ๋“œ 1 (ํ•„์ˆ˜)", placeholder="์˜ˆ: ์Šค๋งˆํŠธํฐ")
532
- text_input2 = gr.Textbox(label="ํ‚ค์›Œ๋“œ 2 (์„ ํƒ)", placeholder="์˜ˆ: ์ธ๊ณต์ง€๋Šฅ")
533
- text_input3 = gr.Textbox(label="ํ‚ค์›Œ๋“œ 3 (์„ ํƒ)", placeholder="์˜ˆ: ํ—ฌ์Šค์ผ€์–ด")
534
- category_radio = gr.Radio(
535
- label="์นดํ…Œ๊ณ ๋ฆฌ ์„ ํƒ",
536
- choices=list(physical_transformation_categories.keys()),
537
- value=list(physical_transformation_categories.keys())[0],
538
- info="์ถœ๋ ฅํ•  ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  )
540
- status_msg = gr.Markdown("๐Ÿ’ก '์•„์ด๋””์–ด ์ƒ์„ฑํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์„ ํƒํ•œ ์นดํ…Œ๊ณ ๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ์•„์ด๋””์–ด์™€ ๋””์ž์ธ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.")
541
 
542
- processing_indicator = gr.HTML("""
543
- <div style="display: flex; justify-content: center; align-items: center; margin: 10px 0;">
544
- <div style="border: 5px solid #f3f3f3; border-top: 5px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 2s linear infinite;"></div>
545
- <p style="margin-left: 10px; font-weight: bold; color: #3498db;">์ฒ˜๋ฆฌ ์ค‘์ž…๋‹ˆ๋‹ค...</p>
546
- </div>
547
- <style>
548
- @keyframes spin {
549
- 0% { transform: rotate(0deg); }
550
- 100% { transform: rotate(360deg); }
551
- }
552
- </style>
553
- """, visible=False)
554
 
555
- submit_button = gr.Button("์•„์ด๋””์–ด ์ƒ์„ฑํ•˜๊ธฐ", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
- with gr.Column(scale=2):
558
- idea_output = gr.Markdown(label="์•„์ด๋””์–ด ๊ฒฐ๊ณผ")
559
- generated_image = gr.Image(label="์ƒ์„ฑ๋œ ๋””์ž์ธ ์ด๋ฏธ์ง€", type="pil")
560
-
561
- gr.Examples(
562
- examples=[
563
- ["์Šค๋งˆํŠธํฐ", "", "", "์„ผ์„œ ๊ธฐ๋Šฅ"],
564
- ["์ž๋™์ฐจ", "", "", "ํฌ๊ธฐ์™€ ํ˜•ํƒœ ๋ณ€ํ™”"],
565
- ["์ž๋™์ฐจ", "์ธ๊ณต์ง€๋Šฅ", "", "ํ‘œ๋ฉด ๋ฐ ์™ธ๊ด€ ๋ณ€ํ™”"],
566
- ["๋“œ๋ก ", "์ธ๊ณต์ง€๋Šฅ", "", "๋ฌผ์งˆ์˜ ์ƒํƒœ ๋ณ€ํ™”"],
567
- ["์šด๋™ํ™”", "์›จ์–ด๋Ÿฌ๋ธ”", "๊ฑด๊ฐ•", "๊ตฌ์กฐ์  ๋ณ€ํ™”"],
568
- ],
569
- inputs=[text_input1, text_input2, text_input3, category_radio],
570
- )
571
-
572
- def show_processing_indicator():
573
- return gr.update(visible=True)
574
-
575
- def hide_processing_indicator():
576
- return gr.update(visible=False)
577
-
578
- submit_button.click(
579
- fn=show_processing_indicator,
580
- inputs=None,
581
- outputs=processing_indicator
582
- ).then(
583
- fn=process_all,
584
- inputs=[text_input1, text_input2, text_input3, category_radio],
585
- outputs=[idea_output, generated_image]
586
- ).then(
587
- fn=hide_processing_indicator,
588
- inputs=None,
589
- outputs=processing_indicator
590
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
 
592
  if __name__ == "__main__":
593
  demo.launch(debug=True)
 
12
  import re
13
 
14
  ##############################################################################
15
+ # 1) ZeroGPU Environment Setup + Device and Dtype Configuration
16
  ##############################################################################
17
  try:
18
  import zerogpu
 
34
  print(f"Using device: {device}, dtype: {dtype}")
35
 
36
  ##############################################################################
37
+ # 2) Load Models: Translation Model, Diffusion Pipeline
38
  ##############################################################################
39
  try:
40
  translator = hf_pipeline(
 
71
  MAX_IMAGE_SIZE = 2048
72
 
73
  ##############################################################################
74
+ # Korean detection and input text cleaning functions
75
  ##############################################################################
76
  def contains_korean(text):
77
  for char in text:
 
79
  return True
80
  return False
81
 
 
 
 
82
  def clean_input_text(text):
83
  """
84
+ Allows only Korean, English, numbers, whitespace and common punctuation marks.
85
+ Adjust allowed characters as needed.
86
  """
87
  allowed = re.compile(r'[^ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9\s\.\,\!\?\-\:\;\'\"]')
88
  cleaned_text = allowed.sub('', text)
89
  return cleaned_text
90
 
 
 
 
91
  def log_unexpected_characters(text):
92
  allowed = re.compile(r'[ใ„ฑ-ใ…Ž๊ฐ€-ํžฃa-zA-Z0-9\s\.\,\!\?\-\:\;\'\"]')
93
  unexpected_chars = [char for char in text if not allowed.match(char)]
94
  if unexpected_chars:
95
+ print("Unexpected characters found:", set(unexpected_chars))
96
  else:
97
+ print("No unexpected characters in the input text.")
98
 
99
  ##############################################################################
100
+ # Image Generation Function
101
  ##############################################################################
102
  def generate_design_image(prompt, seed=42, randomize_seed=True, width=1024, height=1024, num_inference_steps=4):
103
  original_prompt = prompt
104
  translated = False
105
 
106
+ # Clean the input text
107
  prompt = clean_input_text(prompt)
108
 
109
+ # Pre-process: if input is too long, trim to 1000 characters
110
  if len(prompt) > 1000:
111
  prompt = prompt[:1000]
112
 
113
  if contains_korean(prompt):
114
+ # When calling translation, add max_length and truncation options to avoid length issues
115
  translation = translator(prompt, max_length=400, truncation=True)
116
  prompt = translation[0]['translation_text']
117
  translated = True
 
132
 
133
  return image
134
 
 
135
  ##############################################################################
136
+ # Logging Setup
137
  ##############################################################################
138
  logging.basicConfig(
139
  level=logging.INFO,
 
146
  logger = logging.getLogger("idea_generator")
147
 
148
  ##############################################################################
149
+ # Gemini API Key
150
  ##############################################################################
151
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
152
  genai.configure(api_key=GEMINI_API_KEY)
153
 
154
  ##############################################################################
155
+ # Optional Transformation Choice Function
156
  ##############################################################################
157
  def choose_alternative(transformation):
158
  if "/" not in transformation:
 
176
  return random.choice([left, right])
177
 
178
  ##############################################################################
179
+ # Transformation Categories Dictionaries
180
  ##############################################################################
181
+ # Korean version
182
  physical_transformation_categories = {
183
  "์„ผ์„œ ๊ธฐ๋Šฅ": [
184
  "์‹œ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "์ฒญ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "์ด‰๊ฐ ์„ผ์„œ/๊ฐ์ง€", "๋ฏธ๊ฐ ์„ผ์„œ/๊ฐ์ง€", "ํ›„๊ฐ ์„ผ์„œ/๊ฐ์ง€",
 
208
  "๊ด‘ํƒ/์œค๊ธฐ ๋ณ€ํ™”", "์ƒ‰์กฐ/์ฑ„๋„ ๋ณ€ํ™”", "๋ฐœ๊ด‘/ํ˜•๊ด‘", "๋น› ์‚ฐ๋ž€ ํšจ๊ณผ",
209
  "๋น› ํก์ˆ˜ ๋ณ€ํ™”", "๋ฐ˜ํˆฌ๋ช… ํšจ๊ณผ", "๊ทธ๋ฆผ์ž ํšจ๊ณผ ๋ณ€ํ™”", "์ž์™ธ์„  ๋ฐ˜์‘ ๋ณ€ํ™”",
210
  "์•ผ๊ด‘ ํšจ๊ณผ"
211
+ ],
 
 
 
212
  "๋ฌผ์งˆ์˜ ์ƒํƒœ ๋ณ€ํ™”": [
213
  "๊ณ ์ฒด/์•ก์ฒด/๊ธฐ์ฒด ์ „ํ™˜", "๊ฒฐ์ •ํ™”/์šฉํ•ด", "์‚ฐํ™”/๋ถ€์‹", "๋”ฑ๋”ฑํ•ด์ง/๋ถ€๋“œ๋Ÿฌ์›Œ์ง",
214
  "ํŠน์ˆ˜ ์ƒํƒœ ์ „ํ™˜", "๋ฌด์ •ํ˜•/๊ฒฐ์ •ํ˜• ์ „ํ™˜", "์„ฑ๋ถ„ ๋ถ„๋ฆฌ", "๋ฏธ์„ธ ์ž…์ž ํ˜•์„ฑ/๋ถ„ํ•ด",
 
217
  "๊ฑด์กฐ/์Šต์œค", "ํŒฝ์œค/์ˆ˜์ถ•", "๋™๊ฒฐ/ํ•ด๋™", "ํ’ํ™”/์นจ์‹", "์ถฉ์ „/๋ฐฉ์ „",
218
  "๊ฒฐํ•ฉ/๋ถ„๋ฆฌ", "๋ฐœํšจ/๋ถ€ํŒจ"
219
  ],
 
220
  "์›€์ง์ž„ ํŠน์„ฑ ๋ณ€ํ™”": [
221
  "๊ฐ€์†/๊ฐ์†", "์ผ์ • ์†๋„ ์œ ์ง€", "์ง„๋™/์ง„๋™ ๊ฐ์†Œ", "๋ถ€๋”ชํž˜/ํŠ•๊น€",
222
  "ํšŒ์ „ ์†๋„ ์ฆ๊ฐ€/๊ฐ์†Œ", "ํšŒ์ „ ๋ฐฉํ–ฅ ๋ณ€ํ™”", "๋ถˆ๊ทœ์น™ ์›€์ง์ž„", "๋ฉˆ์ท„๋‹ค ๋ฏธ๋„๋Ÿฌ์ง€๋Š” ํ˜„์ƒ",
 
289
  "์ด์˜จํ™”", "ํ™”ํ•™์  ํก์ฐฉ/ํƒˆ์ฐฉ", "์ด‰๋งค ํšจ์œจ ๋ณ€ํ™”", "ํšจ์†Œ ํ™œ์„ฑ ๋ณ€ํ™”", "๋ฐœ์ƒ‰ ๋ฐ˜์‘",
290
  "pH ๋ณ€ํ™”", "ํ™”ํ•™์  ํ‰ํ˜• ์ด๋™", "๊ฒฐํ•ฉ ํ˜•์„ฑ/๋ถ„ํ•ด", "์šฉํ•ด๋„ ๋ณ€ํ™”"
291
  ],
 
292
  "์ƒ๋ฌผํ•™์  ๋ณ€ํ™”": [
293
  "์ƒ์žฅ/์œ„์ถ•", "์„ธํฌ ๋ถ„์—ด/์‚ฌ๋ฉธ", "์ƒ๋ฌผ ๋ฐœ๊ด‘", "์‹ ์ง„๋Œ€์‚ฌ ๋ณ€ํ™”", "๋ฉด์—ญ ๋ฐ˜์‘",
294
  "ํ˜ธ๋ฅด๋ชฌ ๋ถ„๋น„", "์‹ ๊ฒฝ ๋ฐ˜์‘", "์œ ์ „์  ๋ฐœํ˜„", "์ ์‘/์ง„ํ™”", "์ƒ์ฒด๋ฆฌ๋“ฌ ๋ณ€ํ™”",
 
304
  "ํ™˜๊ฒฝ ์˜ค์—ผ ๋ฐ˜์‘", "๋‚ ์”จ ๋ฐ˜์‘", "๊ณ„์ ˆ ๋ณ€ํ™” ๋ฐ˜์‘", "์ผ์ฃผ๊ธฐ ๋ฐ˜์‘", "์ƒํƒœ๊ณ„ ์ƒํ˜ธ์ž‘์šฉ",
305
  "๊ณต์ƒ/๊ฒฝ์Ÿ ๋ฐ˜์‘", "ํฌ์‹/ํ”ผ์‹ ๊ด€๊ณ„", "๊ตฐ์ง‘ ํ˜•์„ฑ", "์˜์—ญ ์„ค์ •", "์ด์ฃผ/์ •์ฐฉ ํŒจํ„ด"
306
  ]
307
+ }
308
 
309
+ # English version
310
+ physical_transformation_categories_en = {
311
+ "Sensor Functions": [
312
+ "Visual sensor/detection", "Auditory sensor/detection", "Tactile sensor/detection", "Taste sensor/detection", "Olfactory sensor/detection",
313
+ "Temperature sensor/detection", "Humidity sensor/detection", "Pressure sensor/detection", "Acceleration sensor/detection", "Rotational sensor/detection",
314
+ "Proximity sensor/detection", "Position sensor/detection", "Motion sensor/detection", "Gas sensor/detection", "Infrared sensor/detection",
315
+ "Ultraviolet sensor/detection", "Radiation sensor/detection", "Magnetic sensor/detection", "Electric field sensor/detection", "Chemical sensor/detection",
316
+ "Biosignal sensor/detection", "Vibration sensor/detection", "Noise sensor/detection", "Light intensity sensor/detection", "Light wavelength sensor/detection",
317
+ "Tilt sensor/detection", "pH sensor/detection", "Current sensor/detection", "Voltage sensor/detection", "Image sensor/detection",
318
+ "Distance sensor/detection", "Depth sensor/detection", "Gravity sensor/detection", "Speed sensor/detection", "Flow sensor/detection",
319
+ "Water level sensor/detection", "Turbidity sensor/detection", "Salinity sensor/detection", "Metal detection", "Piezoelectric sensor/detection",
320
+ "Photovoltaic sensor/detection", "Thermocouple sensor/detection", "Hall effect sensor/detection", "Ultrasonic sensor/detection", "Radar sensor/detection",
321
+ "Lidar sensor/detection", "Touch sensor/detection", "Gesture sensor/detection", "Heart rate sensor/detection", "Blood pressure sensor/detection"
322
+ ],
323
+ "Size and Shape Change": [
324
+ "Volume increase/decrease", "Length increase/decrease", "Width increase/decrease", "Height increase/decrease",
325
+ "Density change", "Weight increase/decrease", "Shape deformation", "State change", "Uneven deformation",
326
+ "Complex shape deformation", "Twisting/entwining", "Non-uniform expansion/contraction", "Rounded/sharpened edges",
327
+ "Cracking/splitting", "Fragmentation", "Water resistance", "Dust resistance", "Denting/recovery",
328
+ "Folding/unfolding", "Compression/expansion", "Stretching/contraction", "Wrinkling/flattening", "Crushing/hardening",
329
+ "Rolling/unrolling", "Bending/curving"
330
+ ],
331
+ "Surface and Appearance Change": [
332
+ "Color change", "Texture change", "Transparency change", "Glossy/matte change",
333
+ "Light reflection variation", "Pattern change", "Angle-dependent color change", "Light-induced color change",
334
+ "Temperature-dependent color change", "Holographic effect", "Angle-specific light reflection", "Surface shape alteration",
335
+ "Nano-scale surface structure change", "Self-cleaning effect", "Stain/pattern formation", "Blurriness/clarity change",
336
+ "Luster/shine change", "Hue/saturation change", "Luminescence/fluorescence", "Light scattering effect",
337
+ "Light absorption change", "Translucency effect", "Shadow effect change", "UV response change",
338
+ "Glow effect"
339
+ ],
340
+ "Material State Change": [
341
+ "Solid/liquid/gas transition", "Crystallization/dissolution", "Oxidation/corrosion", "Hardening/softening",
342
+ "Special state transition", "Amorphous/crystalline transition", "Component separation", "Particle formation/disintegration",
343
+ "Gel formation/dissolution", "Metastable state change", "Molecular self-assembly/disintegration", "Delayed state change",
344
+ "Melting", "Solidification", "Evaporation/condensation", "Sublimation/deposition", "Precipitation/suspension", "Dispersion/aggregation",
345
+ "Drying/moistening", "Swelling/shrinkage", "Freezing/thawing", "Weathering/erosion", "Charging/discharging",
346
+ "Bonding/separation", "Fermentation/decay"
347
+ ],
348
+ "Movement Characteristics Change": [
349
+ "Acceleration/deceleration", "Maintaining constant speed", "Vibration/vibration reduction", "Collision/bouncing",
350
+ "Increase/decrease in rotational speed", "Change in rotational direction", "Irregular movement", "Stop-and-slide phenomenon",
351
+ "Resonance/anti-resonance", "Resistance/lift change in fluid", "Change in movement resistance", "Complex vibrational movement",
352
+ "Movement in special fluid", "Rotational-translational movement", "Inertial stoppage", "Shock absorption",
353
+ "Shock transfer", "Conservation of momentum", "Friction change", "Overcoming inertia", "Unstable equilibrium",
354
+ "Dynamic stability", "Damping of oscillation", "Path predictability", "Evasive movement"
355
+ ],
356
+ "Structural Change": [
357
+ "Addition/removal of components", "Assembly/disassembly", "Folding/unfolding", "Deformation/recovery", "Optimal structural change",
358
+ "Self-rearrangement", "Natural pattern formation/disappearance", "Regular pattern change", "Modular transformation",
359
+ "Increased structural complexity", "Memory of original shape effect", "Shape change over time", "Partial removal",
360
+ "Partial replacement", "Bonding", "Separation", "Division/integration", "Overlaying", "Internal structure change",
361
+ "External structure change", "Shift of center axis", "Balance point change", "Hierarchical structure change", "Support structure change",
362
+ "Stress distribution structure", "Shock absorption structure", "Grid/matrix structure change", "Interconnectivity change"
363
+ ],
364
+ "Spatial Movement": [
365
+ "Forward/backward movement", "Left/right movement", "Up/down movement", "Vertical axis rotation (nodding)",
366
+ "Horizontal axis rotation (shaking head)", "Longitudinal axis rotation (tilting sideways)", "Circular motion", "Spiral movement",
367
+ "Slipping due to inertia", "Change of rotation axis", "Irregular rotation", "Shaking movement", "Parabolic motion",
368
+ "Zero-gravity floating", "Floating on water surface", "Jump/leap", "Sliding", "Rolling", "Free fall",
369
+ "Reciprocating motion", "Elastic bouncing", "Penetration", "Evasive movement", "Zigzag movement", "Swinging movement"
370
+ ],
371
+ "Time-Related Change": [
372
+ "Aging/weathering", "Wear/corrosion", "Fading/discoloration", "Damage/recovery", "Lifecycle change",
373
+ "Adaptation through user interaction", "Learning-based shape optimization", "Property change over time",
374
+ "Collective memory effect", "Cultural significance change", "Delayed response", "History-dependent change",
375
+ "Gradual time change", "Evolutionary change", "Periodic regeneration", "Seasonal adaptation",
376
+ "Circadian rhythm change", "Lifecycle stage", "Growth/decline", "Self-repair/regeneration",
377
+ "Natural cycle adaptation", "Persistence/transience", "Memory effect", "Delayed effect", "Cumulative effect"
378
+ ],
379
+ "Light and Visual Effects": [
380
+ "Illumination/shutdown", "Light transmission/blocking", "Light scattering/concentration", "Color spectrum change", "Light diffraction",
381
+ "Light interference", "Hologram creation", "Laser effect", "Light polarization", "Fluorescence/phosphorescence",
382
+ "UV/IR emission", "Optical illusion", "Light refraction", "Shadow creation/removal",
383
+ "Chromatic aberration", "Rainbow effect", "Glow effect", "Flash effect", "Lighting pattern",
384
+ "Beam effect", "Light filter effect", "Change in light direction", "Projection effect", "Light detection/response",
385
+ "Luminance change"
386
+ ],
387
+ "Sound and Vibration Effects": [
388
+ "Sound generation/cessation", "Pitch change", "Volume change", "Timbre change",
389
+ "Resonance/antiresonance", "Acoustic vibration", "Ultrasonic/infrasonic emission", "Sound concentration/distribution",
390
+ "Sound reflection/absorption", "Acoustic Doppler effect", "Sound wave interference", "Acoustic resonance",
391
+ "Vibration pattern change", "Percussive effect", "Audio feedback", "Sound shielding/amplification",
392
+ "Directional sound", "Sound distortion", "Beat generation", "Harmonics generation", "Frequency modulation",
393
+ "Acoustic shockwave", "Sound filtering"
394
+ ],
395
+ "Thermal Changes": [
396
+ "Temperature rise/fall", "Thermal expansion/contraction", "Heat transfer/blocking", "Pressure increase/decrease",
397
+ "Magnetization due to heat change", "Entropy change", "Thermoelectric effect", "Magnetic-induced thermal change",
398
+ "Heat storage/release during phase change", "Thermal stress buildup/release", "Impact of rapid temperature change",
399
+ "Radiative cooling/heating", "Exothermic/endothermic", "Heat distribution change", "Heat reflection/absorption",
400
+ "Cooling condensation", "Thermal activation", "Thermal discoloration", "Coefficient of thermal expansion change", "Thermal stability change",
401
+ "Heat resistance/cold resistance", "Self-heating", "Thermal equilibrium/imbalance", "Thermal deformation", "Heat dispersion/concentration"
402
+ ],
403
+ "Electrical and Magnetic Changes": [
404
+ "Magnetism creation/cessation", "Charge increase/decrease", "Electric field creation/cessation", "Magnetic field creation/cessation",
405
+ "Superconducting transition", "Ferroelectric property change", "Quantum state change", "Plasma formation/cessation",
406
+ "Spin wave transmission", "Electricity generation by light", "Electricity generation by pressure", "Current change in magnetic field",
407
+ "Electrical resistance change", "Electrical conductivity change", "Static electricity generation/discharge", "Electromagnetic induction",
408
+ "Electromagnetic wave emission/absorption", "Capacitance change", "Magnetic hysteresis", "Electrical polarization",
409
+ "Electron flow direction change", "Electrical resonance", "Electrical shielding/exposure", "Magnetic shielding/exposure",
410
+ "Magnetic field alignment"
411
+ ],
412
+ "Chemical Change": [
413
+ "Surface coating change", "Material composition change", "Chemical reaction change", "Catalytic action start/stop",
414
+ "Light-induced chemical reaction", "Electricity-induced chemical reaction", "Monolayer formation", "Molecular-level structural change",
415
+ "Biomimetic surface change", "Environmentally responsive material change", "Periodic chemical reaction", "Oxidation", "Reduction",
416
+ "Polymerization", "Water splitting", "Compound formation", "Radiation effects", "Acid-base reaction", "Neutralization reaction",
417
+ "Ionization", "Chemical adsorption/desorption", "Catalytic efficiency change", "Enzyme activity change", "Colorimetric reaction",
418
+ "pH change", "Chemical equilibrium shift", "Bond formation/breakage", "Solubility change"
419
+ ],
420
+ "Biological Change": [
421
+ "Growth/shrinkage", "Cell division/death", "Bioluminescence", "Metabolic change", "Immune response",
422
+ "Hormone secretion", "Neural response", "Genetic expression", "Adaptation/evolution", "Circadian rhythm change",
423
+ "Regeneration/healing", "Aging/maturation", "Biomimetic change", "Biofilm formation", "Biological degradation",
424
+ "Enzyme activation/inactivation", "Biological signaling", "Stress response", "Thermoregulation", "Biological clock change",
425
+ "Extracellular matrix change", "Biomechanical response", "Cell motility", "Cell polarity change", "Nutritional status change"
426
+ ],
427
+ "Environmental Interaction": [
428
+ "Temperature response", "Humidity response", "Pressure response", "Gravity response", "Magnetic field response",
429
+ "Light response", "Sound response", "Chemical detection", "Mechanical stimulus detection", "Electrical stimulus response",
430
+ "Radiation response", "Vibration detection", "pH response", "Solvent response", "Gas exchange",
431
+ "Pollution response", "Weather response", "Seasonal response", "Circadian response", "Ecosystem interaction",
432
+ "Symbiotic/competitive interaction", "Predator/prey relationship", "Swarm formation", "Territorial behavior", "Migration/settlement pattern"
433
+ ]
434
  }
435
 
436
  ##############################################################################
437
+ # Gemini API Call Function (Language Independent)
438
  ##############################################################################
439
  def query_gemini_api(prompt):
440
  try:
 
464
  return f"An error occurred while calling the API: {str(e)}"
465
 
466
  ##############################################################################
467
+ # Description Expansion Functions (LLM) - Korean and English Versions
468
  ##############################################################################
469
  def enhance_with_llm(base_description, obj_name, category):
470
  prompt = f"""
 
477
  """
478
  return query_gemini_api(prompt)
479
 
480
+ def enhance_with_llm_en(base_description, obj_name, category):
481
+ prompt = f"""
482
+ Below is a brief description related to '{category}' for '{obj_name}':
483
+ "{base_description}"
484
+ Please expand the above content into a more detailed explanation, focusing on:
485
+ 1) Creative transformation of the model/concept/shape,
486
+ 2) Innovative aspects and functionality,
487
+ in 3-4 sentences.
488
+ """
489
+ return query_gemini_api(prompt)
490
+
491
  ##############################################################################
492
+ # Transformation Idea Generation Functions for Both Languages
493
  ##############################################################################
494
+ def generate_single_object_transformation_for_category_lang(obj, selected_category, categories_dict, lang="ko"):
495
+ transformations = categories_dict.get(selected_category)
496
  if not transformations:
497
  return {}
498
  transformation = choose_alternative(random.choice(transformations))
499
+ if lang == "ko":
500
+ base_description = f"{obj}์ด(๊ฐ€) {transformation} ํ˜„์ƒ์„ ๋ณด์ธ๋‹ค"
501
+ else:
502
+ base_description = f"{obj} exhibits {transformation}"
503
  return {selected_category: {"base": base_description, "enhanced": None}}
504
 
505
+ def generate_two_objects_interaction_for_category_lang(obj1, obj2, selected_category, categories_dict, lang="ko"):
506
+ transformations = categories_dict.get(selected_category)
507
  if not transformations:
508
  return {}
509
  transformation = choose_alternative(random.choice(transformations))
510
+ if lang == "ko":
511
+ template = random.choice([
512
+ "{obj1}์ด(๊ฐ€) {obj2}์— ๊ฒฐํ•ฉํ•˜์—ฌ {change}๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค",
513
+ "{obj1}๊ณผ(์™€) {obj2}์ด(๊ฐ€) ์ถฉ๋Œํ•˜๋ฉด์„œ {change}๊ฐ€ ์ผ์–ด๋‚ฌ๋‹ค"
514
+ ])
515
+ else:
516
+ template = random.choice([
517
+ "{obj1} combined with {obj2} resulted in {change}",
518
+ "A collision between {obj1} and {obj2} led to {change}"
519
+ ])
520
  base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
521
  return {selected_category: {"base": base_description, "enhanced": None}}
522
 
523
+ def generate_three_objects_interaction_for_category_lang(obj1, obj2, obj3, selected_category, categories_dict, lang="ko"):
524
+ transformations = categories_dict.get(selected_category)
525
  if not transformations:
526
  return {}
527
  transformation = choose_alternative(random.choice(transformations))
528
+ if lang == "ko":
529
+ template = random.choice([
530
+ "{obj1}, {obj2}, {obj3}์ด(๊ฐ€) ์‚ผ๊ฐํ˜• ๊ตฌ์กฐ๋กœ ๊ฒฐํ•ฉํ•˜์—ฌ {change}๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค",
531
+ "{obj1}์ด(๊ฐ€) {obj2}์™€(๊ณผ) {obj3} ์‚ฌ์ด์—์„œ ๋งค๊ฐœ์ฒด ์—ญํ• ์„ ํ•˜๋ฉฐ {change}๋ฅผ ์ด‰์ง„ํ–ˆ๋‹ค"
532
+ ])
533
+ else:
534
+ template = random.choice([
535
+ "{obj1}, {obj2}, and {obj3} formed a triangular structure resulting in {change}",
536
+ "{obj1} acted as an intermediary between {obj2} and {obj3}, facilitating {change}"
537
+ ])
538
  base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
539
  return {selected_category: {"base": base_description, "enhanced": None}}
540
 
541
+ def enhance_descriptions_lang(results, objects, lang="ko"):
542
+ obj_name = " ๋ฐ ".join([obj for obj in objects if obj]) if lang=="ko" else " and ".join([obj for obj in objects if obj])
 
 
 
543
  for category, result in results.items():
544
+ if lang == "ko":
545
+ result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
546
+ else:
547
+ result["enhanced"] = enhance_with_llm_en(result["base"], obj_name, category)
548
  return results
549
 
550
+ def generate_transformations_lang(text1, text2, text3, selected_category, categories_dict, lang="ko"):
 
 
 
551
  if text2 and text3:
552
+ results = generate_three_objects_interaction_for_category_lang(text1, text2, text3, selected_category, categories_dict, lang)
553
  objects = [text1, text2, text3]
554
  elif text2:
555
+ results = generate_two_objects_interaction_for_category_lang(text1, text2, selected_category, categories_dict, lang)
556
  objects = [text1, text2]
557
  else:
558
+ results = generate_single_object_transformation_for_category_lang(text1, selected_category, categories_dict, lang)
559
  objects = [text1]
560
+ return enhance_descriptions_lang(results, objects, lang)
561
 
562
+ def format_results_lang(results, lang="ko"):
 
 
 
563
  formatted = ""
564
+ if lang == "ko":
565
+ for category, result in results.items():
566
+ formatted += f"## {category}\n**๊ธฐ๋ณธ ์•„์ด๋””์–ด**: {result['base']}\n\n**ํ™•์žฅ๋œ ์•„์ด๋””์–ด**: {result['enhanced']}\n\n---\n\n"
567
+ else:
568
+ for category, result in results.items():
569
+ formatted += f"## {category}\n**Base Idea**: {result['base']}\n\n**Expanded Idea**: {result['enhanced']}\n\n---\n\n"
570
  return formatted
571
 
572
+ def process_inputs_lang(text1, text2, text3, selected_category, categories_dict, lang="ko", progress=gr.Progress()):
 
 
 
573
  text1 = text1.strip() if text1 else None
574
  text2 = text2.strip() if text2 else None
575
  text3 = text3.strip() if text3 else None
576
 
577
  if not text1:
578
+ return "์˜ค๋ฅ˜: ์ตœ์†Œ ํ•˜๋‚˜์˜ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”." if lang=="ko" else "Error: Please enter at least one keyword."
579
 
580
+ if lang == "ko":
581
+ progress(0.05, desc="์•„์ด๋””์–ด ์ƒ์„ฑ ์ค€๋น„ ์ค‘...")
582
+ time.sleep(0.3)
583
+ progress(0.1, desc="์ฐฝ์˜์ ์ธ ์•„์ด๋””์–ด ์ƒ์„ฑ ์‹œ์ž‘...")
584
+ else:
585
+ progress(0.05, desc="Preparing idea generation...")
586
+ time.sleep(0.3)
587
+ progress(0.1, desc="Generating creative idea...")
588
 
589
+ results = generate_transformations_lang(text1, text2, text3, selected_category, categories_dict, lang)
590
 
591
+ if lang == "ko":
592
+ progress(0.8, desc="๊ฒฐ๊ณผ ํฌ๋งทํŒ… ์ค‘...")
593
+ formatted = format_results_lang(results, lang)
594
+ progress(1.0, desc="์™„๋ฃŒ!")
595
+ else:
596
+ progress(0.8, desc="Formatting results...")
597
+ formatted = format_results_lang(results, lang)
598
+ progress(1.0, desc="Done!")
599
  return formatted
600
 
601
+ def process_all_lang(text1, text2, text3, selected_category, categories_dict, lang="ko", progress=gr.Progress()):
602
+ idea_result = process_inputs_lang(text1, text2, text3, selected_category, categories_dict, lang, progress)
 
 
 
603
  image_result = generate_design_image(
604
  idea_result,
605
  seed=42,
 
611
  return idea_result, image_result
612
 
613
  ##############################################################################
614
+ # Warning Message Function for API Key (Language Specific)
615
  ##############################################################################
616
+ def get_warning_message_lang(lang="ko"):
617
  if not GEMINI_API_KEY:
618
+ return "โš ๏ธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Gemini API ํ‚ค๋ฅผ ์„ค์ •ํ•˜์„ธ์š”." if lang=="ko" else "โš ๏ธ The GEMINI_API_KEY environment variable is not set. Please set your Gemini API key."
619
  return ""
620
 
621
+
622
  ##############################################################################
623
+ # Gradio UI with Two Tabs: English (Main Home) and Korean
624
  ##############################################################################
625
  with gr.Blocks(
626
+ title="Idea Transformer",
627
  theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")
628
  ) as demo:
629
 
 
665
  </style>
666
  """)
667
 
668
+ with gr.Tabs():
669
+ with gr.Tab(label="English"):
670
+ gr.Markdown("# ๐Ÿš€ Idea Transformer")
671
+ gr.Markdown("Based on up to **three keywords** and a **selected category**, this tool generates a creative transformation idea and a design image using the expanded idea as a prompt.")
672
+
673
+ warning_en = gr.Markdown(get_warning_message_lang("en"))
674
+
675
+ with gr.Row():
676
+ with gr.Column(scale=1):
677
+ text_input1_en = gr.Textbox(label="Keyword 1 (required)", placeholder="e.g., Smartphone")
678
+ text_input2_en = gr.Textbox(label="Keyword 2 (optional)", placeholder="e.g., Artificial Intelligence")
679
+ text_input3_en = gr.Textbox(label="Keyword 3 (optional)", placeholder="e.g., Healthcare")
680
+ category_radio_en = gr.Radio(
681
+ label="Select Category",
682
+ choices=list(physical_transformation_categories_en.keys()),
683
+ value=list(physical_transformation_categories_en.keys())[0],
684
+ info="Select a category."
685
+ )
686
+ status_msg_en = gr.Markdown("๐Ÿ’ก Click the 'Generate Idea' button to create an idea and design image based on the selected category.")
687
+
688
+ processing_indicator_en = gr.HTML("""
689
+ <div style="display: flex; justify-content: center; align-items: center; margin: 10px 0;">
690
+ <div style="border: 5px solid #f3f3f3; border-top: 5px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 2s linear infinite;"></div>
691
+ <p style="margin-left: 10px; font-weight: bold; color: #3498db;">Processing...</p>
692
+ </div>
693
+ <style>
694
+ @keyframes spin {
695
+ 0% { transform: rotate(0deg); }
696
+ 100% { transform: rotate(360deg); }
697
+ }
698
+ </style>
699
+ """, visible=False)
700
+
701
+ submit_button_en = gr.Button("Generate Idea", variant="primary")
702
+
703
+ with gr.Column(scale=2):
704
+ idea_output_en = gr.Markdown(label="Idea Output")
705
+ generated_image_en = gr.Image(label="Generated Design Image", type="pil")
706
+
707
+ gr.Examples(
708
+ examples=[
709
+ ["Smartphone", "", "", "Sensor Functions"],
710
+ ["Car", "", "", "Size and Shape Change"],
711
+ ["Car", "Artificial Intelligence", "", "Surface and Appearance Change"],
712
+ ["Drone", "Artificial Intelligence", "", "Material State Change"],
713
+ ["Sneakers", "Wearable", "Health", "Structural Change"],
714
+ ],
715
+ inputs=[text_input1_en, text_input2_en, text_input3_en, category_radio_en],
716
  )
 
717
 
718
+ def show_processing_indicator_en():
719
+ return gr.update(visible=True)
720
+
721
+ def hide_processing_indicator_en():
722
+ return gr.update(visible=False)
 
 
 
 
 
 
 
723
 
724
+ submit_button_en.click(
725
+ fn=show_processing_indicator_en,
726
+ inputs=None,
727
+ outputs=processing_indicator_en
728
+ ).then(
729
+ fn=process_all_lang,
730
+ inputs=[text_input1_en, text_input2_en, text_input3_en, category_radio_en, gr.Variable(physical_transformation_categories_en), gr.Variable("en")],
731
+ outputs=[idea_output_en, generated_image_en]
732
+ ).then(
733
+ fn=hide_processing_indicator_en,
734
+ inputs=None,
735
+ outputs=processing_indicator_en
736
+ )
737
 
738
+ with gr.Tab(label="ํ•œ๊ตญ์–ด"):
739
+ gr.Markdown("# ๐Ÿš€ ์•„์ด๋””์–ด ํŠธ๋žœ์Šคํฌ๋จธ")
740
+ gr.Markdown("์ž…๋ ฅํ•œ **ํ‚ค์›Œ๋“œ**(์ตœ๋Œ€ 3๊ฐœ)์™€ **์นดํ…Œ๊ณ ๋ฆฌ**๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ์ฐฝ์˜์ ์ธ ๋ชจ๋ธ/์ปจ์…‰/ํ˜•์ƒ ๋ณ€ํ™” ์•„์ด๋””์–ด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ํ™•์žฅ ์•„์ด๋””์–ด๋ฅผ ํ”„๋กฌํ”„ํŠธ๋กœ ํ•˜์—ฌ ๋””์ž์ธ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.")
741
+
742
+ warning_ko = gr.Markdown(get_warning_message_lang("ko"))
743
+
744
+ with gr.Row():
745
+ with gr.Column(scale=1):
746
+ text_input1_ko = gr.Textbox(label="ํ‚ค์›Œ๋“œ 1 (ํ•„์ˆ˜)", placeholder="์˜ˆ: ์Šค๋งˆํŠธํฐ")
747
+ text_input2_ko = gr.Textbox(label="ํ‚ค์›Œ๋“œ 2 (์„ ํƒ)", placeholder="์˜ˆ: ์ธ๊ณต์ง€๋Šฅ")
748
+ text_input3_ko = gr.Textbox(label="ํ‚ค์›Œ๋“œ 3 (์„ ํƒ)", placeholder="์˜ˆ: ํ—ฌ์Šค์ผ€์–ด")
749
+ category_radio_ko = gr.Radio(
750
+ label="์นดํ…Œ๊ณ ๋ฆฌ ์„ ํƒ",
751
+ choices=list(physical_transformation_categories.keys()),
752
+ value=list(physical_transformation_categories.keys())[0],
753
+ info="์ถœ๋ ฅํ•  ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”."
754
+ )
755
+ status_msg_ko = gr.Markdown("๐Ÿ’ก '์•„์ด๋””์–ด ์ƒ์„ฑํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์„ ํƒํ•œ ์นดํ…Œ๊ณ ๋ฆฌ์— ํ•ด๋‹นํ•˜๋Š” ์•„์ด๋””์–ด์™€ ๋””์ž์ธ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.")
756
+
757
+ processing_indicator_ko = gr.HTML("""
758
+ <div style="display: flex; justify-content: center; align-items: center; margin: 10px 0;">
759
+ <div style="border: 5px solid #f3f3f3; border-top: 5px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 2s linear infinite;"></div>
760
+ <p style="margin-left: 10px; font-weight: bold; color: #3498db;">์ฒ˜๋ฆฌ ์ค‘์ž…๋‹ˆ๋‹ค...</p>
761
+ </div>
762
+ <style>
763
+ @keyframes spin {
764
+ 0% { transform: rotate(0deg); }
765
+ 100% { transform: rotate(360deg); }
766
+ }
767
+ </style>
768
+ """, visible=False)
769
+
770
+ submit_button_ko = gr.Button("์•„์ด๋””์–ด ์ƒ์„ฑํ•˜๊ธฐ", variant="primary")
771
+
772
+ with gr.Column(scale=2):
773
+ idea_output_ko = gr.Markdown(label="์•„์ด๋””์–ด ๊ฒฐ๊ณผ")
774
+ generated_image_ko = gr.Image(label="์ƒ์„ฑ๋œ ๋””์ž์ธ ์ด๋ฏธ์ง€", type="pil")
775
+
776
+ gr.Examples(
777
+ examples=[
778
+ ["์Šค๋งˆํŠธํฐ", "", "", "์„ผ์„œ ๊ธฐ๋Šฅ"],
779
+ ["์ž๋™์ฐจ", "", "", "ํฌ๊ธฐ์™€ ํ˜•ํƒœ ๋ณ€ํ™”"],
780
+ ["์ž๋™์ฐจ", "์ธ๊ณต์ง€๋Šฅ", "", "ํ‘œ๋ฉด ๋ฐ ์™ธ๊ด€ ๋ณ€ํ™”"],
781
+ ["๋“œ๋ก ", "์ธ๊ณต์ง€๋Šฅ", "", "๋ฌผ์งˆ์˜ ์ƒํƒœ ๋ณ€ํ™”"],
782
+ ["์šด๋™ํ™”", "์›จ์–ด๋Ÿฌ๋ธ”", "๊ฑด๊ฐ•", "๊ตฌ์กฐ์  ๋ณ€ํ™”"],
783
+ ],
784
+ inputs=[text_input1_ko, text_input2_ko, text_input3_ko, category_radio_ko],
785
+ )
786
+
787
+ def show_processing_indicator_ko():
788
+ return gr.update(visible=True)
789
+
790
+ def hide_processing_indicator_ko():
791
+ return gr.update(visible=False)
792
+
793
+ submit_button_ko.click(
794
+ fn=show_processing_indicator_ko,
795
+ inputs=None,
796
+ outputs=processing_indicator_ko
797
+ ).then(
798
+ fn=process_all_lang,
799
+ inputs=[text_input1_ko, text_input2_ko, text_input3_ko, category_radio_ko, gr.Variable(physical_transformation_categories), gr.Variable("ko")],
800
+ outputs=[idea_output_ko, generated_image_ko]
801
+ ).then(
802
+ fn=hide_processing_indicator_ko,
803
+ inputs=None,
804
+ outputs=processing_indicator_ko
805
+ )
806
 
807
  if __name__ == "__main__":
808
  demo.launch(debug=True)