day13-Trae开发微信小程序02

day13-Trae开发微信小程序02

今日内容

0 回顾项目开发流程

######### 1 标准企业中软件开发流程#####################
# 1 公司立项: 一键换脸微信小程序
# 2 产品经理设计:项目需求,功能-使用工具,软件:墨刀,制作  原型图--》基本都是黑白的--》展示项目功能和流程# 3 UI部门设计软件界面-参照原型图设计---》UI设计图-美工:PS软件,画图,切图# 4 分任务,部门开发-在分部门开发之前--》有个架构说明书做指导-前端:我们看到的页面--》拼多多小程序-后端:对前端功能的数据和业务支撑-后端开发:后端--》项目架构设计会-订单组-用户组-前端开发:小程序-订单组-用户组# 5 测试:软件测试,联调# 6 运维部门:上线-服务器---》互联网用户都可以使用# 7 运营################# 2 一键换脸微信小程序  ###########
1 微信小程序端:             2 个人-界面--》UI设计图2 后端:Python + Django:   2 个人3 数据库:存储数据-mysql

image-20260616200455249

1 UI示意图

# 1 美工上场---》设计软件的界面,图片等等# 2 我们借助于Trae帮我们生成界面图---》可能不会完全符合我们的需求---》需要多次调整
# 3 使用Trae生成UI示意图三种生成方式:结合起来用

1.1 通过提示词生成

你是一位资深设计师,你非常了解微信小程序的设计风格,拥有丰富的全栈开发经验和极高的审美,擅长设计现代风格的微信小程序端界面## 我的微信小程序需求是:
我要做一款智能换脸微信小程序,你根据需求分析书,设计出界面## 我的要求
1.页面元素尽量高级美观,遵循移动端设计规范,注重UI设计细节。
2.所有数据使用假数据,所有页面都可以点击交互。
3.图标使用CDN方式引入。
4.把设计图生成在  目录下,每个子页面都是一个但单独的html,方便在一个页面展示全,index.html里把所有子页面展示出来。
5.界面尺寸模拟IPhone17 Pro,让页面圆角化,使其更像真实微信小程序界面。
6.不要带网络,时间等状态栏。请按以上要求生成完整的高保真原型图(html)

生成的UI示意图,我们查看后,如果有不满意的地方--》继续跟 Trae交互,让它修改--->直到我们满意即可

1.2 通过手绘图生成

# 1 提示词生成---》界面布局,颜色,功能按钮---》提示中没有描述特别清楚---》好多是大模型自己按自己的想法生成的# 2 我们想按自己想法做# 3 提示词 + 手画一个界面图我想做一个英语单词词汇量测试的小程序,根据这张手绘图,帮我生成首页UI设计,以html形式输出,尽量美观好看一些,你可以有自己的想法加入改动,帮我生成在当前项目目录下。

image-20260616211602314

1.3 通过图片生成

# 1 使用提示词,每次生成的界面样式可能不一样
# 2 如果我们要控制一样--》严格--》使用图片生成
# 3 示意图哪里来?1 截图别人的软件截图使用2 找专业美工设计好---》使用设计图,让Trae生成

image-20260616210340521

2 项目架构设计

分前后端部门开发代码

-根据UI示意图--》设计项目功能,用代码实现

后端:python + django

​ -架构说明书:用什么技术?用什么数据库存数据?密码加密用什么方式?

前端:微信小程序原生开发

​ -架构说明书

2.1 Django介绍

# 1 Python 编程语言,可以写软件---》用来写 换脸小程序后端# 2 使用Python编写后端,需要使用一些框架:Web框架---》对外提供API接口-Django--》Python 界用来写web应用的框架# 3 框架:提供了很多基础模块和功能--》我们只需要在固定的位置写python代码,就能实现一个web软件# 4 开发在本地:使用django开发--》上线要把开发完的django项目,放在服务器上--》所有互联网用户都可以调用# 5 如果有同学想学django,网上找资料系统学习一下-我不建议【比较难】

image-20260616213435287

2.2 前后端架构设计提示词

# 1 架构说明书是由公司架构师编写,规定,规范的--》后期开发人员按照这个说明书的要求开发项目-内部涵盖开发技术,数据库等等# 2 使用Trae生成---》大家不用改了,如果大家不懂后端和小程序开发,好多技术点大家可能看不懂根据需求文档和UI设计图,生成项目架构设计文档,包含后端架构文档和微信小程序架构文档要求:1.后端使用Python+Django 4 + Mysql8 + DjangoRestFramework等技术实现。2.微信小程序端使用小程序原生框架。3.后台管理使用django 自带admin和Simpleui美化。4.前后端目录结构都一并生成,后端接口格式和参数和返回值格式也生成。5.后端数据库设计:设计出项目所需表和字段(简要ER图),用户表使用Django自带的User表。6.以Markdown格式生成并输出。7.后端文档写入到文件中: 3-架构设计 /1-项目后端架构文档.md。8.微信小程序文档写入文件: 3-架构设计 /2-微信小程序架构文档.md。

3 后端环境搭建

Trae可以帮我们开发后端项目,但是最好,我们先把环境搭建好

在本地开发--》需要搭建本地的开发环境

直接让Trae写代码,然后写完,我们运行测试即可

3.1 Python环境

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

image-20260616220148774

3.2 Django环境

# 1 Django 环境,可以不用搭建
# 2 Trae会帮我们搭建的# 3 想搭建:按照如下步骤1 打开cmd2 pip install django==4.2# 4 在我们本地的python解释器上,装了django框架python3.13+django4.2 ---》就可以开发Django项目了

image-20260616220728813

3.4 Python调用Coze换脸工作流代码

# 1 同学们不需要懂--》是我+AI写的-纯AI写有bug---》python调用coze工作流--》API是Coze提供的--》有的ai读不到Coze提供的文档--》有时候Coze文档改了--》ai还是用老办法写,就会有bug-把coze文档的说明网页给AI不行吗?--》》可以解决百分之90的问题-Coze的官方文档--》可能更新不及时-# 2 我之前讲课,写好一版--》能用-但是后来coze工作流API更新了---》就不能用了-我调了一下--》改好了---》之前视频的代码是不能用的-最新的代码才可以# 3 使用代码之前:1 获取换脸工作流的id号:75369600502929981542 获取令牌:https://www.coze.cn/open/oauth/pats-pat_jrwsm03uyMusYK15j9Fm7rMLKZ34uslMY5Wl0m0rcsKdm8jlYy40zpi3FV9WZ2TV3 修改下面代码

image-20260616221321758

import requests
import json
import time
import os
from typing import Optional, Dict, Any'''
个人访问令牌:https://www.coze.cn/open/oauth/pats
轮询配置说明:
POLL_INTERVAL: 每次查询间隔(秒)
MAX_WAIT_SECONDS: 任务最大等待总时长(秒),超时直接终止
'''class CozeAPI:"""Coze API客户端,用于调用Coze的换脸工作流"""# 轮询全局配置POLL_INTERVAL = 20    # 每20秒查询一次任务状态MAX_WAIT_SECONDS = 600 # 最长等待600秒,超时失败REQUEST_TIMEOUT = 15  # 单次http请求超时时间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('face_swap', 'coze_results')os.makedirs(result_dir, exist_ok=True)filename = f"result_{task_id}_{int(time.time())}.jpg"return os.path.join(result_dir, filename)def download_image(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, timeout=self.REQUEST_TIMEOUT)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 Nonedef 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}")upload_header = {'Authorization': f'Bearer {self.api_key}'}with open(file_path, 'rb') as f:files = {'file': (os.path.basename(file_path), f)}resp = requests.post(self.upload_url,headers=upload_header,files=files,timeout=self.REQUEST_TIMEOUT)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_idraise Exception(f"文件上传失败: {result}")except Exception as e:print(f"文件上传异常: {str(e)}")raisedef run_workflow(self, source_image: str, target_image: str) -> Dict[str, Any]:"""运行Coze换脸工作流,异步提交任务,返回task_id"""try:# 批量上传文件source_id, target_id = self.upload_file(source_image), self.upload_file(target_image)payload = {"workflow_id": self.workflow_id,"parameters": {"face": json.dumps({"file_id": source_id}),"backend": 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,timeout=self.REQUEST_TIMEOUT)if resp.status_code != 200:raise Exception(f"工作流调用失败: {resp.status_code} | {resp.text}")result = resp.json()if result.get('code') == 0 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)}")raisedef get_workflow_result(self, task_id: str) -> Dict[str, Any]:"""单次查询工作流执行结果"""try:print(f"查询任务 {task_id} 状态...")query_url = f"{self.base_url}/v1/workflows/{self.workflow_id}/run_histories/{task_id}"resp = requests.get(query_url, headers=self.headers, timeout=self.REQUEST_TIMEOUT)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_list = result.get('data', [])if not data_list:return {'status': 'processing', 'task_id': task_id}data = data_list[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': data.get('error_reason', '未知执行错误'),'task_id': task_id}# 其余状态统一视为处理中return {'status': 'processing', 'task_id': task_id}except Exception as e:print(f"查询结果异常: {str(e)}")raisedef wait_workflow_finish(self, task_id: str) -> Dict[str, Any]:"""循环轮询等待任务完成:param task_id: 异步任务ID:return: 最终任务结果(成功/失败)"""start_time = time.time()while True:# 判断是否超时elapsed = time.time() - start_timeif elapsed >= self.MAX_WAIT_SECONDS:return {'status': 'timeout','error_message': f"任务超时,已等待{self.MAX_WAIT_SECONDS}秒仍未完成",'task_id': task_id}try:res = self.get_workflow_result(task_id)status = res.get('status')if status in ('success', 'failed'):return resprint(f"任务仍在处理中,已等待{round(elapsed,1)}s,{self.POLL_INTERVAL}s后重新查询...")except Exception as e:print(f"本次查询接口出错,跳过本次: {str(e)}")time.sleep(self.POLL_INTERVAL)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', '{}'))image_url = result_data.get('out') # 原来是output,现在变成 outif not image_url:return {'status': 'success','message': '任务成功但未返回图片链接','task_id': task_id}local_path = self.download_image(image_url, task_id)return {'status': 'success','result_image_url': image_url,'local_image_path': local_path,'processing_time': data.get('processing_time', 0),'task_id': task_id}except (json.JSONDecodeError, KeyError) as e:print(f"解析输出JSON失败: {str(e)}")return {'status': 'success','message': f'任务执行成功,但解析返回数据异常:{str(e)}','task_id': task_id}if __name__ == '__main__':try:coze_api = CozeAPI()source_path, target_path = './test_source.jpg', './test_target.jpg'print("===== 开始测试Coze异步换脸工作流 =====")# 1. 提交异步任务run_result = coze_api.run_workflow(source_path, target_path)print(f"任务提交返回: {run_result}")if run_result.get('code') == 0:task_id = run_result['data']['task_id']print(f"获取任务ID: {task_id}")# 2. 循环轮询等待任务结束(替换原来固定sleep)final_result = coze_api.wait_workflow_finish(task_id)print("\n===== 任务最终结果 =====")print(final_result)# 3. 结果分类打印status = final_result.get('status')if status == 'success':print(f"\n✅ 换脸成功!")print(f"在线图片地址:{final_result['result_image_url']}")print(f"本地保存路径:{final_result['local_image_path']}")elif status == 'failed':print(f"\n❌ 任务执行失败:{final_result['error_message']}")elif status == 'timeout':print(f"\n⏰ 任务等待超时:{final_result['error_message']}")else:print(f"\n❓ 未知任务状态:{status}")except Exception as e:print(f"\n❌ 程序整体异常: {str(e)}")

image-20260616221700175

image-20260616221737309

4 微信小程序学习

# 如果大家想学习---》一套资料给大家
视频:https://www.bilibili.com/video/BV1WgQdYNERe/
笔记:https://pan.baidu.com/s/1VTd6S3rJKQ42MRFPsFwaZQ 提取码: bpxa