Add the interface testing interface for model API deployment.

pull/205/head
jingsongliujing 2025-02-21 17:21:27 +08:00
parent e34d4e9371
commit d37481f48c
1 changed files with 190 additions and 0 deletions

190
scripts/web_app.py Normal file
View File

@ -0,0 +1,190 @@
from flask import Flask, request, Response, render_template_string
import json
from openai import OpenAI
import logging
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__)
# 初始化OpenAI客户端
client = OpenAI(
api_key="none",
base_url="http://localhost:8998/v1"
)
# 对话配置
MODEL_NAME = "model-identifier"
SYSTEM_PROMPT = "你是一个有帮助的AI助手,请用中文回答"
MAX_HISTORY = 6 # 保留最近3轮对话
class ChatManager:
def __init__(self):
self.conversations = {} # 存储对话历史的字典
def get_conversation(self, session_id):
"""获取或初始化对话历史"""
if session_id not in self.conversations:
self.conversations[session_id] = [
{"role": "system", "content": SYSTEM_PROMPT}
]
return self.conversations[session_id]
def update_conversation(self, session_id, user_input, assistant_response):
"""更新对话历史"""
conv = self.conversations[session_id]
conv.extend([
{"role": "user", "content": user_input},
{"role": "assistant", "content": assistant_response}
])
# 保留最近N轮对话(考虑系统提示)
self.conversations[session_id] = conv[-MAX_HISTORY*2:]
chat_manager = ChatManager()
@app.route('/')
def home():
return render_template_string('''
<!DOCTYPE html>
<html>
<head>
<title>AI Chat</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.chat-container { height: 500px; border: 1px solid #ddd; padding: 20px; overflow-y: auto; margin-bottom: 20px; }
.message { margin: 10px 0; padding: 10px; border-radius: 5px; }
.user-message { background-color: #e3f2fd; }
.ai-message { background-color: #f5f5f5; }
.input-area { display: flex; gap: 10px; }
input { flex: 1; padding: 10px; }
button { padding: 10px 20px; background-color: #007bff; color: white; border: none; cursor: pointer; }
button:disabled { background-color: #6c757d; }
</style>
</head>
<body>
<div class="chat-container" id="chatBox"></div>
<div class="input-area">
<input type="text" id="userInput" placeholder="输入你的问题...">
<button onclick="sendMessage()" id="sendBtn">发送</button>
</div>
<script>
const chatBox = document.getElementById('chatBox');
const userInput = document.getElementById('userInput');
const sendBtn = document.getElementById('sendBtn');
function appendMessage(role, content) {
const div = document.createElement('div');
div.className = `message ${role}-message`;
div.innerHTML = `<strong>${role === 'user' ? '你' : 'AI'}:</strong> ${content}`;
chatBox.appendChild(div);
chatBox.scrollTop = chatBox.scrollHeight;
}
async function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
// 禁用输入
userInput.value = '';
userInput.disabled = true;
sendBtn.disabled = true;
// 显示用户消息
appendMessage('user', message);
// 创建AI消息占位符
const aiDiv = document.createElement('div');
aiDiv.className = 'message ai-message';
aiDiv.innerHTML = '<strong>AI:</strong> ';
chatBox.appendChild(aiDiv);
try {
const response = await fetch('/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: message })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let aiResponse = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
try {
const data = JSON.parse(chunk);
aiResponse += data.content;
aiDiv.innerHTML = `<strong>AI:</strong> ${aiResponse}`;
} catch (e) {
console.error('解析错误:', e);
}
}
} catch (error) {
aiDiv.innerHTML += ' [连接错误]';
console.error('Error:', error);
} finally {
userInput.disabled = false;
sendBtn.disabled = false;
userInput.focus();
}
}
// 支持回车发送
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
</script>
</body>
</html>
''')
@app.route('/chat', methods=['POST'])
def chat():
try:
data = request.json
user_message = data.get('message', '')
session_id = 'default' # 实际应用中应使用真实会话ID
if not user_message:
return json.dumps({"error": "空输入"}), 400
# 获取对话历史
conversation = chat_manager.get_conversation(session_id)
conversation.append({"role": "user", "content": user_message})
# 创建流式响应
response = client.chat.completions.create(
model=MODEL_NAME,
messages=conversation,
temperature=0.7,
max_tokens=512,
stream=True
)
def generate():
full_response = ''
for chunk in response:
content = chunk.choices[0].delta.content or ""
full_response += content
yield json.dumps({"content": content}) + "\n"
# 更新对话历史
chat_manager.update_conversation(session_id, user_message, full_response)
logger.info(f"会话 {session_id} 更新,历史长度: {len(conversation)}")
return Response(generate(), content_type='text/event-stream')
except Exception as e:
logger.error(f"请求失败: {str(e)}")
return json.dumps({"error": str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)