Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -448,296 +448,5 @@ with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
|
|
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)
|
|
|
448 |
outputs=processing_indicator
|
449 |
)
|
450 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
if __name__ == "__main__":
|
452 |
demo.launch(debug=True)
|