feat: 支持文字输入对话
This commit is contained in:
Binary file not shown.
BIN
logs/server.log
BIN
logs/server.log
Binary file not shown.
41
server.py
41
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):
|
||||
"""删除对话"""
|
||||
|
||||
@@ -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 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-section">
|
||||
<div class="text-input-wrapper">
|
||||
<input type="text" id="textInput" placeholder="输入文字消息..." class="text-input">
|
||||
<button id="sendTextBtn" class="send-text-btn">发送</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-section" id="chatSection">
|
||||
<div class="hint">开始你的第一次语音对话吧!</div>
|
||||
</div>
|
||||
@@ -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秒检查状态
|
||||
|
||||
Reference in New Issue
Block a user