Spaces:
Running
Running
File size: 58,304 Bytes
c99406b 59177aa c99406b 1df6810 cf8b7b0 e41b021 9a48a94 1df6810 59177aa 79f2daf 59177aa 9a48a94 59177aa fe49aa3 d3caf4c 9a48a94 79f2daf d3caf4c 5eb15fa d3caf4c 22eda88 5eb15fa 59177aa c99406b 9a48a94 71c328b 59177aa 9a48a94 71c328b 9a48a94 71c328b d3caf4c cf8b7b0 59177aa 4b763b1 d3caf4c 15955aa 4b763b1 cf8b7b0 4b763b1 cf8b7b0 d3caf4c 79f2daf 59177aa fe49aa3 59177aa fe49aa3 d3caf4c fe49aa3 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa 5eb15fa 59177aa fe49aa3 c99406b d3caf4c fe49aa3 59177aa d3caf4c 59177aa fe49aa3 59177aa fe49aa3 4f228ef 5eb15fa 59177aa 5eb15fa 59177aa d3caf4c 5eb15fa 59177aa 5eb15fa fe49aa3 59177aa c99406b fe49aa3 59177aa d3caf4c 59177aa d3caf4c 59177aa c99406b 59177aa 79f2daf c99406b fe49aa3 59177aa fe49aa3 79f2daf 59177aa 79f2daf d3caf4c 59177aa c99406b 3f26784 c99406b d3caf4c 59177aa 1df6810 c99406b d3caf4c 1df6810 59177aa 6db8a66 d3caf4c 6db8a66 d3caf4c 59177aa fe49aa3 59177aa fe49aa3 d3caf4c 24cd13f 59177aa 5eb15fa 59177aa d3caf4c 4b763b1 d3caf4c 4b763b1 d3caf4c c99406b cf8b7b0 d3caf4c 1e4825e d3caf4c 1e4825e d3caf4c 1e4825e d3caf4c 59177aa d3caf4c 59177aa d3caf4c c99406b d3caf4c c99406b 59177aa c99406b 59177aa c99406b 59177aa d3caf4c 59177aa fe49aa3 59177aa d3caf4c 59177aa d3caf4c 59177aa d3caf4c 59177aa d3caf4c 59177aa d3caf4c fe49aa3 1df6810 d3caf4c a589da1 59177aa 62d2b15 d3caf4c 8761807 d3caf4c 8761807 62d2b15 d3caf4c 59177aa 62d2b15 cd508a6 ef79581 59177aa ef79581 eb59db6 59177aa 75e05d9 59177aa eb59db6 ef79581 62d2b15 ef79581 59177aa 82507ef eb59db6 4f228ef ef79581 eb59db6 9a48a94 d3caf4c ef79581 c1866e9 eb59db6 ef79581 e41b021 59177aa eb59db6 e41b021 d3caf4c 59177aa eb59db6 59177aa d3caf4c ef79581 e41b021 59177aa e41b021 d3caf4c ef79581 cd508a6 d3caf4c cd508a6 eb59db6 d3caf4c cd508a6 d3caf4c cd508a6 eb59db6 82507ef cd508a6 eb59db6 82507ef eb59db6 cd508a6 24cd13f cd508a6 1e4825e cd508a6 1e4825e eb59db6 1e4825e eb59db6 1e4825e eb59db6 ef79581 cd508a6 ef79581 cd508a6 ef79581 cd508a6 ef79581 fa21362 eb59db6 82507ef d3caf4c 59177aa 24cd13f d3caf4c 71c328b 24cd13f 71c328b 24cd13f 71c328b 59177aa d3caf4c 4f228ef 59177aa 4f228ef 59177aa 4f228ef 59177aa e41b021 59177aa 1df6810 59177aa d3caf4c 1df6810 d3caf4c 42b0fff |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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 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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
# ──────────────────────────────── Imports ────────────────────────────────
import os, json, re, logging, requests, markdown, time, io
from datetime import datetime
import streamlit as st
st.set_page_config(layout="wide")
from openai import OpenAI # OpenAI 라이브러리
from gradio_client import Client
import pandas as pd
import PyPDF2 # For handling PDF files
# ──────────────────────────────── Environment Variables / Constants ─────────────────────────
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
BRAVE_KEY = os.getenv("SERPHOUSE_API_KEY", "") # Keep this name
BRAVE_ENDPOINT = "https://api.search.brave.com/res/v1/web/search"
IMAGE_API_URL = "http://211.233.58.201:7896" # 이미지 생성용 API
MAX_TOKENS = 7999
# ──────────────────────────────── Physical Transformation Categories (KR & EN) ─────────────────
physical_transformation_categories = {
"센서 기능": [
"시각 센서/감지", "청각 센서/감지", "촉각 센서/감지", "미각 센서/감지", "후각 센서/감지",
"온도 센서/감지", "습도 센서/감지", "압력 센서/감지", "가속도 센서/감지", "회전 센서/감지",
"근접 센서/감지", "위치 센서/감지", "운동 센서/감지", "가스 센서/감지", "적외선 센서/감지",
"자외선 센서/감지", "방사선 센서/감지", "자기장 센서/감지", "전기장 센서/감지", "화학물질 센서/감지",
"생체신호 센서/감지", "진동 센서/감지", "소음 센서/감지", "빛 세기 센서/감지", "빛 파장 센서/감지",
"기울기 센서/감지", "pH 센서/감지", "전류 센서/감지", "전압 센서/감지", "이미지 센서/감지",
"거리 센서/감지", "깊이 센서/감지", "중력 센서/감지", "속도 센서/감지", "흐름 센서/감지",
"수위 센서/감지", "탁도 센서/감지", "염도 센서/감지", "금속 감지", "압전 센서/감지",
"광전 센서/감지", "열전대 센서/감지", "홀 효과 센서/감지", "초음파 센서/감지", "레이더 센서/감지",
"라이다 센서/감지", "터치 센서/감지", "제스처 센서/감지", "심박 센서/감지", "혈압 센서/감지"
],
"크기와 형태 변화": [
"부피 늘어남/줄어듦", "길이 늘어남/줄어듦", "너비 늘어남/줄어듦", "높이 늘어남/줄어듦",
"밀도 변화", "무게 증가/감소", "모양 변형", "상태 변화", "불균등 변형",
"복잡한 형태 변형", "비틀림/꼬임", "불균일한 확장/축소", "모서리 둥글게/날카롭게",
"깨짐/갈라짐", "여러 조각 나눠짐", "물 저항", "먼지 저항", "찌그러짐/복원",
"접힘/펼쳐짐", "압착/팽창", "늘어남/수축", "구겨짐/평평해짐", "뭉개짐/단단해짐",
"말림/펴짐", "꺾임/구부러짐"
],
"표면 및 외관 변화": [
"색상 변화", "질감 변화", "투명/불투명 변화", "반짝임/무광 변화",
"빛 반사 정도 변화", "무늬 변화", "각도에 따른 색상 변화", "빛에 따른 색상 변화",
"온도에 따른 색상 변화", "홀로그램 효과", "표면 각도별 빛 반사", "표면 모양 변형",
"초미세 표면 구조 변화", "자가 세정 효과", "얼룩/패턴 생성", "흐림/선명함 변화",
"광택/윤기 변화", "색조/채도 변화", "발광/형광", "빛 산란 효과",
"빛 흡수 변화", "반투명 효과", "그림자 효과 변화", "자외선 반응 변화",
"야광 효과"
],
"물질의 상태 변화": [
"고체/액체/기체 전환", "결정화/용해", "산화/부식", "딱딱해짐/부드러워짐",
"특수 상태 전환", "무정형/결정형 전환", "성분 분리", "미세 입자 형성/분해",
"젤 형성/풀어짐", "준안정 상태 변화", "분자 자가 정렬/분해", "상태변화 지연 현상",
"녹음", "굳음", "증발/응축", "승화/증착", "침전/부유", "분산/응집",
"건조/습윤", "팽윤/수축", "동결/해동", "풍화/침식", "충전/방전",
"결합/분리", "발효/부패"
],
"움직임 특성 변화": [
"가속/감속", "일정 속도 유지", "진동/진동 감소", "부딪힘/튕김",
"회전 속도 증가/감소", "회전 방향 변화", "불규칙 움직임", "멈췄다 미끄러지는 현상",
"공진/반공진", "유체 속 저항/양력 변화", "움직임 저항 변화", "복합 진동 움직임",
"특수 유체 속 움직임", "회전-이동 연계 움직임", "관성 정지", "충격 흡수",
"충격 전달", "운동량 보존", "마찰력 변화", "관성 탈출", "불안정 균형",
"동적 안정성", "흔들림 감쇠", "경로 예측성", "회피 움직임"
],
"구조적 변화": [
"부품 추가/제거", "조립/분해", "접기/펴기", "변형/원상복구", "최적 구조 변화",
"자가 재배열", "자연 패턴 형성/소멸", "규칙적 패턴 변화", "모듈식 변형",
"복잡성 증가 구조", "원래 모양 기억 효과", "시간에 따른 형태 변화", "부분 제거",
"부분 교체", "결합", "분리", "분할/통합", "중첩/겹침", "내부 구조 변화",
"외부 구조 변화", "중심축 이동", "균형점 변화", "계층 구조 변화", "지지 구조 변화",
"응력 분산 구조", "충격 흡수 구조", "그리드/매트릭스 구조 변화", "상호 연결성 변화"
],
"공간 이동": [
"앞/뒤 이동", "좌/우 이동", "위/아래 이동", "세로축 회전(고개 끄덕임)",
"가로축 회전(고개 젓기)", "길이축 회전(옆으로 기울임)", "원 운동", "나선형 이동",
"관성에 의한 미끄러짐", "회전축 변화", "불규칙 회전", "흔들림 운동", "포물선 이동",
"무중력 부유", "수면 위 부유", "점프/도약", "슬라이딩", "롤링", "자유 낙하",
"왕복 운동", "탄성 튕김", "관통", "회피 움직임", "지그재그 이동", "스윙 운동"
],
"시간 관련 변화": [
"노화/풍화", "마모/부식", "색 바램/변색", "손상/회복", "수명 주기 변화",
"사용자 상호작용에 따른 적응", "학습 기반 형태 최적화", "시간에 따른 물성 변화",
"집단 기억 효과", "문화적 의미 변화", "지연 반응", "이전 상태 의존 변화",
"점진적 시간 변화", "진화적 변화", "주기적 재생", "계절 변화 적응",
"생체리듬 변화", "생애 주기 단계", "성장/퇴화", "자가 복구/재생",
"자연 순환 적응", "지속성/일시성", "기억 효과", "지연된 작용", "누적 효과"
],
"빛과 시각 효과": [
"발광/소등", "빛 투과/차단", "빛 산란/집중", "색상 스펙트럼 변화", "빛 회절",
"빛 간섭", "홀로그램 생성", "레이저 효과", "빛 편광", "형광/인광",
"자외선/적외선 발광", "광학적 착시", "빛 굴절", "그림자 생성/제거",
"색수차 효과", "무지개 효과", "글로우 효과", "플래시 효과", "조명 패턴",
"빔 효과", "광 필터 효과", "빛의 방향성 변화", "투영 효과", "빛 감지/반응",
"광도 변화"
],
"소리와 진동 효과": [
"소리 발생/소멸", "음 높낮이 변화", "음량 변화", "음색 변화",
"공명/반공명", "음향 진동", "초음파/저음파 발생", "소리 집중/분산",
"음향 반사/흡수", "음향 도플러 효과", "음파 간섭", "음향 공진",
"진동 패턴 변화", "타악 효과", "음향 피드백", "음향 차폐/증폭",
"소리 지향성", "소리 왜곡", "비트 생성", "배음 생성", "주파수 변조",
"음향 충격파", "음향 필터링"
],
"열 관련 변화": [
"온도 상승/하강", "열 팽창/수축", "열 전달/차단", "압력 상승/하강",
"열 변화에 따른 자화", "엔트로피 변화", "열전기 효과", "자기장에 의한 열 변화",
"상태 변화 중 열 저장/방출", "열 스트레스 발생/해소", "급격한 온도 변화 영향",
"복사 냉각/가열", "발열/흡열", "열 분포 변화", "열 반사/흡수",
"냉각 응축", "열 활성화", "열 변색", "열 팽창 계수 변화", "열 안정성 변화",
"내열성/내한성", "자가 발열", "열적 평형/불균형", "열적 변형", "열 분산/집중"
],
"전기 및 자기 변화": [
"자성 생성/소멸", "전하량 증가/감소", "전기장 생성/소멸", "자기장 생성/소멸",
"초전도 상태 전환", "강유전체 특성 변화", "양자 상태 변화", "플라즈마 형성/소멸",
"스핀파 전달", "빛에 의한 전기 발생", "압력에 의한 전기 발생", "자기장 내 전류 변화",
"전기 저항 변화", "전기 전도성 변화", "정전기 발생/방전", "전자기 유도",
"전자기파 방출/흡수", "전기 용량 변화", "자기 이력 현상", "전기적 분극",
"전자 흐름 방향 변화", "전기적 공명", "전기적 차폐/노출", "자기 차폐/노출",
"자기장 정렬"
],
"화학적 변화": [
"표면 코팅 변화", "물질 성분 변화", "화학 반응 변화", "촉매 작용 시작/중단",
"빛에 의한 화학 반응", "전기에 의한 화학 반응", "단분자막 형성", "분자 수준 구조 변화",
"생체 모방 표면 변화", "환경 반응형 물질 변화", "주기적 화학 반응", "산화", "환원",
"고분자화", "물 분해", "화합", "방사선 영향", "산-염기 반응", "중화 반응",
"이온화", "화학적 흡착/탈착", "촉매 효율 변화", "효소 활성 변화", "발색 반응",
"pH 변화", "화학적 평형 이동", "결합 형성/분해", "용해도 변화"
],
"생물학적 변화": [
"성장/위축", "세포 분열/사멸", "생물 발광", "신진대사 변화", "면역 반응",
"호르몬 분비", "신경 반응", "유전적 발현", "적응/진화", "생체리듬 변화",
"재생/치유", "노화/성숙", "생체 모방 변화", "바이오필름 형성", "생물학적 분해",
"효소 활성화/비활성화", "생물학적 신호 전달", "스트레스 반응", "체온 조절", "생물학적 시계 변화",
"세포외 기질 변화", "생체 역학적 반응", "세포 운동성", "세포 극성 변화", "영양 상태 변화"
],
"환경 상호작용": [
"온도 반응", "습도 반응", "기압 반응", "중력 반응", "자기장 반응",
"빛 반응", "소리 반응", "화학 물질 감지", "기계적 자극 감지", "전기 자극 반응",
"방사선 반응", "진동 감지", "pH 반응", "용매 반응", "기체 교환",
"환경 오염 반응", "날씨 반응", "계절 반응", "일주기 반응", "생태계 상호작용",
"공생/경쟁 반응", "포식/피식 관계", "군집 형성", "영역 설정", "이주/정착 패턴"
],
"비즈니스 아이디어": [
"시장 재정의/신규 시장 개척",
"비즈니스 모델 혁신/디지털 전환",
"고객 경험 혁신/서비스 혁신",
"협력 및 파트너십 강화/생태계 구축",
"글로벌 확장/지역화 전략",
"운영 효율성 증대/원가 절감",
"브랜드 리포지셔닝/이미지 전환",
"지속 가능한 성장/사회적 가치 창출",
"데이터 기반 의사결정/AI 도입",
"신기술 융합/혁신 투자"
]
}
physical_transformation_categories_en = {
"Sensor Functions": [
"Visual sensor/detection", "Auditory sensor/detection", "Tactile sensor/detection", "Taste sensor/detection", "Olfactory sensor/detection",
"Temperature sensor/detection", "Humidity sensor/detection", "Pressure sensor/detection", "Acceleration sensor/detection", "Rotational sensor/detection",
"Proximity sensor/detection", "Position sensor/detection", "Motion sensor/detection", "Gas sensor/detection", "Infrared sensor/detection",
"Ultraviolet sensor/detection", "Radiation sensor/detection", "Magnetic sensor/detection", "Electric field sensor/detection", "Chemical sensor/detection",
"Biosignal sensor/detection", "Vibration sensor/detection", "Noise sensor/detection", "Light intensity sensor/detection", "Light wavelength sensor/detection",
"Tilt sensor/detection", "pH sensor/detection", "Current sensor/detection", "Voltage sensor/detection", "Image sensor/detection",
"Distance sensor/detection", "Depth sensor/detection", "Gravity sensor/detection", "Speed sensor/detection", "Flow sensor/detection",
"Water level sensor/detection", "Turbidity sensor/detection", "Salinity sensor/detection", "Metal detection", "Piezoelectric sensor/detection",
"Photovoltaic sensor/detection", "Thermocouple sensor/detection", "Hall effect sensor/detection", "Ultrasonic sensor/detection", "Radar sensor/detection",
"Lidar sensor/detection", "Touch sensor/detection", "Gesture sensor/detection", "Heart rate sensor/detection", "Blood pressure sensor/detection"
],
"Size and Shape Change": [
"Volume increase/decrease", "Length increase/decrease", "Width increase/decrease", "Height increase/decrease",
"Density change", "Weight increase/decrease", "Shape deformation", "State change", "Uneven deformation",
"Complex shape deformation", "Twisting/entwining", "Non-uniform expansion/contraction", "Rounded/sharpened edges",
"Cracking/splitting", "Fragmentation", "Water resistance", "Dust resistance", "Denting/recovery",
"Folding/unfolding", "Compression/expansion", "Stretching/contraction", "Wrinkling/flattening", "Crushing/hardening",
"Rolling/unrolling", "Bending/curving"
],
"Surface and Appearance Change": [
"Color change", "Texture change", "Transparency change", "Glossy/matte change",
"Light reflection variation", "Pattern change", "Angle-dependent color change", "Light-induced color change",
"Temperature-dependent color change", "Holographic effect", "Angle-specific light reflection", "Surface shape alteration",
"Nano-scale surface structure change", "Self-cleaning effect", "Stain/pattern formation", "Blurriness/clarity change",
"Luster/shine change", "Hue/saturation change", "Luminescence/fluorescence", "Light scattering effect",
"Light absorption change", "Translucency effect", "Shadow effect change", "UV response change",
"Glow effect"
],
"Material State Change": [
"Solid/liquid/gas transition", "Crystallization/dissolution", "Oxidation/corrosion", "Hardening/softening",
"Special state transition", "Amorphous/crystalline transition", "Component separation", "Particle formation/disintegration",
"Gel formation/dissolution", "Metastable state change", "Molecular self-assembly/disintegration", "Delayed state change",
"Melting", "Solidification", "Evaporation/condensation", "Sublimation/deposition", "Precipitation/suspension", "Dispersion/aggregation",
"Drying/moistening", "Swelling/shrinkage", "Freezing/thawing", "Weathering/erosion", "Charging/discharging",
"Bonding/separation", "Fermentation/decay"
],
"Movement Characteristics Change": [
"Acceleration/deceleration", "Maintaining constant speed", "Vibration/vibration reduction", "Collision/bouncing",
"Increase/decrease in rotational speed", "Change in rotational direction", "Irregular movement", "Stop-and-slide phenomenon",
"Resonance/anti-resonance", "Resistance/lift change in fluid", "Change in movement resistance", "Complex vibrational movement",
"Movement in special fluid", "Rotational-translational movement", "Inertial stoppage", "Shock absorption",
"Shock transfer", "Conservation of momentum", "Friction change", "Overcoming inertia", "Unstable equilibrium",
"Dynamic stability", "Damping of oscillation", "Path predictability", "Evasive movement"
],
"Structural Change": [
"Addition/removal of components", "Assembly/disassembly", "Folding/unfolding", "Deformation/recovery", "Optimal structural change",
"Self-rearrangement", "Natural pattern formation/disappearance", "Regular pattern change", "Modular transformation",
"Increased structural complexity", "Memory of original shape effect", "Shape change over time", "Partial removal",
"Partial replacement", "Bonding", "Separation", "Division/integration", "Overlaying", "Internal structure change",
"External structure change", "Shift of center axis", "Balance point change", "Hierarchical structure change", "Support structure change",
"Stress distribution structure", "Shock absorption structure", "Grid/matrix structure change", "Interconnectivity change"
],
"Spatial Movement": [
"Forward/backward movement", "Left/right movement", "Up/down movement", "Vertical axis rotation (nodding)",
"Horizontal axis rotation (shaking head)", "Longitudinal axis rotation (tilting sideways)", "Circular motion", "Spiral movement",
"Slipping due to inertia", "Change of rotation axis", "Irregular rotation", "Shaking movement", "Parabolic motion",
"Zero-gravity floating", "Floating on water surface", "Jump/leap", "Sliding", "Rolling", "Free fall",
"Reciprocating motion", "Elastic bouncing", "Penetration", "Evasive movement", "Zigzag movement", "Swinging movement"
],
"Time-Related Change": [
"Aging/weathering", "Wear/corrosion", "Fading/discoloration", "Damage/recovery", "Lifecycle change",
"Adaptation through user interaction", "Learning-based shape optimization", "Property change over time",
"Collective memory effect", "Cultural significance change", "Delayed response", "History-dependent change",
"Gradual time change", "Evolutionary change", "Periodic regeneration", "Seasonal adaptation",
"Circadian rhythm change", "Lifecycle stage", "Growth/decline", "Self-repair/regeneration",
"Natural cycle adaptation", "Persistence/transience", "Memory effect", "Delayed effect", "Cumulative effect"
],
"Light and Visual Effects": [
"Illumination/shutdown", "Light transmission/blocking", "Light scattering/concentration", "Color spectrum change", "Light diffraction",
"Light interference", "Hologram creation", "Laser effect", "Light polarization", "Fluorescence/phosphorescence",
"UV/IR emission", "Optical illusion", "Light refraction", "Shadow creation/removal",
"Chromatic aberration", "Rainbow effect", "Glow effect", "Flash effect", "Lighting pattern",
"Beam effect", "Light filter effect", "Change in light direction", "Projection effect", "Light detection/response",
"Luminance change"
],
"Sound and Vibration Effects": [
"Sound generation/cessation", "Pitch change", "Volume change", "Timbre change",
"Resonance/antiresonance", "Acoustic vibration", "Ultrasonic/infrasonic emission", "Sound concentration/distribution",
"Sound reflection/absorption", "Acoustic Doppler effect", "Sound wave interference", "Acoustic resonance",
"Vibration pattern change", "Percussive effect", "Audio feedback", "Sound shielding/amplification",
"Directional sound", "Sound distortion", "Beat generation", "Harmonics generation", "Frequency modulation",
"Acoustic shockwave", "Sound filtering"
],
"Thermal Changes": [
"Temperature rise/fall", "Thermal expansion/contraction", "Heat transfer/blocking", "Pressure increase/decrease",
"Magnetization due to heat change", "Entropy change", "Thermoelectric effect", "Magnetic-induced thermal change",
"Heat storage/release during phase change", "Thermal stress buildup/release", "Impact of rapid temperature change",
"Radiative cooling/heating", "Exothermic/endothermic", "Heat distribution change", "Heat reflection/absorption",
"Cooling condensation", "Thermal activation", "Thermal discoloration", "Coefficient of thermal expansion change", "Thermal stability change",
"Heat resistance/cold resistance", "Self-heating", "Thermal equilibrium/imbalance", "Thermal deformation", "Heat dispersion/concentration"
],
"Electrical and Magnetic Changes": [
"Magnetism creation/cessation", "Charge increase/decrease", "Electric field creation/cessation", "Magnetic field creation/cessation",
"Superconducting transition", "Ferroelectric property change", "Quantum state change", "Plasma formation/cessation",
"Spin wave transmission", "Electricity generation by light", "Electricity generation by pressure", "Current change in magnetic field",
"Electrical resistance change", "Electrical conductivity change", "Static electricity generation/discharge", "Electromagnetic induction",
"Electromagnetic wave emission/absorption", "Capacitance change", "Magnetic hysteresis", "Electrical polarization",
"Electron flow direction change", "Electrical resonance", "Electrical shielding/exposure", "Magnetic shielding/exposure",
"Magnetic field alignment"
],
"Chemical Change": [
"Surface coating change", "Material composition change", "Chemical reaction change", "Catalytic action start/stop",
"Light-induced chemical reaction", "Electricity-induced chemical reaction", "Monolayer formation", "Molecular-level structural change",
"Biomimetic surface change", "Environmentally responsive material change", "Periodic chemical reaction", "Oxidation", "Reduction",
"Polymerization", "Water splitting", "Compound formation", "Radiation effects", "Acid-base reaction", "Neutralization reaction",
"Ionization", "Chemical adsorption/desorption", "Catalytic efficiency change", "Enzyme activity change", "Colorimetric reaction",
"pH change", "Chemical equilibrium shift", "Bond formation/breakage", "Solubility change"
],
"Biological Change": [
"Growth/shrinkage", "Cell division/death", "Bioluminescence", "Metabolic change", "Immune response",
"Hormone secretion", "Neural response", "Genetic expression", "Adaptation/evolution", "Circadian rhythm change",
"Regeneration/healing", "Aging/maturation", "Biomimetic change", "Biofilm formation", "Biological degradation",
"Enzyme activation/inactivation", "Biological signaling", "Stress response", "Thermoregulation", "Biological clock change",
"Extracellular matrix change", "Biomechanical response", "Cell motility", "Cell polarity change", "Nutritional status change"
],
"Environmental Interaction": [
"Temperature response", "Humidity response", "Pressure response", "Gravity response", "Magnetic field response",
"Light response", "Sound response", "Chemical detection", "Mechanical stimulus detection", "Electrical stimulus response",
"Radiation response", "Vibration detection", "pH response", "Solvent response", "Gas exchange",
"Pollution response", "Weather response", "Seasonal response", "Circadian response", "Ecosystem interaction",
"Symbiotic/competitive interaction", "Predator/prey relationship", "Swarm formation", "Territorial behavior", "Migration/settlement pattern"
],
"Business Ideas": [
"Market redefinition / New market creation",
"Business model innovation / Digital transformation",
"Customer experience innovation / Service innovation",
"Strengthened collaboration and partnerships / Ecosystem building",
"Global expansion / Localization strategy",
"Increased operational efficiency / Cost reduction",
"Brand repositioning / Image transformation",
"Sustainable growth / Social value creation",
"Data-driven decision making / AI adoption",
"Convergence of new technologies / Innovative investments"
]
}
# ──────────────────────────────── Logging ────────────────────────────────
logging.basicConfig(level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s")
# ──────────────────────────────── OpenAI Client ──────────────────────────
@st.cache_resource
def get_openai_client():
"""Create an OpenAI client with timeout and retry settings."""
if not OPENAI_API_KEY:
raise RuntimeError("⚠️ OPENAI_API_KEY 환경 변수가 설정되지 않았습니다.")
return OpenAI(
api_key=OPENAI_API_KEY,
timeout=60.0, # 타임아웃 60초로 설정
max_retries=3 # 재시도 횟수 3회로 설정
)
# ──────────────────────────────── New System Prompt for Idea Generation ─────────────────────
# ───────────────── System Prompt (REPORT STYLE) ─────────────────
def get_idea_system_prompt(selected_category: str | None = None) -> str:
"""
새로운 CCM(크로스 카테고리 매트릭스) 방법론을 적용한 시스템 프롬프트
"""
cat_clause = (
f'\n**추가 지침**: 선택된 카테고리 "{selected_category}"에 특별한 주의를 기울이십시오. '
f'이 카테고리의 항목들을 2단계와 3단계 모두에서 우선적으로 고려하십시오.\n'
) if selected_category else ""
prompt = f"""
반드시 한글(한국어)로 답변하라. 당신은 혁신 컨설턴트로서 CCM(크로스 카테고리 매트릭스) 방법론을 활용하여 창의적 아이디어를 도출합니다.
### CCM 방법론 프로세스
다음 단계를 통해 체계적으로 아이디어를 도출하십시오:
1. **문제 분석 및 지식 베이스 구축**
- 입력된 프롬프트의 요구사항을 명확히 정의하고 핵심 니즈 추출
- 웹검색 결과를 분석하여 관련 트렌드, 기술, 사례 파악
- 문제 해결에 필요한 핵심 기능과 속성 식별
2. **카테고리별 적합성 매핑**
- 모든 카테고리에서 문제 해결에 적합한 항목들을 식별
- 각 카테고리별로 최소 1개 이상의 관련 항목 선정
- 선정 항목과 문제 간의 연결성 설명
3. **랜덤 크로스 매트릭스 생성**
- 16개 카테고리 중 6개를 무작위로 선정
- 선정된 각 카테고리에서 1개 항목을 추출
- 이 6개 항목을 조합하여 통합적 솔루션 도출
### 출력 형식
최종 보고서를 다음 구조로 마크다운 형식으로 작성하십시오:
## 1️⃣ 문제 분석 및 지식 베이스
- **문제 정의**: [프롬프트 핵심 요구사항 요약]
- **핵심 니즈**: [불릿 3-5개로 주요 니즈 리스트]
- **현황 분석**: [웹검색이나 배경지식 기반 현재 상황 요약]
## 2️⃣ 카테고리별 적합성 매핑
[각 카테고리별로 가장 적합한 항목들을 표 형식으로 정리]
| 카테고리 | 적합 항목 | 연결성 |
|---------|----------|--------|
| [카테고리1] | [선정 항목] | [문제와의 연결성 설명] |
| [카테고리2] | [선정 항목] | [문제와의 연결성 설명] |
... (최소 5개 카테고리)
## 3️⃣ CCM 통합 솔루션
### 랜덤 선정 카테고리/항목
[무작위 선정된 6개 카테고리와 항목을 표로 정리]
| 선정 카테고리 | 선정 항목 |
|--------------|----------|
| [카테고리1] | [항목1] |
| [카테고리2] | [항목2] |
...
### 최종 아이디어: [아이디어 제목]
- **개념 요약**: [2-3문장으로 핵심 아이디어 설명]
- **상세 설명**: [3-4 문단으로 아이디어 구체화]
- **구현 방식**: [아이디어 실현을 위한 단계/방법]
- **차별화 요소**: [선정된 6개 항목이 어떻게 시너지를 내는지 설명]
### 기대 효과
- [불릿 포인트로 3-5개 주요 기대효과 나열]
### 한계 및 도전 과제
- [불릿 포인트로 2-3개 잠재적 한계/도전 제시]
### 이미지 프롬프트
[아이디어를 시각화할 수 있는 영문 이미지 프롬프트 1줄]
{cat_clause}
Step-by-step 사고 과정을 따르되, 출력에는 최종 보고서만 표시하십시오.
"""
return prompt.strip()
# ──────────────────────────────── Brave Search API ────────────────────────
@st.cache_data(ttl=3600)
def brave_search(query: str, count: int = 20):
"""
Call the Brave Web Search API → list[dict]
Returns fields: index, title, link, snippet, displayed_link
"""
if not BRAVE_KEY:
raise RuntimeError("⚠️ SERPHOUSE_API_KEY (Brave API Key) 환경 변수가 비어있습니다.")
headers = {
"Accept": "application/json",
"Accept-Encoding": "gzip",
"X-Subscription-Token": BRAVE_KEY
}
params = {"q": query, "count": str(count)}
for attempt in range(3):
try:
r = requests.get(BRAVE_ENDPOINT, headers=headers, params=params, timeout=15)
r.raise_for_status()
data = r.json()
logging.info(f"Brave search result data structure: {list(data.keys())}")
raw = data.get("web", {}).get("results") or data.get("results", [])
if not raw:
logging.warning(f"No Brave search results found. Response: {data}")
raise ValueError("No search results found.")
arts = []
for i, res in enumerate(raw[:count], 1):
url = res.get("url", res.get("link", ""))
host = re.sub(r"https?://(www\.)?", "", url).split("/")[0]
arts.append({
"index": i,
"title": res.get("title", "No title"),
"link": url,
"snippet": res.get("description", res.get("text", "No snippet")),
"displayed_link": host
})
logging.info(f"Brave search success: {len(arts)} results")
return arts
except Exception as e:
logging.error(f"Brave search failure (attempt {attempt+1}/3): {e}")
if attempt < 2:
time.sleep(2)
return []
def mock_results(query: str) -> str:
"""Fallback if search API fails"""
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return (f"# Fallback Search Content (Generated: {ts})\n\n"
f"The web search API request failed. Please generate the ideas based on general knowledge about '{query}'.\n\n"
f"You may consider aspects such as:\n\n"
f"- Basic definition or concept of {query}\n"
f"- Commonly known facts or challenges\n"
f"- Potential categories from the transformation list\n\n"
f"Note: This is fallback guidance, not real-time data.\n\n")
def do_web_search(query: str) -> str:
"""Perform web search and format the results."""
try:
arts = brave_search(query, 20)
if not arts:
logging.warning("No search results, using fallback content")
return mock_results(query)
hdr = "# Web Search Results\nUse the information below to inspire or validate your ideas.\n\n"
body = "\n".join(
f"### Result {a['index']}: {a['title']}\n\n{a['snippet']}\n\n"
f"**Source**: [{a['displayed_link']}]({a['link']})\n\n---\n"
for a in arts
)
return hdr + body
except Exception as e:
logging.error(f"Web search process failed: {str(e)}")
return mock_results(query)
# ──────────────────────────────── File Upload Handling ─────────────────────
def process_text_file(file):
"""Handle text file"""
try:
content = file.read()
file.seek(0)
text = content.decode('utf-8', errors='ignore')
if len(text) > 10000:
text = text[:9700] + "...(truncated)..."
result = f"## Text File: {file.name}\n\n"
result += text
return result
except Exception as e:
logging.error(f"Error processing text file: {str(e)}")
return f"Error processing text file: {str(e)}"
def process_csv_file(file):
"""Handle CSV file"""
try:
content = file.read()
file.seek(0)
df = pd.read_csv(io.BytesIO(content))
result = f"## CSV File: {file.name}\n\n"
result += f"- Rows: {len(df)}\n"
result += f"- Columns: {len(df.columns)}\n"
result += f"- Column Names: {', '.join(df.columns.tolist())}\n\n"
result += "### Data Preview\n\n"
preview_df = df.head(10)
try:
markdown_table = preview_df.to_markdown(index=False)
if markdown_table:
result += markdown_table + "\n\n"
else:
result += "Unable to display CSV data.\n\n"
except Exception as e:
logging.error(f"Markdown table conversion error: {e}")
result += "Displaying data as text:\n\n"
result += str(preview_df) + "\n\n"
num_cols = df.select_dtypes(include=['number']).columns
if len(num_cols) > 0:
result += "### Basic Statistical Information\n\n"
try:
stats_df = df[num_cols].describe().round(2)
stats_markdown = stats_df.to_markdown()
if stats_markdown:
result += stats_markdown + "\n\n"
else:
result += "Unable to display statistical information.\n\n"
except Exception as e:
logging.error(f"Statistical info conversion error: {e}")
result += "Unable to generate statistical information.\n\n"
return result
except Exception as e:
logging.error(f"CSV file processing error: {str(e)}")
return f"Error processing CSV file: {str(e)}"
def process_pdf_file(file):
"""Handle PDF file"""
try:
file_bytes = file.read()
file.seek(0)
pdf_file = io.BytesIO(file_bytes)
reader = PyPDF2.PdfReader(pdf_file, strict=False)
result = f"## PDF File: {file.name}\n\n"
result += f"- Total pages: {len(reader.pages)}\n\n"
max_pages = min(5, len(reader.pages))
all_text = ""
for i in range(max_pages):
try:
page = reader.pages[i]
page_text = page.extract_text()
current_page_text = f"### Page {i+1}\n\n"
if page_text and len(page_text.strip()) > 0:
if len(page_text) > 1500:
current_page_text += page_text[:1500] + "...(truncated)...\n\n"
else:
current_page_text += page_text + "\n\n"
else:
current_page_text += "(No text could be extracted)\n\n"
all_text += current_page_text
if len(all_text) > 8000:
all_text += "...(truncating remaining pages; PDF is too large)...\n\n"
break
except Exception as page_err:
logging.error(f"Error processing PDF page {i+1}: {str(page_err)}")
all_text += f"### Page {i+1}\n\n(Error extracting content: {str(page_err)})\n\n"
if len(reader.pages) > max_pages:
all_text += f"\nNote: Only the first {max_pages} pages are shown out of {len(reader.pages)} total.\n\n"
result += "### PDF Content\n\n" + all_text
return result
except Exception as e:
logging.error(f"PDF file processing error: {str(e)}")
return f"## PDF File: {file.name}\n\nError occurred: {str(e)}\n\nThis PDF file cannot be processed."
def process_uploaded_files(files):
"""Combine the contents of all uploaded files into one string."""
if not files:
return None
result = "# Uploaded File Contents\n\n"
result += "Below is the content from the files provided by the user. Integrate this data as needed for generating ideas.\n\n"
for file in files:
try:
ext = file.name.split('.')[-1].lower()
if ext == 'txt':
result += process_text_file(file) + "\n\n---\n\n"
elif ext == 'csv':
result += process_csv_file(file) + "\n\n---\n\n"
elif ext == 'pdf':
result += process_pdf_file(file) + "\n\n---\n\n"
else:
result += f"### Unsupported File: {file.name}\n\n---\n\n"
except Exception as e:
logging.error(f"File processing error {file.name}: {e}")
result += f"### File processing error: {file.name}\n\nError: {e}\n\n---\n\n"
return result
# ──────────────────────────────── Image & Utility ─────────────────────────
def generate_image(prompt, w=768, h=768, g=3.5, steps=30, seed=3):
"""Image generation function."""
if not prompt:
return None, "Insufficient prompt"
try:
res = Client(IMAGE_API_URL).predict(
prompt=prompt, width=w, height=h, guidance=g,
inference_steps=steps, seed=seed,
do_img2img=False, init_image=None,
image2image_strength=0.8, resize_img=True,
api_name="/generate_image"
)
return res[0], f"Seed: {res[1]}"
except Exception as e:
logging.error(e)
return None, str(e)
def md_to_html(md: str, title="Idea Output"):
"""Convert Markdown to HTML."""
return f"<!DOCTYPE html><html><head><title>{title}</title><meta charset='utf-8'></head><body>{markdown.markdown(md)}</body></html>"
def keywords(text: str, top=5):
"""Simple keyword extraction (for web search)."""
cleaned = re.sub(r"[^가-힣a-zA-Z0-9\s]", "", text)
return " ".join(cleaned.split()[:top])
# ──────────────────────────────── Streamlit UI ────────────────────────────
def idea_generator_app():
st.title("Creative Idea Generator")
# Set default session state
if "ai_model" not in st.session_state:
st.session_state.ai_model = "gpt-4.1-mini"
if "messages" not in st.session_state:
st.session_state.messages = []
if "auto_save" not in st.session_state:
st.session_state.auto_save = True
if "generate_image" not in st.session_state:
st.session_state.generate_image = True # 기본값: True
if "web_search_enabled" not in st.session_state:
st.session_state.web_search_enabled = True
# Sidebar UI
sb = st.sidebar
sb.title("Idea Generator Settings")
sb.toggle("Auto Save", key="auto_save")
sb.toggle("Auto Image Generation", key="generate_image")
web_search_enabled = sb.toggle("Use Web Search", value=st.session_state.web_search_enabled)
st.session_state.web_search_enabled = web_search_enabled
if web_search_enabled:
sb.info("✅ Web search results will be integrated.")
# 예시 주제들 (원래 예시 블로그 토픽 -> 이제는 예시 아이디어 주제로 전환)
example_topics = {
"example1": "도시 물 부족 문제 해결을 위한 혁신적 방안",
"example2": "노인 돌봄 서비스의 디지털 전환",
"example3": "지속가능한 식품 포장 솔루션"
}
sb.subheader("Category Focus (Optional)")
category_keys = ["(None)"] + list(physical_transformation_categories.keys())
sb.selectbox(
"Generate ideas mainly using this category",
options=category_keys,
key="category_focus",
index=0 # 기본값 "(None)"
)
sb.subheader("Example Prompts")
c1, c2, c3 = sb.columns(3)
if c1.button("도시 물 부족 문제", key="ex1"):
process_example(example_topics["example1"])
if c2.button("노인 돌봄 서비스", key="ex2"):
process_example(example_topics["example2"])
if c3.button("지속가능한 식품 포장", key="ex3"):
process_example(example_topics["example3"])
# Download the latest ideas
latest_ideas = next(
(m["content"] for m in reversed(st.session_state.messages)
if m["role"] == "assistant" and m["content"].strip()),
None
)
if latest_ideas:
title_match = re.search(r"# (.*?)(\n|$)", latest_ideas)
title = title_match.group(1).strip() if title_match else "ideas"
sb.subheader("Download Latest Ideas")
d1, d2 = sb.columns(2)
d1.download_button("Download as Markdown", latest_ideas,
file_name=f"{title}.md", mime="text/markdown")
d2.download_button("Download as HTML", md_to_html(latest_ideas, title),
file_name=f"{title}.html", mime="text/html")
# JSON conversation record upload
up = sb.file_uploader("Load Conversation History (.json)", type=["json"], key="json_uploader")
if up:
try:
st.session_state.messages = json.load(up)
sb.success("Conversation history loaded successfully")
except Exception as e:
sb.error(f"Failed to load: {e}")
# JSON conversation record download
if sb.button("Download Conversation as JSON"):
sb.download_button(
"Save JSON",
data=json.dumps(st.session_state.messages, ensure_ascii=False, indent=2),
file_name="chat_history.json",
mime="application/json"
)
# File Upload
st.subheader("File Upload (Optional)")
uploaded_files = st.file_uploader(
"Upload files to reference in the idea generation (txt, csv, pdf)",
type=["txt", "csv", "pdf"],
accept_multiple_files=True,
key="file_uploader"
)
if uploaded_files:
file_count = len(uploaded_files)
st.success(f"{file_count} files uploaded.")
with st.expander("Preview Uploaded Files", expanded=False):
for idx, file in enumerate(uploaded_files):
st.write(f"**File Name:** {file.name}")
ext = file.name.split('.')[-1].lower()
if ext == 'txt':
preview = file.read(1000).decode('utf-8', errors='ignore')
file.seek(0)
st.text_area(
f"Preview of {file.name}",
preview + ("..." if len(preview) >= 1000 else ""),
height=150
)
elif ext == 'csv':
try:
df = pd.read_csv(file)
file.seek(0)
st.write("CSV Preview (up to 5 rows)")
st.dataframe(df.head(5))
except Exception as e:
st.error(f"CSV preview failed: {e}")
elif ext == 'pdf':
try:
file_bytes = file.read()
file.seek(0)
pdf_file = io.BytesIO(file_bytes)
reader = PyPDF2.PdfReader(pdf_file, strict=False)
pc = len(reader.pages)
st.write(f"PDF File: {pc} pages")
if pc > 0:
try:
page_text = reader.pages[0].extract_text()
preview = page_text[:500] if page_text else "(No text)"
st.text_area("Preview of the first page", preview + "...", height=150)
except:
st.warning("Failed to extract text from the first page")
except Exception as e:
st.error(f"PDF preview failed: {e}")
if idx < file_count - 1:
st.divider()
# Display existing messages in chat
for m in st.session_state.messages:
with st.chat_message(m["role"]):
st.markdown(m["content"])
if "image" in m:
st.image(m["image"], caption=m.get("image_caption", ""))
# User input for idea generation
prompt = st.chat_input("Enter a topic or concept to generate 3 new ideas.")
if prompt:
process_input(prompt, uploaded_files)
# Sidebar footer
sb.markdown("---")
sb.markdown("Created by [Ginigen.com](https://ginigen.com) | [YouTube](https://www.youtube.com/@ginipickaistudio)")
def process_example(topic):
"""Handle example prompts."""
process_input(topic, [])
# ── 수정된 process_input 전체 ────────────────────────────────────────────
# ── 수정된 process_input (중복 출력 제거 + 카테고리 DB 전달 + 이미지 프롬프트 통합) ──
def process_input(prompt: str, uploaded_files):
"""
1. 사용자 메시지 기록 및 UI 출력
2. 웹검색·파일내용·카테고리 DB를 포함한 GPT 호출
3. 최종 응답 스트리밍, 이미지 생성(선택), 결과 저장·다운로드(1회만)
"""
# ── 사용자 메시지 저장 ───────────────────────────────────────────────
if not any(m["role"] == "user" and m["content"] == prompt
for m in st.session_state.messages):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# ── 어시스턴트 응답 영역 ────────────────────────────────────────────
with st.chat_message("assistant"):
placeholder = st.empty()
message_placeholder = st.empty()
full_response = ""
use_web_search = st.session_state.web_search_enabled
has_uploaded = bool(uploaded_files)
try:
# ① 모델 초기화
status = st.status("Preparing to generate ideas…")
status.update(label="Initializing model…")
client = get_openai_client()
# ② 시스템 프롬프트 + 카테고리 DB
selected_cat = st.session_state.get("category_focus", "(None)")
if selected_cat == "(None)":
selected_cat = None
sys_prompt = get_idea_system_prompt(selected_category=selected_cat)
def category_context(sel):
if sel:
return json.dumps({sel: physical_transformation_categories[sel]},
ensure_ascii=False)
return "ALL_CATEGORIES: " + ", ".join(physical_transformation_categories.keys())
# ③ (선택) 웹 검색 · 파일 처리
search_content = None
if use_web_search:
status.update(label="Searching the web…")
with st.spinner("Searching…"):
search_content = do_web_search(keywords(prompt, top=5))
file_content = None
if has_uploaded:
status.update(label="Reading uploaded files…")
with st.spinner("Processing files…"):
file_content = process_uploaded_files(uploaded_files)
# ④ 사용자 메시지 결합
user_content = prompt
if search_content:
user_content += "\n\n" + search_content
if file_content:
user_content += "\n\n" + file_content
api_messages = [
{"role": "system", "content": sys_prompt},
{"role": "system", "name": "category_db",
"content": category_context(selected_cat)},
{"role": "user", "content": user_content},
]
# ⑤ GPT 스트리밍 호출
status.update(label="Generating ideas…")
stream = client.chat.completions.create(
model="gpt-4.1-mini",
messages=api_messages,
temperature=1,
max_tokens=MAX_TOKENS,
top_p=1,
stream=True
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
full_response += chunk.choices[0].delta.content
message_placeholder.markdown(full_response + "▌")
message_placeholder.markdown(full_response)
status.update(label="Ideas created!", state="complete")
# ⑥ 이미지 생성 (CCM 헤딩 or 레거시 패턴 자동 탐지)
if st.session_state.generate_image and full_response:
ccm_match = re.search(r"###\s*이미지\s*프롬프트\s*\n+([^\n]+)",
full_response, flags=re.IGNORECASE)
legacy_match = None
if not ccm_match:
legacy_match = re.search(
r"\|\s*(?:\*\*)?Image\s+Prompt(?:\*\*)?\s*\|\s*([^|\n]+)",
full_response, flags=re.IGNORECASE) \
or re.search(r"(?i)Image\s+Prompt\s*[:\-]\s*([^\n]+)",
full_response)
match = ccm_match or legacy_match
if match:
raw_prompt = re.sub(r"[\r\n`\"'\\]", " ", match.group(1)).strip()
with st.spinner("아이디어 이미지 생성 중…"):
img, cap = generate_image(raw_prompt)
if img:
st.image(img, caption=f"아이디어 시각화 – {cap}")
st.session_state.messages.append({
"role": "assistant",
"content": "",
"image": img,
"image_caption": f"아이디어 시각화 – {cap}"
})
# ⑦ 결과를 한 번만 저장·다운로드·자동백업
write_output(full_response, prompt)
# ── 예외 처리 (중복 출력 방지) ──────────────────────────────────
except Exception as e:
err = str(e)
placeholder.error(f"⚠️ Error: {err}")
logging.error(err)
st.session_state.messages.append({
"role": "assistant",
"content": f"⚠️ 작업 중 오류가 발생했습니다: {err}"
})
# ---- 카테고리/하위항목 컨텍스트 추가 ---------------------------
def category_context(sel):
if sel: # 특정 카테고리 선택 시
return json.dumps(
{sel: physical_transformation_categories[sel]},
ensure_ascii=False)
# (None) → 키 목록만 전달
return "ALL_CATEGORIES: " + ", ".join(
physical_transformation_categories.keys())
api_messages = [
{"role": "system", "content": sys_prompt},
{"role": "system", "name": "category_db",
"content": category_context(selected_cat)},
{"role": "user", "content": user_content},
]
# --------------------------------------------------------------
# ④ OpenAI 스트리밍 호출
status.update(label="Generating ideas…")
stream = client.chat.completions.create(
model="gpt-4.1-mini",
messages=api_messages,
temperature=1, max_tokens=MAX_TOKENS,
top_p=1, stream=True
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
full_response += chunk.choices[0].delta.content
message_placeholder.markdown(full_response + "▌")
message_placeholder.markdown(full_response)
status.update(label="Ideas created!", state="complete")
# ⑤ 이미지 생성 (CCM 헤딩 or 레거시 패턴 모두 지원)
if st.session_state.generate_image and full_response:
# CCM 헤딩
ccm_match = re.search(
r"###\s*이미지\s*프롬프트\s*\n+([^\n]+)",
full_response, flags=re.IGNORECASE)
legacy_match = None
if not ccm_match:
legacy_match = re.search(
r"\|\s*(?:\*\*)?Image\s+Prompt(?:\*\*)?\s*\|\s*([^|\n]+)",
full_response, flags=re.IGNORECASE) \
or re.search(r"(?i)Image\s+Prompt\s*[:\-]\s*([^\n]+)",
full_response)
match = ccm_match or legacy_match
if match:
raw_prompt = re.sub(r"[\r\n`\"'\\]", " ",
match.group(1)).strip()
with st.spinner("아이디어 이미지 생성 중…"):
img, cap = generate_image(raw_prompt)
if img:
st.image(img, caption=f"아이디어 시각화 – {cap}")
st.session_state.messages.append({
"role": "assistant",
"content": "",
"image": img,
"image_caption": f"아이디어 시각화 – {cap}"
})
# ── 헬퍼: 결과를 한 번만 기록·다운로드·저장 ─────────────────────────────
def write_output(md_text: str, prompt: str):
# ① 채팅 기록 저장
st.session_state.messages.append({"role": "assistant", "content": md_text})
# ② 다운로드 버튼
st.subheader("Download This Output")
col_md, col_html = st.columns(2)
col_md.download_button("Markdown", md_text,
file_name=f"{prompt[:30]}.md", mime="text/markdown")
col_html.download_button("HTML", md_to_html(md_text, prompt[:30]),
file_name=f"{prompt[:30]}.html", mime="text/html")
# ③ JSON 자동 저장
if st.session_state.auto_save:
fn = f"chat_history_auto_{datetime.now():%Y%m%d_%H%M%S}.json"
with open(fn, "w", encoding="utf-8") as fp:
json.dump(st.session_state.messages, fp, ensure_ascii=False, indent=2)
except Exception as e:
err = str(e)
placeholder.error(f"Error: {err}")
logging.error(err)
st.session_state.messages.append({
"role": "assistant",
"content": f"⚠️ 작업 중 오류가 발생했습니다: {err}"
})
# Download buttons
if full_response:
st.subheader("Download This Output")
c1, c2 = st.columns(2)
c1.download_button(
"Markdown",
data=full_response,
file_name=f"{prompt[:30]}.md",
mime="text/markdown"
)
c2.download_button(
"HTML",
data=md_to_html(full_response, prompt[:30]),
file_name=f"{prompt[:30]}.html",
mime="text/html"
)
# Auto-save
if st.session_state.auto_save and st.session_state.messages:
try:
fn = f"chat_history_auto_{datetime.now():%Y%m%d_%H%M%S}.json"
with open(fn, "w", encoding="utf-8") as fp:
json.dump(st.session_state.messages, fp, ensure_ascii=False, indent=2)
except Exception as e:
logging.error(f"Auto-save failed: {e}")
except Exception as e:
error_message = str(e)
placeholder.error(f"An error occurred: {error_message}")
logging.error(f"Process input error: {error_message}")
ans = f"An error occurred while processing your request: {error_message}"
st.session_state.messages.append({"role": "assistant", "content": ans})
# ──────────────────────────────── main ────────────────────────────────────
def main():
idea_generator_app()
if __name__ == "__main__":
main()
|