day15-Codex开发数字人后端-微信小程序创建-仅笔记

今日内容

1 立项:决定开发xx项目

2 需求调研:需求分析书

3 设计图:html版本----》转到了figma中微调

4 分任务开发

​ -架构文档

​ -前端:微信小程序

​ -后端:Django后端

5 联调-测试

6 上线

1 后端环境搭建

本地开发完【我们目前用的机器】---》测试通过---》上线到服务器【购买阿里云】

1.1 Python环境【必须】

# 0 前置条件:先刷苑老师讲的python课,两三天才能继续往后做
	-最好全看完,至少看到pycharm环境装好
    -我们的后端使用Python编写,本地开发,本地要有Python环境
    -Go,java,php,c。。。其实都可以编写后端---》但是都需要搭建对应语言的环境

# 1 老师用的Python3.13.11
	-如果大家会装python解释器---》最好跟我一样【3.13  小版本不需要区分】
    -如果大家不会--》之前装了其他版本,用其他版本也可以--》3.14 ,3.12
    
# 2 验证一下自己python版本
	#  验证-打开cmd,输入
    python --version
    Python 3.13.11 

image-20260816201304850

1.2 Django环境【可以不装】

# 1 Python 环境搭建好,可以写python代码,并运行了
# 2 我们后端项目还基于Django,其实需要安装Django环境
# 3 Django 环境,可以不用搭建,Codex可以帮我们装好
# 4 想搭建:按照如下步骤
	1 打开cmd
    2 pip install django==4.2
    
# 4 在我们本地的python解释器上,装了django框架
	python3.13+django4.2 ---》就可以开发Django项目了

image-20260816202009901

image-20260816202321730

1.3 Pycharm环境【必须】

# 1 有了Python环境,我们可以开发python代码并运行
# 2 代码编辑器:python代码-pycharm软件
	-vscode
    -记事本
    。。。
    
# 3 按照苑老师视频下载并破解成功

1.4 Python调用Coze口播工作流代码【可以不测-给Codex用而已】

# 1 使用Python 调用我们coze工作流:口播数字人
	-能调通,就能集成到我们项目中
    
# 2 同学们不需要懂--》是我 + AI写的
	-纯AI写有bug---》python调用coze工作流--》API是Coze提供的--》有的ai读不到Coze提供的文档--》有时候Coze文档改了--》ai还是用老办法写,就会有bug
    -把coze文档的说明网页给AI不行吗?--》》可以解决百分之90的问题
    -Coze的官方文档--》可能更新不及时
    
    
# 3 使用代码之前:
	1 获取口播工作流的id号【必须发布】:7669850629418647590
    2 获取令牌:https://www.coze.cn/open/oauth/pats:只会出现一次
    	-pat_MU1wMhrbv1NbXEK43vUTvZSKJHiu5sy8aaF8rH3HbpIED69FxPIaG5ogE7fOraVE
    3 修改下面代码:你们改  14-api_key密钥行 和  15行-id号
    	
        

image-20260816203403200

image-20260816203553034

image-20260816203630284

image-20260816204023666

import requests
import json
import time
import os
from typing import Optional, Dict, Any
'''
个人访问令牌:https://www.coze.cn/open/oauth/pats
'''

class CozeAPI:

    def __init__(self, api_key: str = None, workflow_id: str = None):
        self.api_key = api_key or '你们要改'
        self.workflow_id = workflow_id or '你们要改'
        self.base_url = 'https://api.coze.cn'
        self.upload_url = f"{self.base_url}/v1/files/upload"
        self.run_url = f"{self.base_url}/v1/workflow/run"
        self.headers = {'Authorization': f'Bearer {self.api_key}', 'Content-Type': 'application/json'}

    def _get_save_path(self, task_id: str) -> str:
        """内部方法:生成视频保存路径(精简路径处理逻辑)"""
        result_dir = os.path.join('coze_results')
        os.makedirs(result_dir, exist_ok=True)
        filename = f"result_{task_id}_{int(time.time())}.mp4"
        return os.path.join(result_dir, filename)

    def download_video(self, image_url: str, task_id: str) -> Optional[str]:
        """下载视频到本地,返回跨平台路径"""
        try:
            save_path = self._get_save_path(task_id)
            resp = requests.get(image_url, stream=True)
            resp.raise_for_status()

            with open(save_path, 'wb') as f:
                for chunk in resp.iter_content(chunk_size=8192):
                    f.write(chunk)

            print(f"视频下载成功: {save_path}")
            return save_path.replace('\\', '/')
        except Exception as e:
            print(f"视频下载失败: {str(e)}")
            return None

    def upload_file(self, file_path: str) -> str:
        """上传文件到Coze并获取文件ID"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")

        try:
            print(f"开始上传文件: {file_path}")
            with open(file_path, 'rb') as f:
                files = {'file': (os.path.basename(file_path), f)}
                resp = requests.post(self.upload_url, headers={'Authorization': f'Bearer {self.api_key}'}, files=files)

            print(f"上传响应: {resp.status_code} | {resp.text}")
            result = resp.json()

            if resp.status_code == 200 and result.get('code') == 0 and 'data' in result:
                file_id = result['data'].get('id')
                if not file_id:
                    raise Exception(f"未提取到文件ID: {result}")
                print(f"文件上传成功,ID: {file_id}")
                return file_id
            raise Exception(f"文件上传失败: {result}")
        except Exception as e:
            print(f"文件上传异常: {str(e)}")
            raise

    def run_workflow(self, source_image: str, target_image: str) -> Dict[str, Any]:
        """运行Coze换脸工作流,返回任务信息"""
        try:
            # 批量上传文件
            source_id, target_id = self.upload_file(source_image), self.upload_file(target_image)

            payload = {
                "workflow_id": self.workflow_id,
                "parameters": {
                    "voice": json.dumps({"file_id": source_id}),
                    "video": json.dumps({"file_id": target_id}),
                    "text": "执行数字人操作"
                },
                "app_id": "",
                #"is_async": True
            }

            print(f"调用工作流 {self.workflow_id}...")
            resp = requests.post(self.run_url, headers=self.headers, json=payload)

            if resp.status_code != 200:
                raise Exception(f"工作流调用失败: {resp.status_code} | {resp.text}")

            result = resp.json()
            if (result.get('code') == 0 or result.get('msg') == '') and (task_id := result.get('execute_id')):
                print(f"工作流调用成功,任务ID: {task_id}")
                return {'code': 0, 'msg': 'success',
                        'data': {'task_id': task_id, 'workflow_id': self.workflow_id, 'status': 'pending'}}

            raise Exception(f"工作流调用失败: {result.get('msg')} | {result}")
        except Exception as e:
            print(f"工作流调用异常: {str(e)}")
            raise

    def get_workflow_result(self, task_id: str) -> Dict[str, Any]:
        """查询工作流执行结果"""
        try:
            print(f"查询任务 {task_id} 结果...")
            # 简化URL拼接(移除模板字符串,直接格式化)
            query_url = f"{self.base_url}/v1/workflows/{self.workflow_id}/run_histories/{task_id}"
            resp = requests.get(query_url, headers=self.headers)

            if resp.status_code != 200:
                raise Exception(f"查询失败: {resp.status_code} | {resp.text}")

            result = resp.json()
            if result.get('code') != 0:
                raise Exception(f"查询结果失败: {result.get('msg')} | {result}")

            # 提取核心数据
            data = result.get('data', [{}])[0]
            exec_status = data.get('execute_status', '')

            if exec_status == 'Success':
                return self._parse_success_result(data, task_id)
            elif exec_status == 'Fail':
                return {'status': 'failed', 'error_message': '任务执行失败', 'task_id': task_id}
            return {'status': 'processing', 'task_id': task_id}

        except Exception as e:
            print(f"查询结果异常: {str(e)}")
            raise

    def _parse_success_result(self, data: Dict[str, Any], task_id: str) -> Dict[str, Any]:
        """内部方法:解析成功的任务结果(拆分复杂的解析逻辑)"""
        try:
            output = json.loads(data.get('output', '{}'))
            result_data = json.loads(output.get('Output', '{}'))
            video_url = result_data.get('output')

            if not video_url:
                return {'status': 'success', 'message': '任务成功但未返回视频', 'task_id': task_id}

            local_path = self.download_video(video_url, task_id)
            return {
                'status': 'success',
                'result_video_url': video_url,
                'local_video_path': local_path,
                'processing_time': data.get('processing_time', 0),
                'task_id': task_id
            }
        except (json.JSONDecodeError, KeyError) as e:
            print(f"解析输出失败: {str(e)}")
            return {'status': 'success', 'message': '任务成功但解析输出失败', 'task_id': task_id}


if __name__ == '__main__':
    try:
        coze_api = CozeAPI()
        voice_path, video_path = './lqz.mp3', './lqz.mp4'
        print("开始测试Coze数字人工作流...")

        # 运行工作流并获取任务ID
        run_result = coze_api.run_workflow(voice_path, video_path)
        print(f"工作流提交结果: {run_result}")

        if run_result.get('code') == 0:
            task_id = run_result['data']['task_id']
            print(f"任务ID: {task_id}")
            time.sleep(60)  # 等待任务处理

            # 查询结果
            result = coze_api.get_workflow_result(task_id)
            print(f"任务结果: {result}")

            # 精简结果判断逻辑
            status_map = {
                'success': f"测试成功!\nURL: {result.get('result_video_url')}\n本地路径: {result.get('local_video_path')}",
                'processing': "任务仍在处理中",
                'failed': f"任务失败: {result.get('error_message')}"
            }
            print(status_map.get(result.get('status'), " 未知状态"))
    except Exception as e:
        print(f" 测试失败: {str(e)}", exc_info=True)

2 前后端架构文档

# 1 架构说明书是由公司架构师编写,规定,规范的--》后期开发人员按照这个说明书的要求开发项目
	-内部涵盖开发技术,数据库等等
    
# 2 使用Codex生成---》大家不用改了,如果大家不懂后端和小程序开发,好多技术点大家可能看不懂


# 3 提示词
根据01-需求分析/项目需求.md 和02-UI设计下所有html设计图,生成项目架构设计文档,包含后端架构文档和微信小程序架构文档

要求:

1.后端使用Python+Django 4 + Mysql8 + DjangoRestFramework等技术实现。

2.微信小程序端使用小程序原生框架。

3.后台管理使用django 自带admin和Simpleui美化。

4.前后端目录结构都一并生成,后端接口格式和参数和返回值格式也生成。

5.后端数据库设计:设计出项目所需表和字段(简要ER图),用户表使用Django自带的User表。

6.以Markdown格式生成并输出。

7.后端文档写入到文件中: 03-架构设计 /1-项目后端架构文档.md。

8.微信小程序文档写入文件: 03-架构设计 /2-微信小程序架构文档.md。

2.1 详见老师的--》在资料中存放

3 Mysql数据库环境

3.1 本地安装mysql

# 1 本地安装mysql【本地开发和测试】---》后续项目上线,要在服务器上安装mysql【简单一些】

# 2 mysql 开源数据库,有很多版本
	-企业主流使用:mysql8版本
    -少量企业:mysql7版本
    -极少量企业:mysql9版本
    
# 3 mysql 数据库管理软件
	-1 软件--》装在操作系统上-->就像qq,微信,是个软件,需要转在操作系统上
    -2 库 :你家,张三家,李四家--》有好几个库,相互隔离
    -3 表 :你家有一个个房间:你的房间,你爸的房间,你妹妹的房间
    -4 数据:房间中存放的物品
    

# 4 具体例子【excel表格】:用户表、口播历史表。。。
# User 表
id   name        password    age
1    zhangsan     1234        18
2    lqz          666         19


# 5 使用python程序来操作数据库:安全,可靠,效率高

image-20260816210217741

# 1 我很早之前写一了一篇文章:安装mysql :https://zhuanlan.zhihu.com/p/571585588


############### 具体步骤 ######################
# 1 下载mysql8.4.4
	-https://downloads.mysql.com/archives/community/
# 2 解压到某个路径下--》不要带中文
	-D:\soft\mysql-8.4.4-winx64
        
        
# 3 在 bin所在目录创建 my.ini   # 后缀名注意,不要带 .txt

# 4 创建 data文件夹:D:\soft\mysql-8.4.4-winx64\data\
########## 在 my.ini 中写入

[mysqld]
port=3306
basedir=D:\\soft\\mysql-8.4.4-winx64\
datadir=D:\\soft\\mysql-8.4.4-winx64\\data\
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为utf8
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8mb4
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8mb4




# 5 来到mysql解压后的bin路径下(以管理员身份运行)
以管理员打开cmd
D:   # 回车
cd D:\soft\mysql-8.4.4-winx64\bin
    
    
# 6 安装mysql  安装完成后Mysql会有一个随机密码(记住这个密码)--》这里可能会出错  dll文件缺失
mysqld --initialize --console

# 密码: FXfM&kQoi2lL


# 7 把mysql创建成系统服务 :以后开机后自启动
mysqld --install mysql844

# 8 启动mysql服务
net start mysql844

# 9 停止服务
net stop mysql844
#### 或者在我的电脑--》管理--》服务中--》点击开启或停止

# 9 做成服务后,没有开启自启动--》win关机了,再开启,mysql没启动
命令行中执行:net start mysql844
在服务上点右键启动
如果做成了  自动  --》以后重启后,都是自动开启

# 10 做成开机自启动
	如下图

image-20260816211646613

image-20260816212627062

image-20260816213039564

3.2 修改mysql密码

# 1 打开cmd
以管理员打开cmd
D:   # 回车
cd D:\soft\mysql-8.4.4-winx64\bin

# 2 来到这个路径下输入:D:\soft\mysql-8.4.4-winx64\bin  输入 
mysql -uroot -p -P 3306  # 回车后,输入密码,进入后
# 3 改密码
ALTER USER 'root'@'localhost' IDENTIFIED BY 'lqz123?';
FLUSH PRIVILEGES;
quit # 退出

# 4 mysql 装好后,可以在黑色的命令窗口下操作mysql--》需要用命令
	- 不学命令,学习使用图形化界面操作

3.3 Navicat操作mysql

# 1 在黑色命令下操作数据库,需要会很多命令--》很难记---》使用图形化界面连接操作--》点点的即可

# 2 mysql官方没有提供可视化,只能用命令,有很多第三方,用谁都行:收费的,免费的,最好用的: Navicat
### DBeaver
优点:DBeaver功能比较强大,使用也较便利。缺点:对于系统资源要求较高,运行速度相对较慢,特别是导入大文件时比较明显。官方主页:https://dbeaver.io/
    
#### Navicat--收费的--》破解--》好用
# 个人没事

# 不要在公司内部使用破解--》这个公司能根据你的ip--》定位到你公司--》发律师函--》告你
优点:Navicat使用普及率较高,功能非常完整,包括比较强大的SQL补全、导入导出、结果集编辑、E-R模型、数据对比、结构对比、数据迁移等,但有部分功能仅企业版才具备。缺点:需要注册为Navicat用户才能够使用,而且定期会失效,需要重新下载和登录申请为免费使用。官方主页:https://navicat.com/
    
####SQLyog
SQLyog更多的是专注于数据库的管理,包括性能、监控、优化等方面,也提供基础SQL编辑功能,所以在早期,其在DBA群体中比较受欢迎,但是在整体的开发者中,使用比率并不高。缺点:在云时代对于监控与实例管理方面的诉求在降低,在SQL开发与云适配上需求更强,但这方面发展缓慢,而且产品以商业收费版为主。官方主页:https://webyog.com/product/sqlyog/

3.3.1 破解Navicat

# 1 双击安装:navicat160_premium_cs_x64.exe
	-安装完后,要付费,可以试用30天--》嫌破解麻烦可以试用30天
    
    
# 2 如下步骤破解
    1. 以管理员身份运行 NavicatCracker.exe
    2. 断网
    3. 选择安装目录
    4. 点击 Patch!
    5. 点击 Generate!
    6. 使用生成的序列号激活
    7. 弹出激活失败窗口 选择 手动激活
    8. 将 Navicat 给的请求码复制到注册机 Request Code 中
    9. 点击 Generate Activation Code!
    10. 使用激活码激活
# 3 连接mysql :如下图


# 4 创建一个数据库:shuziren

image-20260805035958367

image-20260805040020613

image-20260805040127075

image-20260805040151872

3.3.2 操作mysql

# 1 Navicat连接到mysql【图形化界面】

# 2 创建一个数据库:shuziren
	-字符集:utf8mb4

image-20260623211945309

image-20260623212035792

image-20260623212143675

image-20260623212329967

image-20260816215030232

4 Codex编写后端项目

4.1 提示词

# 1 本地后端环境搭建好了--》使用提示词,让Codex编写后端了

# 2 提示词:思考模式改成 高
根据项目需求:01-需求分析/项目需求.md 和项目后端架构文档:03-架构设计/1-项目后端架构文档.md  和前端设计图:02-UI设计 ,生成口播数字人微信小程序后台Django的项目和代码
要求:
1.项目写入到目录shuziren_api中。
2.生成相关表模型,写入到每个app的models中。
3.生成所有接口,并能正常调用。
4.链接数据库地址为:
    -host:127.0.0.1
    -port:3306
    -database:shuziren
    -user:root
    -password:lqz123?
5.Django 后台admin使用django-simpleui美化,项目做好本地化和时区设置。
6.口播数字人功能对接Coze数字人工作流,对接方案参照代码:coze_shuziren.py
	-API_KEY:pat_v3bcwP3HOJxuUr7a6VWau4HEbFBMwFNzlHvy6vhQ3URBIaxMBFZOpDBuFUrEYBfE
    -工作流ID:7669850629418647590

5 小程序概述

5.1 创建小程序账号

# 1 访问【微信公众平台】,注册一个微信小程序账号
	-https://mp.weixin.qq.com/
# 2 申请账号需要准备一个邮箱,该邮箱要求:
    -未被微信公众平台注册
    -未被微信开放平台注册
    -未被个人微信号绑定过
    -如果被绑定了需要解绑 或 使用其他邮箱
    
# 3 注册过程中需要微信扫码-->绑定你个人微信--》后续用微信扫码登录

image-20240401162948430

image-20240401163023686

image-20240401163050951

image-20240401163142613

image-20240401163812295

image-20240401163835864

image-20240401163920407

image-20260623221003511

image-20260816220120056

5.2 小程序开发流程

# 1 注册号微信小程序账号,就可以开发微信小程序了

# 2 使用微信提供的专门的开发工具:类似于Pycharm


5.3 微信开发者工具

# 0 后端代码Codex帮我们写的,前端小程序代码:Codex帮我们写的---》运行项目查看样子?
	-后端:Pycharm
	-微信小程序:微信开发者工具


# 1 查看codex帮我们写的样子,调试bug--》需要用微信开发者工具
# 2 微信开发者工具:
	-https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
# 3 一路下一步安装
# 4 双击点开
# 5 创建项目,进入

image-20260626204648254

5.4 创建微信小程序项目

# 0 Codex 无论项目有或没有,都能帮我们做
	0--1 一个项目:Django后端
    1--100:这个项目有了,我们让Codex加功能,改bug,以微信小程序为例

# 1 Django项目,我们创建了吗?没有,Codex从0到1写的
	
# 2 微信小程序,我们不从0创建了【绝对能从0创建】,我们先创建好,有个页面【很简单】--》继续编写完成我们的要求


# 3 我们创建的小程序项目,有一个页面,显示 LQZ
	-我们的数字人,有很多页面
    -从1--100:项目有页面,只是不符合我们需求,我们继续使用Codex帮我们开发完成

image-20251214222738937

image-20251214222834477

image-20260626204957355

image-20260816222144212

image-20260626205730090

image-20251214223322534

image-20260816222324467

image-20260816222506896

posted @ 2026-08-23 09:41  凫弥  阅读(2)  评论(0)    收藏  举报