aiqcamp commited on
Commit
95d0883
Β·
verified Β·
1 Parent(s): 03b18cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +291 -0
app.py CHANGED
@@ -448,5 +448,296 @@ with gr.Blocks(title="ν‚€μ›Œλ“œ 기반 창의적 λ³€ν™” 아이디어 생성기",
448
  outputs=processing_indicator
449
  )
450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  if __name__ == "__main__":
452
  demo.launch(debug=True)
 
448
  outputs=processing_indicator
449
  )
450
 
451
+ if __name__ == "__main__":
452
+ demo.launch(debug=True)
453
+
454
+ ],
455
+
456
+ "ν™˜κ²½ μƒν˜Έμž‘μš©": [
457
+ "μ˜¨λ„ λ°˜μ‘", "μŠ΅λ„ λ°˜μ‘", "κΈ°μ•• λ°˜μ‘", "쀑λ ₯ λ°˜μ‘", "자기μž₯ λ°˜μ‘",
458
+ "λΉ› λ°˜μ‘", "μ†Œλ¦¬ λ°˜μ‘", "ν™”ν•™ 물질 감지", "기계적 자극 감지", "μ „κΈ° 자극 λ°˜μ‘",
459
+ "방사선 λ°˜μ‘", "진동 감지", "pH λ°˜μ‘", "용맀 λ°˜μ‘", "기체 κ΅ν™˜",
460
+ "ν™˜κ²½ μ˜€μ—Ό λ°˜μ‘", "날씨 λ°˜μ‘", "κ³„μ ˆ λ³€ν™” λ°˜μ‘", "일주기 λ°˜μ‘", "μƒνƒœκ³„ μƒν˜Έμž‘μš©",
461
+ "곡생/경쟁 λ°˜μ‘", "포식/피식 관계", "κ΅°μ§‘ ν˜•μ„±", "μ˜μ—­ μ„€μ •", "이주/μ •μ°© νŒ¨ν„΄"
462
+ ],
463
+
464
+ "μ„Όμ„œ κΈ°λŠ₯": [
465
+ "μ‹œκ° μ„Όμ„œ/감지", "청각 μ„Όμ„œ/감지", "촉각 μ„Όμ„œ/감지", "미각 μ„Όμ„œ/감지", "후각 μ„Όμ„œ/감지",
466
+ "μ˜¨λ„ μ„Όμ„œ/감지", "μŠ΅λ„ μ„Όμ„œ/감지", "μ••λ ₯ μ„Όμ„œ/감지", "가속도 μ„Όμ„œ/감지", "νšŒμ „ μ„Όμ„œ/감지",
467
+ "κ·Όμ ‘ μ„Όμ„œ/감지", "μœ„μΉ˜ μ„Όμ„œ/감지", "μš΄λ™ μ„Όμ„œ/감지", "κ°€μŠ€ μ„Όμ„œ/감지", "적외선 μ„Όμ„œ/감지",
468
+ "μžμ™Έμ„  μ„Όμ„œ/감지", "방사선 μ„Όμ„œ/감지", "자기μž₯ μ„Όμ„œ/감지", "μ „κΈ°μž₯ μ„Όμ„œ/감지", "ν™”ν•™λ¬Όμ§ˆ μ„Όμ„œ/감지",
469
+ "μƒμ²΄μ‹ ν˜Έ μ„Όμ„œ/감지", "진동 μ„Όμ„œ/감지", "μ†ŒμŒ μ„Όμ„œ/감지", "λΉ› μ„ΈκΈ° μ„Όμ„œ/감지", "λΉ› 파μž₯ μ„Όμ„œ/감지",
470
+ "기울기 μ„Όμ„œ/감지", "pH μ„Όμ„œ/감지", "μ „λ₯˜ μ„Όμ„œ/감지", "μ „μ•• μ„Όμ„œ/감지", "이미지 μ„Όμ„œ/감지",
471
+ "거리 μ„Όμ„œ/감지", "깊이 μ„Όμ„œ/감지", "쀑λ ₯ μ„Όμ„œ/감지", "속도 μ„Όμ„œ/감지", "흐름 μ„Όμ„œ/감지",
472
+ "μˆ˜μœ„ μ„Όμ„œ/감지", "탁도 μ„Όμ„œ/감지", "염도 μ„Όμ„œ/감지", "κΈˆμ† 감지", "μ••μ „ μ„Όμ„œ/감지",
473
+ "κ΄‘μ „ μ„Όμ„œ/감지", "μ—΄μ „λŒ€ μ„Όμ„œ/감지", "홀 효과 μ„Όμ„œ/감지", "초음파 μ„Όμ„œ/감지", "λ ˆμ΄λ” μ„Όμ„œ/감지",
474
+ "라이닀 μ„Όμ„œ/감지", "ν„°μΉ˜ μ„Όμ„œ/감지", "제슀처 μ„Όμ„œ/감지", "심박 μ„Όμ„œ/감지", "ν˜ˆμ•• μ„Όμ„œ/감지"
475
+ ]
476
+ }
477
+
478
+ ##############################################################################
479
+ # Gemini API 호좜 ν•¨μˆ˜ (예: gemini-2.0-flash-thinking-exp-01-21 -> λ‹€λ₯Έ λͺ¨λΈ μ‚¬μš© μ‹œ μˆ˜μ •)
480
+ ##############################################################################
481
+ def query_gemini_api(prompt):
482
+ try:
483
+ # μ˜ˆμ‹œ: κΈ°μ‘΄ gemini-2.0... λŒ€μ‹ , λ‹€λ₯Έ λͺ¨λΈμ΄ ν•„μš”ν•˜λ‹€λ©΄ κ΅μ²΄ν•˜μ„Έμš”.
484
+ model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
485
+
486
+ response = model.generate_content(prompt)
487
+
488
+ # 응닡 ꡬ쑰 λ°©μ–΄μ μœΌλ‘œ 처리
489
+ try:
490
+ if hasattr(response, 'text'):
491
+ return response.text
492
+
493
+ if hasattr(response, 'candidates') and response.candidates:
494
+ if len(response.candidates) > 0:
495
+ candidate = response.candidates[0]
496
+ if hasattr(candidate, 'content'):
497
+ content = candidate.content
498
+ if hasattr(content, 'parts') and content.parts:
499
+ if len(content.parts) > 0:
500
+ return content.parts[0].text
501
+ if hasattr(response, 'parts') and response.parts:
502
+ if len(response.parts) > 0:
503
+ return response.parts[0].text
504
+
505
+ return "Unable to generate a response. API response structure is different than expected."
506
+
507
+ except Exception as inner_e:
508
+ logger.error(f"Error processing response: {inner_e}")
509
+ return f"An error occurred while processing the response: {str(inner_e)}"
510
+
511
+ except Exception as e:
512
+ logger.error(f"Error calling Gemini API: {e}")
513
+ if "API key not valid" in str(e):
514
+ return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
515
+ return f"An error occurred while calling the API: {str(e)}"
516
+
517
+ ##############################################################################
518
+ # μ„€λͺ… ν™•μž₯ ν•¨μˆ˜: "λͺ¨λΈ/컨셉/ν˜•μƒμ˜ 변화에 λŒ€ν•œ 이해와 ν˜μ‹  포인트, κΈ°λŠ₯μ„± 등을 쀑심"으둜
519
+ ##############################################################################
520
+ def enhance_with_llm(base_description, obj_name, category):
521
+ prompt = f"""
522
+ λ‹€μŒμ€ '{obj_name}'의 '{category}' κ΄€λ ¨ κ°„λ‹¨ν•œ μ„€λͺ…μž…λ‹ˆλ‹€:
523
+ "{base_description}"
524
+ μœ„ λ‚΄μš©μ„ 보닀 κ΅¬μ²΄ν™”ν•˜μ—¬,
525
+ 1) 창의적인 λͺ¨λΈ/컨셉/ν˜•μƒμ˜ 변화에 λŒ€ν•œ 이해,
526
+ 2) ν˜μ‹  ν¬μΈνŠΈμ™€ κΈ°λŠ₯μ„± 등을 μ€‘μ‹¬μœΌλ‘œ
527
+ 3~4λ¬Έμž₯의 μ•„μ΄λ””μ–΄λ‘œ ν™•μž₯ν•΄ μ£Όμ„Έμš”.
528
+ """
529
+ return query_gemini_api(prompt)
530
+
531
+ ##############################################################################
532
+ # 단일 ν‚€μ›Œλ“œ(였브젝트)에 λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
533
+ ##############################################################################
534
+ def generate_single_object_transformations(obj):
535
+ results = {}
536
+ for category, transformations in physical_transformation_categories.items():
537
+ transformation = choose_alternative(random.choice(transformations))
538
+ base_description = f"{obj}이(κ°€) {transformation} ν˜„μƒμ„ 보인닀"
539
+ results[category] = {"base": base_description, "enhanced": None}
540
+ return results
541
+
542
+ ##############################################################################
543
+ # 두 ν‚€μ›Œλ“œμ— λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
544
+ ##############################################################################
545
+ def generate_two_objects_interaction(obj1, obj2):
546
+ results = {}
547
+ for category, transformations in physical_transformation_categories.items():
548
+ transformation = choose_alternative(random.choice(transformations))
549
+ template = random.choice([
550
+ "{obj1}이(κ°€) {obj2}에 κ²°ν•©ν•˜μ—¬ {change}κ°€ λ°œμƒν–ˆλ‹€",
551
+ "{obj1}κ³Ό(와) {obj2}이(κ°€) μΆ©λŒν•˜λ©΄μ„œ {change}κ°€ 일어났닀"
552
+ ])
553
+ base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
554
+ results[category] = {"base": base_description, "enhanced": None}
555
+ return results
556
+
557
+ ##############################################################################
558
+ # μ„Έ ν‚€μ›Œλ“œμ— λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
559
+ ##############################################################################
560
+ def generate_three_objects_interaction(obj1, obj2, obj3):
561
+ results = {}
562
+ for category, transformations in physical_transformation_categories.items():
563
+ transformation = choose_alternative(random.choice(transformations))
564
+ template = random.choice([
565
+ "{obj1}, {obj2}, {obj3}이(κ°€) μ‚Όκ°ν˜• ꡬ쑰둜 κ²°ν•©ν•˜μ—¬ {change}κ°€ λ°œμƒν–ˆλ‹€",
566
+ "{obj1}이(κ°€) {obj2}와(κ³Ό) {obj3} μ‚¬μ΄μ—μ„œ 맀개체 역할을 ν•˜λ©° {change}λ₯Ό μ΄‰μ§„ν–ˆλ‹€"
567
+ ])
568
+ base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
569
+ results[category] = {"base": base_description, "enhanced": None}
570
+ return results
571
+
572
+ ##############################################################################
573
+ # μƒμ„±λœ κΈ°λ³Έ μ„€λͺ…을 LLM을 톡해 ν™•μž₯
574
+ ##############################################################################
575
+ def enhance_descriptions(results, objects):
576
+ obj_name = " 및 ".join([obj for obj in objects if obj])
577
+
578
+ for category, result in results.items():
579
+ result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
580
+
581
+ return results
582
+
583
+ ##############################################################################
584
+ # μ‚¬μš©μž μž…λ ₯(μ΅œλŒ€ 3개 ν‚€μ›Œλ“œ)에 따라 창의적 λ³€ν™” 아이디어 생성
585
+ ##############################################################################
586
+ def generate_transformations(text1, text2=None, text3=None):
587
+ if text2 and text3:
588
+ results = generate_three_objects_interaction(text1, text2, text3)
589
+ objects = [text1, text2, text3]
590
+ elif text2:
591
+ results = generate_two_objects_interaction(text1, text2)
592
+ objects = [text1, text2]
593
+ else:
594
+ results = generate_single_object_transformations(text1)
595
+ objects = [text1]
596
+
597
+ return enhance_descriptions(results, objects)
598
+
599
+ ##############################################################################
600
+ # κ²°κ³Ό ν¬λ§·νŒ…
601
+ ##############################################################################
602
+ def format_results(results):
603
+ formatted = ""
604
+ for category, result in results.items():
605
+ formatted += f"## {category}\n**κΈ°λ³Έ 아이디어**: {result['base']}\n\n**ν™•μž₯된 아이디어**: {result['enhanced']}\n\n---\n\n"
606
+ return formatted
607
+
608
+ ##############################################################################
609
+ # Gradio UIμ—μ„œ ν˜ΈμΆœν•  ν•¨μˆ˜
610
+ ##############################################################################
611
+ def process_inputs(text1, text2, text3, selected_category, progress=gr.Progress()):
612
+ text1 = text1.strip() if text1 else None
613
+ text2 = text2.strip() if text2 else None
614
+ text3 = text3.strip() if text3 else None
615
+
616
+ if not text1:
617
+ return "였λ₯˜: μ΅œμ†Œ ν•˜λ‚˜μ˜ ν‚€μ›Œλ“œλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”."
618
+
619
+ keyword_info = f"ν‚€μ›Œλ“œ: {text1}"
620
+ if text2:
621
+ keyword_info += f", {text2}"
622
+ if text3:
623
+ keyword_info += f", {text3}"
624
+
625
+ progress(0.05, desc="아이디어 생성 μ€€λΉ„ 쀑...")
626
+ time.sleep(0.3) # μ‹œκ°μ  효과λ₯Ό μœ„ν•œ 짧은 μ§€μ—°
627
+
628
+ progress(0.1, desc="창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™” 아이디어 생성 μ‹œμž‘...")
629
+
630
+ results = generate_transformations(text1, text2, text3)
631
+
632
+ # μ„ νƒν•œ μΉ΄ν…Œκ³ λ¦¬μ— ν•΄λ‹Ήν•˜λŠ” 결과만 필터링
633
+ if selected_category in results:
634
+ results = {selected_category: results[selected_category]}
635
+ else:
636
+ return "μ„ νƒν•œ μΉ΄ν…Œκ³ λ¦¬κ°€ 결과에 μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
637
+
638
+ progress(0.8, desc="κ²°κ³Ό ν¬λ§·νŒ… 쀑...")
639
+ formatted = format_results(results)
640
+
641
+ progress(1.0, desc="μ™„λ£Œ!")
642
+ return formatted
643
+
644
+ ##############################################################################
645
+ # API ν‚€ κ²½κ³  λ©”μ‹œμ§€
646
+ ##############################################################################
647
+ def get_warning_message():
648
+ if not GEMINI_API_KEY:
649
+ return "⚠️ ν™˜κ²½ λ³€μˆ˜ GEMINI_API_KEYκ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. Gemini API ν‚€λ₯Ό μ„€μ •ν•˜μ„Έμš”."
650
+ return ""
651
+
652
+ ##############################################################################
653
+ # Gradio UI
654
+ ##############################################################################
655
+ with gr.Blocks(title="ν‚€μ›Œλ“œ 기반 창의적 λ³€ν™” 아이디어 생성기",
656
+ theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
657
+
658
+ gr.HTML("""
659
+ <style>
660
+ body { background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Arial', sans-serif; }
661
+ .gradio-container { padding: 20px; }
662
+ h1, h2 { text-align: center; }
663
+ h1 { color: #333; }
664
+ h2 { color: #555; }
665
+ .output { background-color: #ffffff; padding: 15px; border-radius: 8px; }
666
+ .gr-button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; padding: 8px 16px; }
667
+ .progress-message { color: #2196F3; font-weight: bold; margin-top: 10px; }
668
+ </style>
669
+ """)
670
+
671
+ gr.Markdown("# πŸš€ ν‚€μ›Œλ“œ 기반 창의적 λ³€ν™” 아이디어 생성기")
672
+ gr.Markdown("μž…λ ₯ν•œ **ν‚€μ›Œλ“œ**(μ΅œλŒ€ 3개)와 **μΉ΄ν…Œκ³ λ¦¬**λ₯Ό λ°”νƒ•μœΌλ‘œ, **창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™”**에 λŒ€ν•œ 이해와 **ν˜μ‹  포인트**, **κΈ°λŠ₯μ„±** 등을 μ€‘μ‹¬μœΌλ‘œ ν™•μž₯된 아이디어λ₯Ό μ œμ‹œν•©λ‹ˆλ‹€.")
673
+
674
+ warning = gr.Markdown(get_warning_message())
675
+
676
+ # 쒌츑 μž…λ ₯ μ˜μ—­
677
+ with gr.Row():
678
+ with gr.Column(scale=1):
679
+ text_input1 = gr.Textbox(label="ν‚€μ›Œλ“œ 1 (ν•„μˆ˜)", placeholder="예: 슀마트폰")
680
+ text_input2 = gr.Textbox(label="ν‚€μ›Œλ“œ 2 (선택)", placeholder="예: 인곡지λŠ₯")
681
+ text_input3 = gr.Textbox(label="ν‚€μ›Œλ“œ 3 (선택)", placeholder="예: ν—¬μŠ€μΌ€μ–΄")
682
+ # μΉ΄ν…Œκ³ λ¦¬ 선택 λ“œλ‘­λ‹€μš΄ μΆ”κ°€
683
+ category_dropdown = gr.Dropdown(
684
+ label="μΉ΄ν…Œκ³ λ¦¬ 선택",
685
+ choices=list(physical_transformation_categories.keys()),
686
+ value=list(physical_transformation_categories.keys())[0],
687
+ info="좜λ ₯ν•  μΉ΄ν…Œκ³ λ¦¬λ₯Ό μ„ νƒν•˜μ„Έμš”."
688
+ )
689
+
690
+ status_msg = gr.Markdown("πŸ’‘ '아이디어 μƒμ„±ν•˜κΈ°' λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ 아이디어 생성이 μ‹œμž‘λ©λ‹ˆλ‹€.")
691
+
692
+ processing_indicator = gr.HTML("""
693
+ <div style="display: flex; justify-content: center; align-items: center; margin: 10px 0;">
694
+ <div style="border: 5px solid #f3f3f3; border-top: 5px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 2s linear infinite;"></div>
695
+ <p style="margin-left: 10px; font-weight: bold; color: #3498db;">처리 μ€‘μž…λ‹ˆλ‹€...</p>
696
+ </div>
697
+ <style>
698
+ @keyframes spin {
699
+ 0% { transform: rotate(0deg); }
700
+ 100% { transform: rotate(360deg); }
701
+ }
702
+ </style>
703
+ """, visible=False)
704
+
705
+ submit_button = gr.Button("아이디어 μƒμ„±ν•˜κΈ°", variant="primary")
706
+
707
+ # 우츑 좜λ ₯ μ˜μ—­
708
+ with gr.Column(scale=2):
709
+ idea_output = gr.Markdown(label="아이디어 κ²°κ³Ό")
710
+
711
+ gr.Examples(
712
+ examples=[
713
+ ["슀마트폰", "", "", list(physical_transformation_categories.keys())[0]],
714
+ ["μžλ™μ°¨", "", "", list(physical_transformation_categories.keys())[0]],
715
+ ["μžλ™μ°¨", "인곡지λŠ₯", "", list(physical_transformation_categories.keys())[0]],
716
+ ["λ“œλ‘ ", "인곡지λŠ₯", "", list(physical_transformation_categories.keys())[0]],
717
+ ["μš΄λ™ν™”", "μ›¨μ–΄λŸ¬λΈ”", "건강", list(physical_transformation_categories.keys())[0]],
718
+ ],
719
+ inputs=[text_input1, text_input2, text_input3, category_dropdown],
720
+ )
721
+
722
+ def show_processing_indicator():
723
+ return gr.update(visible=True)
724
+
725
+ def hide_processing_indicator():
726
+ return gr.update(visible=False)
727
+
728
+ submit_button.click(
729
+ fn=show_processing_indicator,
730
+ inputs=None,
731
+ outputs=processing_indicator
732
+ ).then(
733
+ fn=process_inputs,
734
+ inputs=[text_input1, text_input2, text_input3, category_dropdown],
735
+ outputs=idea_output
736
+ ).then(
737
+ fn=hide_processing_indicator,
738
+ inputs=None,
739
+ outputs=processing_indicator
740
+ )
741
+
742
  if __name__ == "__main__":
743
  demo.launch(debug=True)