Error in user YAML: (<unknown>): found a tab character that violate indentation while scanning a plain scalar at line 3 column 3
---
- oeasy Python 0780
- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。
- 本教程同步发布在:
- 个人网站: `https://oeasy.org`
- 蓝桥云课: `https://www.lanqiao.cn/courses/3584`
- GitHub: `https://github.com/overmind1980/oeasy-python-tutorial`
- Gitee: `https://gitee.com/overmind1980/oeasypython`
---- 上次 我们了解了
- 智能体的推理能力(reasoning)
- 可以把智能体放到浏览器里面吗?🤔
- 可以把这个修改为网页应用吗?
from openai import OpenAI
client = OpenAI(
base_url='https://api-inference.modelscope.cn/v1', api_key='ms-0b109ff5-6dc9-452b-be7d-1171078fb624',
)
response = client.chat.completions.create(
model='Qwen/Qwen3-Next-80B-A3B-Instruct', # ModelScope Model-Id
messages=[
{
'role': 'system',
'content': 'You are a helpful assistant.'
},
{
'role': 'user',
'content': '你好'
}
],
stream=True
)
for chunk in response:
print(chunk.choices[0].delta.content, end='', flush=True)
- 将终端应用转化为
- web应用
- 核心提示
- Flask
- RESTful API接口
请将现有的命令行AI对话脚本转换为完整的Web应用,包含以下要求:
1. **后端架构**:
- 使用Flask框架创建Web服务器
- 保持现有的OpenAI客户端配置(ModelScope API)
- 实现RESTful API接口 `/api/chat`
- 支持流式响应(Server-Sent Events)
- 添加CORS支持以允许前端访问
2. **前端界面**:
- 创建简洁的HTML页面,包含消息显示区域和输入框
- 实现实时流式对话显示
- 支持用户输入和AI回复的区分显示
- 添加基础的CSS样式(黑白配色)
3. **核心功能**:
- 保持原有的AI模型调用逻辑
- 实现前后端通信
- 支持实时流式响应显示
- 确保用户体验流畅
- app.py
from flask import Flask, request, send_file, Response
from flask_cors import CORS
from openai import OpenAI
import json
app = Flask(__name__)
CORS(app)
client = OpenAI(
base_url='https://api-inference.modelscope.cn/v1',
api_key = 'ms-81c1f87a-fa0a-4edc-a4a5-4bc7ba3cbbba'
)
@app.route('/')
def index():
return send_file('index.html')
@app.route('/api/chat', methods=['POST'])
def chat():
data = request.get_json()
user_message = data.get('message', '')
def generate():
try:
response = client.chat.completions.create(
model='Qwen/Qwen3-Next-80B-A3B-Instruct',
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": user_message}
],
stream=True
)
for chunk in response:
if chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
yield f"data: {json.dumps({'content': content})}\n\n"
yield f"data: {json.dumps({'done': True})}\n\n"
except Exception as e:
# 输出错误信息到控制台,方便调试
print(f"OpenAI API Error: {str(e)}")
yield f"data: {json.dumps({'error': str(e)})}\n\n"
return Response(generate(), mimetype='text/plain')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8080)
- index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>对话</title>
<style>
body { margin: 0; padding: 20px; font-family: Arial; }
#messages { height: 400px; overflow-y: auto; border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; }
.user, .assistant { margin: 5px 0; padding: 8px; border-radius: 5px; }
.user { text-align: right; background: #e3f2fd; }
.assistant { background: #f5f5f5; }
input { width: 75%; padding: 10px; border: 1px solid #ccc; }
button { padding: 10px 15px; background: #333; color: white; border: none; cursor: pointer; }
</style>
</head>
<body>
<div id="messages"></div>
<input type="text" id="input" placeholder="输入消息...">
<button onclick="send()">发送</button>
<script>
async function send() {
const input = document.getElementById('input');
const button = document.querySelector('button');
const msg = input.value.trim();
if (!msg) return;
button.disabled = true;
button.textContent = '发送中...';
add(msg, 'user');
input.value = '';
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({message: msg})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let content = '', assistantDiv;
while (true) {
const { done, value } = await reader.read();
if (done) break;
const lines = decoder.decode(value, { stream: true }).split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.substring(6));
if (data.content) {
content += data.content;
if (!assistantDiv) {
assistantDiv = document.createElement('div');
assistantDiv.className = 'assistant';
document.getElementById('messages').appendChild(assistantDiv);
}
assistantDiv.textContent = content;
document.getElementById('messages').scrollTop = 999999;
} else if (data.error) {
if (!assistantDiv) {
assistantDiv = document.createElement('div');
assistantDiv.className = 'assistant';
document.getElementById('messages').appendChild(assistantDiv);
}
assistantDiv.textContent = '错误: ' + data.error;
}
} catch (e) {}
}
}
}
} catch (error) {
add('错误: ' + (error.message || '未知错误'), 'assistant');
} finally {
button.disabled = false;
button.textContent = '发送';
input.focus();
}
}
function add(content, type) {
const div = document.createElement('div');
div.className = type;
div.textContent = content;
document.getElementById('messages').appendChild(div);
document.getElementById('messages').scrollTop = 999999;
}
</script>
</body>
</html>
- 如何设置 系统人设(system)
messages=[
{
'role': 'system',
'content': '你是孙悟空,我是猪八戒'
},
{
'role': 'user',
'content': input("问题:")
}
]
- 效果
- 这次 可以在
网页里- 和 大模型对话了
- 但是使用两个文件
- app.py
- index.html
- 可以把他俩
整合起来吗?🤔 - 下次再说👋
- 本文来自 oeasy Python 系统教程。
- 想完整、扎实学 Python,
- 搜索 oeasy 即可。




