@@ -338,6 +338,7 @@ const COPY = {
338338 promptNeeded: ' 请输入问题或上传图片' ,
339339 strategyPromptNeeded: ' 请先写一点策略想法' ,
340340 generateFailed: ' 生成失败' ,
341+ streamInterrupted: ' 连接中断,已保留当前内容,请重试。' ,
341342 desktopOnly: ' 手机端仅支持使用与监控,请在电脑端完成代码编辑或回测。' ,
342343 taskDiagnose: ' 诊断标的' ,
343344 taskDiagnoseDesc: ' 趋势、量能、支撑阻力和风险' ,
@@ -382,6 +383,7 @@ const COPY = {
382383 promptNeeded: ' 請輸入問題或上傳圖片' ,
383384 strategyPromptNeeded: ' 請先寫一點策略想法' ,
384385 generateFailed: ' 生成失敗' ,
386+ streamInterrupted: ' 連線中斷,已保留目前內容,請重試。' ,
385387 desktopOnly: ' 手機端僅支援使用與監控,請在電腦端完成程式碼編輯或回測。' ,
386388 taskDiagnose: ' 診斷標的' ,
387389 taskDiagnoseDesc: ' 趨勢、量能、支撐阻力和風險' ,
@@ -426,6 +428,7 @@ const COPY = {
426428 promptNeeded: ' Enter a question or upload an image' ,
427429 strategyPromptNeeded: ' Write a short strategy idea first' ,
428430 generateFailed: ' Generation failed' ,
431+ streamInterrupted: ' The connection was interrupted. The current response was kept; please retry.' ,
429432 desktopOnly: ' Mobile supports usage and monitoring only. Use desktop for code editing or backtesting.' ,
430433 taskDiagnose: ' Diagnose' ,
431434 taskDiagnoseDesc: ' Trend, volume, levels, and risk' ,
@@ -470,6 +473,7 @@ const COPY = {
470473 promptNeeded: ' 質問を入力するか画像をアップロードしてください' ,
471474 strategyPromptNeeded: ' まず戦略アイデアを入力してください' ,
472475 generateFailed: ' 生成に失敗しました' ,
476+ streamInterrupted: ' 接続が中断されました。現在の内容を保持しました。再試行してください。' ,
473477 desktopOnly: ' モバイルは利用と監視専用です。コード編集やバックテストはデスクトップで行ってください。' ,
474478 taskDiagnose: ' 銘柄診断' ,
475479 taskDiagnoseDesc: ' トレンド、出来高、重要水準、リスク' ,
@@ -514,6 +518,7 @@ const COPY = {
514518 promptNeeded: ' 질문을 입력하거나 이미지를 업로드하세요' ,
515519 strategyPromptNeeded: ' 먼저 전략 아이디어를 입력하세요' ,
516520 generateFailed: ' 생성 실패' ,
521+ streamInterrupted: ' 연결이 중단되었습니다. 현재 내용을 유지했으니 다시 시도해 주세요.' ,
517522 desktopOnly: ' 모바일은 사용 및 모니터링 전용입니다. 코드 편집과 백테스트는 데스크톱에서 진행하세요.' ,
518523 taskDiagnose: ' 종목 진단' ,
519524 taskDiagnoseDesc: ' 추세, 거래량, 레벨, 리스크' ,
@@ -888,39 +893,46 @@ export default {
888893 },
889894 async sendMessageStream (payload , pendingMsg ) {
890895 let hasContent = false
891- await aiChatApi .streamMessage (payload, async (event , data ) => {
892- if (event === ' meta' ) {
893- this .sessionId = data? .session_id || this .sessionId
894- return
895- }
896- if ([' delta' , ' message' , ' content' ].includes (event )) {
897- const text = this .extractStreamText (data)
898- if (! text) return
899- if (! hasContent) {
900- this .updatePendingMessage (pendingMsg, { content: ' ' , loading: false })
901- hasContent = true
896+ try {
897+ await aiChatApi .streamMessage (payload, async (event , data ) => {
898+ if (event === ' meta' ) {
899+ this .sessionId = data? .session_id || this .sessionId
900+ return
902901 }
903- await this .revealStreamText (pendingMsg, text)
904- return
905- }
906- if (event === ' done' ) {
907- this .sessionId = data? .session_id || this .sessionId
908- this .updatePendingMessage (pendingMsg, { id: data? .message_id || pendingMsg .id })
909- const finalText = this .extractStreamText (data)
910- if (finalText && ! hasContent) {
911- this .updatePendingMessage (pendingMsg, { content: ' ' , loading: false })
912- hasContent = true
913- await this .revealStreamText (pendingMsg, finalText)
902+ if ([' delta' , ' message' , ' content' ].includes (event )) {
903+ const text = this .extractStreamText (data)
904+ if (! text) return
905+ if (! hasContent) {
906+ this .updatePendingMessage (pendingMsg, { content: ' ' , loading: false })
907+ hasContent = true
908+ }
909+ await this .revealStreamText (pendingMsg, text)
910+ return
911+ }
912+ if (event === ' done' ) {
913+ this .sessionId = data? .session_id || this .sessionId
914+ this .updatePendingMessage (pendingMsg, { id: data? .message_id || pendingMsg .id })
915+ const finalText = this .extractStreamText (data)
916+ if (finalText && ! hasContent) {
917+ this .updatePendingMessage (pendingMsg, { content: ' ' , loading: false })
918+ hasContent = true
919+ await this .revealStreamText (pendingMsg, finalText)
920+ }
921+ if (data? .actions ) {
922+ this .updatePendingMessage (pendingMsg, { actions: this .filterMobileActions (data .actions || []) })
923+ }
924+ return
914925 }
915- if (data ? . actions ) {
916- this . updatePendingMessage (pendingMsg, { actions : this . filterMobileActions (data . actions || []) } )
926+ if (event === ' error ' ) {
927+ throw new Error (data? . msg || data ? . message || this . text . generateFailed )
917928 }
918- return
919- }
920- if (event === ' error ' ) {
921- throw new Error (data ? . msg || data ? . message || this . text . generateFailed )
929+ })
930+ } catch (error) {
931+ if (error && typeof error === ' object ' ) {
932+ error . streamHasContent = hasContent
922933 }
923- })
934+ throw error
935+ }
924936 if (! hasContent && pendingMsg .content === this .text .sending ) {
925937 throw new Error (this .text .generateFailed )
926938 }
@@ -929,7 +941,12 @@ export default {
929941 try {
930942 await this .sendMessageStream (payload, pendingMsg)
931943 return
932- } catch (_) {
944+ } catch (error) {
945+ if (error? .streamHasContent ) {
946+ this .updatePendingMessage (pendingMsg, { loading: false })
947+ showToast ({ message: this .text .streamInterrupted , type: ' fail' })
948+ return
949+ }
933950 this .updatePendingMessage (pendingMsg, {
934951 content: this .text .sending ,
935952 loading: true ,
0 commit comments