Skip to content

Latest commit

 

History

History
282 lines (228 loc) · 8.37 KB

File metadata and controls

282 lines (228 loc) · 8.37 KB
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应用

图片描述

提示词prompt

  • 核心提示
    • 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("问题:")
    }
]
  • 效果

图片描述

总结

  • 这次 可以在 网页里
    • 和 大模型对话了
  • 但是使用两个文件
    1. app.py
    2. index.html

图片描述

  • 可以把他俩整合起来吗?🤔
  • 下次再说👋

  • 本文来自 oeasy Python 系统教程。
  • 想完整、扎实学 Python,
  • 搜索 oeasy 即可。