From 9c2d8dc9b257cbadb30f9b275ea1cbf7b1a5030a Mon Sep 17 00:00:00 2001 From: Minseo-Jo Date: Wed, 29 Oct 2025 16:14:32 +0900 Subject: [PATCH] =?UTF-8?q?AI=20=EC=A0=9C=EC=95=88=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EC=B6=94=EC=B6=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20API=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ClaudeService에 analyze_suggestions 메서드 추가 - 개선된 제안사항 추출 프롬프트 생성 (구체적이고 실행 가능한 제안사항) - API 경로 수정: /api/v1/ai/suggestions → /api/ai/suggestions - 프론트엔드 HTML API 경로 업데이트 (v1 제거) - RealtimeSuggestionsResponse 모델 export 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ai-python/__pycache__/main.cpython-313.pyc | Bin 1862 -> 1862 bytes .../app/__pycache__/__init__.cpython-313.pyc | Bin 216 -> 216 bytes .../app/__pycache__/config.cpython-313.pyc | Bin 2523 -> 2523 bytes .../api/__pycache__/__init__.cpython-313.pyc | Bin 180 -> 180 bytes ai-python/app/api/v1/__init__.py | 2 + .../v1/__pycache__/__init__.cpython-313.pyc | Bin 437 -> 581 bytes .../__pycache__/suggestions.cpython-313.pyc | Bin 5575 -> 5575 bytes .../__pycache__/transcripts.cpython-313.pyc | Bin 2481 -> 2481 bytes ai-python/app/models/__init__.py | 6 ++ .../__pycache__/__init__.cpython-313.pyc | Bin 375 -> 502 bytes .../__pycache__/response.cpython-313.pyc | Bin 2172 -> 2172 bytes .../__pycache__/transcript.cpython-313.pyc | Bin 3511 -> 3617 bytes .../consolidate_prompt.cpython-313.pyc | Bin 3423 -> 4671 bytes ai-python/app/prompts/suggestions_prompt.py | 72 ++++++++++++++++++ .../__pycache__/__init__.cpython-313.pyc | Bin 191 -> 191 bytes .../claude_service.cpython-313.pyc | Bin 4053 -> 5885 bytes .../__pycache__/redis_service.cpython-313.pyc | Bin 5361 -> 5361 bytes .../transcript_service.cpython-313.pyc | Bin 4717 -> 5300 bytes ai-python/app/services/claude_service.py | 49 ++++++++++++ test-audio/stt-test-ai.html | 4 +- test-audio/stt-test-wav.html | 2 +- 21 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 ai-python/app/prompts/suggestions_prompt.py diff --git a/ai-python/__pycache__/main.cpython-313.pyc b/ai-python/__pycache__/main.cpython-313.pyc index 4f0d34fa240150ecc4085fa40232271d143960e6..f86462a8e2c1341fa8fced3b02f24ad91721a9aa 100644 GIT binary patch delta 19 ZcmX@ccZ`qgGcPX}0}yoY-pFOc4gfc#1r7iJ delta 19 ZcmX@ccZ`qgGcPX}0}$9nZ{)IJ2LLnn1YrOG diff --git a/ai-python/app/__pycache__/__init__.cpython-313.pyc b/ai-python/app/__pycache__/__init__.cpython-313.pyc index c84f132c5e7ba30577cbb3b4444c183c21497767..0c780e2229f28d7935450fee924111ae608bb896 100644 GIT binary patch delta 18 Ycmcb?c!QDaGcPX}0}$lyp2&3$05bLkWdHyG delta 18 Ycmcb?c!QDaGcPX}0}${=PvklW056sVr2qf` diff --git a/ai-python/app/__pycache__/config.cpython-313.pyc b/ai-python/app/__pycache__/config.cpython-313.pyc index 1f295f0d4a2af4154de66b49d133c5bdf18abcee..24fa9a1bdc0fb6bc08e8bb129a288a39f63e5a31 100644 GIT binary patch delta 29 jcmcaDd|R07GcPX}0}yoY-pIwn%wk|>WUyI^`5+qrc<2Xl delta 29 jcmcaDd|R07GcPX}0}$9nZ{*@(W-&A{GTJP~e2@(QZe0e! diff --git a/ai-python/app/api/__pycache__/__init__.cpython-313.pyc b/ai-python/app/api/__pycache__/__init__.cpython-313.pyc index 27e7bd315b29a2c28b188a5635030f686c01e640..aaf83d5a8b2c365529ac2bfd8c73fd7bdf2e107a 100644 GIT binary patch delta 18 YcmdnOxP_7HGcPX}0}$lyp2)Qd04@py`2YX_ delta 18 YcmdnOxP_7HGcPX}0}${=Pvlw!04k~kIRF3v diff --git a/ai-python/app/api/v1/__init__.py b/ai-python/app/api/v1/__init__.py index cf5f171..b5b6d39 100644 --- a/ai-python/app/api/v1/__init__.py +++ b/ai-python/app/api/v1/__init__.py @@ -1,8 +1,10 @@ """API v1 Router""" from fastapi import APIRouter from .transcripts import router as transcripts_router +from .suggestions import router as suggestions_router router = APIRouter() # 라우터 등록 router.include_router(transcripts_router, prefix="/transcripts", tags=["Transcripts"]) +router.include_router(suggestions_router, prefix="/ai/suggestions", tags=["AI Suggestions"]) diff --git a/ai-python/app/api/v1/__pycache__/__init__.cpython-313.pyc b/ai-python/app/api/v1/__pycache__/__init__.cpython-313.pyc index 09b89a509c2907be8f0b9af7502a37bef8e9eaa6..82f3c7745ea792acc74c1a471c402fb5a9fa8d9b 100644 GIT binary patch delta 242 zcmdnWe3XUnGcPX}0}#C1%a~ciIFV0+v1y{ZqFgX@FpD>v7fTVl0z(Xw5`!s74GUI(Mt?5MIgrl0Haep%K!iX delta 107 zcmX@gvXzk4g^IkF)Ts66Vnt}(m6Ca zC$5WT_S0matjlOOxrZ@ILJ+8e5r~WRfy4)9Mn=Y)48nIAWG6E+DRNw52rJ?TiUR>#L1g-!8 diff --git a/ai-python/app/models/__init__.py b/ai-python/app/models/__init__.py index a8b9a1b..0863f5d 100644 --- a/ai-python/app/models/__init__.py +++ b/ai-python/app/models/__init__.py @@ -6,6 +6,10 @@ from .transcript import ( ParticipantMinutes, ExtractedTodo ) +from .response import ( + SimpleSuggestion, + RealtimeSuggestionsResponse +) __all__ = [ "ConsolidateRequest", @@ -13,4 +17,6 @@ __all__ = [ "AgendaSummary", "ParticipantMinutes", "ExtractedTodo", + "SimpleSuggestion", + "RealtimeSuggestionsResponse", ] diff --git a/ai-python/app/models/__pycache__/__init__.cpython-313.pyc b/ai-python/app/models/__pycache__/__init__.cpython-313.pyc index ed1e908cbe26b8d2cb39b6388cc79b6efb9d9825..5d30b7f045648fae0d99a82170be99bcc86df33f 100644 GIT binary patch delta 199 zcmey)^o^PKGcPX}0}%A>W6WGXkynz@W}>>POfX|Gvp2gJM-hh?XA!3YgFZtrOCVzr zS30XE+r)@`V@;-80>PQN1v#m~rRnLZ#U+{fdAFp4QWJAZGINo{ii1*%3-a@dQ#IKq z-k0Pp;sDxI#0ez)G`T09(ih+;g33c>CVmY!5Clpy0&%e%kodsN$jEq;LGU{h8za+K X1|adBkC~C_6Bh?JQzLs3KTrt(xJEQe delta 82 zcmeyy{GEySGcPX}0}$9nGiItx%l;@KG8#hxUdl3&%2ms*%5N!Ye diff --git a/ai-python/app/models/__pycache__/response.cpython-313.pyc b/ai-python/app/models/__pycache__/response.cpython-313.pyc index e2cc2c15840d689458beea7f3ecc1a34619c063e..87af357538b0d5f681421389d09399b9f5c00106 100644 GIT binary patch delta 19 Zcmew(@JE2_GcPX}0}$ly-pEzN0RTTa1(yH- delta 19 Zcmew(@JE2_GcPX}0}${=Z{#ZC0027~1lIrn diff --git a/ai-python/app/models/__pycache__/transcript.cpython-313.pyc b/ai-python/app/models/__pycache__/transcript.cpython-313.pyc index 63d57343a4e4c8da93b8eb21cac5ac9ea93a77fa..28e6f240deecf6e844632d5d4a80780d7b109337 100644 GIT binary patch delta 584 zcmdlky-3`ek_I*<+)DiTT;))bli zlD)8A2Poj^sqm(G?wgj43U8J#e>1m1;mxcmZ>H{5&@gI2Ufj>()I$kvC0i z-cDVs{c6*OHw&ghI64YI`i;h{m0-g=W&kA=UTtW2-L+Kn7CY3AQeL3xuQzXby>!Op zRU8VFpK};73QzvWB0t%Z(}GcL@_IIj$^D#sjOCN(aT?0TU6hP(@SR|MnI-)J)>?nat1bIJuY0E}9(}5|eK&4QLUo3VQ$lQThjiou$AUvJ*>dMVIM zu&&8WoW_hIll6JzCx>!cu$cli6sb*K&n7W>87CiO_vEddhK6nzCEXi*Cm3I5ala`h zJ;QlL{6#U_2CoUsmsxCYN-Jy-IbeTLI=I2Jqhx|}XXRy<;K|HfK8$-N2XNIzamDaM z1A+%0OaehlKx@!IFfTahgkl7MLCOyfGy!0s32F-65_Sf8F5 zzOIhdk>BVW#__muwf=-b|IM84Fg4%{hZadtL z38%ZAnNEWwi~M7D5(e2z=_ zMUuwjLGoo+*Kt~?$gMcySIamUK=KSJW?7cPFq_oU<3tpJFHGVf`B@mE>#*c0)H0QX z`Iit2WK$j_&q)x?Ae@@fuFFzfIU$Jo@Qk2@8G~35gjKCMwMsj(a2zemT2YjpgpOMwABBz$LtCks5O-(9}ebARs7km%po^Q?ge0 zP*d4(EQMSem;;m<1ZIfDabhLAHcdE`fu&%1#grS_jU*&e@?1#awCsHf{sq~eQ5md~ zCf!<-XGV%5vHXoVL(U>|N=Ms}bI4hhJf(Zx7O}zfNR;+9@RknR5VB~~r&)Kyr}&oR zW!-JiQtyValvDMfpKYb2>8~c9;i;K23c+RwHY0m4hzhEetrLiPRC$X;j;j8Z6;vLz zL`zEc62D2?yux~-cOu~`PTIC83P_b4T^Qtu{fp#+wg5E!pFW9-f+B2Hc0#cw4e6Wi z(Fxb29rf~5!ZA|7Ts0*ZQ}3x=EuvkU5k)fluhKlCtcpJp(8k)?GvY8iz?@B|*gFjK zPHZt>KG4#W8Qylhc6{nOmpT5itM8{l-!DEeqrQHI&Fl2%YrpIC2Wx%ioXOb41vi}^Rts6 zBZD{dCMdj_yXAG$7ELY%1qEFNEv=Ny;^fle;>`R!EiEgB*R6Zr%$=d|X7Qdk3+5)PdELEJ;my>JR~xq|yxP+6dcg|K&HFh%GftM_ZuC~t0l5SSln^davQkij zx&&f1k|LOmKsC`y5Gx@zD#dPA;^|iOD|%f(ca-d}+*x_Y zz;cKB6$7U)%uHUB;{+9)y%@PZGcY+Ya(`rClHl&(`M|*<#Q1@Ofl2HFgV= tuple[str, str]: + """ + 회의 텍스트에서 AI 제안사항을 추출하는 프롬프트 생성 + + Returns: + (system_prompt, user_prompt) 튜플 + """ + + system_prompt = """당신은 회의 내용 분석 전문가입니다. +회의 텍스트를 분석하여 실행 가능한 제안사항을 추출해주세요.""" + + user_prompt = f"""다음 회의 내용을 분석하여 **구체적이고 실행 가능한 제안사항**을 추출해주세요. + +# 회의 내용 +{transcript_text} + +--- + +# 제안사항 추출 기준 +1. **실행 가능성**: 바로 실행할 수 있는 구체적인 액션 아이템 +2. **명확성**: 누가, 무엇을, 언제까지 해야 하는지 명확한 내용 +3. **중요도**: 회의 목표 달성에 중요한 사항 +4. **완결성**: 하나의 제안사항이 독립적으로 완결된 내용 + +# 제안사항 유형 예시 +- **후속 작업**: "시장 조사 보고서를 다음 주까지 작성하여 공유" +- **의사결정 필요**: "예산안 3안 중 최종안을 이번 주 금요일까지 결정" +- **리스크 대응**: "법률 검토를 위해 법무팀과 사전 협의 필요" +- **일정 조율**: "다음 회의를 3월 15일로 확정하고 참석자에게 공지" +- **자료 준비**: "경쟁사 분석 자료를 회의 전까지 준비" +- **검토 요청**: "초안에 대한 팀원들의 피드백 수집 필요" +- **승인 필요**: "최종 기획안을 경영진에게 보고하여 승인 받기" + +# 제안사항 작성 가이드 +- **구체적으로**: "검토 필요" (X) → "법무팀과 계약서 조항 검토 미팅 잡기" (O) +- **명확하게**: "나중에 하기" (X) → "다음 주 화요일까지 완료" (O) +- **실행 가능하게**: "잘 되길 바람" (X) → "주간 진행상황 공유 미팅 설정" (O) + +--- + +# 출력 형식 +반드시 아래 JSON 형식으로만 응답하세요: + +```json +{{ + "suggestions": [ + {{ + "content": "제안사항 내용 (구체적이고 실행 가능하게, 50자 이상 작성)", + "confidence": 0.85 (이 제안사항의 중요도/확실성, 0.7-1.0 사이) + }}, + {{ + "content": "또 다른 제안사항", + "confidence": 0.92 + }} + ] +}} +``` + +# 중요 규칙 +1. **회의 내용에 명시된 사항만** 추출 (추측하지 않기) +2. **최소 3개, 최대 7개**의 제안사항 추출 +3. 중요도가 높은 순서로 정렬 +4. confidence는 **0.7 이상**만 포함 +5. 각 제안사항은 **50자 이상** 구체적으로 작성 +6. JSON만 출력 (```json이나 다른 텍스트 포함 금지) + +이제 위 회의 내용에서 제안사항을 JSON 형식으로 추출해주세요.""" + + return system_prompt, user_prompt diff --git a/ai-python/app/services/__pycache__/__init__.cpython-313.pyc b/ai-python/app/services/__pycache__/__init__.cpython-313.pyc index 3546a4cf7a0585571fd125c47369130574e4e6f6..37982cc87b19f721ca1efe778d8676a278b9939a 100644 GIT binary patch delta 18 YcmdnbxSx^hGcPX}0}$lyp2)Qo056LL8UO$Q delta 18 YcmdnbxSx^hGcPX}0}${=PvqJP04ys6S^xk5 diff --git a/ai-python/app/services/__pycache__/claude_service.cpython-313.pyc b/ai-python/app/services/__pycache__/claude_service.cpython-313.pyc index 667eda0dc199dbe41c6f5a20c36a87399adfd6f2..3580aa6f09bb9d15a42aa9d7a7e3a9b87f0d9815 100644 GIT binary patch delta 1932 zcmaJ?ZERCj7(VCT-mbm9ZMU{=tn1o4_8}L-hTEF4ZmiZJuurkqiaN|}w%b|k?&`TM z;z%qiCIdkrbzzf{k;sq5V6vcDrojXPe~f?HOu|y(2Y*b2F6kHs4U%|H*SblJC+RuQ zdC&7c=RNOv@99m)ldXmoy`BZQ{rCe6UMV_bcnrO97TO^f7hsiTzq*kUSt~f8LaeAm zx*?UI|3-wDxmd~=L4H{oK*4aNKO!B93{XTS*El?WjDIU{U~47d!8j11NOgfuC{vx3 zO!H(;chQ|HS(U}AE~b-_nJi|y)Uw(Re5#GW2c2+LGm4eMhkU?mB=fkBGL~z61){o{ z>Hs41HVwc*I8OI69FVm>t+yzCjj>eK0cS2Onf0+|@TyLs>VQI-!Jc;jkaa#?mS~P? zM3`raTGtf-2C-jH82~>6=x1sh(i~bU2+dC+qsGS^xNF>XNraL!TqB=Hv1@1|S+6 z==_WaJ_;w46APPR70`g*IfdeJE@WK*RDeD{?_U7?&*I$ZbNblqt;ESR$BKM<18AT` zlW1EjiS+pie(95w>Ejod zj?bsho=zW~;yoRF`odItd@TLZrKRz&`Sjf9>A5ME^`Ife#qzjiOD(omYcBq2DVFt0 zktmXL4qnM0iUfxxF*-CPDUslatav3Qj0cIoH+w#P`CAr|!Vsub+5d1;g<^0x99or$ zWpxCYDjt#|{mPnhe;ADnha-4JGw6>j(oi7V zes!Y?OdHiy?{QW4xT?jWhHSg<7E~!JIG9~cX=6lKiTH=Z=mkuV7UJ&d)J2Q1@!srI zE{A-2^6339PY4ishzAMgUzxr?cQk$UJfHsb;?jv37yk-5f^=x0KPU%A1XGIjhr_kQ zBZE>%K|4SUAEyl~r0m4JdS<0|-O+M+KyFMz&l9F98pYu^6G-Evp$38&Vr)#&^2mEB zjS@itaxPSjmrzZX8IokwNT$!>PB5Tif?Klt?;wx_v9<}?L#C^Fjw%w$N701MslxT) z;mh%-ppwl6+K!hM1MWzDtu;hG*p%5X`$O-KO6zYq6{~0u`J;o9D4~PF0jc&sIIj`W z7W`oS29AJ77NG5ccQhS$G}XUo%o!E0b>9`-SB(q8-XvEu){{{K8-J^;Az9Y2Sh8`^ zz9qu|TVn>$Hp3%87aPWQWjMgsOpi{E&TO4G#TFc`3C^}`0oKhcMs1nlfdQk_o<+0e ztn-X>!gk@^1+y?CCe7Pcj7*U!S;*fmu}(BjyCz-dS{F(-E!xT_f|K2g_L}L?WaylH z%kE6towElP?4CsjKOLQnUf4g|xZv3SP>bD{Ijo*B0{w;zz?(fRjsd;-RM)Ytgmv?! zhMB_)TUrvETNAB4i4DC!b1&UB*Uq;j&ASua?&YmG_&*<*u-6|C?Vzx91<+deZO(M6 z`&f6PtZ5$3Dv8pTtAk_RNv?}H)+fzvH@UXQnF37wOL-Hg@uSk6Ti{fAdlUE$wr^8? zZ*31Wfom3Pd%fyfy~l!w>uLe7Uay0gczqirxSk<>6T5R0eFNHdR?;`hA;ESAb8b{J z1aG1-7F3A*jUe){Bl684@~jK6SK#8jVIPHFjz|(Z%G_CmaiH4*$)E_@$Y%M(up?eu*`wwVf Ma>N}U8nX1i0kM7$`v3p{ delta 141 zcmeyXdsUwAGcPX}0}$9nGiHi$PvrZ}=rWm$QI3&ovL>SnTM<_}izfHxM8-`#lNCj! z7`Z3gh=xy|A!@|vH2JisrPOy$M@Ckm4-6o(ND6375j&93sRAPv18{!90Q4?I%(=8O$qJ6R+NXbc4-ufF@A)ljf2)3 zP$E^i^n!%cR)f?uQfPWhg^&V4Cbw* z&HvB;egFLb>}Vc0ejb*eNRj~Xcuj@Ukx+bC+0S$Ua?LbSouilz=oq5uQ|Dl>r^ z_SjF+P7qH5P^3u2%cUsAY{E<#D14MY=HX~-Z35c6+-5DZ)dKs+eunF6=yW;9Pnpap$Lk8*Mg-loWr;&^L{Q*2hC*wF|x4ISuv zrU5$9F7u-4M9Mr;kNQL>tU>LjS3|B8FM}whxD`)~3W7XPEJePLFTesgO9wy!cG3kH z_M*>BE3-4hXaDCh6~HHx7#vO|gDt_G<<*_*3p*d(e6(^s_;~(c$te}gVG$f?kaR=F$CjT+5gP-iH#ZN30sLUsJbS;={$ z|NZ_s^QNV4+u|U0*%RBebp7ONx=C%@T(`wr;#_vIesSzxq+EAuxvuPM-?VicM81x$ zYTtyvyjJNRC=V-@Ze>ne4Bxr7lw8V|1EtNFThZ%6?CpdM*X(k<5v&Co;(q2^>bxI24+1b=&pZge(u19K zAH=M6KTGUJAtBQ1t)2u+KV(hVekjs7I;gquk!WrL9s*trS#skJhlHTmX}XUu2aBqr zdnGA0LAzP8#Qt%)2R=rhSo|TW4RlaXbw&PCOp!y_Niod_sWJ=zmlBEpGTOAky^}BI z)Z%!U)lOr9)=A(Dff#`<0#O2u1djSN%vbW$?@emClELTlS+%527E3tC{*iPa@q381 zUx;NqU(9P6J)cWw^e}ouZs;XfFf3@K)Bifkr#dl%g}F>Rm(eo@L%KOA2d&9YHbS)Z z$dH?0KZ4e|HecxO(4C>B#IjcLb!|QCoeWeZ&hGew<|Vmm1-?GG+k}3!o(s7GwCMI)JSM$AE5}k1LK39NHsN!b> RW0D50P^G4M132~te*?n4STq0t delta 953 zcmZuvOK1~87@pZ@cDK8mO-j>%F=M97ojE#EE6PRK-#0yo4fScTtW zFV>((+KiiEQfk3El%yj`V_GrL2oMu5ee=aEerSbJ`4|x*v6(ol%_gn(;-J6 zmD705OQ3_#5z=PFh$fAphSF1xjyh(N#R&ata+DJgI=bHpLz|h@t$$usplqh- zN4aZeT6?HC5G&ml{XNY9AI4yUE zrpuiw&h&3B&&z!4$bd>NNOG1me$AXX2^>C;8oqIo2X+PFZV+@va_u-^}emU8ov{- zwQZ_vQdnI^lA`|nwgoOlPQ(Uj#(?)LBoGR2z7p`RSD_VriL`6G>D3Bdhzx+)+}Sc9 zMm|`*%Oc&EC8TzKml-n_wsHe~*Jmh2%UxPuvTYQ+|= 0.7 # 신뢰도 0.7 이상만 + ] + + logger.info(f"AI 제안사항 {len(suggestions)}개 추출 완료") + + return RealtimeSuggestionsResponse(suggestions=suggestions) + + except Exception as e: + logger.error(f"제안사항 분석 실패: {e}", exc_info=True) + # 빈 응답 반환 + return RealtimeSuggestionsResponse(suggestions=[]) + # 싱글톤 인스턴스 claude_service = ClaudeService() diff --git a/test-audio/stt-test-ai.html b/test-audio/stt-test-ai.html index 7466d40..5092cc7 100644 --- a/test-audio/stt-test-ai.html +++ b/test-audio/stt-test-ai.html @@ -179,7 +179,7 @@

📋 테스트 정보

STT Service: ws://localhost:8084/ws/audio

-

AI Service: http://localhost:8086/api/v1/ai/suggestions

+

AI Service: http://localhost:8086/api/ai/suggestions

Meeting ID: test-meeting-001

@@ -345,7 +345,7 @@ // AI SSE 연결 function connectAIEventSource() { - const sseUrl = `http://localhost:8086/api/v1/ai/suggestions/meetings/${meetingId}/stream`; + const sseUrl = `http://localhost:8086/api/ai/suggestions/meetings/${meetingId}/stream`; addLog('AI SSE 연결 시도...', 'info'); aiEventSource = new EventSource(sseUrl); diff --git a/test-audio/stt-test-wav.html b/test-audio/stt-test-wav.html index 04b995a..23fb242 100644 --- a/test-audio/stt-test-wav.html +++ b/test-audio/stt-test-wav.html @@ -467,7 +467,7 @@ // AI 제안사항 SSE 연결 function connectAISuggestions() { - const sseUrl = `${aiServiceUrl}/api/v1/ai/suggestions/meetings/${meetingId}/stream`; + const sseUrl = `${aiServiceUrl}/api/ai/suggestions/meetings/${meetingId}/stream`; addLog('AI 제안사항 SSE 연결 시도: ' + sseUrl, 'info'); eventSource = new EventSource(sseUrl);