From bcb0fbb3841f78a115916767e3c0db3965c5c976 Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Tue, 21 Apr 2026 18:51:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=96=87=E5=AD=97?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E5=AF=B9=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/server.cpython-310.pyc | Bin 4473 -> 5489 bytes logs/server.log | Bin 4685 -> 2686 bytes server.py | 41 ++++++++++++ static/index.html | 102 +++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) diff --git a/__pycache__/server.cpython-310.pyc b/__pycache__/server.cpython-310.pyc index f0f53b4b025ed0f689c1e9fbb333c5e29b9f669f..bed4e99a16bf3547c98a451f43c6857cc2d22b25 100644 GIT binary patch delta 1099 zcmY+D-ER{|5Wsi#&S(34_Sq(B63Y-{Fo{W1H-VNf0S^%n6v~GP&_-=T$Q&XD#b~*d zVx4iqhu{G}pp^*XOZH==exXP_zyp;k@h|Yk8;&Yfm5^FhjnvSc3m@%D`@7kh*`3*) zxxcfo*2hZGsL9lrKDsdRs_kYh4L?8Z8G>qYHFi5`OxL($VFvS<^(BsLNIJ=Jy_3b9 zqdVCSc2dV4{P0TPGK{QsQuQ46HbB|3%IhO6T+x+&ozspVpXTBP0`fCmBVA5cvD-;u zpVNZN*&%s+vr;p7|_JJmw;6E-L;${UeQJ#(69Crt+-Me5{0X>!sT zcPC1d8Aphc*qZtEFJSCX`Fo@f=H@fjaj1T+Jj;>7H>HVjr{Fr@x>J_YG;dvN-utfk z=z4SJM{!gs#<{}V5mExZ&o648`$?TR1LX%Ut3!irWP2IHAiHzD!j*~_9?-h#@uKbq?lRQxb5CdnkRg9P4&&of{-YS*C zuW;EejGdkMPuavSG8G8B3Dg*34`Gntw+3~E7$WQ=d`8%>P)-c1!e_=$jk#|dWmp^_ z>mh}FtN4Uul~0w4!z2z9ju0Y*&4e7m&u<$^#|S~f7D5|g6G0<>zx_7%=&dmFf&rpN>+xSC!!$U64=na1ugbfevyYn(J6>H~JUjZE>Xu zO~;@G;_Azn#OVA?bQTP{m>86+>^?Xq588X+2YK7>g%k3borApm&2Far`%zMY{t+=s m7$cmJ3-OImlZwvGI;kQly1mSd3@J>(V63UP`2*t-P9aUEB730W zMMfaP7)Vr2KE`dXt;t*@0TPh}5mF#wA?N(Oywv29%=|os)S{yNA}fW=?~Du#rIR&y z3>h^yNAV;uGKOzX5uDD*<^|H_Hknb_kTGDgv9LR1>*Q)-UB;-%D}_}VH71`IekSS% lQX&r`!a+nNh=`heUc>~bibXV#hr>{Sk%NzeQG}7@9{^^OKkWbj diff --git a/logs/server.log b/logs/server.log index 9171fd90005c2a25d7dca6e63629a004c2496258..8e45bc0b3035d7069f3c8821613ae516c8d7fac9 100644 GIT binary patch delta 49 zcmX@B@=s)fDvPCodFxx8c$YWRGiGhD9LPWjLbIQtiagJu{nTo68q%E NoLAW_%uS4Axd4#+5+MKp diff --git a/server.py b/server.py index f9d2a0b..079bb8c 100644 --- a/server.py +++ b/server.py @@ -130,6 +130,47 @@ async def voice_chat( raise HTTPException(status_code=500, detail=str(e)) +@app.post("/voice/text", response_model=VoiceResponse) +async def text_chat( + text: str = Form(..., description="文本消息"), + conversation_id: Optional[str] = Form(None, description="对话ID") +): + """ + 文字聊天接口 + 转发到模型服务 + """ + try: + async with aiohttp.ClientSession() as session: + form = aiohttp.FormData() + form.add_field('text', text) + if conversation_id: + form.add_field('conversation_id', conversation_id) + + async with session.post( + f"{MODEL_SERVICE_URL}/api/voice/text", + data=form, + timeout=aiohttp.ClientTimeout(total=120) + ) as resp: + if resp.status != 200: + error_text = await resp.text() + logger.error(f"Model service error: {error_text}") + raise HTTPException(status_code=resp.status, detail=error_text) + + data = await resp.json() + return VoiceResponse( + reply=data["reply"], + conversation_id=data["conversation_id"], + timestamp=data.get("timestamp", datetime.now().isoformat()) + ) + + except aiohttp.ClientError as e: + logger.error(f"Connection error: {e}") + raise HTTPException(status_code=503, detail="模型服务连接失败") + except Exception as e: + logger.error(f"Text chat error: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + @app.delete("/conversation/{conversation_id}") async def delete_conversation(conversation_id: str): """删除对话""" diff --git a/static/index.html b/static/index.html index db04ee6..9f82394 100644 --- a/static/index.html +++ b/static/index.html @@ -127,6 +127,50 @@ font-weight: bold; } + .text-section { + margin: 20px 0; + } + + .text-input-wrapper { + display: flex; + gap: 10px; + } + + .text-input { + flex: 1; + padding: 12px 15px; + border: 2px solid #eee; + border-radius: 10px; + font-size: 15px; + outline: none; + transition: border-color 0.2s; + } + + .text-input:focus { + border-color: #667eea; + } + + .send-text-btn { + padding: 12px 20px; + border: none; + border-radius: 10px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + font-size: 15px; + cursor: pointer; + transition: all 0.2s; + } + + .send-text-btn:hover { + transform: scale(1.05); + } + + .send-text-btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + } + .waveform { display: flex; justify-content: center; @@ -319,6 +363,13 @@ +
+
+ + +
+
+
开始你的第一次语音对话吧!
@@ -350,6 +401,46 @@ const clearBtn = document.getElementById('clearBtn'); const statusDot = document.getElementById('statusDot'); const statusText = document.getElementById('statusText'); + const textInput = document.getElementById('textInput'); + const sendTextBtn = document.getElementById('sendTextBtn'); + + // 发送文字消息 + async function sendText(text) { + if (!text.trim()) return; + + try { + showLoading(); + + const formData = new FormData(); + formData.append('text', text); + if (conversationId) { + formData.append('conversation_id', conversationId); + } + + const resp = await fetch(`${API_URL}/voice/text`, { + method: 'POST', + body: formData + }); + + if (!resp.ok) { + const error = await resp.text(); + throw new Error(error); + } + + const data = await resp.json(); + conversationId = data.conversation_id; + + // 显示消息 + addMessage('user', text); + addMessage('assistant', data.reply); + + textInput.value = ''; + + } catch (e) { + console.error('发送失败:', e); + showError('发送失败: ' + e.message); + } + } // 检查服务状态 async function checkStatus() { @@ -650,6 +741,17 @@ clearBtn.addEventListener('click', clearChat); + // 文字输入事件 + sendTextBtn.addEventListener('click', () => { + sendText(textInput.value); + }); + + textInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + sendText(textInput.value); + } + }); + // 初始化 checkStatus(); setInterval(checkStatus, 10000); // 每10秒检查状态