553 Commits

Author SHA1 Message Date
c649907222 数据迁移代码 2025-08-31 14:16:08 +08:00
c93ae85b65 BUGFIX: 1、singleDesign使用generate的印花没有传minio导致出现错误
2、项目中没有保存生成和上传的印花的类型
2025-08-29 14:18:17 +08:00
6441bfbbba BUGFIX: 子账号信息无法正确导出为excel 2025-08-28 19:22:55 +08:00
933522482b TASK:审批affiliate 2025-08-28 14:01:48 +08:00
56b56981b1 TASK:便利查询,查询所有用户id时根据用户身份限定查询范围 2025-08-28 11:29:30 +08:00
9e2ea2de62 TASK:导出数据时添加校验 2025-08-27 17:40:05 +08:00
7005b75e11 TASK:导出数据时添加校验 2025-08-27 15:24:43 +08:00
5b09d2cbf5 BUGFIX:查询design使用情况数据不对 2025-08-27 14:57:15 +08:00
126ac209c6 BUGFIX:普通生成积分扣除有误 2025-08-27 14:15:58 +08:00
98eb29eeb5 BUGFIX:普通生成积分扣除有误 2025-08-27 13:44:32 +08:00
ee551a0be2 BUGFIX:编辑子账号邮箱时积分回流策略有漏洞 2025-08-27 11:41:07 +08:00
c3cbb61c16 BUGFIX:积分扣除失败 2025-08-27 11:22:08 +08:00
71f0293cd9 BUGFIX:修改用户邮箱异常时事务没回滚 2025-08-27 10:39:46 +08:00
35604e5130 BUGFIX:超管创建机构管理员 2025-08-27 10:15:59 +08:00
18c38b020e TASK:默认积分分配改为平均分配;超级管理员可新增教育、企业管理员账户;组织成员使用积分时需要记录creditsUsage;试用用户初始50积分 2025-08-26 23:53:40 +08:00
6e9213ec5a BUGFIX:获取brand dna计算时间为空 2025-08-26 16:24:52 +08:00
83ba69c950 BUGFIX:子账号批量导入、brand dna返回计算时间、按权限范围查询design频次 2025-08-26 15:49:02 +08:00
3cc329f983 param change 2025-08-26 14:49:43 +08:00
c42ee8a1bf Merge branch 'dev/dev_xp' into dev/dev 2025-08-26 14:27:50 +08:00
9a650afc7d TASK:优化查询子账号design试用频次,根据管理员身份限定查询范围 2025-08-26 14:10:28 +08:00
45a336ced3 TASK:brand dna获取进度 返回计算时间 2025-08-26 13:33:28 +08:00
e258166a16 Merge branch 'dev/dev_xp' into dev/dev 2025-08-26 11:54:24 +08:00
f9ec733f07 BUGFIX: 编辑referral状态 2025-08-26 11:53:53 +08:00
54b09b4940 TASK:万相补偿获取结果之后通知用户 2025-08-26 09:35:18 +08:00
6d0c29f5c3 TASK:motion生成完成后邮件通知 2025-08-25 18:16:57 +08:00
23523f73da TASK:教育版子账号积分刷新策略更新 2025-08-25 18:07:37 +08:00
e45d572078 TASK:Stripe订阅,添加月付(经济版)及相应费用、积分的更新 2025-08-25 15:02:34 +08:00
eebb790aeb BUGFIX:教育子账号新增-积分分配问题 2025-08-25 09:18:07 +08:00
9c6573f1a6 BUGFIX:删除library元素时没有将brand中关联的数据删除,导致出现空指针 2025-08-22 15:27:09 +08:00
6a5282e4d5 BUGFIX:将已存在的账号添加到子账号中,积分计算混乱 2025-08-21 16:03:24 +08:00
3c5a5ff225 Merge branch 'dev/dev' into dev/dev_xp 2025-08-21 13:22:48 +08:00
e4ce7e9e63 TASK:获取affiliate的用户名和id;BUGFIX:模特无法保存 2025-08-21 13:22:22 +08:00
1089a5a2a5 TASK:flux 生成pattern时输出图片比例设置为1:1 2025-08-20 18:15:46 +08:00
156fcfae6b Merge branch 'dev/dev_xp' into dev/dev 2025-08-20 18:02:18 +08:00
7436fa17c0 TASK:添加接口说明 2025-08-20 18:01:28 +08:00
d9f19f1728 Merge branch 'dev/dev_xp' into dev/dev 2025-08-20 16:41:14 +08:00
81c417ed76 BUGFIX:1、子账号查询,无法批量根据用户名或邮箱查
2、教育版子账号创建及修改涉及的积分问题
2025-08-20 16:40:44 +08:00
59a3015170 TASK:查affiliate列表接口添加参数校验;打开佣金计算定时器 2025-08-20 09:37:35 +08:00
b02009bf14 Merge branch 'dev/dev_xp' into dev/dev 2025-08-19 17:45:11 +08:00
caa9985d11 TASK: 1.affiliate 新增referral新增、查询、修改以及其他相关的自动结算佣金的功能;2.删除affiliate_income表及相关mapper 2025-08-19 17:44:34 +08:00
80957bfc00 Merge branch 'dev/dev_xp' into dev/dev 2025-08-19 09:33:16 +08:00
552ec828ab BUGFIX:1、删除模特后保存失败
2、获取个人库中的模特不准确
2025-08-18 16:18:51 +08:00
42273750f4 BUGFIX:从缓存获取模特 2025-08-15 18:00:41 +08:00
45d6af92e8 BUGFIX:1、教育通过上传文件批量创建子账号没有任何校验
2、下载子账号所有信息接口缺失(原下载模板接口保留)
3、保存个人模特到collection时类型设置为System
4、创建子账号时设置积分无效
2025-08-15 17:44:45 +08:00
c28db81893 BUGFIX:同一浏览器切换版本登录时,密码被置空 2025-08-13 16:45:30 +08:00
1e25ae36f1 TASK:1、教育版添加新用户、修改用户、移除用户需求更改;2、修改登入校验条件
BUGFIX:当用户积分为空时报错
2025-08-13 15:52:19 +08:00
9bf40d879f BUGFIX: 用户选择作品进行二创后,无法正确展示原作品中被like的design 2025-08-05 16:50:54 +08:00
878f556a0b BUGFIX:分页查询所有项目历史记录,根据更新时间排序,解决项目记录没有更新时间导致空指针问题 2025-08-04 13:29:12 +08:00
4ad2cd027c TASK:1. 通过定时任务,补偿获取第三方api的运行结果;
2. pose 生成,对使用万相模型的生成限流,最大支持5个并发
3. Slogan限流,一分钟内,最多接收3个请求
2025-08-01 17:21:41 +08:00
132f48eb60 CONFIG:dev添加死信队列信息 2025-08-01 11:29:47 +08:00
5b33e31504 BUGFIX:画布存在minioUrl为空的情况,此时不处理minio地址 2025-08-01 11:12:11 +08:00
e16268a013 TASK: 邮件模板 2025-07-31 18:20:43 +08:00
739e637267 TASK: 发送邮件功能及发送失败后的重试机制 2025-07-31 15:57:47 +08:00
7edc959432 TASK: 保存画布时返回画布id
BUGFIX: 用户输入的prompt没有传入flux
2025-07-31 14:57:20 +08:00
c444d5a69f TASK: to product、relight、pose未like的数据也需要返回parentId 2025-07-30 15:12:38 +08:00
830d06a900 BUGFIX: 更新flux生成结果失败 2025-07-29 15:59:57 +08:00
0fcd8e5444 BUGFIX: 1、修改画布时,不再上传新文件,改为覆盖原文件
2、删除toProduct relight结果时没删干净导致获取源文件失败
2025-07-29 15:00:13 +08:00
020cfe9016 TASK:design single中添加单件衣服画布保存 2025-07-29 13:12:20 +08:00
39903f3da6 BUGFIX:循环依赖导致项目无法启动 2025-07-28 17:27:00 +08:00
b1d682a909 TASK:1、to product修改任务状态字段为task 2、异步向api_generate表中添加记录 3、优化flux结果获取,避免重复获取结果时因图片过期覆盖原可用图片 2025-07-28 15:01:16 +08:00
07d60303db BUGFIX: to product 用户未输入prompt时,出现空指针 2025-07-28 12:10:39 +08:00
5287d83b82 BUGFIX:1、userLikeService中业务划分不清晰导致与generateService出现循环依赖问题。解决:将CollectionSort单独划分为一个Service
2、新建t_api_generate表用于补偿查询生成结果
2025-07-25 17:13:06 +08:00
e2085190d1 BUGFIX:单品设计存储时,不要涉及body相关数据 2025-07-25 13:17:23 +08:00
565b5c3de1 BUGFIX:单品设计偏移量为空问题 2025-07-24 17:18:40 +08:00
fd29452e0c BUGFIX:flux请求失败后的日志打印问题 2025-07-24 11:33:28 +08:00
0f93099d04 BUGFIX:修改获取flux结果的get方法名 2025-07-24 09:40:34 +08:00
e2d50a6dfa TASK: 优化generate请求方法,将长方法拆分为由多个小方法组成 2025-07-23 17:25:00 +08:00
c4d20cd522 TASK: 1、印花生成允许使用flux
2、修改sketch\print允许修改上传的元素
3、印花生成结果中添加level2Type
2025-07-23 16:59:41 +08:00
229e1353f4 BUGFIX: 获取万相的生成结果时没有返回status 2025-07-22 17:36:16 +08:00
07571aaad1 TASK: 画布数据 回参处理不为空时的minio地址 2025-07-22 13:42:07 +08:00
bb0a3bd1cd BUGFIX: 1、允许存储没有潘通值的颜色
2、getModule时design子元素回参增加
2025-07-22 11:09:47 +08:00
3bd9ff82d7 BUGFIX: 获取我的作品时,无法查看设置为私有的作品 2025-07-21 17:54:12 +08:00
f0fccaaf51 TASK:pose transfer添加返回参数 2025-07-21 17:11:10 +08:00
2041809ea6 TASK:pose transfer添加返回参数 2025-07-20 19:19:07 +08:00
e2e0bd6b47 TASK:toProduct relight pose 返回的数据中需包含设置的参数信息 2025-07-18 16:37:37 +08:00
785ae33e86 BUGFIX: 旧作品中有的没有项目id 2025-07-17 17:34:03 +08:00
20f7dc0ef9 TASK:作品更新接口,将通过projectId替换userLikeGroupId 2025-07-17 17:21:14 +08:00
0155154664 BUGFIX: cloudTask数据插入的时间晚于python端向MQ中发消息的时间 2025-07-17 11:48:38 +08:00
d264c29557 TASK: 删除toProduct Relight Pose后重新排序 2025-07-17 10:51:43 +08:00
432149dce2 TASK: 拼贴 未进行生成时也显示上传的图片 2025-07-16 19:29:52 +08:00
5b3a52152a TASK: ToProduct Relight Pose新增删除接口 2025-07-16 19:14:41 +08:00
301f58bc62 TASK: 拼贴功能保存用户上传的图片并返回 2025-07-15 18:11:12 +08:00
64318de24a BUGFIX: 创建pose transfer任务error 2025-07-15 13:12:29 +08:00
fb01250142 BUGFIX: 通过projectId获取pose transfer结果路径出错 2025-07-15 13:02:59 +08:00
0beec5392e Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java
2025-07-15 12:10:55 +08:00
f551ba452f BUGFIX: 通过projectId获取pose transfer结果路径出错 2025-07-15 11:58:13 +08:00
f4b22fe874 BUGFIX: 1、还未生成出结果但是没有失败的pose transfer需返回taskID 2025-07-14 19:17:21 +08:00
e95444266b BUGFIX: 1、getModuleContent没有返回taskId
2、万相生成的pose没有更新状态
2025-07-14 18:05:10 +08:00
e361960e51 TASK: 1、对于生成失败情况,在数据库添加状态记录,并在getModuleContent时不返回该条记录 2025-07-11 17:56:15 +08:00
d0a9c05d4b BUGFIX: 1、相同的relation_id,relation_type重复排序,针对脏数据做处理 2、传入数据库中没有的userLikeSortId 2025-07-11 14:22:38 +08:00
f852927116 BUGFIX: 1、积分重复扣除 2、pose transfer没有开始时间,没有项目id 2025-07-11 11:07:27 +08:00
daa88889d0 TASK:1、印花允许修改并保存
BUGFIX: 1、批量生成有的类型没有任务开始执行时间,任务结束时间有误
2025-07-10 17:50:31 +08:00
766e75f2ed BUGFIX: 批量生成积分扣除有误 2025-07-10 13:38:00 +08:00
eb7f2a1419 BUGFIX: 批量生成积分扣除有误 2025-07-10 11:24:25 +08:00
c7c69417ef TASK: 1、更换pose,重新生成templateId
2、brandDNA 开启分析attributes功能
2025-07-09 17:01:53 +08:00
9f548d299b TASK: 默认不like时,不要将元素添加到父元素子集但是要返回parentId 2025-07-09 12:10:10 +08:00
1dc6c6f8c4 TASK:生成获取结果接口返回parentId 2025-07-08 18:53:21 +08:00
5472e59a84 TASK: sketchboard library数据添加年龄组 2025-07-08 16:09:01 +08:00
d379f778dc TASK: 默认不like的元素,如有parentId,需要添加到CollectionSort表中 2025-07-08 14:29:54 +08:00
ec44c2a6b5 TASK: 1、默认不like的元素,如有parentId,需要回传
2、project查询 需要按id查
2025-07-08 13:54:27 +08:00
1f77500d61 TASK:product/relight/pose transfer的入参添加是否需要默认like 2025-07-08 11:39:05 +08:00
060db899cf TASK:product/pose transfer的回参添加sort和id 2025-07-08 10:21:28 +08:00
9fc8f52aca BUGFIX: 1、对话历史记录 有的回答没有深度思考标识 2、批量生成,积分扣除不足 2025-07-07 18:32:14 +08:00
9af1bc867a TASK:to product\relight的结果分like 没like返回 2025-07-07 16:34:22 +08:00
e92bb0c7cd TASK:获取模板内容 不再限制是否like 2025-07-07 14:49:36 +08:00
1d07d7d88a TASK:generate 普通生成改回按生成次数收费 2025-07-07 14:26:21 +08:00
ec7d84b354 BUGFIX:未生成完成的项目获取moduleContent报错 2025-07-07 14:14:45 +08:00
0a2c5e028f BUGFIX:对项目进行各种生成修改时没有更新项目更新时间 2025-07-07 11:53:50 +08:00
4379b9cff1 BUGFIX:design中的排序问题 倒序问题 再次修改 2025-07-04 19:08:59 +08:00
1b7c2041be BUGFIX:design中的排序问题 2025-07-04 17:20:35 +08:00
f3632f53e3 BUGFIX:生成没出结果之前获取结果报空指针 2025-07-04 12:43:14 +08:00
d76a9e6afd 1、design流程中使用to product、relight、pose transfer默认加到like
2、万象的pose transfer结果存到redis
2025-07-04 12:02:05 +08:00
e67acc4319 1、添加日志打印
2、batch获取结果报错
2025-07-03 19:03:45 +08:00
373a360e76 BUGFIX:FLUX童装prompt修改;获取video结果允许传入list 2025-07-03 14:20:33 +08:00
f541bee0e7 Merge branch 'dev/dev_xp' into dev/dev 2025-07-03 11:24:59 +08:00
75d086f680 pose transfer 万象入参添加日志打印 2025-07-03 11:21:10 +08:00
81ca723486 BUGFIX:Batch_Relight默认创建的项目类型是ToProduct 2025-07-03 09:48:21 +08:00
d51bbffb3e TASK:BrandDNA 2025-07-03 09:40:56 +08:00
07aad4afa0 Merge branch 'dev/dev_xp' into dev/dev 2025-07-02 19:04:52 +08:00
6495bb2be3 TASK:语言适配 2025-07-02 19:02:39 +08:00
3d8363c99b BUGFIX:批量生成创建姿势变更项目失败 2025-07-02 17:44:32 +08:00
333c11f81e 增加日志打印 2025-07-02 17:03:40 +08:00
77fc3e967a TASK: 批量生成 prompt微调获取接口,端口变更 2025-07-02 16:29:00 +08:00
a447cde05b TASK: 批量生成获取任务序号 2025-07-02 16:16:15 +08:00
e8ad241653 TASK: 生成项目参数 参数变更 2025-07-02 15:06:52 +08:00
1f824f3ae6 BUGFIX: 获取模块内容-pose transfer返回的图片无法显示 2025-07-02 13:35:15 +08:00
8c87333fa2 Merge branch 'dev/dev_xp' into dev/dev 2025-06-30 19:34:34 +08:00
4273d0efc0 BUGFIX: 系列设计 修改模特后,原模特丢失问题 2025-06-30 19:32:16 +08:00
a37b64be91 BUGFIX: 使用万象生成失败时直接报错 2025-06-30 15:54:58 +08:00
905d296bdf TASK: 批量生成 存储任务序号 2025-06-30 15:17:07 +08:00
9a25e8ce4a TASK: 批量生成 获取任务序号 2025-06-30 15:11:31 +08:00
68311e1d8b TASK: 通过对话创建项目 请求地址变更 2025-06-30 13:13:58 +08:00
de5da5b299 TASK: 对话 扣除积分 2025-06-30 12:03:23 +08:00
dcd63668bd TASK: 添加注释 2025-06-27 13:09:36 +08:00
shahaibo
1a52399ec9 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-27 09:59:39 +08:00
shahaibo
b01f5f59d1 TASK: 数据迁移拆分; 2025-06-27 09:59:08 +08:00
c70231d5de Merge branch 'dev/dev_xp' into dev/dev 2025-06-26 14:15:35 +08:00
d3deec72eb TASK: 切换chat agent请求api地址 2025-06-26 14:11:42 +08:00
shahaibo
a7347c9dc0 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-26 11:53:53 +08:00
shahaibo
6ad5d373d5 bugfix: single design没结果,posetransfer没回显正在进行的结果; 2025-06-26 11:21:35 +08:00
e048b75ed7 BUGFIX: 去除base64控制台输出 2025-06-25 19:13:57 +08:00
469681b96c BUGFIX: 向flux发起生成请求时,功能指定错误 2025-06-25 19:04:29 +08:00
89457b0593 TASK: 使用Flux生成前,to Product Image,为输入透明图添加白色背景 2025-06-25 18:43:52 +08:00
7a6b257714 BUGFIX:批量生成,获取design的结果中缺失ResultType 2025-06-25 17:20:35 +08:00
443b557623 BUGFIX:1、design 渐变色没存 2、展示文本更新 3、取消拼贴图入参日志打印 2025-06-25 17:10:56 +08:00
shahaibo
84691f45b5 bugfix: parentId结果返回; 2025-06-25 15:52:11 +08:00
de65f78e89 BUGFIX:Batch generation 创建时允许projectId为空 2025-06-25 14:10:24 +08:00
252cd0a69c BUGFIX:design 没有存储渐变色 2025-06-25 11:30:36 +08:00
d77aabca92 TASK:修改relight默认prompt 2025-06-24 19:35:07 +08:00
eaf90ab9e8 BUGFIX:注册用户登录没有邮件发送记录和登录记录 2025-06-24 17:53:52 +08:00
f828983969 BUGFIX:对话 控制台输出改为日志输出 2025-06-24 16:41:41 +08:00
be6eb64b35 Merge branch 'dev/dev_xp' into dev/dev 2025-06-24 16:30:28 +08:00
abc6c088fe BUGFIX:批量生成 relight和design创建的任务查不到 2025-06-24 16:27:15 +08:00
6f44489c6e BUGFIX:消息监听,消息解析失败,重复消费异常消息导致日志文件内容骤增 2025-06-24 16:11:53 +08:00
a809905c52 BUGFIX:batch generation like报错 2025-06-24 15:03:17 +08:00
7abab7121a BUGFIX:batch generate积分扣除报错 2025-06-24 14:22:41 +08:00
8e31968fd3 BUGFIX:1、积分消耗值不准确 2、flux获取结果报错 2025-06-23 18:16:23 +08:00
3d08e86049 BUGFIX:图片分割参数值变更 2025-06-23 13:44:56 +08:00
e0fdf1cc88 Merge branch 'dev/dev_xp' into dev/dev 2025-06-23 13:09:13 +08:00
4acdd8adb9 BUGFIX:1、积分扣除,金额不对 2、图片分割允许指定上传图片id 2025-06-23 12:02:16 +08:00
shahaibo
e8e6f8bc17 bugfix: posetransfer结果; 2025-06-20 17:28:34 +08:00
shahaibo
27983fe8ee bugfix: collectionSortParentId非必穿; 2025-06-20 17:01:47 +08:00
shahaibo
c3d92aacd5 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-20 16:29:06 +08:00
shahaibo
b287ec8529 bugfix: 对话中断排查日志添加; 2025-06-20 16:27:27 +08:00
07d3f6e224 Merge branch 'dev/dev_xp' into dev/dev 2025-06-20 16:23:38 +08:00
fc42f361fa BUGFIX:含小数的积分扣除失败 2025-06-20 16:14:56 +08:00
shahaibo
424f9a126d TASK: 结果返回parentId; 2025-06-20 15:20:35 +08:00
a042f05401 Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/model/vo/MagicToolResultVO.java
2025-06-20 14:57:39 +08:00
f59adbe9bd TASK:更新各生成功能需要消耗的积分 2025-06-20 14:53:10 +08:00
a0ece486d8 TASK:更新各生成功能需要消耗的积分 2025-06-20 14:49:15 +08:00
shahaibo
4caa0a9b0d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-20 13:51:21 +08:00
shahaibo
df5bbc3675 TASK: 结果返回parentId; 2025-06-20 13:50:29 +08:00
92278cf91b BUGFIX:获取all pose的预览地址报错 2025-06-20 12:01:17 +08:00
6b165fe5bc Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 18:26:16 +08:00
64b32dc3a3 BUGFIX:sketch搜索出的图片去白边失败 2025-06-19 18:24:07 +08:00
1f84b4b3e6 BUGFIX: 2025-06-19 17:22:43 +08:00
a0979caba6 Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 17:20:04 +08:00
18be52e806 BUGFIX: 1、llm使用sketch查询工具数据没有保存到历史记录中
2、flux运行失败状态下,获取结果报错
3、618福利邮件通知
2025-06-19 17:16:48 +08:00
shahaibo
627dad7aac Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-19 15:57:40 +08:00
shahaibo
7166db59bd Bugfix: 对话历史记录; 2025-06-19 15:44:26 +08:00
13759d806b Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 14:58:56 +08:00
0fd1ddcde1 TASK: 1、LLM对话新增两个工具,查找sketch和修改项目参数 2、新增接口获取最新的minio图片预览地址 2025-06-19 14:56:18 +08:00
shahaibo
a5e743ce84 TASK: 数据迁移; 2025-06-19 14:29:44 +08:00
161bba896c BUGFIX: 获取当前任务结果报错(获取模型名出现空指针) 2025-06-19 14:08:25 +08:00
shahaibo
da8338be3f Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-19 11:52:03 +08:00
shahaibo
ea235b0d5c bugfix: delete collection; 2025-06-19 11:50:39 +08:00
98ea6004b4 TASK: 新增pose transfer模特姿势选项 2025-06-18 14:19:45 +08:00
62cbc612a7 Merge branch 'dev/dev_xp' into dev/dev 2025-06-17 16:56:45 +08:00
589fa8501e TASK: 优化童装prompt 2025-06-17 16:54:23 +08:00
shahaibo
d6285781f2 bugfix: delete collection; 2025-06-17 16:29:06 +08:00
shahaibo
137ef7045b TASK: cloud、posetransfer; 2025-06-17 16:25:57 +08:00
shahaibo
5e066995e8 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-17 14:53:52 +08:00
shahaibo
c1c50cb28b TASK: cloud、posetransfer; 2025-06-17 14:51:19 +08:00
3f13f64ab9 Merge branch 'dev/dev_xp' into dev/dev 2025-06-17 14:43:10 +08:00
5abe45ff34 TASK: 当选择童装时,sketch生成和to product的prompt需添加儿童限定词 2025-06-17 14:41:27 +08:00
shahaibo
0970127f68 TASK: collection sort; 2025-06-17 10:10:00 +08:00
shahaibo
93bb8d2f31 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-17 09:42:15 +08:00
shahaibo
88d8b75298 TASK: collection sort; 2025-06-17 09:41:19 +08:00
ea395e87ba Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 18:52:41 +08:00
8d7b4adf48 BUGFIX: 1、sketch extract 没返回taskId
2、relight输入文本太长导致数据存储报错
2025-06-16 18:51:09 +08:00
e3ee724e6f BUGFIX:pose transfer 视频转GIF依赖操作系统环境切换 2025-06-16 18:25:32 +08:00
shahaibo
9d022ae13e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 16:55:37 +08:00
shahaibo
8b0f9cfd11 TASK: cloud、posetransfer、sort; 2025-06-16 16:53:50 +08:00
f36b3818c5 Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 16:17:56 +08:00
2ccbbf8893 BUGFIX:pose transfer 视频转GIF依赖缺失 2025-06-16 16:16:08 +08:00
76219aa4fe BUGFIX:pose transfer 记录重复存储问题 2025-06-16 15:32:32 +08:00
5ed3d8dfab Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 15:08:50 +08:00
4dd3ddb1d0 BUGFIX:无法获取wx pose transfer的结果 2025-06-16 15:07:22 +08:00
fb16840a98 Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 14:06:34 +08:00
9ad6acf28c BUGFIX:1、修改新增生成接口失败的状态 2、添加aliyun请求接口的密钥 2025-06-16 13:49:30 +08:00
shahaibo
774a20257d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 13:45:25 +08:00
shahaibo
3db0a94981 TASK: cloud、posetransfer; 2025-06-16 13:44:22 +08:00
891b26d493 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 11:04:34 +08:00
86a991db81 BUGFIX:获取当前生成来自哪个模型 2025-06-16 11:03:40 +08:00
shahaibo
fd8e6fd2e8 BUGFIX: 切换性别 年龄段; 2025-06-13 17:03:07 +08:00
78239d3ead Merge branch 'dev/dev_xp' into dev/dev 2025-06-13 16:41:15 +08:00
174d1bf0d0 TASK:1、将imageToSketch接口调用转为异步 2、imageToSketch加入flux 2025-06-13 16:37:45 +08:00
da9f54982c Merge branch 'dev/dev_xp' into dev/dev 2025-06-13 15:58:37 +08:00
b6993b04c2 TASK:视频图像处理依赖包精简 2025-06-13 15:55:17 +08:00
shahaibo
4cca30ec75 BUGFIX: cloud; 2025-06-13 15:09:32 +08:00
shahaibo
b6c43e534b BUGFIX: 上传元素删除; 2025-06-13 14:07:38 +08:00
shahaibo
942b5eb19b BUGFIX: cloud; 2025-06-13 11:48:08 +08:00
shahaibo
31b2bd97b4 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-13 10:56:44 +08:00
shahaibo
3eaa0d017c BUGFIX: cloud; 2025-06-13 10:55:55 +08:00
be42550d0a Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/model/dto/ToProductImageDTO.java
2025-06-12 16:54:15 +08:00
6e32289b98 TASK:Flux接入,应用于to product image和relight 2025-06-12 16:50:27 +08:00
shahaibo
a750a91f7b BUGFIX: 创建项目; 2025-06-12 15:59:15 +08:00
shahaibo
2cf3b75e46 BUGFIX: 创建项目; 2025-06-12 15:47:46 +08:00
shahaibo
9586be40ce TASK:3d print; 2025-06-12 13:50:04 +08:00
shahaibo
4494ec7dbc TASK:cloud; 2025-06-12 13:41:13 +08:00
shahaibo
33af9d0b9d TASK:cloud; 2025-06-12 13:31:34 +08:00
shahaibo
7f30b2d05b Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-12 13:13:31 +08:00
shahaibo
3cd86042ff TASK:上传回显; 2025-06-12 13:12:44 +08:00
af1fab644a pose transform 打开输入图片的检测 2025-06-11 17:45:17 +08:00
ace53e81f2 pose transform 开放自定义输入图片 2025-06-11 17:35:00 +08:00
shahaibo
f179368668 BUGFIX:library ageGroup切换; 2025-06-11 15:58:06 +08:00
shahaibo
9134933a07 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-11 11:39:01 +08:00
shahaibo
290f6a9a35 BUGFIX:library ageGroup切换; 2025-06-11 11:37:29 +08:00
ac2d1e611b BUGFIX: prompt提取接口传参格式修改 2025-06-10 18:13:53 +08:00
1b75e2ab55 TASK: prompt提取接口地址切换 2025-06-10 18:08:16 +08:00
de9750b24a Merge branch 'dev/dev_xp' into dev/dev 2025-06-10 17:53:03 +08:00
595effa04c TASK: 接入第三方api freepik 新增sketch extract variation 2025-06-10 17:50:04 +08:00
shahaibo
09e24ab062 TASK:cloud; 2025-06-10 15:05:41 +08:00
shahaibo
391208f8bd TASK:cloud; 2025-06-10 15:02:44 +08:00
shahaibo
3cf47eb723 TASK:cloud; 2025-06-10 11:13:17 +08:00
shahaibo
c3ce25315c TASK:cloud; 2025-06-10 11:03:15 +08:00
shahaibo
ae71564b94 TASK:cloud; 2025-06-10 10:55:56 +08:00
shahaibo
d6bd24865e TASK:cloud; 2025-06-09 13:41:02 +08:00
shahaibo
c420300c11 TASK:cloud; 2025-06-09 11:30:23 +08:00
shahaibo
4c67fce8d1 TASK:cloud; 2025-06-09 10:15:40 +08:00
shahaibo
b8d3b0192d TASK:cloud; 2025-06-06 17:18:59 +08:00
shahaibo
1afd86d3ce Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 15:25:26 +08:00
shahaibo
daa133b993 TASK:cloud; 2025-06-06 15:22:07 +08:00
shahaibo
bf258ee4f9 TASK:cloud; 2025-06-06 15:19:00 +08:00
2bc17ec4d0 Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 13:54:00 +08:00
090b9ab6ab TASK: 取消animate假数据,直接调用第三方接口 2025-06-06 13:53:43 +08:00
shahaibo
fb5b52bec2 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:58:01 +08:00
shahaibo
df678a12b9 TASK:cloud; 2025-06-06 11:57:10 +08:00
21f85a7322 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:51:34 +08:00
4e2590fd0f Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 11:51:06 +08:00
31c5fef5c0 BUGFIX: 获取万象生成结果时,需指定api_key 2025-06-06 11:50:41 +08:00
shahaibo
94e26ac912 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:10:58 +08:00
shahaibo
711859ce89 TASK:cloud; 2025-06-06 11:08:53 +08:00
8502fffb68 Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 11:03:45 +08:00
6f0cc3aaf8 TASK: 更换第三方access key获取方式,从系统变量中获取改为从配置文件中获取 2025-06-06 10:59:13 +08:00
shahaibo
ce13874431 TASK:cloud; 2025-06-06 10:51:25 +08:00
shahaibo
054c9fd604 TASK:cloud; 2025-06-06 10:46:57 +08:00
f5501db19e TASK: 接入第三方api 添加access key 2025-06-06 09:56:02 +08:00
4609af875e Merge branch 'dev/dev_xp' into dev/dev 2025-06-05 18:36:22 +08:00
1dad0a008a TASK: 接入第三方api 通过万象实现text2image和animate,完成数据传输与原接口的兼容 2025-06-05 18:03:19 +08:00
shahaibo
b757cdc5dd TASK:batch toProductImage;chatStream; 2025-06-05 17:09:03 +08:00
shahaibo
249351bf52 TASK:batch toProductImage;chatStream; 2025-06-05 17:06:11 +08:00
shahaibo
38ca810068 TASK:batch toProductImage;chatStream; 2025-06-05 15:44:23 +08:00
shahaibo
bab5c9a8e6 TASK:batch toProductImage;chatStream; 2025-06-05 15:33:08 +08:00
shahaibo
4e80493a26 TASK:batch toProductImage;chatStream; 2025-06-05 14:00:38 +08:00
shahaibo
12dbe90150 TASK:batch toProductImage;chatStream; 2025-06-05 13:35:13 +08:00
shahaibo
f2c268683c TASK:collection sort; 2025-06-03 15:05:40 +08:00
shahaibo
f69eaa4fe3 TASK:collection sort; 2025-06-03 14:39:56 +08:00
shahaibo
a9172dcd36 TASK:collection sort; 2025-06-03 14:31:51 +08:00
shahaibo
442e87267a TASK:collection sort; 2025-06-03 13:41:45 +08:00
shahaibo
32c8aaec9b TASK:collection sort; 2025-06-03 11:26:21 +08:00
shahaibo
112294bd7b TASK:collection sort; 2025-06-03 11:23:13 +08:00
shahaibo
3bfbd8abc1 TASK:collection sort; 2025-06-03 10:42:11 +08:00
shahaibo
78341850e1 TASK:collection sort; 2025-06-02 16:31:17 +08:00
shahaibo
becdbf1891 TASK:collection sort; 2025-06-02 16:19:41 +08:00
shahaibo
f0b1d3f9ce TASK:collection sort; 2025-05-30 15:02:39 +08:00
shahaibo
73bab2338e TASK:collection sort; 2025-05-30 14:04:18 +08:00
shahaibo
448e6d2c40 TASK:mannequin; 2025-05-30 13:08:19 +08:00
shahaibo
131d782b54 TASK:test; 2025-05-30 11:49:10 +08:00
shahaibo
d6cc8ab9a2 TASK:test; 2025-05-30 11:42:27 +08:00
shahaibo
d9e25fd0e4 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-05-29 16:17:49 +08:00
shahaibo
276994759e TASK:mannequin; 2025-05-29 16:17:39 +08:00
a569ee7736 Merge remote-tracking branch 'origin/dev/dev' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/mapper/primary/entity/DesignItem.java
2025-05-28 16:57:49 +08:00
d7762cbfed Merge branch 'dev/dev_xp' into dev/dev 2025-05-28 16:57:15 +08:00
8356326c7d TASK: DesignDetail中允许修改模特 2025-05-28 16:56:32 +08:00
shahaibo
8003a799c2 TASK:mannequin; 2025-05-28 16:42:54 +08:00
shahaibo
6de1ad150c TASK:mannequin; 2025-05-28 15:28:55 +08:00
shahaibo
b6a7354322 TASK:mannequin; 2025-05-28 13:59:52 +08:00
shahaibo
6e96f38c90 TASK:mannequin; 2025-05-28 13:59:00 +08:00
shahaibo
fc24e1fab8 TASK:mannequin; 2025-05-28 13:47:45 +08:00
shahaibo
718e1c93f6 TASK:mannequin; 2025-05-28 11:12:26 +08:00
shahaibo
74540610c6 TASK:mannequin; 2025-05-28 10:34:54 +08:00
shahaibo
1be4701f6d TASK:mannequin; 2025-05-28 09:37:27 +08:00
shahaibo
d3b4d15df8 TASK:mannequin; 2025-05-23 16:33:43 +08:00
shahaibo
8fc79f6699 TASK:mannequin; 2025-05-23 15:13:46 +08:00
shahaibo
91ee58db1b TASK:LLM; 2025-05-22 13:43:50 +08:00
shahaibo
af1c839495 TASK:LLM; 2025-05-22 13:24:28 +08:00
shahaibo
083416951a TASK:LLM; 2025-05-22 12:34:01 +08:00
shahaibo
cd20bdd88f TASK:LLM; 2025-05-22 12:27:00 +08:00
shahaibo
5a0fb6fd3f TASK:LLM; 2025-05-22 10:11:21 +08:00
shahaibo
93fe0781b2 TASK:LLM; 2025-05-21 21:04:28 +08:00
shahaibo
94e00459b6 TASK:LLM; 2025-05-21 21:03:15 +08:00
shahaibo
9614985690 TASK:LLM; 2025-05-20 16:59:07 +08:00
shahaibo
8c597db8a9 TASK:LLM; 2025-05-20 16:54:20 +08:00
shahaibo
a0bd4cfa38 TASK:LLM; 2025-05-20 16:47:43 +08:00
shahaibo
82388b0c19 TASK:LLM; 2025-05-20 16:12:08 +08:00
shahaibo
588202311c TASK:LLM; 2025-05-20 16:02:38 +08:00
shahaibo
46820505ae TASK:LLM; 2025-05-20 14:37:34 +08:00
shahaibo
b030e9c09b TASK:LLM; 2025-05-20 14:31:05 +08:00
shahaibo
f1adbb4da7 TASK:LLM; 2025-05-20 14:24:16 +08:00
shahaibo
4dfee09abb TASK:LLM; 2025-05-20 13:56:42 +08:00
shahaibo
16e4f7c5b5 TASK:LLM; 2025-05-20 13:37:46 +08:00
shahaibo
e9e40e53bc TASK:LLM; 2025-05-20 13:16:57 +08:00
shahaibo
a2625fa73f TASK:LLM; 2025-05-20 11:24:02 +08:00
shahaibo
ab804d57c1 TASK:LLM; 2025-05-20 10:42:18 +08:00
shahaibo
cef2fca099 TASK:LLM; 2025-05-20 10:39:00 +08:00
shahaibo
3d783974fc Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-05-20 10:29:30 +08:00
shahaibo
7f5a1615b3 TASK:LLM; 2025-05-20 10:29:22 +08:00
6c625de936 Merge branch 'dev/dev_xp' into dev/dev 2025-05-19 14:04:40 +08:00
aeb372bc17 TASK:企业、教育版library元素共享、作品广场作品发布到公共gallery 2025-05-19 14:02:42 +08:00
shahaibo
738144ad22 TASK:LLM; 2025-05-19 10:47:02 +08:00
shahaibo
a67b487dc0 TASK:LLM; 2025-05-19 10:23:53 +08:00
shahaibo
8613d4fc7a TASK:LLM; 2025-05-19 10:15:16 +08:00
shahaibo
6aa1a3d167 TASK:LLM; 2025-05-19 10:00:19 +08:00
shahaibo
59ffa38ff7 TASK:LLM; 2025-05-18 12:46:12 +08:00
bf92edb267 BUGFIX: 消息被双重转义时无法被正常解析,导致消息一直被重复消费 2025-05-09 07:51:37 +08:00
c72f382804 designSingle 取消颜色限制 2025-05-08 14:23:40 +08:00
shahaibo
6d6768e6cb TASK:模块化; 2025-05-06 17:30:01 +08:00
shahaibo
a84fe12a28 TASK:模块化; 2025-05-02 14:33:53 +08:00
shahaibo
be019dcdd0 TASK:模块化; 2025-05-02 14:26:21 +08:00
shahaibo
82d65c3015 TASK:模块化; 2025-04-29 17:21:16 +08:00
shahaibo
815392fffa TASK:模块化; 2025-04-29 16:16:36 +08:00
shahaibo
35e95c835e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-29 15:09:09 +08:00
shahaibo
1263409d7c TASK:模块化; 2025-04-29 15:08:59 +08:00
e5b184ea6d Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 15:26:35 +08:00
aa0778958e BUGFIX: 用户被删除的情况下,获取该云过户原来的评论,点赞等记录 2025-04-28 15:26:07 +08:00
50b78e9898 Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 14:56:48 +08:00
58af5c5570 删除优惠券 2025-04-28 14:56:13 +08:00
63cde1f6a0 Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 14:53:04 +08:00
89e6ee9eff 用户账号不存在的情况下获取评论报错 2025-04-28 14:51:19 +08:00
200c0adfba Affiliate 允许为不同的用户设置不同的affiliate
Stripe 添加优惠券删除接口;限制优惠券只能在订阅时使用
2025-04-28 14:40:42 +08:00
shahaibo
306f4f3987 TASK:模块化; 2025-04-25 15:34:35 +08:00
shahaibo
1240a57405 TASK:模块化; 2025-04-25 11:01:06 +08:00
shahaibo
a9acc83bdf TASK:模块化; 2025-04-25 10:19:12 +08:00
a2d259aea1 从Stripe退款后,修改订单状态,添加退款记录 2025-04-25 10:06:07 +08:00
shahaibo
7ff8a9db22 TASK:模块化; 2025-04-23 15:36:56 +08:00
shahaibo
7b6904059f TASK:模块化; 2025-04-23 15:35:21 +08:00
shahaibo
eec9c6ebf2 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-23 14:52:39 +08:00
shahaibo
1e8884a7c3 TASK:模块化; 2025-04-23 14:52:32 +08:00
9d591bb070 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-23 14:23:46 +08:00
db4bad22f4 Merge branch 'dev/dev_xp' into dev/dev 2025-04-23 14:23:30 +08:00
58bd986090 图片分割,区分类型 2025-04-23 14:22:21 +08:00
shahaibo
9e5bafc75e TASK:模块化; 2025-04-23 14:05:14 +08:00
shahaibo
938ad7366f TASK:模块化; 2025-04-23 11:22:52 +08:00
shahaibo
56ec903807 TASK:模块化; 2025-04-23 10:56:32 +08:00
shahaibo
5913445257 TASK:模块化; 2025-04-23 10:25:02 +08:00
shahaibo
2d1d458929 TASK:模块化; 2025-04-23 10:14:15 +08:00
shahaibo
5a0c461961 TASK:模块化; 2025-04-22 16:24:05 +08:00
shahaibo
74ad20646d TASK:模块化; 2025-04-22 16:11:00 +08:00
shahaibo
604c57c208 TASK:模块化; 2025-04-22 15:59:08 +08:00
shahaibo
aca21b9d98 TASK:模块化; 2025-04-22 15:26:55 +08:00
shahaibo
b83a416dda TASK:模块化; 2025-04-22 14:20:57 +08:00
shahaibo
d1858ddf83 TASK:模块化; 2025-04-22 14:18:54 +08:00
shahaibo
aa1c48fcfe TASK:模块化; 2025-04-22 13:48:36 +08:00
shahaibo
b19bbf91f2 TASK:模块化; 2025-04-22 11:24:28 +08:00
shahaibo
d9e4fb3022 TASK:模块化; 2025-04-22 09:58:14 +08:00
shahaibo
cc8f2e0778 TASK:模块化; 2025-04-21 23:44:55 +08:00
shahaibo
9b1881349f TASK:模块化; 2025-04-21 23:40:30 +08:00
shahaibo
eacceb4b76 TASK:模块化; 2025-04-21 22:36:03 +08:00
shahaibo
c50c193a46 TASK:模块化; 2025-04-21 22:35:32 +08:00
shahaibo
dfe99ef080 TASK:模块化; 2025-04-21 22:13:53 +08:00
shahaibo
98e1f37c1d TASK:模块化; 2025-04-21 21:50:03 +08:00
shahaibo
05295b1a0d TASK:模块化; 2025-04-21 21:21:23 +08:00
shahaibo
6fb04a66df TASK:模块化; 2025-04-21 21:18:29 +08:00
shahaibo
ba14b67c24 TASK:模块化; 2025-04-21 19:40:41 +08:00
shahaibo
0a4d6ff13b TASK:模块化; 2025-04-21 18:51:43 +08:00
shahaibo
fc2795b83e TASK:模块化; 2025-04-17 16:30:06 +08:00
shahaibo
4c726ff747 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-17 16:08:17 +08:00
shahaibo
4ed93c7e48 TASK:模块化; 2025-04-17 16:08:10 +08:00
shahaibo
acb37bc255 TASK:模块化; 2025-04-17 16:07:50 +08:00
shahaibo
9b5040d449 TASK:模块化; 2025-04-16 16:35:51 +08:00
shahaibo
fe0d1f39b0 TASK:模块化; 2025-04-16 16:28:27 +08:00
79d2720733 Merge branch 'dev/dev_xp' into dev/dev 2025-04-15 15:58:51 +08:00
218d828e0d Stripe推广码 部分功能完善 2025-04-15 15:58:22 +08:00
2269662290 Stripe支付测试--切换支付方式配置 2025-04-15 11:20:03 +08:00
eaec1e4177 Stripe支付测试--切换支付环境 2025-04-15 10:38:10 +08:00
eaff87882e Merge branch 'dev/dev_xp' into dev/dev 2025-04-15 10:23:30 +08:00
0ba28588da Stripe支付--添加推广码功能及相应佣金计算 2025-04-15 10:22:45 +08:00
25f64831f3 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 15:20:32 +08:00
d6c869727a 应要求修改参数名 2025-04-14 15:18:54 +08:00
77a06e0edd bugfix:account mapper count 去重问题 2025-04-14 14:58:23 +08:00
21efcf3ea6 查询所有的生成功能名字 2025-04-14 14:14:45 +08:00
d77e1d74b0 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 13:37:25 +08:00
1ce6c74f2c 优惠券查询DTO 2025-04-14 13:37:01 +08:00
3c4b645772 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 13:34:56 +08:00
909978467c 查询积分DTO 2025-04-14 13:34:35 +08:00
912c449161 Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/service/CollectionElementService.java
#	src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java
2025-04-14 13:30:02 +08:00
7f05bb2f7d 新增接口:图片分割 2025-04-14 13:26:56 +08:00
cbc760ebaf 便利查询--各版本管理员查看用户的design频次和各生成功能使用频次以及积分使用情况 2025-04-13 17:20:14 +08:00
shahaibo
48bb0cbff5 TASK:模块化; 2025-04-11 17:42:36 +08:00
shahaibo
1403b7851a TASK:模块化; 2025-04-11 15:11:44 +08:00
shahaibo
c36081996d TASK:模块化; 2025-04-11 14:33:25 +08:00
shahaibo
14dbc35eda TASK:模块化; 2025-04-11 14:16:54 +08:00
shahaibo
64c03768ff TASK:模块化; 2025-04-11 14:07:37 +08:00
shahaibo
b806bef0bf TASK:模块化; 2025-04-11 11:03:48 +08:00
shahaibo
811d22e229 TASK:模块化; 2025-04-11 10:49:22 +08:00
shahaibo
1ee612674e TASK:模块化; 2025-04-11 10:10:38 +08:00
shahaibo
cf9b621159 TASK:模块化; 2025-04-10 14:17:28 +08:00
shahaibo
03ae184541 TASK:模块化; 2025-04-10 14:00:33 +08:00
shahaibo
6b62d26544 TASK:模块化; 2025-04-10 11:01:24 +08:00
shahaibo
3883864558 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-09 10:30:56 +08:00
shahaibo
1089f37022 TASK:模块化; 2025-04-09 10:30:25 +08:00
c661767de3 Merge branch 'dev/dev_xp' into dev/dev 2025-04-09 09:48:51 +08:00
7b75e6ac69 获取所有姿势变换的pose 2025-04-09 09:48:00 +08:00
bd1f1deb53 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-08 18:07:00 +08:00
e142d50d18 Merge branch 'dev/dev_xp' into dev/dev 2025-04-08 18:06:40 +08:00
6250e763c3 获取所有姿势变换的pose 2025-04-08 18:05:49 +08:00
shahaibo
4cda43f3b5 TASK:模块化; 2025-04-08 17:29:10 +08:00
shahaibo
fd8d71e2a2 TASK:模块化; 2025-04-08 15:15:39 +08:00
shahaibo
87b702c24b TASK:模块化; 2025-04-08 11:09:28 +08:00
shahaibo
27cd98f0db TASK:模块化; 2025-04-07 17:12:33 +08:00
shahaibo
d1603fbc16 TASK:模块化; 2025-04-07 16:07:26 +08:00
shahaibo
96ba29a9a2 TASK:模块化; 2025-04-03 15:31:39 +08:00
shahaibo
5d9ca09272 TASK:模块化; 2025-04-03 14:27:03 +08:00
shahaibo
64676736b5 TASK:模块化; 2025-04-03 14:22:21 +08:00
shahaibo
7106482831 TASK:模块化; 2025-04-03 14:14:28 +08:00
shahaibo
b1c8606432 TASK:模块化; 2025-04-03 13:49:36 +08:00
shahaibo
0eb02c598e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 17:14:32 +08:00
shahaibo
b6367d72ba TASK:模块化; 2025-04-02 17:13:58 +08:00
2e76bded8c Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 15:57:18 +08:00
0e7c07b3b5 上传模特时保存点位信息接口修改 2025-04-02 15:56:05 +08:00
shahaibo
3e3b1eb868 TASK:模块化; 2025-04-02 15:32:48 +08:00
shahaibo
ec0309d6f2 TASK:模块化; 2025-04-02 15:27:16 +08:00
shahaibo
8ee7a030bd Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 15:18:27 +08:00
shahaibo
ca9778a416 TASK:模块化; 2025-04-02 15:18:20 +08:00
07504d8412 Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 13:34:11 +08:00
88796f7f28 修改添加系统模特到个人lib接口和保存模特接口 2025-04-02 13:32:12 +08:00
shahaibo
8764e750ff Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 13:14:16 +08:00
shahaibo
9d2cb29255 TASK:模块化; 2025-04-02 13:09:48 +08:00
a1b8f9e000 修改添加系统模特到个人lib接口 2025-04-02 12:03:48 +08:00
6f2c670fce Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 11:09:41 +08:00
d21cb4adfc 修改模特保存接口和添加系统模特到个人lib接口 2025-04-02 11:08:35 +08:00
shahaibo
97b922c1be TASK:模块化; 2025-04-01 17:52:55 +08:00
shahaibo
0af5b2121c TASK:模块化; 2025-04-01 17:44:16 +08:00
36be8b5420 修改模特比例接口不再与模特点位信息关联 2025-04-01 17:22:45 +08:00
a34d775f63 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-01 17:16:49 +08:00
1bee672592 Merge branch 'dev/dev_xp' into dev/dev 2025-04-01 17:16:27 +08:00
shahaibo
cf08f9126e TASK:模块化; 2025-04-01 17:16:27 +08:00
8e938e9f06 更新模特点位接口修改 2025-04-01 17:15:38 +08:00
shahaibo
a08744f71a TASK:模块化; 2025-04-01 15:42:15 +08:00
shahaibo
913c4c1ece TASK:模块化; 2025-04-01 15:20:59 +08:00
shahaibo
03f3162dc1 TASK:模块化; 2025-03-31 15:40:36 +08:00
shahaibo
0eb839e7c7 TASK:模块化; 2025-03-31 15:37:05 +08:00
shahaibo
807d3e1c46 TASK:模块化; 2025-03-31 15:27:17 +08:00
shahaibo
e6f990b766 TASK:模块化; 2025-03-31 15:02:44 +08:00
shahaibo
6dcc492127 TASK:模块化; 2025-03-31 11:53:43 +08:00
shahaibo
a2bd2fa6c6 TASK:模块化; 2025-03-31 11:21:45 +08:00
shahaibo
2edf7d211b TASK:模块化; 2025-03-30 23:31:00 +08:00
shahaibo
890265611a TASK:模块化; 2025-03-30 16:14:13 +08:00
shahaibo
48c7182f98 TASK:模块化; 2025-03-30 15:56:03 +08:00
shahaibo
2cfd342ef8 TASK:模块化; 2025-03-28 11:14:48 +08:00
shahaibo
63513df053 TASK:模块化; 2025-03-28 11:05:45 +08:00
shahaibo
bb00d9a714 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-28 09:37:51 +08:00
shahaibo
3398992bcd TASK:模块化; 2025-03-28 09:37:42 +08:00
2912463562 Merge branch 'dev/dev_xp' into dev/dev 2025-03-27 17:46:47 +08:00
3df4433381 BUGFIX: sketch拼贴 2025-03-27 17:46:09 +08:00
shahaibo
a8f868e215 TASK:模块化; 2025-03-27 14:32:56 +08:00
shahaibo
78a5bebb4f TASK:模块化; 2025-03-27 13:55:16 +08:00
shahaibo
33582922be TASK:模块化; 2025-03-27 13:38:47 +08:00
shahaibo
e6234213f0 TASK:模块化; 2025-03-27 13:33:09 +08:00
shahaibo
1d9a89d7c7 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-26 15:13:06 +08:00
shahaibo
b0560b840f TASK:模块化; 2025-03-26 15:12:55 +08:00
20b15c0b78 sketch拼贴 添加返回服装分类 2025-03-26 13:39:39 +08:00
a4365abd4d 模特比例修改参数变换 2025-03-25 17:37:35 +08:00
1cb02a62e8 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 16:20:14 +08:00
67225c1a96 从统一接口获取pose transformation的生成记录 2025-03-25 16:20:00 +08:00
50ecc3a177 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 16:11:33 +08:00
63c9ff36a1 新增like\dislike pose transformation接口 2025-03-25 16:11:03 +08:00
shahaibo
dc62ca956c Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 16:10:19 +08:00
shahaibo
d45c555415 TASK:模块化; 2025-03-25 16:10:10 +08:00
a657464d22 sketch拼贴 获取模块信息走统一接口 2025-03-25 14:56:16 +08:00
b5b67e0c75 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 14:43:47 +08:00
619d0e817f sketch拼贴 获取画布走统一接口 2025-03-25 14:37:38 +08:00
shahaibo
5d7beca57d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 13:16:40 +08:00
shahaibo
9a933e74ff TASK:模块化; 2025-03-25 13:16:31 +08:00
0b60dd799f Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 11:45:37 +08:00
a38c15005e 开发环境 添加邮件相关配置信息 2025-03-25 11:45:10 +08:00
b5a8c635d6 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 11:38:31 +08:00
6b288a3b3c 邮件发送系统-初版 2025-03-25 11:37:53 +08:00
9a5718cc35 Merge remote-tracking branch 'origin/dev/dev' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2025-03-25 11:26:50 +08:00
cc804bac7d Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2025-03-25 11:25:22 +08:00
b18a5a0050 模特比例修改、sketch拼贴 2025-03-25 11:22:17 +08:00
078a0c0dfb 模特比例修改、sketch拼贴 2025-03-25 11:19:55 +08:00
shahaibo
d080fc04bb TASK:模块化; 2025-03-25 10:51:16 +08:00
shahaibo
ae484c9e6c TASK:模块化; 2025-03-24 15:59:46 +08:00
shahaibo
39cb20618b TASK:代码覆盖修复; 2025-03-24 15:08:23 +08:00
shahaibo
5b95401204 TASK:AiDA模块化 2025-03-21 09:59:42 +08:00
6b62cf7299 PoseTransformation-初版 2025-03-20 17:42:16 +08:00
shahaibo
af352bbfe8 TASK:AiDA模块化 2025-03-20 16:47:34 +08:00
shahaibo
4d7673e8df TASK:AiDA模块化 2025-03-20 16:46:13 +08:00
shahaibo
55ec6da74b TASK:AiDA模块化 2025-03-19 14:13:16 +08:00
shahaibo
83d9a5befb TASK:AiDA模块化 2025-03-19 14:08:16 +08:00
shahaibo
ec836a6470 TASK:AiDA模块化 2025-03-19 12:17:29 +08:00
shahaibo
d6f9aa155e TASK:AiDA模块化 2025-03-19 11:55:38 +08:00
shahaibo
d3b507ed45 TASK:AiDA模块化 2025-03-19 11:35:13 +08:00
shahaibo
b027396567 TASK:AiDA模块化 2025-03-19 11:09:15 +08:00
shahaibo
7d0a6ae2bf TASK:AiDA模块化 2025-03-19 11:02:13 +08:00
shahaibo
d12bf41021 TASK:AiDA模块化 2025-03-19 10:51:15 +08:00
shahaibo
ca3a584100 TASK:AiDA模块化 2025-03-19 10:47:39 +08:00
shahaibo
47d0856296 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-19 10:39:52 +08:00
shahaibo
a828d75248 TASK:AiDA模块化 2025-03-19 10:39:42 +08:00
edc769ca79 to dev 2025-03-19 09:56:21 +08:00
0a22f01587 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-19 09:52:49 +08:00
45f0d571d6 Merge branch 'release/3.0' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/common/config/MyTaskScheduler.java
2025-03-19 09:51:36 +08:00
shahaibo
880adf7c69 TASK:AiDA模块化 2025-03-19 09:48:14 +08:00
shahaibo
591b4bf119 TASK:AiDA模块化 2025-03-19 09:27:10 +08:00
shahaibo
2db65776b1 TASK:AiDA模块化 2025-03-18 17:38:28 +08:00
shahaibo
7742bd56f8 TASK:AiDA模块化 2025-03-18 17:11:36 +08:00
shahaibo
3159208a0a TASK:AiDA模块化 2025-03-18 16:54:21 +08:00
shahaibo
971b2034ee TASK:AiDA模块化 2025-03-18 13:43:59 +08:00
shahaibo
f17d171231 TASK:AiDA模块化 2025-03-17 11:42:02 +08:00
shahaibo
4be008382f TASK:AiDA模块化 2025-03-17 11:37:12 +08:00
shahaibo
1ae1703f53 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-17 11:30:48 +08:00
shahaibo
340227d9a6 TASK:AiDA模块化 2025-03-17 11:30:09 +08:00
shahaibo
fb99e83b2d TASK:AIDA模块化; 2025-03-16 13:48:54 +08:00
shahaibo
8fa76c6732 TASK:AiDA模块化 2025-03-16 13:09:50 +08:00
shahaibo
1637db2fe3 TASK:AiDA模块化 2025-03-13 17:57:27 +08:00
shahaibo
575d1492ad BUGFIX: 隐藏加载不出minio的相关数据; 2025-03-12 23:22:41 +08:00
79abe93744 Stripe 回调判空并直接返回 2025-02-28 14:27:36 +08:00
f580955c97 Stripe 回调判空 2025-02-28 14:18:32 +08:00
6a625ed4ea 设置未修改局部design图时的图片地址 2025-02-27 09:58:35 +08:00
8a47d9f3da 修改历史数据中的mask分割状态 2025-02-25 18:27:23 +08:00
148b6492ea 现在design后的mask 默认已分割 2025-02-25 18:14:43 +08:00
be3fa7a704 编辑前后片,添加日志打印 2025-02-25 18:03:52 +08:00
63af2daf28 打开前后片编辑 2025-02-25 15:44:21 +08:00
37be3a1759 1、局部design 未保存前,不覆盖原图
2、打开前后片编辑
2025-02-25 15:22:14 +08:00
df2547ff81 参数名统一 2025-02-25 14:24:15 +08:00
7693de93dc 参数名统一 2025-02-25 14:19:32 +08:00
c061045466 Merge branch 'dev/dev_xp' into dev/dev 2025-02-25 14:02:58 +08:00
abd68f2dc8 参数结构修改 2025-02-25 14:02:29 +08:00
285f956caa 配置修改 添加桶 2025-02-25 13:03:52 +08:00
019cf4adf4 Merge branch 'dev/dev_xp' into dev/dev 2025-02-25 11:48:39 +08:00
cf38e7253f 局部design 2025-02-25 11:48:08 +08:00
387 changed files with 28146 additions and 6707 deletions

93
pom.xml
View File

@@ -29,6 +29,10 @@
<activation>1.1.1</activation> <activation>1.1.1</activation>
<easy-captcha>1.6.2</easy-captcha> <easy-captcha>1.6.2</easy-captcha>
<aws.java.sdk.version>2.20.43</aws.java.sdk.version> <aws.java.sdk.version>2.20.43</aws.java.sdk.version>
<javacv.version>1.5.5</javacv.version>
<system.windowsx64>windows-x86_64</system.windowsx64>
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
@@ -159,7 +163,7 @@
<dependency> <dependency>
<groupId>com.tencentcloudapi</groupId> <groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId> <artifactId>tencentcloud-sdk-java-ses</artifactId>
<version>3.1.572</version> <version>3.1.572</version>
</dependency> </dependency>
@@ -316,6 +320,93 @@
<version>1.41.5</version> <version>1.41.5</version>
</dependency> </dependency>
<!-- 邮件发送 -->
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
<!-- JSON 转义恢复 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version> <!-- 使用最新版本 -->
</dependency>
<!-- 最新版本号https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
<!-- 万象SDK -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.20.1</version>
</dependency>
<!-- FFmpeg封装JavaCV 视频转gif 全部依赖-->
<!--<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>-->
<!-- javacv+javacpp核心库-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>${javacv.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp-platform</artifactId>
<version>${javacv.version}</version>
</dependency>
<!-- 最小opencv依赖包 必须包含上面的javacv+javacpp -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.13-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>flycapture</artifactId>
<version>2.13.3.31-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<!-- FFmpeg视频处理解决你的报错 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.4-1.5.6</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<!-- GIFEncoder 视频转gif-->
<dependency>
<groupId>com.madgag</groupId>
<artifactId>animated-gif-lib</artifactId>
<version>1.4</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -3,11 +3,13 @@ package com.ai.da;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j @Slf4j
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
@EnableAsync
public class AiDaApplication { public class AiDaApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -0,0 +1,96 @@
package com.ai.da.common.RabbitMQ;
import com.ai.da.common.utils.MailUtil;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.core.exception.RetryableException;
import org.springframework.amqp.core.Message;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
public class EmailRetryConsumer {
@Resource
private MailUtil mailUtil;
@Resource
private MQPublisher mqPublisher;
@Resource
private EmailService emailService;
// @RabbitListener(queues = "#{rabbitMQProperties.deadLetter.queue}")
public void handleRetry(Map<String, String> mailParams, Message message, Channel channel) throws IOException {
long tag = message.getMessageProperties().getDeliveryTag();
try {
log.info("死信队列收到消息:{}", message);
// 处理邮件发送参数
BasicEmailParamDTO basicEmailParamDTO = JSONObject.parseObject(mailParams.get("dto"), BasicEmailParamDTO.class);
String fileName = mailParams.get("filename");
InputStreamSource inputStreamSource = Objects.isNull(mailParams.get("source")) ?
null : JSONObject.parseObject(mailParams.get("source"), InputStreamSource.class);
JSONObject templateParams = JSONObject.parseObject(mailParams.get("templateParams"), JSONObject.class);
String templateName = mailParams.get("templatePath");
long logId = Long.parseLong(mailParams.get("logId"));
basicEmailParamDTO.setContent(mailUtil.setContent(templateParams, templateName));
// 发邮件
int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
if (lastReturnCode == 250) {
log.info("邮件发送成功Subject : {}", basicEmailParamDTO.getSubject());
emailService.updateStatus(logId, EmailService.DELIVERED);
} else if (lastReturnCode == 450) {
log.info("目标邮箱 {} 暂时不可用,请稍后重试", (Object) basicEmailParamDTO.getMailTo());
// 重试
retry(mailParams, message, channel, tag, logId);
} else if (lastReturnCode == 550) {
log.info("目标邮箱 {} 不可用,邮件发送失败", (Object) basicEmailParamDTO.getMailTo());
emailService.updateStatus(logId, EmailService.FAILED);
} else {
log.info("邮件发送失败Subject : {}, 状态码: {}", basicEmailParamDTO.getSubject(), lastReturnCode);
retry(mailParams, message, channel, tag, logId);
emailService.updateStatus(logId, EmailService.FAILED);
}
channel.basicAck(tag, false);
} catch (RetryableException e) {
log.info("邮件重试发生异常:RetryableException -> {}", e.getMessage());
channel.basicAck(tag, false); // 确认原消息
} catch (Exception e) {
log.info("邮件重试发生异常:Exception -> {}", e.getMessage());
channel.basicAck(tag, false); // 确认原消息
}
}
private int getRetryAttempt(Message message) {
Integer attempt = message.getMessageProperties()
.getHeader("x-retry-attempt");
return attempt != null ? attempt : 1;
}
private void retry(Map<String, String> mailParams, Message message, Channel channel, long tag, long logId) throws IOException{
int attempt = getRetryAttempt(message);
if (attempt >= 3) { // 最大重试次数
channel.basicReject(tag, false);
emailService.updateStatus(logId, EmailService.FAILED);
log.error("重试结束,邮件最终发送失败: {}", mailParams);
} else {
log.info("重新将邮件信息发送到重试队列");
mqPublisher.sendEmailMsg(mailParams, attempt);
channel.basicAck(tag, false); // 确认原消息
// 更新数据库
emailService.updateRetryCount(logId, attempt + 1);
}
}
}

View File

@@ -5,13 +5,20 @@ import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.RedisUtil;
import com.ai.da.model.dto.GenerateThroughImageTextDTO; import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.vo.GenerateResultVO; import com.ai.da.model.vo.GenerateResultVO;
import com.ai.da.model.vo.PoseTransformationVO;
import com.ai.da.service.CloudTaskService;
import com.ai.da.service.DesignService;
import com.ai.da.service.GenerateService; import com.ai.da.service.GenerateService;
import com.ai.da.service.UserLikeGroupService; import com.ai.da.service.UserLikeGroupService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Time; import org.apache.commons.text.StringEscapeUtils;
import org.springframework.amqp.core.Message; import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.annotation.RabbitListener;
@@ -22,8 +29,10 @@ import org.springframework.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
@Slf4j @Slf4j
@@ -36,6 +45,12 @@ public class GenerateConsumer {
@Resource @Resource
private UserLikeGroupService userLikeGroupService; private UserLikeGroupService userLikeGroupService;
@Resource
private DesignService designService;
@Resource
private CloudTaskService cloudTaskService;
@Autowired @Autowired
private RabbitMQProperties rabbitMQProperties; private RabbitMQProperties rabbitMQProperties;
@@ -61,9 +76,9 @@ public class GenerateConsumer {
public void generate(Message msg, Channel channel, String consumerName) { public void generate(Message msg, Channel channel, String consumerName) {
log.info("============start listening=========="); log.info("============start listening==========");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Map<String, String> resp = jsonBytesToMap(msg, channel);
GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class); String uniqueId = resp.get("tasks_id");
String uniqueId = generateThroughImageTextDTO.getUniqueId(); // String uniqueId = generateThroughImageTextDTO.getUniqueId();
log.info("From " + consumerName + " : " + uniqueId); log.info("From " + consumerName + " : " + uniqueId);
try { try {
@@ -77,6 +92,7 @@ public class GenerateConsumer {
log.error("手动确认,不返回队列重新消费"); log.error("手动确认,不返回队列重新消费");
} }
} else { } else {
GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class);
generateService.generateThroughImageText(generateThroughImageTextDTO); generateService.generateThroughImageText(generateThroughImageTextDTO);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除 // 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId); redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
@@ -91,13 +107,13 @@ public class GenerateConsumer {
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除 // 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId); redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
String key = generateResultKey + ":" + uniqueId; String key = generateResultKey + ":" + uniqueId;
GenerateResultVO generateResultVO = new GenerateResultVO(generateThroughImageTextDTO.getUniqueId(), null, null, "Fail"); GenerateResultVO generateResultVO = new GenerateResultVO(uniqueId, null, null, "Fail");
redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME); redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
} catch (IOException exception) { } catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费"); log.error("手动确认,取消返回队列,不再重新消费");
} }
// 将入参和错误信息存入数据库 // 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateThroughImageTextDTO) + String exceptionMessage = JSONObject.toJSONString(resp) +
" Exception message " + e.getMessage(); " Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>(); HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage); exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage);
@@ -114,7 +130,7 @@ public class GenerateConsumer {
log.info("============ProcessGenerateResult listening=========="); log.info("============ProcessGenerateResult listening==========");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class); Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("generate response : {}", generateResult); log.info("generate response : {}", generateResult);
try { try {
@@ -162,7 +178,7 @@ public class GenerateConsumer {
log.info("============processToProductImageResult listening=========="); log.info("============processToProductImageResult listening==========");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class); Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("toProductImage response : {}", generateResult); log.info("toProductImage response : {}", generateResult);
try { try {
@@ -178,6 +194,7 @@ public class GenerateConsumer {
} else { } else {
// 修改redis中的数据状态为exception // 修改redis中的数据状态为exception
String key = toProductImageResultKey + ":" + generateResult.get("tasks_id"); String key = toProductImageResultKey + ":" + generateResult.get("tasks_id");
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME); redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中 // 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>(); HashMap<String, String> exceptionInfo = new HashMap<>();
@@ -212,7 +229,7 @@ public class GenerateConsumer {
log.info("============processRelightResult listening=========="); log.info("============processRelightResult listening==========");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class); Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("toProductImage response : {}", generateResult); log.info("toProductImage response : {}", generateResult);
try { try {
@@ -228,6 +245,7 @@ public class GenerateConsumer {
} else { } else {
// 修改redis中的数据状态为exception // 修改redis中的数据状态为exception
String key = relightResultKey + ":" + generateResult.get("tasks_id"); String key = relightResultKey + ":" + generateResult.get("tasks_id");
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME); redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中 // 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>(); HashMap<String, String> exceptionInfo = new HashMap<>();
@@ -258,6 +276,291 @@ public class GenerateConsumer {
log.info("============ProcessRelightResult End listening=========="); log.info("============ProcessRelightResult End listening==========");
} }
public void processPoseTransformResult(Message msg, Channel channel) {
log.info("============ProcessPoseTransformResult listening==========");
long start = System.currentTimeMillis();
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("PoseTransformation response : {}", generateResult);
try {
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
if (generateResult.get("status").equals("SUCCESS")) {
String gifUrl = generateResult.get("gif_url");
String taskId = generateResult.get("tasks_id");
String videoUrl = generateResult.get("video_url");
String imageUrl = generateResult.get("image_url");
generateService.processPoseTransformResult(taskId, gifUrl, videoUrl, imageUrl);
} else {
// 修改redis中的数据状态为exception
String key = generateResultKey + ":" + generateResult.get("tasks_id");
generateService.updatePoseTransferStatus(generateResult.get("tasks_id"), "Fail", null);
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.get("tasks_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("message"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
log.info("============ProcessPoseTransformResult End listening==========");
}
public static Map<String, String> jsonBytesToMap(Message msg, Channel channel) {
try {
// 1. byte[] -> String
String jsonString = new String(msg.getBody(), StandardCharsets.UTF_8).trim();
// 2. 处理可能的双重转义
if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) {
jsonString = jsonString.substring(1, jsonString.length() - 1);
// 使用 Apache Commons Text 将 JSON 字符串中的转义字符还原为原始字符
jsonString = StringEscapeUtils.unescapeJson(jsonString);
}
// 3. 验证 JSON 格式
if (!isValidJson(jsonString)) {
throw new IllegalArgumentException("Invalid JSON format");
}
// 4. 解析为 Map
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonString, new TypeReference<Map<String, String>>() {});
} catch (Exception e) {
log.error("消息解析失败: {}", e.getMessage(), e);
try {
// 仅对不可恢复错误(如非 JSON 数据)进行 ACK
if (e instanceof JsonParseException || e instanceof IllegalArgumentException) {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
log.warn("因消息格式错误,已确认并丢弃消息。原始消息为:{}", msg);
}
} catch (IOException ex) {
log.error("消息确认失败: {}", ex.getMessage(), ex);
}
throw new RuntimeException("Failed to parse JSON to Map", e);
}
}
// 辅助方法:验证字符串是否为合法 JSON
private static boolean isValidJson(String json) {
try {
new ObjectMapper().readTree(json);
return true;
} catch (Exception e) {
return false;
}
}
private void processDesignBatchResult(Message msg, Channel channel) {
log.info("============processDesignBatchResult listening==========");
long start = System.currentTimeMillis();
Map<String, Object> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
log.info("designBatch response : {}", generateResult);
designService.processDesignBatch(generateResult);
}
private void processToProductImageBatchResult(Message msg, Channel channel) {
log.info("============processToProductImageResultBatch listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("toProductImageBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String url = null;
if (!progress.startsWith("0") && !progress.equals("OK")) {
JSONObject result = generateResult.getJSONObject("result");
if (Objects.nonNull(result)) {
url = result.getString("product_img");
String taskId = generateResult.getString("task_id");
userLikeGroupService.toProductBatch(taskId, url, progress);
}
} else if (progress.startsWith("0/")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.startTask(batchTaskId);
}
} else if (progress.equals("OK")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.completeTask(batchTaskId);
}
}
} else {
// 修改redis中的数据状态为exception
String key = toProductImageResultKey + ":" + generateResult.get("task_id");
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
log.info("============ProcessToProductImageBatchResult End listening==========");
}
private void processRelightBatchResult(Message msg, Channel channel) {
log.info("============processRelightResult listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("relightBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String url = null;
if (!progress.startsWith("0") && !progress.equals("OK")) {
JSONObject result = generateResult.getJSONObject("result");
if (Objects.nonNull(result)) {
url = result.getString("relight_img");
String taskId = generateResult.getString("task_id");
userLikeGroupService.relightBatch(taskId, url, progress);
}
} else if (progress.startsWith("0/")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.startTask(batchTaskId);
}
} else if (progress.equals("OK")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.completeTask(batchTaskId);
}
}
} else {
// 修改redis中的数据状态为exception
String key = relightResultKey + ":" + generateResult.get("task_id");
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
log.info("============ProcessRelightBatchResult End listening==========");
}
private void processPoseTransformBatchResult(Message msg, Channel channel) {
log.info("============ProcessPoseTransformBatchResult listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("PoseTransformationBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String taskId = generateResult.getString("task_id");
generateService.processPoseTransformResultBatch(progress, taskId);
JSONArray result = generateResult.getJSONArray("result");
if (!StringUtils.isEmpty(result)) {
JSONObject jsonObject = result.getJSONObject(0);
String gifUrl = jsonObject.getString("gif_url");
String videoUrl = jsonObject.getString("video_url");
String imageUrl = jsonObject.getString("first_image_url");
generateService.processPoseTransformResultBatch(taskId, gifUrl, videoUrl, imageUrl, progress);
}
} else {
// 修改redis中的数据状态为exception
String key = generateResultKey + ":" + generateResult.getString("task_id");
generateService.updatePoseTransferStatus(generateResult.getString("task_id"), "Fail", null);
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.getString("task_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("message"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
log.info("============ProcessPoseTransformResult End listening==========");
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
@RabbitHandler @RabbitHandler
public void generateConsumer1(Message msg, Channel channel) { public void generateConsumer1(Message msg, Channel channel) {
@@ -329,4 +632,32 @@ public class GenerateConsumer {
public void getRelightResult(Message msg, Channel channel) { public void getRelightResult(Message msg, Channel channel) {
processRelightResult(msg, channel); processRelightResult(msg, channel);
} }
@RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
@RabbitHandler
public void getPoseTransformationResult(Message msg, Channel channel) {
processPoseTransformResult(msg, channel);
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
@RabbitHandler
public void getDesignBatchResult(Message msg, Channel channel) {
processDesignBatchResult(msg, channel);
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageBatch}")
@RabbitHandler
public void getToProductImageBatchResult(Message msg, Channel channel) {
processToProductImageBatchResult(msg, channel);
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.relightBatch}")
@RabbitHandler
public void getRelightBatchResult(Message msg, Channel channel) {
processRelightBatchResult(msg, channel);
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransformBatch}")
@RabbitHandler
public void getPoseTransformBatchResult(Message msg, Channel channel) {
processPoseTransformBatchResult(msg, channel);
}
} }

View File

@@ -1,6 +1,6 @@
package com.ai.da.common.RabbitMQ; package com.ai.da.common.RabbitMQ;
import org.springframework.amqp.core.Queue; import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -40,4 +40,43 @@ public class MQConfig {
public Queue relightResultQueue() { public Queue relightResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getRelightResult()); return new Queue(rabbitMQProperties.getQueues().getRelightResult());
} }
@Bean
public Queue poseTransformQueue() {
return new Queue(rabbitMQProperties.getQueues().getPoseTransform());
}
@Bean
public Queue mailRetryQueue() {
// 普通队列不绑定DLX首次失败后才进入MQ
// durable 持久化队列
return QueueBuilder.durable(rabbitMQProperties.getQueues().getEmailRetry())
// 关键参数:绑定死信交换机
.withArgument("x-dead-letter-exchange", rabbitMQProperties.getDeadLetter().getExchange())
// 可选:指定死信路由键(默认使用原消息的路由键)
.withArgument("x-dead-letter-routing-key", rabbitMQProperties.getDeadLetter().getRoutingKey())
.build();
}
// 新增死信交换机
@Bean
public DirectExchange deadLetterExchange() {
return new DirectExchange(rabbitMQProperties.getDeadLetter().getExchange());
}
// 新增死信队列
@Bean
public Queue deadLetterQueue() {
return QueueBuilder.durable(rabbitMQProperties.getDeadLetter().getQueue()).build();
}
// 绑定死信队列
@Bean
public Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue())
.to(deadLetterExchange())
.with(rabbitMQProperties.getDeadLetter().getRoutingKey());
}
} }

View File

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Map;
@Slf4j @Slf4j
@Component @Component
@@ -18,12 +19,38 @@ public class MQPublisher {
private AmqpTemplate amqpTemplate; private AmqpTemplate amqpTemplate;
public void sendGenerateMessage(String mm) { public void sendGenerateMessage(String mm) {
log.info("send message: " + mm); log.info("send generate message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerate(), mm); amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerate(), mm);
} }
public void sendSRMessage(String mm) { public void sendSRMessage(String mm) {
log.info("send message: " + mm); log.info("send message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm); amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm);
} }
/**
*
* @param mailParams 含有的字段
* {"dto": basicEmailParamDTO, "filename": fileName, "source": inputStreamSource,
* "templateParams": jsonObject, "templatePath": path}
* 邮件发送参数,附件文件名,附件数据
* @param retryTimes 重试次数初始为0
*/
public void sendEmailMsg(Map<String, String> mailParams, int retryTimes){
log.info("send email MQ message: {} ", mailParams);
// // 重新入队(指数退避) 时间单位:毫秒
long newDelay = (long) (5000 * Math.pow(2, retryTimes + 1));
log.info("send email MQ delay: {} ms, retry attempt: {}", newDelay, retryTimes + 1);
amqpTemplate.convertAndSend(
rabbitMQProperties.getQueues().getEmailRetry(),
mailParams,
m -> {
m.getMessageProperties().setExpiration(String.valueOf(newDelay));
m.getMessageProperties().setHeader("x-retry-attempt", retryTimes + 1);
return m;
}
);
}
} }

View File

@@ -11,6 +11,7 @@ public class RabbitMQProperties {
private Queues queues; private Queues queues;
private Exchange exchange; private Exchange exchange;
private DeadLetter deadLetter; // 新增死信配置
@Data @Data
public static class Queues { public static class Queues {
@@ -20,11 +21,25 @@ public class RabbitMQProperties {
private String generateResult; private String generateResult;
private String toProductImageResult; private String toProductImageResult;
private String relightResult; private String relightResult;
private String poseTransform;
private String emailRetry;
private String designBatch;
private String relightBatch;
private String toProductImageBatch;
private String poseTransformBatch;
} }
@Data @Data
public static class Exchange { public static class Exchange {
private String generate; private String generate;
} }
// 新增死信配置内部类
@Data
public static class DeadLetter {
private String exchange;
private String queue;
private String routingKey;
}
} }

View File

@@ -0,0 +1,21 @@
package com.ai.da.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class AsyncConfig {
@Bean("asyncTaskExecutor")
public Executor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-ImageToSketch-");
executor.initialize();
return executor;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
package com.ai.da.common.config;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.ThreeDDetailMapper;
import com.ai.da.mapper.primary.ThreeDLayoutMapper;
import com.ai.da.mapper.primary.ThreeDPatternLayoutMapper;
import com.ai.da.mapper.primary.ThreeDSimpleMapper;
import com.ai.da.mapper.primary.entity.ThreeDDetail;
import com.ai.da.mapper.primary.entity.ThreeDLayout;
import com.ai.da.mapper.primary.entity.ThreeDPatternLayout;
import com.ai.da.mapper.primary.entity.ThreeDSimple;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@Component
public class ThreeDSave {
@Resource
private ThreeDDetailMapper threeDDetailMapper;
@Resource
private ThreeDSimpleMapper threeDSimpleMapper;
@Resource
private MinioUtil minioUtil;
@Resource
private ThreeDLayoutMapper threeDLayoutMapper;
@Resource
private ThreeDPatternLayoutMapper threeDPatternLayoutMapper;
@PostConstruct
public void test() {
// minioSave();
// frontBackDataCreate();
// patternDataCreate();
}
private void patternDataCreate() {
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getGender, "female");
qw.lambda().ne(ThreeDSimple::getId, 1);
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
List<Integer> numbers = new ArrayList<>();
String patternPath = "C:\\workspace\\3D\\3D虚拟 1-7\\6.版文件、dxf文件\\女装系列(1)\\女装系列\\56款打版截图";
File directory = new File(patternPath);
if (directory.exists() && directory.isDirectory()) {
// 获取目录下的所有文件名,并建立编号 -> 文件名的映射
Map<Integer, String> fileMap = Arrays.stream(directory.listFiles())
.filter(File::isFile) // 只获取文件
.map(File::getName) // 获取文件名
.collect(Collectors.toMap(
name -> {
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
},
name -> name,
(existing, replacement) -> existing // 处理重复情况,保留原有值
));
for (ThreeDSimple threeDSimple : threeDSimpleList) {
String name = threeDSimple.getName();
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
Matcher matcher = pattern.matcher(name);
if (matcher.find()) {
int number = Integer.parseInt(matcher.group());
numbers.add(number);
// 匹配对应文件夹,并获取文件
if (fileMap.containsKey(number)) {
String matchedFolder = fileMap.get(number);
File folder = new File(directory, matchedFolder);
ThreeDPatternLayout threeDPatternLayout = new ThreeDPatternLayout();
threeDPatternLayout.setThreeDSimpleId(threeDSimple.getId());
threeDPatternLayout.setName(matchedFolder);
String minioUrl = "aida-threed/female/pattern-layout/" + matchedFolder;
minioUtil.upload(minioUrl, folder);
threeDPatternLayout.setUrl(minioUrl);
// threeDPatternLayoutMapper.insert(threeDPatternLayout);
}
}
}
System.out.println("文件编号映射:" + fileMap);
}
}
private void frontBackDataCreate() {
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getGender, "female");
// qw.lambda().ne(ThreeDSimple::getId, 1);
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
List<Integer> numbers = new ArrayList<>();
// 文件夹名列表
String path = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装真反面整理\\female"; // 目标路径
File directory = new File(path);
if (directory.exists() && directory.isDirectory()) {
// 获取文件夹名列表,并建立编号 -> 文件夹名的映射
Map<Integer, String> folderMap = Arrays.stream(directory.listFiles())
.filter(File::isDirectory)
.map(File::getName)
.collect(Collectors.toMap(
name -> {
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
},
name -> name,
(existing, replacement) -> existing // 处理重复情况,保留原有值
));
System.out.println("文件夹编号映射:" + folderMap);
for (ThreeDSimple threeDSimple : threeDSimpleList) {
String name = threeDSimple.getName();
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
Matcher matcher = pattern.matcher(name);
if (matcher.find()) {
int number = Integer.parseInt(matcher.group());
numbers.add(number);
// 匹配对应文件夹,并获取文件
if (folderMap.containsKey(number)) {
String matchedFolder = folderMap.get(number);
File folder = new File(directory, matchedFolder);
if (folder.exists() && folder.isDirectory()) {
for (File file : folder.listFiles()) {
String fileName = file.getName(); // 去掉后缀
ThreeDLayout threeDLayout = new ThreeDLayout();
threeDLayout.setGender("female");
threeDLayout.setThreeDSimpleId(threeDSimple.getId());
threeDLayout.setName(file.getName());
if (fileName.startsWith("")) {
threeDLayout.setType("front");
}else if (fileName.startsWith("")) {
threeDLayout.setType("back");
}
String minioUrl = "aida-threed/female/layout/" + folderMap.get(number) + " " + file.getName();
minioUtil.upload(minioUrl, file);
threeDLayout.setUrl(minioUrl);
// threeDLayoutMapper.insert(threeDLayout);
}
}
}
}
}
System.out.println(numbers);
} else {
System.out.println("路径不存在或不是文件夹");
}
}
private void minioSave() {
// 指定目标文件夹路径
String folderPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\maleZip";
// 创建文件对象
File folder = new File(folderPath);
// 检查文件夹是否存在且是目录
if (folder.exists() && folder.isDirectory()) {
// 获取所有 .zip 文件
File[] zipFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
List<String> zipFileNameList = new ArrayList<>();
// 输出文件名
if (zipFiles != null) {
for (File file : zipFiles) {
String zipFileName = file.getName();
String[] split = zipFileName.split("_");
String zipName = split[0];
String sizeWithSuffix = split[1];
String[] sizeWithSuffixSplit = sizeWithSuffix.split("\\.");
String size = sizeWithSuffixSplit[0];
// 找到第一个字母的位置
int index = 0;
while (index < size.length() && Character.UnicodeBlock.of(size.charAt(index)) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
index++;
}
if (index > 0 && index < size.length()) {
String prefix = size.substring(0, index); // "亚码"
String suffix = size.substring(index); // "L"
ThreeDDetail threeDDetail = new ThreeDDetail();
threeDDetail.setName(zipFileName);
String url = "aida-threed/male/zip/" + zipFileName;
threeDDetail.setGender("male");
threeDDetail.setSizeType(prefix);
threeDDetail.setSize(suffix);
threeDDetail.setUrl(url);
// threeDDetailMapper.insert(threeDDetail);
minioUtil.upload(url, file);
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getName, zipName);
qw.lambda().eq(ThreeDSimple::getGender, "male");
List<ThreeDSimple> threeDSimples = threeDSimpleMapper.selectList(qw);
if (CollectionUtils.isEmpty(threeDSimples)) {
ThreeDSimple threeDSimple = new ThreeDSimple();
threeDSimple.setName(zipName);
threeDSimple.setGender("male");
String glbPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\male\\" + zipName + "\\" +"亚码L";
File glbFolder = new File(glbPath);
// 查找 .glb 文件
if (glbFolder.exists() && glbFolder.isDirectory()) {
File[] glbFiles = glbFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".glb"));
if (glbFiles != null && glbFiles.length > 0) {
for (File glbFile : glbFiles) {
String name = glbFile.getName();
String glbUrl = "aida-threed/male/glb/" + name;
threeDSimple.setUrl(glbUrl);
minioUtil.upload(glbUrl, glbFile);
}
} else {
System.out.println("未找到 GLB 文件。" + glbFolder);
}
} else {
System.out.println("GLB 文件夹不存在: " + glbPath);
}
// threeDSimpleMapper.insert(threeDSimple);
threeDDetail.setThreeDSimpleId(threeDSimple.getId());
threeDDetailMapper.updateById(threeDDetail);
}else {
Long id = threeDSimples.get(0).getId();
threeDDetail.setThreeDSimpleId(id);
threeDDetailMapper.updateById(threeDDetail);
}
} else {
}
}
} else {
System.out.println("未找到 ZIP 文件。");
}
log.info("aaa");
} else {
System.out.println("文件夹不存在或不是一个目录。");
}
}
}

View File

@@ -13,8 +13,6 @@ public class CommonConstant {
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60; public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
// 单位 秒 一天过期 in redis // 单位 秒 一天过期 in redis
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L; public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
// 单位 秒 7天过期
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
public static class Numbers{ public static class Numbers{
public static final Integer NUMBER_10 = 10; public static final Integer NUMBER_10 = 10;
@@ -32,6 +30,8 @@ public class CommonConstant {
public static final String GENERATE_LOGO_SINGLE_CANCEL = "/api/generate_single_logo_cancel/"; public static final String GENERATE_LOGO_SINGLE_CANCEL = "/api/generate_single_logo_cancel/";
public static final String POSE_TRANSFORMATION_CANCEL = "/api/pose_transform_cancel/";
public static final String PYTHON_PORT_9996 = "9996"; public static final String PYTHON_PORT_9996 = "9996";
public static final String PYTHON_PORT_9997 = "9997"; public static final String PYTHON_PORT_9997 = "9997";
@@ -81,7 +81,11 @@ public class CommonConstant {
public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy"; public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy";
public static final String TIME_FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref="; public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref=";
public static final String PARTIAL_DESIGN_FILENAME = "PartialDesign";
public static final String PARTIAL_DESIGN_PREVIEW_FILENAME = "Preview";
} }

View File

@@ -31,9 +31,7 @@ public enum AuthenticationOperationTypeEnum {
/** /**
* 填写用户国家和职业 * 填写用户国家和职业
*/ */
UPDATE_USERINFO, UPDATE_USERINFO;
REGISTER;
public static AuthenticationOperationTypeEnum of(String name) { public static AuthenticationOperationTypeEnum of(String name) {
return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null); return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);

View File

@@ -27,7 +27,9 @@ public enum CollectionLevel1TypeEnum {
/** /**
* 市场 * 市场
*/ */
MARKETING_SKETCH("MarketingSketch"); MARKETING_SKETCH("MarketingSketch"),
MODEL("Models");
private String realName; private String realName;

View File

@@ -3,23 +3,32 @@ package com.ai.da.common.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
public enum CreditsEventsEnum { public enum CreditsEventsEnum {
PRICE("price","6"), PRICE("price","10"),
// PRICE("price","1"),// for test // PRICE("price","1"),// for test
// PRICE("price","0.1"), // PRICE("price","0.1"),
BUY_CREDITS("Buy Credits","60"), BUY_CREDITS("Buy Credits","50"),
// BUY_CREDITS("Buy Credits","10"),// for test // BUY_CREDITS("Buy Credits","10"),// for test
REFUND("Refund","60"), REFUND("Refund","50"),
// BUY_CREDITS("Buy Credits","10"), // BUY_CREDITS("Buy Credits","10"),
// 每月更新 // 每月更新
INIT_YEARLY("init_yearly", "6000"), INIT_YEARLY("init_yearly", "50000"),
INIT_MONTHLY("init_monthly", "5000"), INIT_MONTHLY("init_monthly", "3500"),
INIT_MONTHLY_ECO("init_monthly_eco", "500"),
INIT_QUARTERLY("init_quarterly", "12000"),
INIT_MONTHLY_EDU("init_monthly_edu", "3500"),
INIT_TRIAL("init_trial", "100"), INIT_TRIAL("init_trial", "100"),
INIT_WEEKLY("init_weekly","6000"), INIT_WEEKLY("init_weekly","6000"),
RESET_YEAR_CREDITS("reset_year_credits","6000"), RESET_YEAR_CREDITS("reset_year_credits","6000"),
@@ -32,16 +41,45 @@ public enum CreditsEventsEnum {
MOOD_BOARD("MoodBoard","5"), MOOD_BOARD("MoodBoard","5"),
SKETCH_BOARD("SketchBoard","5"), SKETCH_BOARD("SketchBoard","5"),
TO_PRODUCT_IMAGE("ToProductImage","5"), TO_PRODUCT_IMAGE("ToProductImage","5"),
TO_PRODUCT_IMAGE_FLUX("ToProductImageFlux","10"),
RELIGHT("Relight","5"), RELIGHT("Relight","5"),
RELIGHT_FLUX("RelightFlux","10"),
QUESTIONNAIRE("Questionnaire","100"), QUESTIONNAIRE("Questionnaire","100"),
IMAGE_TO_SKETCH("ImageToSketch","5"), IMAGE_TO_SKETCH("ImageToSketch","5"),
IMAGE_TO_SKETCH_FLUX("ImageToSketchFlux","10"),
POSE_TRANSFORMATION("PoseTransformation","10"),
OTHER("Other","5"),
OTHER("Other","5"); WX_TEXT2IMG("WX_Text2Image", "5"),
WX_ANIMATION("WX_Animation", "30"),
FREEPIK_IMG2IMG("Freepik_img2img", "20"),
FLUX_IMG2IMG("Flux_img2img","10"),
private String name; LOCAL_TEXT2IMG("Local_text2img","1.25"),
LOCAL_IMG2IMG("Local_img2img","1.25"),
LOCAL_TEXT2IMG_HIGH("Local_text2img_high","5"),
LOCAL_IMG2IMG_HIGH("Local_img2img_high","5"),
LOCAL_ANIMATION("Local_Animation","15"),
LLM_CONVERSATION("LLM_Conversation", "0")
;
private final String name;
/** /**
* 对应事件需要消耗or获得的积分 * 对应事件需要消耗or获得的积分
*/ */
private String value; private final String value;
public static List<String> generateFunctionNames() {
return Arrays.asList(SLOGAN.name, LOGO.name, PATTERN.name, MOOD_BOARD.name, SKETCH_BOARD.name,
TO_PRODUCT_IMAGE.name, RELIGHT.name, IMAGE_TO_SKETCH.name, POSE_TRANSFORMATION.name);
}
private static final Map<String, CreditsEventsEnum> BY_TASK_NAME = Arrays.stream(values())
.collect(Collectors.toMap(CreditsEventsEnum::getName, Function.identity()));
public static CreditsEventsEnum getByTaskName(String taskName){
return BY_TASK_NAME.get(taskName);
}
} }

View File

@@ -0,0 +1,34 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum FluxTaskStatusEnum {
SUCCESS("Ready"),
TASK_NOT_FOUND("Task not found"),
REQUEST_MODERATED("Request Moderated"),
CONTENT_MODERATED("Content Moderated"),
ERROR("Error"),
PENDING_F("Pending");
private final String name;
public static FluxTaskStatusEnum fromName(String name) {
for (FluxTaskStatusEnum status : values()) {
if (status.name.equalsIgnoreCase(name)) {
return status;
}
}
// 或者返回默认值
return TASK_NOT_FOUND;
}
}

View File

@@ -28,7 +28,9 @@ public enum LibraryLevel1TypeEnum {
* 模特 * 模特
*/ */
MODELS("Models"), MODELS("Models"),
DESIGN_ELEMENTS("DesignElements"); DESIGN_ELEMENTS("DesignElements"),
BRAND_DNA("BrandDNA");
private String realName; private String realName;

View File

@@ -0,0 +1,80 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
public enum PoseEnum {
// POSE_1(1, "aida-sys-image/pose/pose-1.mp4", "aida-sys-image/pose/pose-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.-E3pujumEfCbDTI_rjSH-A.LwIlGT3j"),
POSE_1(1, "aida-sys-image/pose/pose-1-1.mp4", "aida-sys-image/pose/pose-1-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.qNMWJlyKEfCuORaRJeW4dg.x3wUteVO"),
// POSE_2(2, "aida-sys-image/pose/pose-2.mp4", "aida-sys-image/pose/pose-2.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.TwJLxEv3EfCbDTI_rjSH-A.IOQZCYhf"),
POSE_2(2, "aida-sys-image/pose/pose-2-1.mp4", "aida-sys-image/pose/pose-2-1.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.QpaGOlyLEfCuuJo8eQGF2Q.62EiJj-6"),
// POSE_3(3, "aida-sys-image/pose/pose-3.mp4", "aida-sys-image/pose/pose-3.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.gd3OCkv4EfCxyZo8eQGF2Q.qMm-a1XI"),
POSE_3(3, "aida-sys-image/pose/pose-3-1.mp4", "aida-sys-image/pose/pose-3-1.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.2q5qjFyLEfCImjI_rjSH-A.5cFMwOvi"),
// POSE_4(4, "aida-sys-image/pose/pose-4.mp4", "aida-sys-image/pose/pose-4.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.AUDnuEwDEfCEHBaRJeW4dg.rlx36xEY"),
POSE_4(4, "aida-sys-image/pose/pose-4-1.mp4", "aida-sys-image/pose/pose-4-1.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.KoYMplyPEfCuORaRJeW4dg.MuuBTG78"),
// POSE_5(5, "aida-sys-image/pose/pose-5.mp4", "aida-sys-image/pose/pose-5.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.G8BvkEwEEfCxyZo8eQGF2Q.fo4ryrgR"),
POSE_5(5, "aida-sys-image/pose/pose-5-1.mp4", "aida-sys-image/pose/pose-5-1.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.x54FNFyPEfCuuJo8eQGF2Q.P1egmEZ_"),
// POSE_6(6, "aida-sys-image/pose/pose-6.mp4", "aida-sys-image/pose/pose-6.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.yBIPnEwEEfCxyZo8eQGF2Q.boSFwTG9");
POSE_6(6, "aida-sys-image/pose/pose-6-1.mp4", "aida-sys-image/pose/pose-6-1.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.QSCvBlyQEfCImjI_rjSH-A.G9-Z5ffW");
private final Integer id;
private final String videoPath;
private final String gifPath;
private final String firstFramePath;
private final String templateId;
private static final List<Map<String, String>> PROPERTY_LIST;
static {
PROPERTY_LIST = Arrays.stream(values())
.map(PoseEnum::toMap)
.collect(Collectors.toList());
}
private static final Map<Integer, PoseEnum> BY_ID = Arrays.stream(values())
.collect(Collectors.toMap(PoseEnum::getId, Function.identity()));
private static final Map<String, PoseEnum> BY_VIDEO_PATH = Arrays.stream(values())
.collect(Collectors.toMap(PoseEnum::getVideoPath, Function.identity()));
private static final List<String> VIDEO_PATH = Arrays.stream(values())
.map(PoseEnum::getVideoPath).collect(Collectors.toList());
public static PoseEnum getById(Integer id) {
return BY_ID.get(id);
}
public static PoseEnum getByVideoPath(String videoPath) {
return BY_VIDEO_PATH.get(videoPath);
}
private Map<String, String> toMap() {
Map<String, String> map = new HashMap<>();
map.put("id", String.valueOf(id));
map.put("gif", gifPath);
map.put("firstFrame", firstFramePath);
return map;
}
public static List<Map<String, String>> getPropertyList() {
return PROPERTY_LIST.stream()
.map(HashMap::new) // 深拷贝每个 Map
.collect(Collectors.toList());
}
public static List<String> getVideoList() {
return new ArrayList<>(VIDEO_PATH); // 返回副本以保证不可变性
}
}

View File

@@ -7,13 +7,19 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum ProductEnum { public enum ProductEnum {
// 积分购买 // 积分购买
CreditsProduct("AiDA credits purchase", 6L), CreditsProduct("AiDA credits purchase", 10L, 60L),
// 年度订阅 // 年度订阅
AnnualSubscription("AiDA Annual Subscription", 5000L), AnnualSubscription("AiDA Annual Subscription", 5000L, 50000L),
// 月度订阅 // 月度订阅订阅费500每月3500 积分)
MonthlySubscription("AiDA Monthly Subscription", 500L), MonthlySubscription("AiDA Monthly Subscription", 500L, 3500L),
// 月度订阅 -- 经济实惠版 订阅费100每月500 积分)
Eco_MonthlySubscription("AiDA Eco Monthly Subscription", 100L, 500L),
// 季度订阅
QuarterlySubscription("AiDA Quarterly Subscription", 1500L, 12000L),
// 月度订阅 -- 教育版
EDUMonthlySubscription("AiDA Edu Monthly Subscription", 200L, 3500L),
// 测试 // 测试
DailySubscription("AiDA Daily Subscription", 10L), DailySubscription("AiDA Daily Subscription", 5L, 100L),
; ;
/** /**
@@ -22,4 +28,6 @@ public enum ProductEnum {
private final String name; private final String name;
private final Long price; private final Long price;
private final Long credits;
} }

View File

@@ -0,0 +1,32 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum WangXiangTaskStatusEnum {
SUCCEEDED("SUCCEEDED"),
UNKNOWN_W("UNKNOWN"),
FAILED("FAILED"),
RUNNING("RUNNING"),
PENDING_W("PENDING");
private final String name;
// 通过name查找枚举的静态方法
public static WangXiangTaskStatusEnum fromName(String name) {
for (WangXiangTaskStatusEnum status : values()) {
if (status.name.equalsIgnoreCase(name)) {
return status;
}
}
// 或者返回默认值
return UNKNOWN_W;
}
}

View File

@@ -1,15 +0,0 @@
package com.ai.da.common.response;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@ApiModel("交易记录分页响应结果")
public class TransactionPageResponse<T> extends PageBaseResponse<T> {
private BigDecimal totalAmount;
}

View File

@@ -43,8 +43,8 @@ public class AuthenticationFilter extends OncePerRequestFilter {
private SecurityProperties properties; private SecurityProperties properties;
private static final List<String> FILTER_URL = private static final List<String> FILTER_URL =
Arrays.asList("/favicon.ico", "/doc.html", "api/account/login", "api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired", Arrays.asList("/favicon.ico", "/doc.html", "/api/account/login", "/api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired",
"/webjars/", "/swagger-resources", "/v2/api-docs", "api/account/resetPwd", "/webjars/", "/swagger-resources", "/v2/api-docs", "/api/account/resetPwd",
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId", "/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId",
"/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile", "/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile",
"/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew","/api/third/party/updateNoLoginRequiredNew", "/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew","/api/third/party/updateNoLoginRequiredNew",
@@ -52,14 +52,16 @@ public class AuthenticationFilter extends OncePerRequestFilter {
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify", "/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease", "/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify", "/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify",
"/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode" "/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode","/api/third/party/receiveDesignParams"
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
"/api/llm/stream"
); );
@Override @Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
String requestURI = httpServletRequest.getRequestURI(); String requestURI = httpServletRequest.getRequestURI();
if (calculateUrl(requestURI) || hasAuthorizationToken(httpServletRequest)) { if (calculateUrl(requestURI)/* || hasAuthorizationToken(httpServletRequest)*/) {
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
HttpServletRequest wrappedRequest = httpServletRequest; HttpServletRequest wrappedRequest = httpServletRequest;
HttpServletResponse wrappedResponse = httpServletResponse; HttpServletResponse wrappedResponse = httpServletResponse;
@@ -72,7 +74,12 @@ public class AuthenticationFilter extends OncePerRequestFilter {
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest); wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse); wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
extracted(wrappedRequest); extracted(wrappedRequest);
filterChain.doFilter(wrappedRequest, wrappedResponse); // excel导出使用原始response,不对响应做包装
if (requestURI.equals("/api/account/exportAccountsToExcel")) {
filterChain.doFilter(httpServletRequest, httpServletResponse); // 不包装
} else {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
} }
} catch (Exception e) { } catch (Exception e) {
SecurityContextHolder.clearContext(); SecurityContextHolder.clearContext();

View File

@@ -25,20 +25,20 @@ public class AccountTask {
* 每个月月初只刷新年付用户的积分 * 每个月月初只刷新年付用户的积分
*/ */
// @Scheduled(cron = "59 59 23 * * ?") // @Scheduled(cron = "59 59 23 * * ?")
@Scheduled(cron = "0 0 0 1 * ?") // @Scheduled(cron = "0 0 0 1 * ?")
public void refreshCreditsMonthly() { public void refreshCreditsMonthly() {
log.info("每月1号0点 将年费用户积分重置为 6000"); log.info("每月1号0点 重置教育版子账号为默认积分");
accountService.refreshCreditsWeekly(); accountService.refreshCreditsMonthly();
} }
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes // @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void getPaidUser() { public void getPaidUser() {
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单 // 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
accountService.extendValidityForCC(); accountService.extendValidityForCC();
} }
// 每天凌晨0点执行一次 // 每天凌晨0点执行一次
@Scheduled(cron = "0 0 0 * * ?") // @Scheduled(cron = "0 0 0 * * ?")
public void cancelActivityBenefits() { public void cancelActivityBenefits() {
// 1、查询当前所有参与了活动且过期的用户 // 1、查询当前所有参与了活动且过期的用户
List<Account> accountList = accountService.getExpiredUserBySystemUser(4); List<Account> accountList = accountService.getExpiredUserBySystemUser(4);
@@ -51,7 +51,7 @@ public class AccountTask {
} }
// 每天检测正式用户到期情况每天凌晨0点执行 // 每天检测正式用户到期情况每天凌晨0点执行
@Scheduled(cron = "0 0 0 * * ?") // @Scheduled(cron = "0 0 0 * * ?")
public void paidUserToVisitor() { public void paidUserToVisitor() {
// 1、查询当前已过期正式用户或试用用户 // 1、查询当前已过期正式用户或试用用户
List<Account> accountList = accountService.getExpiredUserBySystemUser(1); List<Account> accountList = accountService.getExpiredUserBySystemUser(1);
@@ -74,7 +74,7 @@ public class AccountTask {
accountService.registerUserToVisitor(); accountService.registerUserToVisitor();
} }
@Scheduled(cron = "0 0 0 1 * ?") // @Scheduled(cron = "0 0 0 1 * ?")
// 每月初刷新所有用户用户名剩余修改次数 // 每月初刷新所有用户用户名剩余修改次数
public void resetUsernameModifyTimes(){ public void resetUsernameModifyTimes(){
log.info("重置所有用户的用户名修改次数"); log.info("重置所有用户的用户名修改次数");

View File

@@ -0,0 +1,151 @@
package com.ai.da.common.task;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.utils.DateUtil;
import com.ai.da.mapper.primary.PoseTransformationMapper;
import com.ai.da.mapper.primary.ToProductImageResultMapper;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.vo.PoseTransformationVO;
import com.ai.da.service.APIGenerateService;
import com.ai.da.service.CreditsService;
import com.ai.da.service.GenerateService;
import com.ai.da.service.MessageCenterService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import static com.ai.da.common.enums.CreditsEventsEnum.TO_PRODUCT_IMAGE;
@Slf4j
@Component
public class GenerateTask {
@Resource
private APIGenerateService apiGenerateService;
@Resource
private CreditsService creditsService;
@Resource
private GenerateService generateService;
@Resource
private MessageCenterService messageCenterService;
@Resource
private ToProductImageResultMapper toProductImageResultMapper;
@Resource
private PoseTransformationMapper poseTransformationMapper;
/*
* 对于使用了第三方api的允许异步获得结果的生成功能可能在第三方接口的结果Ready时没有及时存储结果导致第三方链接失效
* 万相 24h失效
* flux 10mins失效 使用了flux接口的功能 ToProductImage || Relight, Pattern这里不做补偿
* 故这里通过定时任务做补偿
* flux五分钟查询一次万相1小时查询一次
*/
@Scheduled(cron = "0 */4 * * * ?")
public void fluxCompensationMechanism(){
// 1、查所有 任务还没成功、还没失败正在等待或者执行中的任务id有哪些
// 由于获取结果的polling_url在redis中只存一天大部分结果超过一天之后就无法再找到任务小部分可以通过公共路径查到结果
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("flux");
if (apiGenerates != null && !apiGenerates.isEmpty()){
for (APIGenerate apiGenerate : apiGenerates){
String taskId = apiGenerate.getTaskId();
// 1. 根据taskId查toProductImageResult 判断当前任务状态与超时状态
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(new QueryWrapper<ToProductImageResult>().eq("task_id", taskId));
if (Objects.nonNull(toProductImageResult) && "Pending".equals(toProductImageResult.getStatus())){
// 判断当前任务的超时状态
if (!DateUtil.isMoreThanOneDayApart(toProductImageResult.getCreateTime())){
// 1. 未超时,获取当前任务结果
String fileName = toProductImageResult.getResultType().equals(TO_PRODUCT_IMAGE.getName()) ? "product_image" : "relight_image";
String objectName = apiGenerate.getAccountId() + "/" + fileName +"/" + taskId + ".png";
String fluxResult = generateService.getFluxResult(taskId, objectName);
// 2. 成功获取结果下载图片上传至minio,更新toProductImageResult表
if (StringUtil.isNullOrEmpty(fluxResult) || fluxResult.equals("Fail")){
toProductImageResult.setStatus("Fail");
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
} else if (!fluxResult.equals("Pending")){
if (StringUtil.isNullOrEmpty(toProductImageResult.getUrl())){
toProductImageResult.setStatus("Success");
toProductImageResult.setUrl(fluxResult);
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Success");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
}
// 扣积分
Boolean flag = creditsService.taskCreditsDeduction(apiGenerate.getAccountId(), taskId);
if (flag) creditsService.updateChangedCredits(String.valueOf(apiGenerate.getAccountId()), taskId);
}
} else {
// 超时,设置状态为失败
toProductImageResult.setStatus("Fail");
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
}
}
}
}
}
// 万相 -> pose transformation 补偿 一小时执行一次
@Scheduled(fixedDelay = 5 * 60 * 1000)
public void wxCompensationMechanism(){
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("wx");
if (apiGenerates != null && !apiGenerates.isEmpty()){
for (APIGenerate apiGenerate : apiGenerates){
String taskId = apiGenerate.getTaskId();
PoseTransformation poseTransformation = poseTransformationMapper.selectOne(new QueryWrapper<PoseTransformation>().eq("unique_id", taskId));
if (Objects.nonNull(poseTransformation) && "Pending".equals(poseTransformation.getTaskStatus())){
// 判断当前任务的超时状态
if (!DateUtil.isMoreThanOneDayApart(poseTransformation.getCreateTime())){
try {
// 方法中已经完成了pose_transformation和api_generate表的更新不用额外做处理
PoseTransformationVO animateResult = generateService.getAnimateResult(taskId);
if (animateResult.getStatus().equals("Success")){
log.info("补偿获取结果成功,发送系统消息");
sendSysMsgToUser(poseTransformation.getAccountId(), "您的姿势变换生成任务已完成");
}
} catch (BusinessException e){
log.warn("万相 animation 生成失败,原因:{}", e.getMessage());
}
}
} else {
poseTransformation.setTaskStatus("Fail");
poseTransformation.setUpdateTime(LocalDateTime.now());
poseTransformationMapper.updateById(poseTransformation);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
}
}
}
}
public void sendSysMsgToUser(Long accountId, String content){
Notification notification = new Notification();
notification.setType("system");
notification.setReceiverId(accountId);
notification.setContent(content);
messageCenterService.prePushMessage(notification);
}
}

View File

@@ -45,7 +45,7 @@ public class PaymentTask {
@Resource @Resource
private PayPalCheckoutService payPalCheckoutService; private PayPalCheckoutService payPalCheckoutService;
@Scheduled(cron = "0/30 * * * * ?") // @Scheduled(cron = "0/30 * * * * ?")
public void orderConfirmForPaypal() throws SerializeException { public void orderConfirmForPaypal() throws SerializeException {
// log.info("PayPal orderConfirm 被执行......"); // log.info("PayPal orderConfirm 被执行......");
@@ -84,7 +84,6 @@ public class PaymentTask {
}*/ }*/
} }
// !!关闭此定时器,改为提前三天站内信提醒!!
// 提前7天向用户发送提醒邮件,每天早上8点执行 // 提前7天向用户发送提醒邮件,每天早上8点执行
// @Scheduled(cron = "0 0 8 * * ?") // @Scheduled(cron = "0 0 8 * * ?")
public void subscriptionReminder(){ public void subscriptionReminder(){
@@ -103,7 +102,13 @@ public class PaymentTask {
affiliateService.updateAffiliateInfoWithPayment(); affiliateService.updateAffiliateInfoWithPayment();
} }
@Scheduled(cron = "0 0 8 28-31 * ?") // 定时同步(每分钟一次)
@Scheduled(fixedRate = 60000)
public void syncLinkViewCountToDB(){
affiliateService.syncLinkViewCountToDB();
}
// @Scheduled(cron = "0 0 8 28-31 * ?")
public void commissionSummaryReminder(){ public void commissionSummaryReminder(){
// 每个月末的最后一天的早上八点执行 // 每个月末的最后一天的早上八点执行
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
@@ -114,9 +119,9 @@ public class PaymentTask {
} }
} }
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes // @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void calcCouponsCommission(){ public void calcCouponsCommission(){
// log.info("优惠券佣金计算定时器"); log.info("优惠券佣金计算定时器");
affiliateService.calcCouponsCommission(); affiliateService.calcCouponsCommission();
} }

View File

@@ -1,88 +0,0 @@
package com.ai.da.common.utils;
import java.util.HashMap;
import java.util.Map;
public class ComprehensivePunctuationConverter {
private static final Map<Character, Character> FULL_TO_HALF_MAP = new HashMap<>();
static {
// 中文标点到英文标点的映射(扩展版)
FULL_TO_HALF_MAP.put('', ',');
FULL_TO_HALF_MAP.put('。', '.');
FULL_TO_HALF_MAP.put('', ';');
FULL_TO_HALF_MAP.put('', ':');
FULL_TO_HALF_MAP.put('', '?');
FULL_TO_HALF_MAP.put('', '!');
FULL_TO_HALF_MAP.put('', '(');
FULL_TO_HALF_MAP.put('', ')');
FULL_TO_HALF_MAP.put('【', '[');
FULL_TO_HALF_MAP.put('】', ']');
FULL_TO_HALF_MAP.put('「', '\'');
FULL_TO_HALF_MAP.put('」', '\'');
FULL_TO_HALF_MAP.put('『', '"');
FULL_TO_HALF_MAP.put('』', '"');
FULL_TO_HALF_MAP.put('、', '\\');
FULL_TO_HALF_MAP.put('', '~');
FULL_TO_HALF_MAP.put('—', '-');
FULL_TO_HALF_MAP.put('', '.');
FULL_TO_HALF_MAP.put('〈', '<');
FULL_TO_HALF_MAP.put('〉', '>');
FULL_TO_HALF_MAP.put('《', '«');
FULL_TO_HALF_MAP.put('》', '»');
FULL_TO_HALF_MAP.put('〝', '"');
FULL_TO_HALF_MAP.put('〞', '"');
FULL_TO_HALF_MAP.put('﹁', '"');
FULL_TO_HALF_MAP.put('﹂', '"');
FULL_TO_HALF_MAP.put('…', '.');
FULL_TO_HALF_MAP.put('', '_');
// 全角字母和数字
for (char c = ''; c <= ''; c++) {
FULL_TO_HALF_MAP.put(c, (char)(c - '' + 'A'));
}
for (char c = ''; c <= ''; c++) {
FULL_TO_HALF_MAP.put(c, (char)(c - '' + 'a'));
}
for (char c = ''; c <= ''; c++) {
FULL_TO_HALF_MAP.put(c, (char)(c - '' + '0'));
}
}
/**
* 将字符串中的全角字符(包括标点、字母、数字)转换为半角字符
*/
public static String convertToHalfWidth(String input) {
if (input == null || input.isEmpty()) {
return input;
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
// 检查映射表
if (FULL_TO_HALF_MAP.containsKey(c)) {
result.append(FULL_TO_HALF_MAP.get(c));
}
// 处理全角空格Unicode 12288
else if (c == ' ') {
result.append(' ');
}
// 其他字符保持不变
else {
result.append(c);
}
}
return result.toString();
}
public static void main(String[] args) {
// String text = "这是一个全角示例,包含:中文标点、全角字母(ABC)、全角数字(123) 还有全角空格!";
String text = "birdsyellow";
String converted = convertToHalfWidth(text);
System.out.println("原始文本: " + text);
System.out.println("转换后: " + converted);
}
}

View File

@@ -5,10 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Instant; import java.time.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@@ -101,4 +98,10 @@ public class DateUtil {
return localDate.format(DateTimeFormatter.ofPattern(CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE, Locale.US)); return localDate.format(DateTimeFormatter.ofPattern(CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE, Locale.US));
} }
public static boolean isMoreThanOneDayApart(LocalDateTime givenDateTime) {
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.between(givenDateTime, now);
return duration.toHours() >= 24;
}
} }

View File

@@ -174,7 +174,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
URL url = new URL(path); URL url = new URL(path);
return url.openStream(); return url.openStream();
} catch (IOException ioException) { } catch (IOException ioException) {
log.error("获取文件尺寸异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException), path); log.error("获取文件异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException), path);
throw new BusinessException("get.file.failed"); throw new BusinessException("get.file.failed");
} }
} }

View File

@@ -28,7 +28,7 @@ public final class LocalCacheUtils {
private static LoadingCache<String, String> loadTokenCache() { private static LoadingCache<String, String> loadTokenCache() {
LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder() LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
.concurrencyLevel(10) .concurrencyLevel(10)
.expireAfterWrite(24 * (7 - 1), TimeUnit.HOURS) .expireAfterWrite(24 * 7 - 1, TimeUnit.HOURS)
.initialCapacity(100) .initialCapacity(100)
.maximumSize(10000) .maximumSize(10000)
.recordStats() .recordStats()

View File

@@ -0,0 +1,176 @@
package com.ai.da.common.utils;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.alibaba.fastjson.JSONObject;
import com.sun.mail.smtp.SMTPTransport;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.*;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
public class MailUtil {
@Resource
private JavaMailSender javaMailSender;
@Resource
private TemplateEngine templateEngine;
/**
* 发送邮件 - 默认发件人
*
* @param basicEmailParamDTO 发送邮件所需参数
* @param inputStreamSource 附件(如果有)
*/
public int sendMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
MimeMessage mimeMessage = createSimpleMail(basicEmailParamDTO, fileName, inputStreamSource);
// 提取配置
String host;
String username;
String password;
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getServiceAddress())) {
host = ((JavaMailSenderImpl) javaMailSender).getHost();
} else {
host = basicEmailParamDTO.getServiceAddress();
}
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getSenderUser())) {
username = ((JavaMailSenderImpl) javaMailSender).getUsername();
} else {
username = basicEmailParamDTO.getSenderUser();
}
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getServiceAddress())) {
password = ((JavaMailSenderImpl) javaMailSender).getPassword();
} else {
password = basicEmailParamDTO.getPassword();
}
return sendMail(mimeMessage, host, username, password);
}
private int sendMail(MimeMessage mimeMessage, String host, String username, String password) throws MessagingException {
SMTPTransport transport = null;
try {
// 获取 SMTPTransport
transport = (SMTPTransport) mimeMessage.getSession().getTransport("smtp");
// 连接到 SMTP 服务器
transport.connect(host, username, password);
// 发送邮件
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
// 获取 SMTP 服务器的响应
String lastServerResponse = transport.getLastServerResponse();
int lastReturnCode = transport.getLastReturnCode();
log.info("SMTP 状态码: {}, SMTP 服务器响应: {}", lastReturnCode, lastServerResponse);
return lastReturnCode;
} catch (MailException | MessagingException e) {
// 记录日志或执行其他补偿逻辑
log.info("邮件发送失败:{}", e.getMessage());
} finally {
// 关闭连接
assert transport != null;
transport.close();
}
return 0;
}
/**
* 创建一封邮件
*
* @param basicEmailParamDTO 创建邮件需要的参数
* @param inputStreamSource 附件(如果有)
* @return 一封邮件
*/
private MimeMessage createSimpleMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
// 创建邮件对象
MimeMessage message = javaMailSender.createMimeMessage();
// 使用 MimeMessageHelper 简化邮件内容和附件的设置
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message, true);
// 设置发件人
mimeMessageHelper.setFrom(new InternetAddress(basicEmailParamDTO.getSenderUserMail()));
// 设置收件人
mimeMessageHelper.setTo(basicEmailParamDTO.getMailTo());
// 设置抄送人
if (basicEmailParamDTO.getCc() != null && basicEmailParamDTO.getCc().length > 0) {
mimeMessageHelper.setCc(basicEmailParamDTO.getCc());
}
// 设置暗送人
if (basicEmailParamDTO.getBcc() != null && basicEmailParamDTO.getBcc().length > 0) {
mimeMessageHelper.setBcc(basicEmailParamDTO.getBcc());
}
// 设置邮件主题
mimeMessageHelper.setSubject(basicEmailParamDTO.getSubject());
// 设置邮件内容HTML 格式)
mimeMessageHelper.setText(basicEmailParamDTO.getContent(), true);
// 设置附件
if (inputStreamSource != null) {
mimeMessageHelper.addAttachment(fileName, inputStreamSource);
}
return message;
}
/**
* 设置实体参数
*
* @param mailTo 接收邮件的邮箱地址
* @param jsonObject 模板中变量的值
* @return 返回一个MailEntity
* @throws AddressException 邮箱地址值异常
*/
public BasicEmailParamDTO setBasicEmailParams(List<String> mailTo, JSONObject jsonObject, String templatePath, String title) throws AddressException {
BasicEmailParamDTO basicEmailParamDTO = new BasicEmailParamDTO();
basicEmailParamDTO.setSenderUserMail("info@aida.com.hk");
basicEmailParamDTO.setMailTo(getInternetAddressList(mailTo));
basicEmailParamDTO.setSubject(title);
// todo 邮件模板不存在的报错与重试机制
basicEmailParamDTO.setContent(setContent(jsonObject, templatePath));
return basicEmailParamDTO;
}
public BasicEmailParamDTO setBasicEmailParams(List<String> mailTo, String title) throws AddressException {
BasicEmailParamDTO basicEmailParamDTO = new BasicEmailParamDTO();
basicEmailParamDTO.setSenderUserMail("info@aida.com.hk");
basicEmailParamDTO.setMailTo(getInternetAddressList(mailTo));
basicEmailParamDTO.setSubject(title);
return basicEmailParamDTO;
}
/**
* 将地址转换为InternetAddress类型
*
* @param addressList 普通的地址字符串列表
* @return InternetAddress类型的地址列表
* @throws AddressException 地址异常
*/
public InternetAddress[] getInternetAddressList(List<String> addressList) throws AddressException {
InternetAddress[] toAddress = new InternetAddress[addressList.size()];
for (String address : addressList) {
toAddress[addressList.indexOf(address)] = new InternetAddress(address);
}
return toAddress;
}
public String setContent(JSONObject jsonObject, String templatePath) {
Context context = new Context();
if (Objects.nonNull(jsonObject)) {
for (String key : jsonObject.keySet()) {
context.setVariable(key, jsonObject.get(key));
}
}
return templateEngine.process(templatePath, context);
}
}

View File

@@ -1,25 +1,30 @@
package com.ai.da.common.utils; package com.ai.da.common.utils;
import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.mapper.primary.entity.ObjectItem; import com.ai.da.mapper.primary.entity.ObjectItem;
import io.minio.*; import io.minio.*;
import io.minio.errors.MinioException; import io.minio.errors.*;
import io.minio.http.Method; import io.minio.http.Method;
import io.minio.messages.DeleteError; import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject; import io.minio.messages.DeleteObject;
import io.minio.messages.Item; import io.minio.messages.Item;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.*; import java.io.*;
import java.net.URL;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -374,16 +379,38 @@ public class MinioUtil {
*/ */
public String getPreSignedUrl(String bucketName, String fileName, int expiry) { public String getPreSignedUrl(String bucketName, String fileName, int expiry) {
try { try {
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder() String lowerName = fileName.toLowerCase();
.bucket(bucketName) boolean isImage = lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")
.object(fileName) || lowerName.endsWith(".png") || lowerName.endsWith(".gif");
.expiry(expiry, TimeUnit.MINUTES)
.method(Method.GET) GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder()
.build() .bucket(bucketName)
); .object(fileName)
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) { .expiry(expiry, TimeUnit.MINUTES)
.method(Method.GET);
if (isImage) {
// 根据后缀名设置正确的 content-type
String contentType = "image/jpeg";
if (lowerName.endsWith(".png")) {
contentType = "image/png";
} else if (lowerName.endsWith(".gif")) { // 新增 GIF
contentType = "image/gif";
}
Map<String, String> queryParams = new HashMap<>();
queryParams.put("response-content-type", contentType);
queryParams.put("response-content-disposition", "inline");
builder.extraQueryParams(queryParams);
}
return minioClient.getPresignedObjectUrl(builder.build());
} catch (MinioException | InvalidKeyException
| IOException | NoSuchAlgorithmException | IllegalArgumentException e) {
e.printStackTrace(); e.printStackTrace();
log.error("bucket: {}, object:{}", bucketName, fileName);
throw new BusinessException(e.getMessage()); throw new BusinessException(e.getMessage());
} }
} }
@@ -570,6 +597,153 @@ public class MinioUtil {
throw new BusinessException(e.getMessage()); throw new BusinessException(e.getMessage());
} }
} }
public void upload(String url, File file) {
try {
// 分割桶名和对象路径
int firstSlashIndex = url.indexOf("/");
if (firstSlashIndex == -1) {
throw new IllegalArgumentException("URL 格式不正确,无法解析桶名和对象路径");
}
String bucketName = url.substring(0, firstSlashIndex);
String objectName = url.substring(firstSlashIndex + 1);
// 读取文件流
try (FileInputStream fileInputStream = new FileInputStream(file)) {
// 上传到 MinIO
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(fileInputStream, file.length(), -1)
.contentType("application/zip")
.build()
);
System.out.println("文件上传成功: " + url);
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("文件上传失败: " + e.getMessage());
}
}
public String getImageAsBase64(String path) throws IOException {
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String fileName = path.substring(index + 1);
// 检查桶是否存在
boolean found = doesObjectExist(bucketName, fileName);
if (!found) {
throw new IOException("Bucket " + bucketName + " does not exist");
}
try (InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build())) {
byte[] bytes = IOUtils.toByteArray(stream);
return Base64.getEncoder().encodeToString(bytes);
} catch (ServerException e) {
throw new RuntimeException(e);
} catch (InsufficientDataException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (InvalidResponseException e) {
throw new RuntimeException(e);
} catch (XmlParserException e) {
throw new RuntimeException(e);
} catch (InternalException e) {
throw new RuntimeException(e);
}
}
public void uploadToMinio(byte[] data, String bucket, String objectName, String contentType) /*throws Exception*/ {
try {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucket)
.object(objectName)
.stream(new ByteArrayInputStream(data), data.length, -1)
.contentType(contentType)
.build());
} catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e){
log.error("图片上传到minio出错{}", e.getMessage());
throw new BusinessException("file upload exception");
}
}
public String changeToWhiteBackground(String minioPath){
try {
// 1. 使用URL读取远程图片
BufferedImage originalImage = ImageIO.read(new URL(getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)));
// 2. 透明图检查(新增核心逻辑)
if (!hasTransparency(originalImage)) {
log.info("图片 {} 无透明通道,无需添加白底", minioPath);
return null; // 返回空
}
// 3. 处理图片(例如:转换为白底)
BufferedImage newImage = new BufferedImage(
originalImage.getWidth(),
originalImage.getHeight(),
BufferedImage.TYPE_INT_RGB
);
// 4. 填充白色背景
java.awt.Graphics2D g = newImage.createGraphics();
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
g.drawImage(originalImage, 0, 0, null);
g.dispose();
// 5. 输出为Base64
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newImage, "PNG", baos);
String base64Image = java.util.Base64.getEncoder().encodeToString(baos.toByteArray());
log.info("为图片 {} 添加白色背景", minioPath);
// System.out.println("data:image/png;base64," + base64Image);
return "data:image/png;base64," + base64Image;
// return base64Image;
} catch (Exception e) {
log.error(e.getMessage());
throw new BusinessException("透明图添加白色背景失败");
}
}
/**
* 检测图片是否包含透明通道
*/
private boolean hasTransparency(BufferedImage image) {
// 情况1图像本身支持透明如TYPE_INT_ARGB
if (image.getTransparency() == Transparency.TRANSLUCENT) {
return true;
}
// 情况2检查像素级透明度适用于TYPE_INT_RGB等格式
if (image.getColorModel().hasAlpha()) {
// 抽样检查前100x100像素避免全图扫描的性能问题
int width = Math.min(image.getWidth(), 100);
int height = Math.min(image.getHeight(), 100);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if ((image.getRGB(x, y) >> 24) == 0x00) {
return true; // 发现透明像素
}
}
}
}
return false;
}
} }

View File

@@ -1,13 +1,27 @@
package com.ai.da.common.utils; package com.ai.da.common.utils;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.python.vo.DesignPythonObject;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations; import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations; import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -19,6 +33,8 @@ public class RedisUtil {
@Resource @Resource
private RedisTemplate<String, String> redisTemplate; private RedisTemplate<String, String> redisTemplate;
public final static String FLUX_POLLING_URL = "Flux:";
public Boolean hasKey(String key){ public Boolean hasKey(String key){
return redisTemplate.hasKey(key); return redisTemplate.hasKey(key);
} }
@@ -84,10 +100,8 @@ public class RedisUtil {
/** /**
* 将数据放入set缓存 * 将数据放入set缓存
*/ */
public void addToSet(String key, String value, Long expiresIn) { public void addToSet(String key, String value) {
redisTemplate.opsForSet().add(key, value); redisTemplate.opsForSet().add(key, value);
// 设置过期时间
redisTemplate.expire(key, expiresIn, TimeUnit.SECONDS);
} }
/** /**
@@ -281,6 +295,77 @@ public class RedisUtil {
redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES); redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES);
} }
public void addPathToCache(Long collectionId, Long userId, String path) {
// Redis 中的键,唯一标识由 collectionId 和 userId 组成
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 增加路径的计数
redisTemplate.opsForHash().increment(redisKey, path, 1);
// 设置过期时间为 2 小时7200 秒)
redisTemplate.expire(redisKey, 8, TimeUnit.HOURS);
}
public int getPathUsageCount(Long collectionId, Long userId, String path) {
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 获取路径的使用次数
Object count = redisTemplate.opsForHash().get(redisKey, path);
return count != null ? Integer.parseInt(count.toString()) : 0;
}
public void addAssembledObjects(Long collectionId, Set<DesignPythonObject> assembledObjects) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 将 assembledObjects 转换为 JSON 格式存储,避免直接存储对象
String assembledObjectsJson = convertToJson(assembledObjects);
// 使用 Redis 的 set 操作更新集合
redisTemplate.opsForValue().set(redisKey, assembledObjectsJson);
// 设置过期时间为 5 分钟300 秒)
redisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
}
// 将 Set<DesignPythonObject> 转换为 JSON 格式
private String convertToJson(Set<DesignPythonObject> assembledObjects) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(assembledObjects);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public Set<DesignPythonObject> getAssembledObjects(Long collectionId) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 从 Redis 获取存储的 JSON 字符串
String assembledObjectsJson = (String) redisTemplate.opsForValue().get(redisKey);
if (assembledObjectsJson == null) {
return new HashSet<>(); // 如果没有找到数据,返回一个空的 Set
}
// 将 JSON 字符串转换为 Set<DesignPythonObject>
return convertFromJson(assembledObjectsJson);
}
// 将 JSON 字符串转换为 Set<DesignPythonObject>
private Set<DesignPythonObject> convertFromJson(String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
// 使用 TypeReference 来指定目标类型是 Set<DesignPythonObject>
return objectMapper.readValue(json, new TypeReference<Set<DesignPythonObject>>() {});
} catch (JsonProcessingException e) {
e.printStackTrace();
return new HashSet<>(); // 如果转换失败,返回空的 Set
}
}
public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime"; public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime";
public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:"; public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:";
@@ -295,6 +380,130 @@ public class RedisUtil {
return redisTemplate.opsForValue().increment(key, 0); return redisTemplate.opsForValue().increment(key, 0);
} }
/**
* 记录任务的耗时到Redis
* @param taskKey 任务标识,如 "taskA"
* @param elapsedTime 本次耗时,单位为毫秒
*/
public void recordTaskElapsedTime(String taskKey, long elapsedTime) {
String hashKey = "task:stats";
// 累加总耗时
redisTemplate.opsForHash().increment(hashKey, taskKey + ":totalTime", elapsedTime);
// 增加计数器
redisTemplate.opsForHash().increment(hashKey, taskKey + ":count", 1);
}
/**
* 获取任务的平均耗时
* @param taskKey 任务标识,如 "taskA"
* @return 平均耗时(毫秒)
*/
public double getTaskAverageTime(String taskKey) {
String hashKey = "task:stats";
// 获取总耗时和计数
Object totalTime = redisTemplate.opsForHash().get(hashKey, taskKey + ":totalTime");
Object count = redisTemplate.opsForHash().get(hashKey, taskKey + ":count");
// 计算平均值
if (totalTime == null || count == null) {
return 0;
}
return Double.parseDouble(totalTime.toString()) / Long.parseLong(count.toString());
}
/**
* 清除指定任务的统计数据
* @param taskKey 任务标识,如 "taskA"
*/
public void clearTaskStats(String taskKey) {
String hashKey = "task:stats";
// 删除总耗时和计数器
redisTemplate.opsForHash().delete(hashKey, taskKey + ":totalTime", taskKey + ":count");
}
public void recordTaskElapsedTime(String taskKey, double elapsedTimeInSeconds) {
// 将耗时转换为 BigDecimal并四舍五入保留四位小数
BigDecimal elapsedTime = new BigDecimal(elapsedTimeInSeconds).setScale(4, RoundingMode.HALF_UP);
// 累加总耗时(以毫秒为单位)
redisTemplate.opsForHash().increment("task:stats", taskKey + ":totalTime", elapsedTime.doubleValue());
// 增加计数器
redisTemplate.opsForHash().increment("task:stats", taskKey + ":count", 1);
}
// 获取第一部分Sketch耗时
public double getFirstSketchTime() {
// 获取 "firstSketchTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "firstSketchTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 获取第二部分(获取特征值)耗时
public double getGetAttributeRecognitionTime() {
// 获取 "getAttributeRecognitionTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "getAttributeRecognitionTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 获取第三部分(搭配 Sketch耗时
public double getOtherSketchTime() {
// 获取 "otherSketchTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "otherSketchTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 清理三部分的缓存
public void clearTaskElapsedTimeCache() {
// 删除第一部分的缓存
redisTemplate.opsForHash().delete("task:stats", "firstSketchTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "firstSketchTime:count");
// 删除第二部分的缓存
redisTemplate.opsForHash().delete("task:stats", "getAttributeRecognitionTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "getAttributeRecognitionTime:count");
// 删除第三部分的缓存
redisTemplate.opsForHash().delete("task:stats", "otherSketchTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "otherSketchTime:count");
}
public boolean incrementLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
try {
redisTemplate.opsForHash().increment(redisKey, sketchPath, 1);
return true;
} catch (Exception e) {
log.error("Error incrementing like count for userId {} and sketchPath {}: {}", userId, sketchPath, e.getMessage());
return false;
}
}
public int getLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
Object count = redisTemplate.opsForHash().get(redisKey, sketchPath);
return count != null ? Integer.parseInt(count.toString()) : 0;
}
public void storeMaxLikeCount(Long userId, int maxLikeCount) {
String redisKey = "user_max_like_count:" + userId;
redisTemplate.opsForValue().set(redisKey, String.valueOf(maxLikeCount));
}
public int getMaxLikeCount(Long userId) {
String redisKey = "user_max_like_count:" + userId;
String maxLikeCount = redisTemplate.opsForValue().get(redisKey);
return maxLikeCount != null ? Integer.parseInt(maxLikeCount) : 0;
}
public final static String IMAGE_SEGMENTATION = "ImageSegmentation:";
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public void batchDeleteKeysWithSamePrefix(String prefix){ public void batchDeleteKeysWithSamePrefix(String prefix){
Set<String> keys = redisTemplate.keys(prefix + "*"); Set<String> keys = redisTemplate.keys(prefix + "*");
assert keys != null; assert keys != null;
@@ -303,6 +512,103 @@ public class RedisUtil {
} }
} }
public final static String STRIPE_EXCEPTION_LOG = "StripeException:"; public void setTaskProgressDTO(String taskId, ProgressDTO dto) {
public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:"; String key = "task:progress:" + taskId;
redisTemplate.opsForValue().set(key, JSON.toJSONString(dto), Duration.ofDays(1));
}
public ProgressDTO getTaskProgressDTO(String taskId) {
String key = "task:progress:" + taskId;
String json = redisTemplate.opsForValue().get(key);
if (StringUtils.isBlank(json)) {
// return new ProgressDTO(0, 0, false);
return null;
}
try {
return JSON.parseObject(json, ProgressDTO.class);
} catch (Exception e) {
log.warn("任务进度解析失败 key={}, json={}", key, json);
return new ProgressDTO(0, 0, false, null);
}
}
// Lua脚本原子化操作
/*private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"if tonumber(current) == 1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";*/
private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"local ttl = redis.call('TTL', KEYS[1])\n" +
"if tonumber(current) == 1 or tonumber(ttl) == -1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";
/**
* 检查是否允许发送
* @param userId 用户ID
* @return true-允许发送false-已超限
*/
public boolean allowSend(Long userId) {
String hourKey = getCurrentHourKey(userId);
// 执行Lua脚本
List<String> keys = Collections.singletonList(hourKey);
List<Long> args = Arrays.asList(
3600L, // 1小时过期
10L // 限制数量 一小时只能向普通用户发10封
);
Boolean result = redisTemplate.execute(
new DefaultRedisScript<>(RATE_LIMIT_SCRIPT, Boolean.class),
keys,
args.toArray()
);
return Boolean.TRUE.equals(result);
}
/**
* 获取当前小时的Key
* 格式email_limit:{userId}:{yyyyMMddHH}
*/
private String getCurrentHourKey(Long userId) {
String hour = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
return String.format("email_limit:%s:%s", userId, hour);
}
/**
* 获取当前已发送数量
*/
public int getCurrentCount(Long userId) {
String key = getCurrentHourKey(userId);
String val = redisTemplate.opsForValue().get(key);
int count;
if (StringUtils.isBlank(val)){
count = 0;
}else {
count = Integer.parseInt(val);
}
return count;
}
public boolean allowRequest(String apiKey) {
String key = "rate_limit:" + apiKey;
ValueOperations<String, String> ops = redisTemplate.opsForValue();
// 使用Redis的INCR命令
Long count = ops.increment(key, 1);
if (count == 1) {
// 第一次调用,设置过期时间
redisTemplate.expire(key, 1, TimeUnit.MINUTES);
}
return count <= 3;
}
} }

View File

@@ -0,0 +1,743 @@
package com.ai.da.common.utils;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.python.vo.DesignPythonObject;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Component
public class RedisUtilEnhance {
@Resource
private RedisTemplate<String, Object> redisTemplate;
private ValueOperations<String, Object> valueOperations;
private SetOperations<String, Object> setOperations;
private HashOperations<String, Object, Object> hashOperations;
private ZSetOperations<String, Object> zSetOperations;
@PostConstruct
public void init() {
this.valueOperations = redisTemplate.opsForValue();
this.setOperations = redisTemplate.opsForSet();
this.hashOperations = redisTemplate.opsForHash();
this.zSetOperations = redisTemplate.opsForZSet();
}
public final static String FLUX_POLLING_URL = "Flux:";
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
//- - - - - - - - - - - - - - - - - - - - - ZSet类型 - - - - - - - - - - - - - - - - - - - -
/**
* 向ZSet中添加元素
*/
public void addToZSet(String key, Object value, Double score) {
zSetOperations.add(key, value, score);
}
/**
* 从ZSet中删除元素
*/
public void removeFromZSet(String key, Object value) {
zSetOperations.remove(key, value);
}
/**
* 获取指定元素的当前排列顺序
*/
public Long getRank(String key, Object value) {
return zSetOperations.rank(key, value);
}
/**
* 获取当前ZSet中的最大score
*/
public Double getMaxScore(String key) {
Set<ZSetOperations.TypedTuple<Object>> set = zSetOperations.reverseRangeWithScores(key, 0, 0);
if (!CollectionUtils.isEmpty(set)) {
Iterator<ZSetOperations.TypedTuple<Object>> iterator = set.iterator();
if (iterator.hasNext()) {
Double score = iterator.next().getScore();
return score != null ? score + 1.0 : 1.0;
}
}
return 1.0;
}
/**
* 判断元素是否存在
*/
public Boolean isElementExistsInZSet(String key, Object value) {
return zSetOperations.score(key, value) != null;
}
/**
* 获取当前ZSet中数据量的总和
*/
public Long getZSetTotalCount(String key) {
return zSetOperations.zCard(key);
}
public Set<Object> getZSetTotalData(String key) {
return zSetOperations.range(key, 0, -1);
}
//- - - - - - - - - - - - - - - - - - - - - set类型 - - - - - - - - - - - - - - - - - - - -
/**
* 将数据放入set缓存
*/
public void addToSet(String key, Object value) {
setOperations.add(key, value);
}
/**
* 弹出变量中的元素
*/
public void removeFromSet(String key, Object value) {
setOperations.remove(key, value);
}
/**
* 检查给定的元素是否在变量中。
*/
public Boolean isElementExistsInSet(String key, Object obj) {
return setOperations.isMember(key, obj);
}
//- - - - - - - - - - - - - - - - - - - - - hash类型 - - - - - - - - - - - - - - - - - - - -
/**
* 加入缓存
*/
public void addToMap(String key, Map<String, String> map) {
hashOperations.putAll(key, map);
}
/**
* 验证指定 key 下 有没有指定的 hashkey
*/
public Boolean isElementExistsInMap(String key, Object hashKey) {
return hashOperations.hasKey(key, hashKey);
}
/**
* 获取指定key的值string
*/
public String getMapValue(String key1, Object key2) {
Object value = hashOperations.get(key1, key2);
return value != null ? value.toString() : null;
}
/**
* 删除指定 hash 的 HashKey
*
* @return 删除成功的 数量
*/
public Long removeFromMap(String key, Object hashKeys) {
return hashOperations.delete(key, hashKeys);
}
//- - - - - - - - - - - - - - - - - - - - - String/Long/Integer类型支持 - - - - - - - - - - - - - - - - - - - -
/**
* 设置字符串值
*/
public void setString(String key, String value) {
valueOperations.set(key, value);
}
/**
* 设置字符串值并设置过期时间
*/
public void setString(String key, String value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置Long值
*/
public void setLong(String key, Long value) {
valueOperations.set(key, value);
}
/**
* 设置Long值并设置过期时间
*/
public void setLong(String key, Long value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置Integer值
*/
public void setInteger(String key, Integer value) {
valueOperations.set(key, value);
}
/**
* 设置Integer值并设置过期时间
*/
public void setInteger(String key, Integer value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置对象值
*/
public void setObject(String key, Object value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 获取字符串值
*/
public String getString(String key) {
Object value = valueOperations.get(key);
return value != null ? value.toString() : null;
}
/**
* 获取Long值
*/
public Long getLong(String key) {
Object value = valueOperations.get(key);
if (value instanceof Long) {
return (Long) value;
} else if (value instanceof Integer) {
return ((Integer) value).longValue();
} else if (value instanceof String) {
try {
return Long.parseLong((String) value);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Long: key={}, value={}", key, value);
return null;
}
} else if (value != null) {
log.warn("不支持的类型转换到Long: key={}, type={}", key, value.getClass().getName());
}
return null;
}
/**
* 获取Long值带默认值
*/
public Long getLong(String key, Long defaultValue) {
try {
Long value = getLong(key);
return value != null ? value : defaultValue;
} catch (Exception e) {
log.warn("获取Long值失败: key={}", key, e);
return defaultValue;
}
}
/**
* 获取Integer值
*/
public Integer getInteger(String key) {
Object value = valueOperations.get(key);
if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof Long) {
return ((Long) value).intValue();
} else if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Integer: key={}, value={}", key, value);
return null;
}
} else if (value != null) {
log.warn("不支持的类型转换到Integer: key={}, type={}", key, value.getClass().getName());
}
return null;
}
/**
* 获取Integer值带默认值
*/
public Integer getInteger(String key, Integer defaultValue) {
try {
Integer value = getInteger(key);
return value != null ? value : defaultValue;
} catch (Exception e) {
log.warn("获取Integer值失败: key={}", key, e);
return defaultValue;
}
}
/**
* 递增操作
*/
public Long increment(String key, long delta) {
return valueOperations.increment(key, delta);
}
/**
* 递增操作double
*/
public Double increment(String key, double delta) {
return valueOperations.increment(key, delta);
}
//- - - - - - - - - - - - - - - - - - - - - 原有方法适配 - - - - - - - - - - - - - - - - - - - -
public void addToString(String key, String value) {
setString(key, value);
}
public void addToString(String key, String value, Long expiresIn) {
setString(key, value, expiresIn, TimeUnit.SECONDS);
}
public String getFromString(String key) {
return getString(key);
}
public Set<String> getKeysFromString(String pattern) {
Set<String> keys = redisTemplate.keys(pattern);
return keys != null ? keys : Collections.emptySet();
}
public Long getSize(String key) {
return setOperations.size(key);
}
public List<Object> getMultiValue(Set<String> keys) {
return valueOperations.multiGet(keys);
}
public Long getExpire(String key) {
return redisTemplate.getExpire(key);
}
public void removeFromString(String key) {
redisTemplate.delete(key);
}
public final static String PORTFOLIO_LIKE_KEY = "portfolio:like:";
public void likePost(Long portfolioId, Long userId) {
setOperations.add(PORTFOLIO_LIKE_KEY + portfolioId, userId.toString());
}
public Long getLikeCount(Long portfolioId) {
String key = PORTFOLIO_LIKE_KEY + portfolioId;
return setOperations.size(key);
}
public List<Long> getLikedPortfolios(Long userId) {
// 获取所有包含PORTFOLIO_LIKE_KEY的键
Set<String> likedPortfolios = redisTemplate.keys(PORTFOLIO_LIKE_KEY + "*");
// 如果没有喜欢的,返回空列表
if (likedPortfolios == null || likedPortfolios.isEmpty()) {
return new ArrayList<>();
}
// 过滤出包含指定用户ID的键并提取投资组合ID
return likedPortfolios.stream()
.filter(key -> setOperations.isMember(key, userId.toString()))
.map(key -> Long.valueOf(key.replace(PORTFOLIO_LIKE_KEY, "")))
.collect(Collectors.toList());
}
public void unLikePost(Long portfolioId, Long userId) {
setOperations.remove(PORTFOLIO_LIKE_KEY + portfolioId, userId.toString());
}
// 检查用户是否喜欢某个作品
public boolean isPostLikedByUser(Long portfolioId, Long userId) {
String key = PORTFOLIO_LIKE_KEY + portfolioId;
Boolean isMember = setOperations.isMember(key, userId.toString());
return isMember != null && isMember;
}
public final static String PORTFOLIO_VIEW_KEY = "portfolio:view:";
public void increaseViewCount(Long portfolioId) {
String key = PORTFOLIO_VIEW_KEY + portfolioId;
increment(key, 1);
}
public Long getViewCount(Long portfolioId) {
String key = PORTFOLIO_VIEW_KEY + portfolioId;
return getLong(key, 0L);
}
public Long getViewCount(String key) {
return getLong(key, 0L);
}
public final static String PERSONAL_HOMEPAGE_VIEW_KEY = "PersonalHomepage:view:";
public void increasePersonalHomepageViewCount(Long accountId) {
String key = PERSONAL_HOMEPAGE_VIEW_KEY + accountId;
increment(key, 1);
}
public Long getPersonalHomepageViewCount(Long accountId) {
String key = PERSONAL_HOMEPAGE_VIEW_KEY + accountId;
return getLong(key, 0L);
}
public final static String MOODBOARD_POSITION_KEY = "moodboard:position:";
public void saveMoodboardPosition(Long id, String moodboardPosition) {
setString(MOODBOARD_POSITION_KEY + id, moodboardPosition);
}
public String getMoodboardPosition(Long id) {
return getString(MOODBOARD_POSITION_KEY + id);
}
public final static String NICKNAME_MODIFY_TIMES = "NicknameModifyTimes:";
public void increaseCount(String key) {
increment(key, 1);
}
public Long getIncrementCount(String key) {
return getLong(key, 0L);
}
public void setKeyExpire(String key, Long expire) {
redisTemplate.expire(key, expire, TimeUnit.DAYS);
}
public final static String CHANGE_MAILBOX = "ChangeMailbox:";
// 每天允许通知3次
public final static String UPLOAD_TIMEOUT_REMINDER_COUNTER = "UploadTimeoutReminderCounter";
public void addProcessId(String processId, int progress) {
// Redis 中的键,可以通过 processId 来唯一标识
String redisKey = "process:progress:" + processId;
setInteger(redisKey, progress);
redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES);
}
public void addPathToCache(Long collectionId, Long userId, String path) {
// Redis 中的键,唯一标识由 collectionId 和 userId 组成
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 增加路径的计数
hashOperations.increment(redisKey, path, 1);
// 设置过期时间为 2 小时7200 秒)
redisTemplate.expire(redisKey, 2, TimeUnit.HOURS);
}
public int getPathUsageCount(Long collectionId, Long userId, String path) {
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 获取路径的使用次数
Object count = hashOperations.get(redisKey, path);
return count != null ? ((Number) count).intValue() : 0;
}
public void addAssembledObjects(Long collectionId, Set<DesignPythonObject> assembledObjects) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 将 assembledObjects 转换为 JSON 格式存储,避免直接存储对象
String assembledObjectsJson = convertToJson(assembledObjects);
if (assembledObjectsJson != null) {
// 使用 Redis 的 set 操作更新集合
setString(redisKey, assembledObjectsJson);
// 设置过期时间为 5 分钟300 秒)
redisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
}
}
private String convertToJson(Set<DesignPythonObject> assembledObjects) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(assembledObjects);
} catch (JsonProcessingException e) {
log.error("JSON转换失败", e);
return null;
}
}
public Set<DesignPythonObject> getAssembledObjects(Long collectionId) {
String redisKey = "collection:assembledObjects:" + collectionId;
String assembledObjectsJson = getString(redisKey);
if (assembledObjectsJson == null) {
return new HashSet<>();
}
return convertFromJson(assembledObjectsJson);
}
private Set<DesignPythonObject> convertFromJson(String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, new TypeReference<Set<DesignPythonObject>>() {});
} catch (JsonProcessingException e) {
log.error("JSON解析失败", e);
return new HashSet<>();
}
}
public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime";
public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:";
public void increaseAffiliateLinkViewCount(Long accountId) {
String key = AFFILIATE_LINK_VIEW_KEY + accountId;
increment(key, 1);
}
public Long getAffiliateLinkViewCount(Long accountId) {
String key = AFFILIATE_LINK_VIEW_KEY + accountId;
return getLong(key, 0L);
}
public Long getAndSetKey(String key, Long count) {
Object oldValue = valueOperations.getAndSet(key, count);
if (oldValue instanceof Long) {
return (Long) oldValue;
} else if (oldValue instanceof Integer) {
return ((Integer) oldValue).longValue();
} else if (oldValue instanceof String) {
try {
return Long.parseLong((String) oldValue);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Long: key={}, value={}", key, oldValue);
return 0L;
}
}
return 0L;
}
/**
* 记录任务的耗时到Redis
*/
public void recordTaskElapsedTime(String taskKey, long elapsedTime) {
String hashKey = "task:stats";
hashOperations.increment(hashKey, taskKey + ":totalTime", elapsedTime);
hashOperations.increment(hashKey, taskKey + ":count", 1);
}
/**
* 获取任务的平均耗时
*/
public double getTaskAverageTime(String taskKey) {
String hashKey = "task:stats";
Object totalTime = hashOperations.get(hashKey, taskKey + ":totalTime");
Object count = hashOperations.get(hashKey, taskKey + ":count");
if (totalTime == null || count == null) {
return 0;
}
try {
double total = ((Number) totalTime).doubleValue();
long cnt = ((Number) count).longValue();
return cnt > 0 ? total / cnt : 0;
} catch (Exception e) {
log.warn("计算平均耗时失败: taskKey={}", taskKey, e);
return 0;
}
}
/**
* 清除指定任务的统计数据
* @param taskKey 任务标识,如 "taskA"
*/
public void clearTaskStats(String taskKey) {
String hashKey = "task:stats";
// 删除总耗时和计数器
hashOperations.delete(hashKey, taskKey + ":totalTime", taskKey + ":count");
}
public void recordTaskElapsedTime(String taskKey, double elapsedTimeInSeconds) {
// 将耗时转换为 BigDecimal并四舍五入保留四位小数
BigDecimal elapsedTime = new BigDecimal(elapsedTimeInSeconds).setScale(4, RoundingMode.HALF_UP);
hashOperations.increment("task:stats", taskKey + ":totalTime", elapsedTime.doubleValue());
hashOperations.increment("task:stats", taskKey + ":count", 1);
}
// 获取第一部分Sketch耗时
public double getFirstSketchTime() {
Object time = hashOperations.get("task:stats", "firstSketchTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 获取第二部分(获取特征值)耗时
public double getGetAttributeRecognitionTime() {
Object time = hashOperations.get("task:stats", "getAttributeRecognitionTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 获取第三部分(搭配 Sketch耗时
public double getOtherSketchTime() {
Object time = hashOperations.get("task:stats", "otherSketchTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 清理三部分的缓存
public void clearTaskElapsedTimeCache() {
String hashKey = "task:stats";
Object[] keysToDelete = {
"firstSketchTime:totalTime", "firstSketchTime:count",
"getAttributeRecognitionTime:totalTime", "getAttributeRecognitionTime:count",
"otherSketchTime:totalTime", "otherSketchTime:count"
};
hashOperations.delete(hashKey, keysToDelete);
}
public boolean incrementLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
try {
hashOperations.increment(redisKey, sketchPath, 1);
return true;
} catch (Exception e) {
log.error("Error incrementing like count for userId {} and sketchPath {}: {}", userId, sketchPath, e.getMessage());
return false;
}
}
public int getLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
Object count = hashOperations.get(redisKey, sketchPath);
return count != null ? ((Number) count).intValue() : 0;
}
public void storeMaxLikeCount(Long userId, int maxLikeCount) {
String redisKey = "user_max_like_count:" + userId;
setInteger(redisKey, maxLikeCount);
}
public int getMaxLikeCount(Long userId) {
String redisKey = "user_max_like_count:" + userId;
return getInteger(redisKey, 0);
}
public final static String IMAGE_SEGMENTATION = "ImageSegmentation:";
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public void batchDeleteKeysWithSamePrefix(String prefix) {
Set<String> keys = redisTemplate.keys(prefix + "*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
public void setTaskProgressDTO(String taskId, ProgressDTO dto) {
String key = "task:progress:" + taskId;
setString(key, JSON.toJSONString(dto));
redisTemplate.expire(key, 1, TimeUnit.DAYS);
}
public ProgressDTO getTaskProgressDTO(String taskId) {
String key = "task:progress:" + taskId;
String json = getString(key);
if (StringUtils.isBlank(json)) {
return null;
}
try {
return JSON.parseObject(json, ProgressDTO.class);
} catch (Exception e) {
log.warn("任务进度解析失败 key={}, json={}", key, json);
return new ProgressDTO(0, 0, false, null);
}
}
// Lua脚本
private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"local ttl = redis.call('TTL', KEYS[1])\n" +
"if tonumber(current) == 1 or tonumber(ttl) == -1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";
/**
* 检查是否允许发送
* @param userId 用户ID
* @return true-允许发送false-已超限
*/
public boolean allowSend(Long userId) {
String hourKey = getCurrentHourKey(userId);
// 执行Lua脚本
List<String> keys = Collections.singletonList(hourKey);
// 1小时过期限制数量 一小时只能向普通用户发10封
String[] args = new String[]{"3600", "10"};
Boolean result = redisTemplate.execute(
new DefaultRedisScript<>(RATE_LIMIT_SCRIPT, Boolean.class),
keys,
args
);
return Boolean.TRUE.equals(result);
}
/**
* 获取当前小时的Key
*/
private String getCurrentHourKey(Long userId) {
String hour = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
return String.format("email_limit:%s:%s", userId, hour);
}
/**
* 获取当前已发送数量
*/
public int getCurrentCount(Long userId) {
String key = getCurrentHourKey(userId);
return getInteger(key, 0);
}
public boolean allowRequest(String apiKey) {
String key = "rate_limit:" + apiKey;
// 使用Redis的INCR命令
Long count = increment(key, 1);
if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.MINUTES);
}
return count <= 3;
}
// 新增方法安全删除key
public boolean safeDelete(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.delete(key));
} catch (Exception e) {
log.error("删除Redis key失败: {}", key, e);
return false;
}
}
// 新增方法:批量设置过期时间
public void batchExpire(Set<String> keys, long timeout, TimeUnit unit) {
if (keys != null && !keys.isEmpty()) {
for (String key : keys) {
redisTemplate.expire(key, timeout, unit);
}
}
}
}

View File

@@ -426,45 +426,7 @@ public class SendEmailUtil {
} }
} }
private final static Long GENERATE_EXCEPTION_WARNING_ID = 122589L; // todo ?需要保留吗
public static void sendGenerateExceptionWarning(String message) {
try {
// 实例化一个认证对象
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ses.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(CODE_CREATE_SEND_ADDRESS);
req.setDestination(new String[]{"xupei3360@163.com"});
// 根据邮件类型设置不同的主题和模板
String subject = "";
Template template = new Template();
subject = "Warning: AiDA 3.0 Generate Exception Warning";
template.setTemplateID(GENERATE_EXCEPTION_WARNING_ID);
JSONObject parameter = new JSONObject();
parameter.put("errorMessage", message);
parameter.put("time", DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD_HH_MM_SS));
template.setTemplateData(parameter.toJSONString());
req.setSubject(subject);
req.setTemplate(template);
// 发送邮件
SendEmailResponse resp = client.SendEmail(req);
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
log.info("邮件发送失败###{}", e.toString());
throw new BusinessException("failed.to.send.mail");
}
}
private final static Long QUESTIONNAIRE_FEEDBACK_EN_ID = 124151L; private final static Long QUESTIONNAIRE_FEEDBACK_EN_ID = 124151L;
private final static Long QUESTIONNAIRE_FEEDBACK_CN_ID = 124156L; private final static Long QUESTIONNAIRE_FEEDBACK_CN_ID = 124156L;
@@ -606,6 +568,7 @@ public class SendEmailUtil {
} }
} }
// todo 目前该定时器已取消,是否需要保留该模板?
private final static Long NEW_USER_REGISTER_NOTIFICATION_EN = 126919L; private final static Long NEW_USER_REGISTER_NOTIFICATION_EN = 126919L;
public static void notificationForRegisterUser(String receiverAddress) { public static void notificationForRegisterUser(String receiverAddress) {
@@ -644,55 +607,11 @@ public class SendEmailUtil {
} }
} }
private final static Long CHANGE_MAILBOX_CONFIRM_CN = 128278L;
private final static Long CHANGE_MAILBOX_CONFIRM_EN = 128277L;
public static void changeMailboxConfirm(String receiverAddress, String language, String name, String link) {
try {
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露并威胁账号下所有资源的安全性。以下代码示例仅供参考建议采用更安全的方式来使用密钥请参见https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ses.tencentcloudapi.com");
// 实例化一个client选项可选的没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(SEND_ADDRESS);
req.setDestination(new String[]{receiverAddress});
Template template = new Template();
if (language.equals("ENGLISH")) {
req.setSubject("Change the email address bound to the AiDA account");
template.setTemplateID(CHANGE_MAILBOX_CONFIRM_EN);
} else {
req.setSubject("更换AiDA账号绑定的邮箱地址");
template.setTemplateID(CHANGE_MAILBOX_CONFIRM_CN);
}
JSONObject param = new JSONObject();
param.put("userName", name);
param.put("link", link);
template.setTemplateData(param.toJSONString());
req.setTemplate(template);
// 返回的resp是一个SendEmailResponse的实例与请求对象对应
SendEmailResponse resp = client.SendEmail(req);
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
log.info("邮件发送失败###{}", e.toString());
throw new BusinessException("failed.to.send.mail");
}
}
private final static Long UPLOAD_TIMEOUT_REMINDER = 128324L; private final static Long UPLOAD_TIMEOUT_REMINDER = 128324L;
public static void uploadTimeoutReminder(String userName, String time) { public static void uploadTimeoutReminder(String userName, String time) {
String xp = "xupei3360@163.com"; String xp = "xupei3360@163.com";
String shb = "shahaibodd99@gmail.com";
String wxd = "X1627315083@163.com"; String wxd = "X1627315083@163.com";
String pkc = "kaicpang.pang@connect.polyu.hk"; String pkc = "kaicpang.pang@connect.polyu.hk";
try { try {
@@ -711,7 +630,7 @@ public class SendEmailUtil {
// 实例化一个请求对象,每个接口都会对应一个request对象 // 实例化一个请求对象,每个接口都会对应一个request对象
SendEmailRequest req = new SendEmailRequest(); SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(SEND_ADDRESS); req.setFromEmailAddress(SEND_ADDRESS);
req.setDestination(new String[]{xp, wxd, pkc}); req.setDestination(new String[]{shb, xp, wxd, pkc});
Template template = new Template(); Template template = new Template();
req.setSubject("上传图片超时提醒"); req.setSubject("上传图片超时提醒");
template.setTemplateID(UPLOAD_TIMEOUT_REMINDER); template.setTemplateID(UPLOAD_TIMEOUT_REMINDER);
@@ -731,7 +650,7 @@ public class SendEmailUtil {
} }
} }
private final static Long HALFPRICEPROMOTION_CN_ID = 128582L; /*private final static Long HALFPRICEPROMOTION_CN_ID = 128582L;
private final static Long HALFPRICEPROMOTION_EN_ID = 128583L; private final static Long HALFPRICEPROMOTION_EN_ID = 128583L;
public static void halfPricePromotion(Account account, String senderAddress, int type) { public static void halfPricePromotion(Account account, String senderAddress, int type) {
@@ -820,18 +739,15 @@ public class SendEmailUtil {
log.info("邮件发送失败###{}", e.toString()); log.info("邮件发送失败###{}", e.toString());
throw new BusinessException("failed.to.send.mail"); throw new BusinessException("failed.to.send.mail");
} }
} }*/
private final static Long CANCEL_MERCHANT_EN = 130720L; private final static Long CANCEL_MERCHANT_EN = 130720L;
// private final static Long NEW_MERCHANT_EN = 130721L; // private final static Long NEW_MERCHANT_EN = 130721L;
// private final static Long NEW_USER_EN = 130722L; // private final static Long NEW_USER_EN = 130722L;
// private final static Long NEW_USER_CN = 130723L; // private final static Long NEW_USER_CN = 130723L;
private final static Long NEW_MERCHANT_EN = 140335L; private final static Long NEW_MERCHANT_EN = 135190L;
// private final static Long NEW_MERCHANT_EN = 135190L; private final static Long NEW_USER_EN = 135189L;
// private final static Long NEW_USER_EN = 135189L; private final static Long NEW_USER_CN = 135186L;
// private final static Long NEW_USER_CN = 135186L;
private final static Long NEW_USER_EN = 140316L;
private final static Long NEW_USER_CN = 140317L;
private final static Long RENEWAL_MERCHANT_EN = 130724L; private final static Long RENEWAL_MERCHANT_EN = 130724L;
private final static Long RENEWAL_USER_EN = 130725L; private final static Long RENEWAL_USER_EN = 130725L;
private final static Long RENEWAL_USER_CN = 130726L; private final static Long RENEWAL_USER_CN = 130726L;
@@ -846,7 +762,7 @@ public class SendEmailUtil {
try { try {
String merchantEmail = "kimwong@code-create.com.hk"; String merchantEmail = "kimwong@code-create.com.hk";
String developer = "xupei3360@163.com"; String developer = "xupei3360@163.com";
String[] receiverEmail = {merchantEmail, developer}; String[] receiverEmail = {/*merchantEmail,*/ developer};
Credential cred = new Credential(SECRET_ID, SECRET_KEy); Credential cred = new Credential(SECRET_ID, SECRET_KEy);
// 实例化一个http选项可选的没有特殊需求可以跳过 // 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile(); HttpProfile httpProfile = new HttpProfile();
@@ -1016,7 +932,7 @@ public class SendEmailUtil {
req.setFromEmailAddress(SEND_ADDRESS); req.setFromEmailAddress(SEND_ADDRESS);
String merchantEmail = "kimwong@code-create.com.hk"; String merchantEmail = "kimwong@code-create.com.hk";
String developerEmail = "xupei@code-create.com.hk"; String developerEmail = "xupei@code-create.com.hk";
req.setDestination(new String[]{merchantEmail, developerEmail}); req.setDestination(new String[]{/*merchantEmail,*/ developerEmail});
Template template = new Template(); Template template = new Template();
req.setSubject("New Credit Purchase Order"); req.setSubject("New Credit Purchase Order");
template.setTemplateID(CREDITS_PURCHASE_MERCHANT); template.setTemplateID(CREDITS_PURCHASE_MERCHANT);
@@ -1076,4 +992,52 @@ public class SendEmailUtil {
} }
} }
private final static Long CN_2025_618 = 141425L;
private final static Long EN_2025_618 = 141424L;
public static void send618PromotionEmailTemp(String receiver, String language){
try {
// 实例化一个认证对象
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ses.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(CODE_CREATE_SEND_ADDRESS);
req.setDestination(new String[]{receiver});
// 根据邮件类型设置不同的主题和模板
String subject = "";
Template template = new Template();
// if (type == 1) {
// subject = "Upcoming System Upgrade for AiDA 3.0";
// template.setTemplateID(UPGRADE_NOTIFICATION_ID);
// }else {
// subject = "即将到来的AiDA 3.0系统升级";
// template.setTemplateID(UPGRADE_NOTIFICATION_ID_CHINESE);
// }
if (language.equals("ENGLISH")) {
subject = "Welcome back Subscribe AiDA with the discount code to enjoy 50% OFF!";
template.setTemplateID(EN_2025_618);
}else {
subject = "设计时速狂飙AiDA 618半价让灵感永不限流";
template.setTemplateID(CN_2025_618);
}
req.setSubject(subject);
req.setTemplate(template);
// 发送邮件
SendEmailResponse resp = client.SendEmail(req);
log.info("邮件发送成功,收件人地址:{}", receiver);
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
log.info(receiver);
log.error("邮件发送失败###{},收件人地址:{}", e.toString(), receiver);
}
}
} }

View File

@@ -0,0 +1,153 @@
package com.ai.da.common.utils;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
@Slf4j
@Component
public class SendRequestUtil {
@Value("${ALIYUN_API_KEY}")
private String ALIYUN_API_KEY;
@Value("${FREEPIK_API_KEY}")
private String FREEPIK_API_KEY;
public String sendAliYunPostAsync(String apiUrl, String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(apiUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.header("X-DashScope-Async", "enable")
.header(Header.CONTENT_TYPE, "application/json")
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
String body = execute.body();
JSONObject bodyJson = JSONUtil.parseObj(body);
return body;
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public String sendAliYunPost(String apiUrl, String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(apiUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.header(Header.CONTENT_TYPE, "application/json")
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
String body = execute.body();
JSONObject bodyJson = JSONUtil.parseObj(body);
return body;
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public static final String FREE_PIK = "https://api.freepik.com/v1/ai/beta/text-to-image/reimagine-flux";
public String sendFreepikPost( String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(FREE_PIK)
.header(Header.CONTENT_TYPE, "application/json")
.header("x-freepik-api-key", FREEPIK_API_KEY)
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
return execute.body();
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public String sendAliYunGet(String fullUrl){
// 发送GET请求 todo 异常处理
HttpResponse httpResponse = HttpRequest.get(fullUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = httpResponse.getStatus();
if (status == 200){
return httpResponse.body();
}else {
return null;
}
}
public String sendFluxPost(String url, String requestBodyStr){
int status;
String body;
try (HttpResponse execute = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, "application/json")
.header("x-key", "d447a0ac-2291-4f1c-9a36-f7614c385989")
.body(requestBodyStr) // Hutool 会自动处理 JSON 序列化
.timeout(180000) // 设置超时(毫秒)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public String sendPost(String url, String requestBodyStr){
int status;
String body;
try (HttpResponse execute = HttpRequest.post(url)
.header("Content-Type", "application/json") // 必须设置 Content-Type
.body(requestBodyStr) // Hutool 会自动处理 JSON 序列化
.timeout(180000) // 设置超时(毫秒)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
}
log.warn("请求失败,状态码为 {}, body: {}", status, body);
return null;
}
public String sendGet(String url, Map<String, Object> params) {
int status;
String body;
try (HttpResponse execute = HttpRequest.get(url)
.form(params) // 直接传入MapHutool会正确处理
.timeout(180000)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
} catch (Exception e) {
log.error("请求发生异常: {}", e.getMessage(), e);
return null;
}
log.warn("请求失败,状态码为: {}, body: {}", status, body);
return body;
}
}

View File

@@ -22,10 +22,12 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
@Api(tags = "Account模块") @Api(tags = "Account模块")
@@ -171,29 +173,30 @@ public class AccountController {
@CrossOrigin @CrossOrigin
@ApiOperation(value = "广场用户注册") @ApiOperation(value = "广场用户注册")
@PostMapping("/designWorksRegisterCode") @PostMapping("/designWorksRegisterCode")
public Response<AccountLoginVO> designWorksRegisterCode(@Valid @RequestBody AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO) { public Response<AccountLoginVO> designWorksRegisterCode(@Valid @RequestBody AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO,
return Response.success(accountService.designWorksRegisterCode(accountDesignWorksRegisterDTO)); HttpServletRequest request) {
return Response.success(accountService.designWorksRegisterCode(accountDesignWorksRegisterDTO, request));
} }
/** /**
* 填写调查问卷 * 填写调查问卷
* @return * @return
*/ */
@ApiOperation(value = "填写调查问卷") /* @ApiOperation(value = "填写调查问卷")
@PostMapping("/questionnaire") @PostMapping("/questionnaire")
public Response<Boolean> questionnaire(@Valid @RequestBody String questionnaireInfo){ public Response<Boolean> questionnaire(@Valid @RequestBody String questionnaireInfo){
return Response.success(accountService.collectQuestionnaires(questionnaireInfo)); return Response.success(accountService.collectQuestionnaires(questionnaireInfo));
} }*/
/** /**
* 参与活动 获取福利 * 参与活动 获取福利
* @return * @return
*/ */
@ApiOperation(value = "参与活动 获取福利") /* @ApiOperation(value = "参与活动 获取福利")
@GetMapping("/activity") @GetMapping("/activity")
public Response<String> getActivityBenefits(){ public Response<String> getActivityBenefits(){
return Response.success(accountService.getActivityBenefits()); return Response.success(accountService.getActivityBenefits());
} }*/
@ApiOperation(value = "将用户账号过期时间设置为过期当天的235959") @ApiOperation(value = "将用户账号过期时间设置为过期当天的235959")
@GetMapping("/setUserValidToDayEnd") @GetMapping("/setUserValidToDayEnd")
@@ -273,16 +276,22 @@ public class AccountController {
@PostMapping("enterpriseLogin") @PostMapping("enterpriseLogin")
@ApiOperation(value = "企业登录") @ApiOperation(value = "企业登录")
public Response<AccountLoginVO> enterpriseLogin(@Valid @RequestBody AccountLoginDTO accountDTO) { public Response<AccountPreLoginVO> enterpriseLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
return Response.success(accountService.enterpriseLogin(accountDTO)); return Response.success(accountService.enterpriseLogin(accountDTO));
} }
@PostMapping("schoolLogin") @PostMapping("schoolLogin")
@ApiOperation(value = "学校登录") @ApiOperation(value = "学校登录")
public Response<AccountLoginVO> schoolLogin(@Valid @RequestBody AccountLoginDTO accountDTO) { public Response<AccountPreLoginVO> schoolLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
return Response.success(accountService.schoolLogin(accountDTO)); return Response.success(accountService.schoolLogin(accountDTO));
} }
@PostMapping("organizationNameSearch")
@ApiOperation(value = "组织名模糊查询")
public Response<Set<String>> organizationNameSearch(@RequestParam("type") String type, @RequestParam("name") String name) {
return Response.success(accountService.organizationNameSearch(type, name));
}
@PostMapping("addOrUpdateSubAccount") @PostMapping("addOrUpdateSubAccount")
@ApiOperation(value = "子账号新增") @ApiOperation(value = "子账号新增")
public Response<Boolean> addSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) { public Response<Boolean> addSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) {
@@ -292,7 +301,9 @@ public class AccountController {
@PostMapping("deleteSubAccount") @PostMapping("deleteSubAccount")
@ApiOperation(value = "子账号删除") @ApiOperation(value = "子账号删除")
public Response<Boolean> deleteSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) { public Response<Boolean> deleteSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) {
return Response.success(accountService.deleteSubAccount(addSubAccountDTO)); // return Response.success(accountService.deleteSubAccount(addSubAccountDTO));
accountService.removeSubAccount(addSubAccountDTO);
return Response.success();
} }
@PostMapping("subAccountList") @PostMapping("subAccountList")
@@ -348,4 +359,37 @@ public class AccountController {
public Response<Boolean> updateUserInfo(@Valid @RequestBody UpdateUserInfoDTO updateUserInfoDTO) { public Response<Boolean> updateUserInfo(@Valid @RequestBody UpdateUserInfoDTO updateUserInfoDTO) {
return Response.success(accountService.updateUserInfo(updateUserInfoDTO)); return Response.success(accountService.updateUserInfo(updateUserInfoDTO));
} }
@GetMapping("/subAccountImportExcelDownload")
@ApiOperation(value = "模板下载")
public void subAccountImportExcelDownload(HttpServletResponse response) {
accountService.subAccountImportExcelDownload(response);
}
@GetMapping("/exportAccountsToExcel")
@ApiOperation(value = "下载子账号信息")
public void exportAccountsToExcel(HttpServletResponse response) {
accountService.exportAccountsToExcel(response);
}
@PostMapping("/subAccountImport")
@ApiOperation(value = "模板导入")
public Response<Boolean> subAccountImport(@RequestParam("file") MultipartFile file) {
return Response.success(accountService.subAccountImport(file));
}
/*@GetMapping("/send618Email")
@ApiOperation(value = "618邮件发送")
public Response<String> send618PromotionEmailTemp() {
accountService.send618PromotionEmailTemp();
return Response.success("success");
}*/
@GetMapping("/refreshCreditsMonthly")
@ApiOperation(value = "刷新子账号积分")
public void refreshCreditsMonthly() {
accountService.refreshCreditsMonthly();
}
} }

View File

@@ -4,17 +4,24 @@ package com.ai.da.controller;
import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.model.dto.AffiliateQueryDTO; import com.ai.da.model.dto.AffiliateQueryDTO;
import com.ai.da.model.dto.EditReferralDTO;
import com.ai.da.model.dto.ReferralPageQueryDTO;
import com.ai.da.model.vo.AffiliateInvitationDetailsVO; import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
import com.ai.da.model.vo.AffiliateVO; import com.ai.da.model.vo.AffiliateVO;
import com.ai.da.model.vo.ReferralPageQueryVO;
import com.ai.da.service.AffiliateService; import com.ai.da.service.AffiliateService;
import com.ai.da.service.ReferralService;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@RestController @RestController
@@ -25,6 +32,9 @@ public class AffiliateController {
@Resource @Resource
private AffiliateService affiliateService; private AffiliateService affiliateService;
@Resource
private ReferralService referralService;
@ApiOperation(value = "注册成为affiliate") @ApiOperation(value = "注册成为affiliate")
@GetMapping("/registration") @GetMapping("/registration")
public Response<Boolean> completeGuidance(@RequestParam(value = "promotionMethod", required = false) String promotionMethod) { public Response<Boolean> completeGuidance(@RequestParam(value = "promotionMethod", required = false) String promotionMethod) {
@@ -33,7 +43,7 @@ public class AffiliateController {
@ApiOperation(value = "获取affiliate列表") @ApiOperation(value = "获取affiliate列表")
@PostMapping("/list") @PostMapping("/list")
public Response<PageBaseResponse<AffiliateVO>> getAffiliateList(@Valid @RequestBody AffiliateQueryDTO affiliateQueryDTO) { public Response<PageBaseResponse<AffiliateVO>> getAffiliateList(@Validated @RequestBody AffiliateQueryDTO affiliateQueryDTO) {
return Response.success(affiliateService.getAffiliateList(affiliateQueryDTO)); return Response.success(affiliateService.getAffiliateList(affiliateQueryDTO));
} }
@@ -45,7 +55,7 @@ public class AffiliateController {
@ApiOperation(value = "获取个人佣金图表数据") @ApiOperation(value = "获取个人佣金图表数据")
@GetMapping("/getPersonalMonthlyIncome") @GetMapping("/getPersonalMonthlyIncome")
public Response<double[]> getPersonalMonthlyIncome(@RequestParam("year")int year) { public Response<BigDecimal[]> getPersonalMonthlyIncome(@RequestParam("year")int year) {
return Response.success(affiliateService.getPersonalMonthlyIncome(year)); return Response.success(affiliateService.getPersonalMonthlyIncome(year));
} }
@@ -53,7 +63,7 @@ public class AffiliateController {
@GetMapping("/approval") @GetMapping("/approval")
public Response<Boolean> applicationApproval(@RequestParam("id") Long id, public Response<Boolean> applicationApproval(@RequestParam("id") Long id,
@RequestParam("isApproved")Boolean isApproved, @RequestParam("isApproved")Boolean isApproved,
@RequestParam("commission") Float commission) { @RequestParam(value = "commission", required = false) Float commission) {
return Response.success(affiliateService.applicationApproval(id, isApproved, commission)); return Response.success(affiliateService.applicationApproval(id, isApproved, commission));
} }
@@ -86,9 +96,35 @@ public class AffiliateController {
@ApiOperation(value = "获取每个affiliate产生的收入") @ApiOperation(value = "获取每个affiliate产生的收入")
@PostMapping("/getEachAffiliateGeneratedRevenue") @PostMapping("/getEachAffiliateGeneratedRevenue")
public Response<IPage<AffiliateInvitationDetailsVO>> getEachAffiliateGeneratedRevenue(@RequestBody AffiliateQueryDTO affiliateQueryDTO) { public Response<IPage<AffiliateInvitationDetailsVO>> getEachAffiliateGeneratedRevenue(@Validated @RequestBody AffiliateQueryDTO affiliateQueryDTO) {
return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(affiliateQueryDTO)); return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(affiliateQueryDTO));
} }
@ApiOperation(value = "分页获取所有的referral")
@PostMapping("/getReferrals")
public Response<IPage<ReferralPageQueryVO>> getReferrals(@RequestBody ReferralPageQueryDTO referralPageQueryDTO) {
return Response.success(referralService.queryByPage(referralPageQueryDTO));
}
@ApiOperation(value = "编辑单个referral")
@PostMapping("/editReferral")
public Response<String> editReferral(@Validated @RequestBody EditReferralDTO editReferralDTO) {
referralService.editReferral(editReferralDTO);
return Response.success();
}
@ApiOperation(value = "批量删除referral")
@PostMapping("/batchDeleteReferral")
public Response<String> batchDeleteReferral(@RequestBody List<Long> idList) {
referralService.deleteReferral(idList);
return Response.success();
}
@ApiOperation(value = "获取所有affiliate用户名")
@GetMapping("/getAllAffiliateUsername")
public Response<List<Map<String, Object>>> getAllAffiliateUsername() {
return Response.success(affiliateService.getAllAffiliateUsername());
}
} }

View File

@@ -6,10 +6,9 @@ import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.DesignMapper; import com.ai.da.mapper.primary.DesignMapper;
import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.Organization;
import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.AccountAddDTO; import com.ai.da.model.dto.*;
import com.ai.da.model.dto.QueryPaymentInfoDTO;
import com.ai.da.model.dto.UserDesignStatisticDTO;
import com.ai.da.model.vo.PaymentInfoVO; import com.ai.da.model.vo.PaymentInfoVO;
import com.ai.da.model.vo.QuestionnaireFeedbackVO; import com.ai.da.model.vo.QuestionnaireFeedbackVO;
import com.ai.da.model.vo.QuestionnaireVO; import com.ai.da.model.vo.QuestionnaireVO;
@@ -17,7 +16,6 @@ import com.ai.da.model.vo.QueryUserConditionsVO;
import com.ai.da.service.AccountService; import com.ai.da.service.AccountService;
import com.ai.da.service.ConvenientInquiryService; import com.ai.da.service.ConvenientInquiryService;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import io.netty.util.internal.StringUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
@@ -51,9 +49,7 @@ public class ConvenientInquiryController {
String userEmail = accountService.getById(accountId).getUserEmail(); String userEmail = accountService.getById(accountId).getUserEmail();
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|| userEmail.equals("joho8228@hotmail.com") || userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com")
|| userEmail.equals("chelseayu@code-create.com.hk")
|| userEmail.equals("cheungzt007@gmail.com")
) { ) {
return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO)); return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO));
} else { } else {
@@ -65,28 +61,7 @@ public class ConvenientInquiryController {
@GetMapping("/getDesignStatistic") @GetMapping("/getDesignStatistic")
public Response<List<UserDesignStatisticDTO>> getDesignStatistic(@RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, public Response<List<UserDesignStatisticDTO>> getDesignStatistic(@RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime,
@RequestParam(required = false) List<Long> ids, @RequestParam(required = false) String email) { @RequestParam(required = false) List<Long> ids, @RequestParam(required = false) String email) {
Long accountId = UserContext.getUserHolder().getId(); return Response.success(convenientInquiryService.getDesignStatistic(startTime, endTime, ids, email));
String userEmail = accountService.getById(accountId).getUserEmail();
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|| userEmail.equals("joho8228@hotmail.com")
|| userEmail.equals("chelseayu@code-create.com.hk")
|| userEmail.equals("cheungzt007@gmail.com")
) {
if (StringUtil.isNullOrEmpty(startTime)) startTime = "2024-02-01 00:00:00";
if (StringUtil.isNullOrEmpty(endTime)) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = new Date();
endTime = simpleDateFormat.format(date);
}
if (!StringUtil.isNullOrEmpty(email)){
email = email.trim();
}
List<UserDesignStatisticDTO> designStatistic = designMapper.getDesignStatistic(startTime, endTime, ids, email);
return Response.success(designStatistic);
} else {
return Response.fail("Sorry, you don't have permission");
}
} }
@@ -188,9 +163,7 @@ public class ConvenientInquiryController {
String userEmail = accountService.getById(accountId).getUserEmail(); String userEmail = accountService.getById(accountId).getUserEmail();
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|| userEmail.equals("joho8228@hotmail.com") || userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com")
|| userEmail.equals("chelseayu@code-create.com.hk")
|| userEmail.equals("cheungzt007@gmail.com")
) { ) {
return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO)); return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO));
} else { } else {
@@ -221,4 +194,30 @@ public class ConvenientInquiryController {
public Response<String> exportTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO, HttpServletResponse response){ public Response<String> exportTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO, HttpServletResponse response){
return Response.success(convenientInquiryService.exportTransactionRecords(queryPaymentInfoDTO, response)); return Response.success(convenientInquiryService.exportTransactionRecords(queryPaymentInfoDTO, response));
} }
@ApiOperation("获取生成功能使用频次")
@PostMapping("/getGenerateFrequency")
public Response<PageBaseResponse<AccountCreditsUsageDTO>> getGenerateFrequency(@Valid @RequestBody AccountCreditsUsageQueryDTO queryDTO){
return Response.success(convenientInquiryService.getGenerateFrequency(queryDTO));
}
@ApiOperation("获取所有生成功能的名字")
@GetMapping("/getAllGenerateFuncName")
public Response<List<String>> getAllGenerateFuncName(){
return Response.success(convenientInquiryService.getAllGenerateFuncName());
}
@ApiOperation("添加组织机构")
@GetMapping("/addOrganization")
public Response<String> addOrganization(@ApiParam(value = "机构名") @RequestParam String name, @ApiParam(value = "Enterprise || Education") @RequestParam String type){
convenientInquiryService.addOrganization(name, type);
return Response.success();
}
@ApiOperation("查询所有企业或教育机构")
@GetMapping("/queryOrganization")
public Response<List<Organization>> queryOrganization(@ApiParam(value = "Enterprise || Education") @RequestParam String type){
return Response.success(convenientInquiryService.queryOrganization(type));
}
} }

View File

@@ -1,12 +1,14 @@
package com.ai.da.controller; package com.ai.da.controller;
import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.CloudTask;
import com.ai.da.mapper.primary.entity.CollectionSort;
import com.ai.da.model.dto.*; import com.ai.da.model.dto.*;
import com.ai.da.model.vo.CollectionSketchVO; import com.ai.da.model.vo.*;
import com.ai.da.model.vo.DesignCollectionVO;
import com.ai.da.model.vo.DesignLikeVO;
import com.ai.da.service.DesignService; import com.ai.da.service.DesignService;
import com.ai.da.service.UserLikeGroupService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
@@ -27,6 +29,8 @@ import java.util.List;
public class DesignController { public class DesignController {
@Resource @Resource
private DesignService designService; private DesignService designService;
@Resource
private UserLikeGroupService userLikeGroupService;
@ApiOperation(value = "设计 Conllection") @ApiOperation(value = "设计 Conllection")
@PostMapping("/designCollection") @PostMapping("/designCollection")
@@ -73,7 +77,7 @@ public class DesignController {
@ApiOperation(value = "Design sort") @ApiOperation(value = "Design sort")
@PostMapping("/sort") @PostMapping("/sort")
public Response<Boolean> sort(@Valid @RequestBody UserLikeSortDTO userLikeSortDTO) { public Response<Boolean> sort(@Valid @RequestBody CollectionSortDTO userLikeSortDTO) {
return Response.success(designService.sort(userLikeSortDTO)); return Response.success(designService.sort(userLikeSortDTO));
} }
@@ -97,8 +101,31 @@ public class DesignController {
@ApiOperation(value = "云生成") @ApiOperation(value = "云生成")
@PostMapping("/designCloud") @PostMapping("/designCloud")
@CrossOrigin public Response<String> designCloud(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
public Response<String> designCloud(@Valid @RequestBody DesignCollectionDTO designDTO) { return Response.success(designService.designCloud(cloudTaskDTO));
return Response.success(designService.designCloud(designDTO)); }
@ApiOperation(value = "云生成修改任务名")
@PostMapping("/cloudTaskNameUpdate")
public Response<Boolean> cloudTaskNameUpdate(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
return Response.success(designService.cloudTaskNameUpdate(cloudTaskDTO));
}
@ApiOperation(value = "云生成删除任务")
@PostMapping("/cloudTaskDelete")
public Response<Boolean> cloudTaskDelete(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
return Response.success(designService.cloudTaskDelete(cloudTaskDTO));
}
@ApiOperation(value = "云生成page")
@PostMapping("/cloudPage")
public Response<PageBaseResponse<CloudTaskVO>> cloudPage(@Valid @RequestBody CloudPageDTO cloudPageDTO) {
return Response.success(PageBaseResponse.success(designService.cloudPage(cloudPageDTO)));
}
@ApiOperation(value = "获取design云生成结果")
@PostMapping("/getDesignCloudResult")
public Response<CloudTaskResultVO> getDesignCloudResult(@Valid @RequestBody DesignCloudResultQuery designCloudResultQuery) {
return Response.success(designService.getDesignCloudResult(designCloudResultQuery));
} }
} }

View File

@@ -18,7 +18,10 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "collection模块") @Api(tags = "collection模块")
@@ -50,13 +53,15 @@ public class ElementController {
@ApiParam("一级类型 Moodboard Printboard Sketchboard MarketingSketch Colorboard") @ApiParam("一级类型 Moodboard Printboard Sketchboard MarketingSketch Colorboard")
@RequestParam(value = "level1Type") String level1Type, @RequestParam(value = "level1Type") String level1Type,
@RequestParam(name = "gender", required = false) String gender, @RequestParam(name = "gender", required = false) String gender,
@RequestParam(name = "level2Type", required = false) String level2Type,
@RequestParam(name = "projectId", required = false) Long projectId,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") @ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone) { @RequestParam(value = "timeZone") String timeZone) {
if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) { if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
throw new BusinessException("file.cannot.be.empty"); throw new BusinessException("file.cannot.be.empty");
} }
return Response.success(collectionElementService.upload( return Response.success(collectionElementService.upload(
new CollectionElementUploadDTO(file, level1Type, gender, timeZone, MD5Utils.encryptFile(file)))); new CollectionElementUploadDTO(file, projectId, level1Type, level2Type, gender, timeZone, MD5Utils.encryptFile(file))));
} }
@ApiOperation(value = "element文件删除") @ApiOperation(value = "element文件删除")
@@ -106,4 +111,33 @@ public class ElementController {
return Response.success(); return Response.success();
} }
@ApiOperation(value = "图片分割")
@PostMapping("/imageSegmentation")
public Response<List<CollectionElementVO>> selectedImageSeg(
@RequestPart(value = "file", required = false) MultipartFile[] file,
@RequestParam(value = "type", required = false) @Pattern(regexp = "sketch|product", message = "Please choose the image type") String type,
@RequestParam(value = "id", required = false) Long id,
@RequestParam(value = "sourceType", required = false) @Pattern(regexp = "Library|Upload", message = "Select an image from the library or upload one.") String sourceType) {
// 过滤空文件
List<MultipartFile> nonEmptyFiles = Arrays.stream(file)
.filter(item -> !item.isEmpty())
.collect(Collectors.toList());
// 参数校验
if ((nonEmptyFiles.isEmpty()) && id == null) {
throw new BusinessException("必须提供文件上传或ID");
}
if (!nonEmptyFiles.isEmpty() && id != null) {
throw new BusinessException("不能同时提供文件上传和ID");
}
return Response.success(collectionElementService.selectedImageSeg(nonEmptyFiles, id, type, sourceType));
}
@ApiOperation(value = "更新element level2type")
@GetMapping("/updateElementLevel2Type")
public Response<String> updateLibraryLevel2Type(@RequestParam(value = "elementId") Long elementId, @RequestParam(value = "level2Type") String level2Type) {
collectionElementService.updateElementLevel2Type(elementId, level2Type);
return Response.success("success");
}
} }

View File

@@ -0,0 +1,42 @@
package com.ai.da.controller;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.context.Context;
import javax.annotation.Resource;
import java.util.Collections;
@Api(tags = "邮件模块")
@Slf4j
@RestController
@RequestMapping("/api/email")
public class EmailController {
@Resource
private EmailService emailService;
@GetMapping("/loadSingleTemplate")
public void loadSingleEmailTemplate(){
emailService.loadSingleEmailTemplate("templates\\upgrade\\122899_AiDA发版完成通知中文版.html");
}
@GetMapping("/loadTemplate")
public void loadTemplatesFromResources(){
emailService.loadTemplatesFromResources("templates");
}
@GetMapping("/sendEmailTest")
public void sendEmailTest(){
Context context = new Context();
context.setVariable("username", "小白");
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "小白");
emailService.sendEmail(Collections.singletonList("xupei3360@163.com"), jsonObject, "132124_affiliate_accepted_en.html", "测试邮件", null, null );
}
}

View File

@@ -1,21 +1,23 @@
package com.ai.da.controller; package com.ai.da.controller;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.model.dto.GenerateLikeDTO; import com.ai.da.mapper.primary.entity.CollectionSort;
import com.ai.da.model.dto.GenerateModifyDTO; import com.ai.da.model.dto.*;
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.dto.ImageToSketchDTO;
import com.ai.da.model.vo.*; import com.ai.da.model.vo.*;
import com.ai.da.service.GenerateService; import com.ai.da.service.GenerateService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author XP * @author XP
@@ -57,8 +59,14 @@ public class GenerateController {
@ApiOperation(value = "发起生成请求,异步获取结果") @ApiOperation(value = "发起生成请求,异步获取结果")
@PostMapping("/prepare") @PostMapping("/prepare")
public Response<PrepareForGenerateVO> prepareForGenerate(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) { public ResponseEntity<Response<PrepareForGenerateVO>> prepareForGenerate(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) {
return Response.success(generateService.prepareForGenerate(generateThroughImageTextDTO)); PrepareForGenerateVO prepareForGenerateVO = generateService.prepareForGenerate(generateThroughImageTextDTO);
if (prepareForGenerateVO.getStatus().equals(200)){
prepareForGenerateVO.setStatus(0);
return ResponseEntity.ok(Response.success(prepareForGenerateVO));
} else {
return ResponseEntity.status(prepareForGenerateVO.getStatus()).body(Response.fail("The rate limit has been exceeded. Please wait 1 minute before retrying."));
}
} }
@ApiOperation(value = "取消继续生成") @ApiOperation(value = "取消继续生成")
@@ -87,8 +95,9 @@ public class GenerateController {
@ApiOperation(value = "imageToSketch") @ApiOperation(value = "imageToSketch")
@PostMapping("/imageToSketch") @PostMapping("/imageToSketch")
public Response<GenerateResultVO> imageToSketch(@Valid @RequestBody ImageToSketchDTO imageToSketchDTO) { public Response<String> imageToSketch(@Valid @RequestBody ImageToSketchDTO imageToSketchDTO) {
return Response.success(generateService.imageToSketch(imageToSketchDTO)); return Response.success(generateService.imageToSketchAsync(imageToSketchDTO, null, null));
// return Response.success(generateService.imageToSketch(imageToSketchDTO, null, null));
} }
// modifySketch // modifySketch
@@ -98,4 +107,134 @@ public class GenerateController {
return Response.success(generateService.modifySketch(generateModifyDTO)); return Response.success(generateService.modifySketch(generateModifyDTO));
} }
@ApiOperation(value = "请求进行姿势变换")
@PostMapping("/poseTransform")
public Response<ToProductImageResultVO> poseTransform(@Valid @RequestBody PoseTransformDTO poseTransformDTO) {
return Response.success(generateService.poseTransform(poseTransformDTO));
}
@ApiOperation(value = "获取姿势变换生成结果")
@PostMapping("/poseTransformResult")
public Response<List<PoseTransformationVO>> getPoseTransformationResults(@Valid @RequestBody List<String> taskIdList) {
List<PoseTransformationVO> generateResult = generateService.getPoseTransformationResult(taskIdList, null, null);
return Response.success(generateResult);
}
@ApiOperation("喜欢或取消喜欢姿势变换生成的图片")
@PostMapping("/likeOrDislike")
public Response<CollectionSort> likeOrDislike(@ApiParam("id") @RequestParam Long transformedId, @ApiParam("like || dislike") @RequestParam String likeOrDislike, @RequestParam("projectId") Long projectId, @RequestParam(value = "collectionSortParentId", required = false) Long collectionSortParentId) {
return Response.success(generateService.disOrLikePose(transformedId, likeOrDislike, projectId, collectionSortParentId));
}
@ApiOperation(value = "修改模特比例")
@PostMapping("/modifyProportion")
public Response<String> modifyModelProportion(@Valid @RequestBody ModifyModelProportionDTO proportionDTO){
String path = generateService.modifyModelProportion(proportionDTO);
return Response.success(path);
}
@ApiOperation(value = "拼贴图生成线稿")
@PostMapping("/genSketchRecon")
public Response<GenerateResultVO> sketchReconstructionGenerate(@Valid @RequestBody SketchReconstructionDTO sketchReconstructionDTO){
GenerateResultVO generateResultVO = generateService.sketchReconstructionGenerate(sketchReconstructionDTO);
return Response.success(generateResultVO);
}
@ApiOperation(value = "获取拼贴图最后一次生成结果")
@GetMapping("/getReconLastResult")
public Response<SketchReconstructionVO> getSketchReconstruction(@RequestParam("projectId") Long projectId){
SketchReconstructionVO sketchReconstruction = generateService.getSketchReconstruction(projectId);
return Response.success(sketchReconstruction);
}
@ApiOperation(value = "获取pose transfer的所有pose")
@GetMapping("/getAllPose")
public Response<List<Map<String, String>>> getAllPose(){
return Response.success(generateService.getAllPose());
}
@ApiOperation(value = "删除pose transfer的结果")
@GetMapping("/deleteResult")
public Response<String> deleteToProductRelightResult(@RequestParam("projectId") @NotNull Long projectId,
@RequestParam("id") @NotNull Long id){
try{
generateService.deleteGeneratedPose(projectId, id);
return Response.success();
}catch (Exception e){
return Response.fail(e.getMessage());
}
}
/*@ApiOperation(value = "万象 t2i 创建异步任务")
@GetMapping("/createAsyncTask")
public Response<String> createAsyncTask(@RequestParam("prompt") String prompt){
return Response.success(generateService.createAsyncTask(87L, prompt, ""));
}
@ApiOperation(value = "万象 t2i 获取异步任务结果")
@GetMapping("/waitAsyncTask")
public Response<GenerateResultVO> waitAsyncTask(@RequestParam("taskId") String taskId){
return Response.success(generateService.getAsyncTaskResult(taskId));
}
@ApiOperation(value = "万象 图生动图")
@GetMapping("/animateAnyone")
public Response<String> animateAnyone(@Valid @RequestBody PoseTransformDTO poseTransformDTO){
return Response.success(generateService.animateAnyone(poseTransformDTO, null));
}
@ApiOperation(value = "万象 获取动图模板id")
@GetMapping("/getVideoTemplateId")
public Response<String> getVideoTemplateId(@RequestParam("videoPath") String videoPath){
return Response.success(generateService.getVideoTemplateId(videoPath));
}
@ApiOperation(value = "万象 获取动图结果")
@GetMapping("/getAnimateResult")
public Response<PoseTransformationVO> getAnimateResult(@RequestParam("taskId") String taskId){
return Response.success(generateService.getAnimateResult(taskId));
}
@ApiOperation(value = "freepik toProductImage")
@GetMapping("/reimagineFreePik")
public Response<String> reimagineFreePik(@RequestParam("path") String path,
@RequestParam("prompt") String prompt,
@RequestParam("style") String style) throws IOException {
return Response.success(generateService.reimagineFreePik(path, prompt, style));
}
@ApiOperation(value = "获取图片描述")
@GetMapping("/getImageDescription")
public Response<String> getImageDescription(@RequestParam("path") String path) {
return Response.success(generateService.getImageDescription(path));
}*/
// @ApiOperation(value = "试用flux")
// @GetMapping("/flux")
public Response<String> flux(@RequestParam(value = "path", required = false) String path,
@RequestParam("type") int type,
@RequestParam(value = "prompt", required = false) String prompt){
CreditsEventsEnum typeEnum = CreditsEventsEnum.RELIGHT;
switch (type){
case 1:
typeEnum = CreditsEventsEnum.TO_PRODUCT_IMAGE;
break;
case 2:
typeEnum = CreditsEventsEnum.IMAGE_TO_SKETCH;
break;
case 3:
typeEnum = CreditsEventsEnum.PATTERN;
break;
}
return Response.success(generateService.flux(typeEnum, prompt, path, false));
}
// @ApiOperation(value = "获取flux结果")
// @GetMapping("/fluxResult")
public Response<String> fluxResult(@RequestParam("taskId") String taskId){
return Response.success(generateService.getFluxResult(taskId, "87/" + taskId + ".png"));
}
} }

View File

@@ -0,0 +1,99 @@
package com.ai.da.controller;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.AccountExtend;
import com.ai.da.mapper.primary.entity.ChatMessage;
import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.AccountLoginVO;
import com.ai.da.model.vo.AccountPreLoginVO;
import com.ai.da.model.vo.BindEmailVO;
import com.ai.da.model.vo.PersonalHomepageVO;
import com.ai.da.service.AccountService;
import com.ai.da.service.LLMService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Api(tags = "llm模块")
@Slf4j
@RestController
@RequestMapping("/api/llm")
public class LLMController {
@Resource
private LLMService llmService;
@ApiOperation(value = "对话")
@CrossOrigin
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamPrompt(@RequestParam String prompt,
@RequestParam(required = false) Long projectId,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList,
@RequestParam(required = false) String process,
@RequestParam String token,
@RequestParam Boolean enableThinking) {
return llmService.stream(prompt, projectId, fileUrl, imageUrlList, token, enableThinking, process);
}
@ApiOperation(value = "对话")
@CrossOrigin
@GetMapping(value = "/streamNew", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamNew(@RequestParam String prompt,
@RequestParam(required = false) Long projectId,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList,
@RequestParam(required = false) String process,
@RequestParam String token,
@RequestParam Boolean enableThinking) {
return llmService.streamNew(prompt, projectId, fileUrl, imageUrlList, token, enableThinking, process);
}
@ApiOperation(value = "对话创建项目")
@GetMapping(value = "/chatCreateProject")
public Response<Long> chatCreateProject(@RequestParam String prompt, @RequestParam String process,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList) {
return Response.success(llmService.chatCreateProject(prompt, process, fileUrl, imageUrlList));
}
@ApiOperation(value = "上传文件")
@PostMapping(value = "/uploadFile")
public Response<List<String>> uploadFile(@RequestParam("file") MultipartFile file) {
return Response.success(llmService.uploadFile(file));
}
@ApiOperation(value = "获取历史聊天记录")
@PostMapping(value = "/getChatHistory")
public Response<PageBaseResponse<ChatMessage>> getChatHistory(@RequestBody ChatHistoryDTO chatHistoryDTO) {
return Response.success(llmService.getChatHistory(chatHistoryDTO));
}
}

View File

@@ -20,6 +20,7 @@ import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@@ -27,9 +28,7 @@ import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.File; import java.io.File;
import java.text.ParseException; import java.text.ParseException;
import java.util.Date; import java.util.*;
import java.util.Objects;
import java.util.UUID;
@Api(tags = "library模块") @Api(tags = "library模块")
@@ -73,6 +72,7 @@ public class LibraryController {
@RequestParam(value = "timeZone") String timeZone, @RequestParam(value = "timeZone") String timeZone,
@RequestParam(value = "modelType") String modelType, @RequestParam(value = "modelType") String modelType,
@RequestParam(value = "sex") String sex, @RequestParam(value = "sex") String sex,
@RequestParam(value = "ageGroup") String ageGroup,
@RequestParam(value = "checkMd5") Integer checkMd5) { @RequestParam(value = "checkMd5") Integer checkMd5) {
if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) { if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
throw new BusinessException("file.cannot.be.empty"); throw new BusinessException("file.cannot.be.empty");
@@ -99,7 +99,7 @@ public class LibraryController {
} }
} }
return Response.success(libraryService.upload(new LibraryUploadDTO(file, level1Type, level2Type, return Response.success(libraryService.upload(new LibraryUploadDTO(file, level1Type, level2Type,
timeZone, md5, high, width, modelType, sex))); timeZone, md5, high, width, modelType, sex, ageGroup)));
} }
@ApiOperation(value = "保存或者编辑template打点") @ApiOperation(value = "保存或者编辑template打点")
@@ -169,7 +169,7 @@ public class LibraryController {
@ApiOperation(value = "更新sketchboard level2type") @ApiOperation(value = "更新sketchboard level2type")
@PostMapping("/updateLibraryLevel2Type") @PostMapping("/updateLibraryLevel2Type")
public Response<Boolean> updateLibraryLevel2Type(@RequestBody LibraryLevel2TypeUpdateDTO libraryLevel2TypeUpdateDTO) { public Response<Boolean> updateLibraryLevel2Type(@Validated @RequestBody LibraryLevel2TypeUpdateDTO libraryLevel2TypeUpdateDTO) {
return Response.success(libraryService.updateLibraryLevel2Type(libraryLevel2TypeUpdateDTO)); return Response.success(libraryService.updateLibraryLevel2Type(libraryLevel2TypeUpdateDTO));
} }
@@ -202,4 +202,45 @@ public class LibraryController {
return Response.success(true); return Response.success(true);
} }
@ApiOperation(value = "将系统模特添加到个人library")
@GetMapping("addSysModelToLib")
public Response<Map<String, String>> addSysModelToLib(@ApiParam("系统模特id") @RequestParam("sysModelId")long sysModelId){
return Response.success(libraryService.addSysModelToLib(sysModelId));
}
@ApiOperation(value = "将个人library元素添加到公共库")
@GetMapping("addToPublicLibrary")
public Response<String> addToPublicLibrary(@ApiParam("元素的libraryId") @RequestParam("libraryId") Long libraryId){
boolean b = libraryService.saveToOrganizationLibrary(libraryId);
if (b){
return Response.success("success");
}else {
return Response.success("fail");
}
}
@ApiOperation(value = "将个人library元素从公共库中删除")
@GetMapping("deleteFromPublicLib")
public Response<String> deleteFromPublicLib(@ApiParam("元素的libraryId") @RequestParam("libraryId") Long libraryId){
libraryService.deleteFromPublicLib(libraryId);
return Response.success("success");
}
@ApiOperation(value = "获取公共库")
@GetMapping("getPublicLib")
public Response<PageBaseResponse<Library>> getPublicLib(@ApiParam("排序" ) @RequestParam(value = "order", defaultValue = "DESC", required = false) String order,
@ApiParam("page") @RequestParam(value = "page", defaultValue = "1", required = false) Long page,
@ApiParam("size") @RequestParam(value = "size", defaultValue = "20", required = false) Long size){
return Response.success(libraryService.getPublicLib(order, page, size));
}
@ApiOperation(value = "管理员获取所有子账号lib元素")
@GetMapping("getAllSubAccLib")
public Response<PageBaseResponse<Library>> getAllSubAccLib(@ApiParam("排序") @RequestParam(value = "order", defaultValue = "DESC", required = false) String order,
@ApiParam("page") @RequestParam(value = "page", defaultValue = "1", required = false) Long page,
@ApiParam("size") @RequestParam(value = "size", defaultValue = "20", required = false) Long size){
return Response.success(libraryService.getAllSubAccLib(order, page, size));
}
} }

View File

@@ -31,7 +31,7 @@ public class PortfolioController {
@ApiOperation(value = "发布作品集") @ApiOperation(value = "发布作品集")
@PostMapping("/publish") @PostMapping("/publish")
public Response<Long> preLogin(@RequestParam("file") MultipartFile canvas, @RequestParam("data") String data) { public Response<Long> publish(@RequestParam("file") MultipartFile canvas, @RequestParam("data") String data) {
return Response.success(portfolioService.publish(canvas, data)); return Response.success(portfolioService.publish(canvas, data));
} }
@@ -57,7 +57,7 @@ public class PortfolioController {
@ApiOperation(value = "选择作品") @ApiOperation(value = "选择作品")
@PostMapping("/choose") @PostMapping("/choose")
public Response<UserLikeChooseVO> choose(@Valid @RequestBody PortfolioDTO portfolioDTO) { public Response<ProjectChooseVO> choose(@Valid @RequestBody PortfolioDTO portfolioDTO) {
return Response.success(portfolioService.choose(portfolioDTO)); return Response.success(portfolioService.choose(portfolioDTO));
} }
@@ -154,4 +154,11 @@ public class PortfolioController {
@RequestParam(value = "tagId", required = false) Long tagId) { @RequestParam(value = "tagId", required = false) Long tagId) {
return Response.success(portfolioService.queryPortfolioByTag(tagName, tagId)); return Response.success(portfolioService.queryPortfolioByTag(tagName, tagId));
}*/ }*/
@ApiOperation(value = "将企业或教育版中的作品发布到公共gallery")
@GetMapping("/toPublic")
public Response<String> setPortfolioToPublic(@RequestParam("portfolioId") Long portfolioId) {
portfolioService.setPortfolioToPublic(portfolioId);
return Response.success("success");
}
} }

View File

@@ -0,0 +1,153 @@
package com.ai.da.controller;
import com.ai.da.common.config.MyTaskScheduler;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.ai.da.service.ProjectService;
import com.ai.da.service.UserLikeGroupService;
import com.ai.da.service.WorkspaceService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.minio.errors.MinioException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
@Api(tags = "Project模块")
@Slf4j
@RestController
@RequestMapping("/api/project")
public class ProjectController {
@Resource
private WorkspaceService workspaceService;
@Resource
private UserLikeGroupService userLikeGroupService;
@Resource
private ProjectService projectService;
@PostMapping("/saveOrUpdate")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "新增或编辑", notes = "传入project")
public Response<SaveOrUpdateProjectVO> saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
}
@PostMapping("/page")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "分页查询", notes = "传入project")
public Response<PageBaseResponse<ProjectVO>> page(@Valid @RequestBody ProjectQueryDTO projectQueryDTO) {
return Response.success(PageBaseResponse.success(userLikeGroupService.getPage(projectQueryDTO)));
}
// @PostMapping("/detail")
// @ApiOperationSupport(order = 3)
// @ApiOperation(value = "详情", notes = "传入project")
// public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
// return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
// }
//
@PostMapping("/choose")
@ApiOperationSupport(order = 4)
@ApiOperation(value = "选择", notes = "传入project")
public Response<ProjectChooseVO> choose(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(userLikeGroupService.choose(projectDTO));
}
@PostMapping("/getModuleContent")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "获取模块内容", notes = "传入project")
public Response<ModuleChooseVO> getModuleContent(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(userLikeGroupService.getModuleContent(projectDTO));
}
@PostMapping("/saveModuleContent")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "存储模块内容", notes = "传入project")
public Response<ModuleChooseVO> saveModuleContent(@Valid @RequestBody ModuleSaveDTO moduleSaveDTO) {
return Response.success(userLikeGroupService.saveModuleContent(moduleSaveDTO));
}
//
// @PostMapping("/delete")
// @ApiOperationSupport(order = 5)
// @ApiOperation(value = "删除", notes = "传入project")
// public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
// return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
// }
@PostMapping("/getMannequinDetail")
@ApiOperationSupport(order = 7)
@ApiOperation(value = "获取模特详情", notes = "传入mannequinId")
public Response<QueryLibraryPageVO> getMannequinDetail(@Valid @RequestBody MannequinDTO mannequinDTO) {
return Response.success(userLikeGroupService.getMannequinDetail(mannequinDTO));
}
@PostMapping("/threeDPage")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "获取3Dpage", notes = "传入ThreeDLayoutQueryDTO")
public Response<PageBaseResponse<ThreeDLayoutVO>> threeDPage(@Valid @RequestBody ThreeDLayoutQueryDTO threeDLayoutQueryDTO) {
return Response.success(PageBaseResponse.success(userLikeGroupService.getThreeDLayoutPage(threeDLayoutQueryDTO)));
}
@PostMapping("/getLayoutDetail")
@ApiOperationSupport(order = 9)
@ApiOperation(value = "获取3D详情", notes = "传入project")
public Response<ThreeDVO> getLayoutDetail(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId) {
return Response.success(userLikeGroupService.getLayoutDetail(threeDSimpleId));
}
@PostMapping("/getThreeDSize")
@ApiOperationSupport(order = 10)
@ApiOperation(value = "获取尺码", notes = "传入project")
public Response<ThreeDSizeVO> getThreeDSize(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId) {
return Response.success(userLikeGroupService.getThreeDSize(threeDSimpleId));
}
@GetMapping("/getThreeDGlb")
@ApiOperationSupport(order = 11)
@ApiOperation(value = "获取GLB", notes = "传入project")
public void getThreeDGlb(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId, HttpServletResponse response) throws MinioException, IOException {
userLikeGroupService.getThreeDGlb(threeDSimpleId, response);
}
@GetMapping("/downloadZip")
@ApiOperationSupport(order = 11)
@ApiOperation(value = "下载", notes = "传入project")
public Response<String> downloadZip(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId, @RequestParam(value = "sizeType") String sizeType, @RequestParam(value = "size") String size, HttpServletResponse response) throws MinioException, IOException {
return Response.success(userLikeGroupService.downloadZip(threeDSimpleId, sizeType, size, response));
}
@PostMapping("/delete")
@ApiOperationSupport(order = 12)
@ApiOperation(value = "删除", notes = "传入project")
public Response<Boolean> delete(@RequestParam("projectId") Long projectId) {
return Response.success(userLikeGroupService.delete(projectId));
}
/*@Resource
private MyTaskScheduler myTaskScheduler;
@GetMapping("/dataMigration")
public String dataMigration(){
myTaskScheduler.projectDataCreate();
return "success";
}*/
@GetMapping("/getNextSequence")
public Response<Integer> getNextSequence(){
return Response.success(projectService.getOrCreateSequence());
}
}

View File

@@ -23,11 +23,14 @@ import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -35,6 +38,7 @@ import java.util.stream.Collectors;
@Api(tags = "History模块(saved Collection)") @Api(tags = "History模块(saved Collection)")
@Slf4j @Slf4j
@RestController @RestController
@Validated
@RequestMapping("/api/history") @RequestMapping("/api/history")
public class SavedCollectionController { public class SavedCollectionController {
@Resource @Resource
@@ -174,32 +178,46 @@ public class SavedCollectionController {
@ApiOperation(value = "exportSave") @ApiOperation(value = "exportSave")
@PostMapping("/exportSave") @PostMapping("/exportSave")
public Response<Boolean> exportSave(@RequestParam("file") MultipartFile file, @RequestParam("userLikeGroupId") Long userLikeGroupId) { public Response<Long> exportSave(@RequestParam("file") MultipartFile file, @RequestParam(value = "projectId", required = false) Long projectId,
return Response.success(userLikeGroupService.exportSave(file, userLikeGroupId)); @RequestParam("module") String module, @RequestParam(value = "designItemDetailId", required = false) Long designItemDetailId) {
return Response.success(userLikeGroupService.exportSave(file, projectId, module, designItemDetailId));
} }
@ApiOperation(value = "exportSearch") @ApiOperation(value = "exportSearch")
@PostMapping("/exportSearch") @PostMapping("/exportSearch")
public Response<JSONObject> exportSearch(@Valid @RequestBody ExportSearchDTO exportSearchDTO) { public Response<JSONObject> exportSearch(@Valid @RequestBody ExportSearchDTO exportSearchDTO) {
return Response.success(userLikeGroupService.exportSearch(exportSearchDTO.getUserLikeGroupId())); return Response.success(userLikeGroupService.exportSearch(exportSearchDTO));
} }
@ApiOperation(value = "toProduct") @ApiOperation(value = "toProduct")
@PostMapping("/toProduct") @PostMapping("/toProduct")
public Response<List<ToProductImageResult>> toProduct(@Valid @RequestBody ToProductImageDTO toProductImageDTO) { public Response<List<ToProductImageResultVO>> toProduct(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
return Response.success(userLikeGroupService.toProduct(toProductImageDTO)); return Response.success(userLikeGroupService.toProduct(toProductImageDTO));
} }
@ApiOperation(value = "toProductImageElementUpload") @ApiOperation(value = "toProductImageElementUpload")
@PostMapping("/toProductImageElementUpload") @PostMapping("/toProductImageElementUpload")
public Response<ToProductElementVO> toProductImageElementUpload(@RequestParam("file") MultipartFile file, @RequestParam(value = "userlikeGroupId") Long userLikeGroupId) { public Response<ToProductElementVO> toProductImageElementUpload(@RequestParam("file") MultipartFile file, @RequestParam(value = "projectId", required = false) Long projectId) {
return Response.success(userLikeGroupService.toProductImageElementUpload(file, userLikeGroupId)); return Response.success(userLikeGroupService.toProductImageElementUpload(file, projectId));
}
@ApiOperation(value = "toProductImageElementDelete")
@PostMapping("/toProductImageElementDelete")
public Response<Boolean> toProductImageElementDelete(@RequestParam(value = "id") Long id) {
return Response.success(userLikeGroupService.toProductImageElementDelete(id));
} }
@ApiOperation(value = "productImageLike") @ApiOperation(value = "productImageLike")
@PostMapping("/productImageLike") @PostMapping("/productImageLike")
public Response<Boolean> productImageLike(@Valid @RequestBody ProductImageLikeDTO productImageLikeDTO) { public Response<CollectionSort> productImageLike(@Valid @RequestBody ProductImageLikeDTO productImageLikeDTO) {
return Response.success(userLikeGroupService.productImageLike(productImageLikeDTO)); CollectionSort collectionSort = userLikeGroupService.productImageLike(productImageLikeDTO);
return Response.success(collectionSort);
}
@ApiOperation(value = "collectionLikeUpdate")
@PostMapping("/collectionLikeUpdate")
public Response<Boolean> collectionLikeUpdate(@Valid @RequestBody CollectionLikeUpdateDTO collectionLikeUpdateDTO) {
return Response.success(userLikeGroupService.collectionLikeUpdate(collectionLikeUpdateDTO));
} }
@ApiOperation(value = "productImageUnLike") @ApiOperation(value = "productImageUnLike")
@@ -229,10 +247,16 @@ public class SavedCollectionController {
@ApiOperation(value = "relight") @ApiOperation(value = "relight")
@PostMapping("/relight") @PostMapping("/relight")
public Response<List<ToProductImageResult>> relight(@Valid @RequestBody ToProductImageDTO toProductImageDTO) { public Response<List<ToProductImageResultVO>> relight(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
return Response.success(userLikeGroupService.relight(toProductImageDTO)); return Response.success(userLikeGroupService.relight(toProductImageDTO));
} }
@ApiOperation(value = "转relight元素")
@PostMapping("/convertRelightElement")
public Response<ToProductElementVO> convertRelightElement(@RequestParam("id") Long id) {
return Response.success(userLikeGroupService.convertRelightElement(id));
}
@ApiOperation(value = "获取relight结果") @ApiOperation(value = "获取relight结果")
@PostMapping("/relightResult") @PostMapping("/relightResult")
public Response<List<MagicToolResultVO>> getRelightResult(@Valid @RequestBody List<String> taskIdList) { public Response<List<MagicToolResultVO>> getRelightResult(@Valid @RequestBody List<String> taskIdList) {
@@ -240,6 +264,19 @@ public class SavedCollectionController {
return Response.success(magicToolResultVOList); return Response.success(magicToolResultVOList);
} }
@ApiOperation(value = "删除toProduct Relight的结果")
@GetMapping("/deleteResult")
public Response<String> deleteResult(@RequestParam("id") Long id,
@RequestParam("projectId") Long projectId,
@RequestParam("type") @Pattern(regexp = "^(Relight|ToProductImage)$", message = "Please choose type from 'Relight|ToProductImage'") String type){
try{
userLikeGroupService.deleteToProductRelightResult(id, projectId, type);
return Response.success();
}catch (Exception e){
return Response.fail(e.getMessage());
}
}
@ApiOperation(value = "likeHistoryRelSketch") @ApiOperation(value = "likeHistoryRelSketch")
@PostMapping("/likeHistoryRelSketch") @PostMapping("/likeHistoryRelSketch")
public Response<String> likeHistoryRelSketch() { public Response<String> likeHistoryRelSketch() {
@@ -257,4 +294,46 @@ public class SavedCollectionController {
public Response<Boolean> productImageUpload(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) { public Response<Boolean> productImageUpload(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) {
return Response.success(userLikeGroupService.productImageInitialize(productImageInitializeDTO)); return Response.success(userLikeGroupService.productImageInitialize(productImageInitializeDTO));
} }
@ApiOperation(value = "getInitializeProgress")
@PostMapping("/getInitializeProgress")
public Response<InitializeProgressVO> getInitializeProgress(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) {
return Response.success(userLikeGroupService.getInitializeProgress(productImageInitializeDTO));
}
@ApiOperation(value = "brandDNASaveOrUpdate")
@PostMapping("/brandDNASaveOrUpdate")
public Response<Boolean> brandDNASaveOrUpdate(@Valid @RequestBody BrandDNADTO brandDNADTO) {
return Response.success(userLikeGroupService.brandDNASaveOrUpdate(brandDNADTO));
}
@ApiOperation(value = "brandDNADelete")
@PostMapping("/brandDNADelete")
public Response<Boolean> brandDNADelete(@Valid @RequestBody BrandDNADTO brandDNADTO) {
return Response.success(userLikeGroupService.brandDNADelete(brandDNADTO));
}
@ApiOperation(value = "brandDNAPage")
@PostMapping("/brandDNAPage")
public Response<PageBaseResponse<BrandDNAVO>> brandDNAPage(@Valid @RequestBody BrandDNAQueryDTO brandDNAQueryDTO) {
return Response.success(userLikeGroupService.brandDNAPage(brandDNAQueryDTO));
}
@ApiOperation(value = "brandLogoUpload")
@PostMapping("/brandLogoUpload")
public Response<BrandLogoUploadVO> brandDNASaveOrUpdate(@RequestParam("file") MultipartFile file) {
return Response.success(userLikeGroupService.brandLogoUpload(file));
}
@ApiOperation(value = "brandDNAUpload")
@PostMapping("/brandDNAUpload")
public Response<LibraryUpdateVo> brandDNAUpload(@RequestParam("file") MultipartFile file, @RequestParam("brandId") Long brandId) throws IOException {
return Response.success(userLikeGroupService.brandDNAUpload(file, brandId));
}
@ApiOperation(value = "brandDNAGenerate")
@PostMapping("/brandDNAGenerate")
public Response<BrandDNAGenerateVO> brandDNAGenerate(@RequestParam("prompt") String prompt) {
return Response.success(userLikeGroupService.brandDNAGenerate(prompt));
}
} }

View File

@@ -137,11 +137,9 @@ public class StripeController {
@ApiOperation("更新推广码信息") @ApiOperation("更新推广码信息")
@GetMapping("/updatePromCodeInfo") @GetMapping("/updatePromCodeInfo")
public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) String paidCommission, public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) Long paidCommission,
@RequestParam(required = false) String cooperator, @RequestParam(required = false) String cooperator, @RequestParam(required = false) String remark){
@RequestParam(required = false) String remark, return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark));
@RequestParam(required = false) Long startTime){
return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark, startTime));
} }
@ApiOperation("删除推广码") @ApiOperation("删除推广码")

View File

@@ -1,6 +1,8 @@
package com.ai.da.controller; package com.ai.da.controller;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.mapper.primary.entity.GoogleUser;
import com.ai.da.model.dto.*; import com.ai.da.model.dto.*;
import com.ai.da.model.vo.AccountLoginVO; import com.ai.da.model.vo.AccountLoginVO;
@@ -35,6 +37,9 @@ public class ThirdPartyController {
@Resource @Resource
private DesignService designService; private DesignService designService;
@Resource
private MinioUtil minioUtil;
/*@ApiOperation(value = "Add user information") /*@ApiOperation(value = "Add user information")
@PostMapping("/addUser") @PostMapping("/addUser")
public Response<Boolean> addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) { public Response<Boolean> addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) {
@@ -146,4 +151,17 @@ public class ThirdPartyController {
public Response<Boolean> receiveDesignResults(@Valid @RequestBody JSONObject responseObject) { public Response<Boolean> receiveDesignResults(@Valid @RequestBody JSONObject responseObject) {
return Response.success(designService.receiveDesignResults(responseObject)); return Response.success(designService.receiveDesignResults(responseObject));
} }
@ApiOperation(value = "接收Design入参")
@PostMapping("/receiveDesignParams")
@CrossOrigin
public Response<Boolean> receiveDesignParams(@Valid @RequestBody ReceiveDesignParam receiveDesignParam) {
return Response.success(designService.receiveDesignParams(receiveDesignParam));
}
@ApiOperation(value = "刷新minio预签名地址")
@GetMapping("/refreshMinioUrl")
public Response<String> refreshMinioUrl(@RequestParam("path") String path){
return Response.success(minioUtil.getPreSignedUrl(path, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
}
} }

View File

@@ -3,6 +3,7 @@ package com.ai.da.controller;
import com.ai.da.common.response.Response; import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Style; import com.ai.da.mapper.primary.entity.Style;
import com.ai.da.mapper.primary.entity.Workspace; import com.ai.da.mapper.primary.entity.Workspace;
import com.ai.da.model.dto.ProjectDTO;
import com.ai.da.model.dto.WorkspaceDTO; import com.ai.da.model.dto.WorkspaceDTO;
import com.ai.da.model.dto.WorkspaceSaveDTO; import com.ai.da.model.dto.WorkspaceSaveDTO;
import com.ai.da.model.enums.BizJson; import com.ai.da.model.enums.BizJson;
@@ -95,8 +96,8 @@ public class WorkspaceController {
@GetMapping("/getMannequins") @GetMapping("/getMannequins")
@ApiOperationSupport(order = 6) @ApiOperationSupport(order = 6)
@ApiOperation(value = "获取模特") @ApiOperation(value = "获取模特")
public Response<List<ModelsVO>> getMannequins(@RequestParam("sex") String sex, @RequestParam("style") String style) { public Response<List<ModelsVO>> getMannequins(@RequestParam("sex") String sex, @RequestParam("style") String style, @RequestParam("ageGroup") String ageGroup) {
List<ModelsVO> modelsVO = workspaceService.getMannequins(sex, style); List<ModelsVO> modelsVO = workspaceService.getMannequins(sex, style, ageGroup);
return Response.success(modelsVO); return Response.success(modelsVO);
} }
@@ -131,4 +132,11 @@ public class WorkspaceController {
public Response<List<StyleVO>> styleList() { public Response<List<StyleVO>> styleList() {
return Response.success(workspaceService.styleList()); return Response.success(workspaceService.styleList());
} }
@PostMapping("/saveOrUpdateProject")
@ApiOperationSupport(order = 3)
@ApiOperation(value = "新增或编辑", notes = "传入project")
public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
}
} }

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.APIGenerate;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface APIGenerateMapper extends BaseMapper<APIGenerate> {
}

View File

@@ -2,8 +2,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.model.dto.AccountCreditsUsageDTO;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@@ -32,4 +32,10 @@ public interface AccountMapper extends CommonMapper<Account> {
void toVisitor(Long id); void toVisitor(Long id);
List<AccountCreditsUsageDTO> selectCreditUsage(boolean groupByEvent, String changeEvent, String role,
String userEmail, Long id, String startTime, String endTime,
Integer size, Integer offset, String organizationName);
int countCreditUsage(boolean groupByEvent, String changeEvent, String role, String userEmail, Long id, String startTime, String endTime, String organizationName);
} }

View File

@@ -1,14 +0,0 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.AffiliateIncome;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.Map;
public interface AffiliateIncomeMapper extends BaseMapper<AffiliateIncome> {
List<Map<String, Object>> getPersonalMonthlyIncome(Long affiliateAccountId, int year);
List<Map<String, Object>> getMonthlyAffiliateIncome(int year, int month);
}

View File

@@ -12,8 +12,10 @@ public interface AffiliateMapper extends BaseMapper<Affiliate> {
Map<String, Long> getMonthlyApprovedAffiliate(int year, int month); Map<String, Long> getMonthlyApprovedAffiliate(int year, int month);
List<AffiliateVO> getAffiliateList(String status, String startTime, String endTime, List<AffiliateVO> getAffiliateList(String status, String startTime, String endTime,
String order, Long affiliateId, int size, int offset); String order, Long affiliateId, String sortField, int size, int offset);
int queryAffiliateTotalCount(String status, String startTime, String endTime, Long affiliateId); int queryAffiliateTotalCount(String status, String startTime, String endTime, Long affiliateId);
List<Map<String, Object>> selectAllAffiliateUsername();
} }

View File

@@ -0,0 +1,16 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.BatchTaskSequence;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface BatchTaskSequenceMapper extends BaseMapper<BatchTaskSequence> {
@Update("UPDATE t_batch_task_sequence SET current_sequence = LAST_INSERT_ID(current_sequence + 1) WHERE account_id = #{userId}")
int incrementSequence(@Param("userId") Long userId);
@Select("SELECT LAST_INSERT_ID()")
Integer getLastInsertId();
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.BrandDNA;
public interface BrandDNAMapper extends CommonMapper<BrandDNA> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.BrandRelLibrary;
public interface BrandRelLibraryMapper extends CommonMapper<BrandRelLibrary> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ChatMessage;
public interface ChatMessageMapper extends CommonMapper<ChatMessage> {
}

View File

@@ -0,0 +1,16 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.CloudTask;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface CloudTaskMapper extends CommonMapper<CloudTask> {
@Update("UPDATE cloud_task SET completed_num = completed_num + 1, update_time = NOW() WHERE task_id = #{taskIdBatch}")
@Options(useGeneratedKeys = false, flushCache = Options.FlushCachePolicy.TRUE)
void increaseCompletedNum(@Param("taskIdBatch") String taskIdBatch);
@Select("SELECT * FROM cloud_task WHERE task_id = #{taskId} FOR UPDATE")
CloudTask selectForUpdate(String taskId);
}

View File

@@ -2,6 +2,9 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.CollectionElement; import com.ai.da.mapper.primary.entity.CollectionElement;
import com.ai.da.mapper.primary.entity.CollectionElementRelModel;
import java.util.List;
/** /**
* Mapper 接口 * Mapper 接口
@@ -11,4 +14,7 @@ import com.ai.da.mapper.primary.entity.CollectionElement;
*/ */
public interface CollectionElementMapper extends CommonMapper<CollectionElement> { public interface CollectionElementMapper extends CommonMapper<CollectionElement> {
List<CollectionElement> selectDeleteList();
List<CollectionElementRelModel> selectByProject(Long projectId);
} }

View File

@@ -0,0 +1,10 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.CollectionElementRelModel;
import java.util.Set;
public interface CollectionElementRelModelMapper extends CommonMapper<CollectionElementRelModel> {
}

View File

@@ -3,6 +3,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Collection; import com.ai.da.mapper.primary.entity.Collection;
import java.util.List;
/** /**
* Mapper 接口 * Mapper 接口
* *
@@ -12,4 +14,6 @@ import com.ai.da.mapper.primary.entity.Collection;
public interface CollectionMapper extends CommonMapper<Collection> { public interface CollectionMapper extends CommonMapper<Collection> {
//返回插入数据后生成的主键 //返回插入数据后生成的主键
Long insertCollection(Collection collection); Long insertCollection(Collection collection);
List<Collection> selectDeleteList();
} }

View File

@@ -0,0 +1,18 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.CollectionSort;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
public interface CollectionSortMapper extends CommonMapper<CollectionSort> {
@Update("UPDATE collection_sort SET sort = sort + 1 " +
"WHERE parent_id = #{parentId} " +
"AND relation_type != 'Design' " +
"AND sort > #{originalSort}")
void increaseGenerateSortAbove(
@Param("parentId") Long parentId,
@Param("relationType") String relationType,
@Param("originalSort") int originalSort
);
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.DesignItemDetailCanvas;
public interface DesignItemDetailCanvasMapper extends CommonMapper<DesignItemDetailCanvas> {
}

View File

@@ -3,6 +3,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.DesignItem; import com.ai.da.mapper.primary.entity.DesignItem;
import java.util.List;
/** /**
* Mapper 接口 * Mapper 接口
* *
@@ -12,4 +14,6 @@ import com.ai.da.mapper.primary.entity.DesignItem;
public interface DesignItemMapper extends CommonMapper<DesignItem> { public interface DesignItemMapper extends CommonMapper<DesignItem> {
Long insertDesignItem(DesignItem designItem); Long insertDesignItem(DesignItem designItem);
List<DesignItem> selectDeleteList();
} }

View File

@@ -18,5 +18,8 @@ public interface DesignMapper extends CommonMapper<Design> {
//返回插入数据后生成的主键 //返回插入数据后生成的主键
Long insertDesign(Design design); Long insertDesign(Design design);
List<UserDesignStatisticDTO> getDesignStatistic(String startTime, String endTime, List<Long> ids, String email); List<UserDesignStatisticDTO> getDesignStatistic(String startTime, String endTime, List<Long> ids, String email,
String role, String organizationName);
List<Design> selectDeleteList();
} }

View File

@@ -0,0 +1,8 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.EducationLibrary;
public interface EductionLibraryMapper extends CommonMapper<EducationLibrary> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.EmailLog;
public interface EmailLogMapper extends CommonMapper<EmailLog> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.EmailTemplate;
public interface EmailTemplateMapper extends CommonMapper<EmailTemplate> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.EnterpriseLibrary;
public interface EnterpriseLibraryMapper extends CommonMapper<EnterpriseLibrary> {
}

View File

@@ -3,6 +3,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Library; import com.ai.da.mapper.primary.entity.Library;
import java.util.List;
/** /**
* Mapper 接口 * Mapper 接口
* *
@@ -11,4 +13,11 @@ import com.ai.da.mapper.primary.entity.Library;
*/ */
public interface LibraryMapper extends CommonMapper<Library> { public interface LibraryMapper extends CommonMapper<Library> {
List<Library> selectCommonLib(Long organizationId, String sort, long limit, long offset);
Long selectCommonLibCount(Long organizationId);
List<Library> selectAllSubAccLib(Long organizationId, String sort, long limit, long offset);
Long selectAllSubAccLibCount(Long organizationId);
} }

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Organization;
public interface OrganizationMapper extends CommonMapper<Organization> {
}

View File

@@ -6,7 +6,6 @@ import com.ai.da.model.vo.PaymentInfoVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -25,10 +24,6 @@ public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
String country, String city, String startTime, String endTime, String payer String country, String city, String startTime, String endTime, String payer
); );
BigDecimal queryTotalPaymentAmount(String paymentType,String payerTotal, String type, String status,
String country, String city, String startTime, String endTime, String payer
);
List<Map<String, String>> getCities(); List<Map<String, String>> getCities();
List<Map<String, String>> getCountries(); List<Map<String, String>> getCountries();

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.PoseTransformation;
public interface PoseTransformationMapper extends CommonMapper<PoseTransformation> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Project;
public interface ProjectMapper extends CommonMapper<Project> {
}

View File

@@ -0,0 +1,32 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.Referral;
import com.ai.da.model.vo.ReferralPageQueryVO;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public interface ReferralMapper extends BaseMapper<Referral> {
// 使用自定义SQL进行分页查询
IPage<ReferralPageQueryVO> selectReferralWithAffiliate(Page<ReferralPageQueryVO> page, @Param("ew") Wrapper<ReferralPageQueryVO> wrapper);
void batchDeleteByIds(List<Long> ids);
BigDecimal sumAmount(
Long affiliateId,
List<String> statusList, // 改为 List 类型
LocalDateTime startTime, // 开始时间(可选)
LocalDateTime endTime // 结束时间(可选)
);
List<Map<String, Object>> getPersonalMonthlyIncome(Long affiliateAccountId, int year);
List<Map<String, Object>> getMonthlyAffiliateIncome(int year, int month);
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.SketchData;
public interface SketchDataMapper extends CommonMapper<SketchData> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.SketchReconstruction;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface SketchReconstructionMapper extends BaseMapper<SketchReconstruction> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.SysFileExtra;
public interface SysFileExtraMapper extends CommonMapper<SysFileExtra> {
}

View File

@@ -29,4 +29,5 @@ public interface TDesignPythonOutfitDetailMapper extends CommonMapper<TDesignPyt
@Delete("DELETE FROM t_design_python_outfit_detail WHERE design_python_outfit_id = #{designPythonOutfitId}") @Delete("DELETE FROM t_design_python_outfit_detail WHERE design_python_outfit_id = #{designPythonOutfitId}")
void deleteByDesignPythonOutfitIdPhysical(@Param("designPythonOutfitId") Long designPythonOutfitId); void deleteByDesignPythonOutfitIdPhysical(@Param("designPythonOutfitId") Long designPythonOutfitId);
List<TDesignPythonOutfitDetail> selectListDelete();
} }

View File

@@ -25,4 +25,5 @@ public interface TDesignPythonOutfitMapper extends CommonMapper<TDesignPythonOut
*/ */
List<TDesignPythonOutfitVO> selectTDesignPythonOutfitPage(IPage page, TDesignPythonOutfitVO tDesignPythonOutfit); List<TDesignPythonOutfitVO> selectTDesignPythonOutfitPage(IPage page, TDesignPythonOutfitVO tDesignPythonOutfit);
List<TDesignPythonOutfit> selectListDelete();
} }

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ThreeDDetail;
public interface ThreeDDetailMapper extends CommonMapper<ThreeDDetail> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ThreeDLayout;
public interface ThreeDLayoutMapper extends CommonMapper<ThreeDLayout> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ThreeDModule;
public interface ThreeDModuleMapper extends CommonMapper<ThreeDModule> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ThreeDPatternLayout;
public interface ThreeDPatternLayoutMapper extends CommonMapper<ThreeDPatternLayout> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.ThreeDSimple;
public interface ThreeDSimpleMapper extends CommonMapper<ThreeDSimple> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.UserBehavior;
public interface UserBehaviorMapper extends CommonMapper<UserBehavior> {
}

View File

@@ -3,6 +3,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper; import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.UserLikeGroup; import com.ai.da.mapper.primary.entity.UserLikeGroup;
import java.util.List;
/** /**
* Mapper 接口 * Mapper 接口
* *
@@ -12,4 +14,6 @@ import com.ai.da.mapper.primary.entity.UserLikeGroup;
public interface UserLikeGroupMapper extends CommonMapper<UserLikeGroup> { public interface UserLikeGroupMapper extends CommonMapper<UserLikeGroup> {
//返回插入数据后生成的主键 //返回插入数据后生成的主键
Long insertUserLikeGroup(UserLikeGroup userLikeGroup); Long insertUserLikeGroup(UserLikeGroup userLikeGroup);
List<UserLikeGroup> getMoreThan50UserLikeAccount();
} }

View File

@@ -1,7 +0,0 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.UserLikeSort;
public interface UserLikeSortMapper extends CommonMapper<UserLikeSort> {
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.UserPreferenceLogTest;
public interface UserPreferenceLogMapper extends CommonMapper<UserPreferenceLogTest> {
}

View File

@@ -0,0 +1,8 @@
package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.UserPreferenceLogPrediction;
import com.ai.da.mapper.primary.entity.UserPreferenceLogTest;
public interface UserPreferenceLogPredictionMapper extends CommonMapper<UserPreferenceLogPrediction> {
}

View File

@@ -0,0 +1,27 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("t_api_generate")
@ApiModel("调用第三方api的所有记录")
public class APIGenerate extends BaseEntity{
// 用户id
private Long accountId;
// 任务id 加唯一索引
private String taskId;
// 什么功能调用的api
private String func;
// 第三方api的服务商 目前只有ali-万相 和 flux
// private String service;
// 模型名
private String modelName;
// 任务状态
private String status;
// 获取结果的重试次数
private int retry_count;
}

View File

@@ -117,11 +117,16 @@ public class Account implements Serializable {
private String organizationName; private String organizationName;
private Long organizationId;
private Long parentId; private Long parentId;
private Integer isAdmin; private Integer isAdmin;
private BigDecimal shareCredits; private BigDecimal creditsUsageLimit;
// 学校分配的积分使用情况
private BigDecimal creditsUsage = BigDecimal.ZERO;
private Integer subAccountNum; private Integer subAccountNum;

View File

@@ -50,4 +50,12 @@ public class AccountLoginLog implements Serializable {
*/ */
private Date createDate; private Date createDate;
public AccountLoginLog() {
}
public AccountLoginLog(Long accountId, String ip, Date createDate) {
this.accountId = accountId;
this.ip = ip;
this.createDate = createDate;
}
} }

View File

@@ -22,7 +22,8 @@ public class Affiliate extends BaseEntity{
private Float unpaidEarnings = 0.00F; private Float unpaidEarnings = 0.00F;
private Integer visits = 0; // 邀请链接的访问人数每分钟从redis同步到数据库
private Long visits = 0L;
private Boolean approved = false; private Boolean approved = false;

View File

@@ -0,0 +1,18 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@TableName("t_batch_task_sequence")
@Data
public class BatchTaskSequence extends BaseEntity{
private Long accountId;
private Integer nextSeq;
private Integer lockedSeq;
}

View File

@@ -0,0 +1,37 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("brand")
public class BrandDNA implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long accountId;
private String brandName;
private String brandSlogan;
private String brandLogo;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,29 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("brand_rel_library")
public class BrandRelLibrary implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long brandId;
private Long libraryId;
}

View File

@@ -0,0 +1,61 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("chat_message")
public class ChatMessage implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("项目ID")
private Long projectId;
@ApiModelProperty("角色system/user")
private String role;
@ApiModelProperty("排序")
private Integer seq;
@ApiModelProperty("内容")
private String content;
@ApiModelProperty("用户ID")
private Long accountId;
@ApiModelProperty("0对话内容1颜色2图片")
private Integer isImage;
/**
* 输入
*/
private Long inputTokens;
/**
* 输出
*/
private Long outputTokens;
/**
* 思考
*/
private Long reasoningTokens;
/**
* 本次输出消耗的总金额
*/
private String totalCost;
@ApiModelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,70 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.apache.poi.hpsf.Decimal;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("cloud_task")
public class CloudTask implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty("任务名")
private String name;
@ApiModelProperty("项目ID")
private Long projectId;
@ApiModelProperty("collectionId")
private Long collectionId;
@ApiModelProperty("designId")
private Long designId;
@ApiModelProperty("任务类型")
private String buildType;
@ApiModelProperty("生成数量")
private Integer nums;
@ApiModelProperty("完成数量")
private Integer completedNum;
@ApiModelProperty("消耗积分")
private Integer costCredits;
@ApiModelProperty("状态1完成0未完成")
private Integer status;
@ApiModelProperty("批处理ID")
private String taskId;
@ApiModelProperty("创建时间")
private LocalDateTime createTime;
@ApiModelProperty("任务开始时间")
private LocalDateTime startTime;
@ApiModelProperty("任务更新时间")
private LocalDateTime updateTime;
@ApiModelProperty("用户ID")
private Long accountId;
@ApiModelProperty("任务序号")
private Long sequence;
}

View File

@@ -86,4 +86,23 @@ public class CollectionElement implements Serializable {
* 更新时间 * 更新时间
*/ */
private Date updateDate; private Date updateDate;
private Long projectId;
private Integer isCompositeImage;
public CollectionElement() {
}
public CollectionElement(Long accountId, String level1Type, String level2Type, String name, String url, Byte hasPin, String md5, Date createDate, Long projectId) {
this.accountId = accountId;
this.level1Type = level1Type;
this.level2Type = level2Type;
this.name = name;
this.url = url;
this.hasPin = hasPin;
this.md5 = md5;
this.createDate = createDate;
this.projectId = projectId;
}
} }

Some files were not shown because too many files have changed in this diff Show More