diff --git a/__pycache__/server.cpython-310.pyc b/__pycache__/server.cpython-310.pyc index f0f53b4..bed4e99 100644 Binary files a/__pycache__/server.cpython-310.pyc and b/__pycache__/server.cpython-310.pyc differ diff --git a/logs/server.log b/logs/server.log index 9171fd9..8e45bc0 100644 Binary files a/logs/server.log and b/logs/server.log differ 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 @@ +