Add the interface testing interface for model API deployment.
parent
e34d4e9371
commit
d37481f48c
|
|
@ -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)
|
||||
Loading…
Reference in New Issue