Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+311
View File
@@ -0,0 +1,311 @@
package ai_image_to_video_ser
import (
"91porn-server/common"
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/commod"
"91porn-server/models/v/aiimagetovideomod"
"91porn-server/models/v/aiplazamod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/walletmod"
"91porn-server/web/webg"
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"strings"
"time"
)
type WebListReq struct {
ID *string `json:"id" form:"id"` // ID
UID *uint64 `json:"uid" form:"uid"` // 用户ID
Status *int `json:"status" form:"status"` // 状态
SceneType *int `json:"sceneType" form:"sceneType"` // 模版场景类型
commod.Page
}
func (q *WebListReq) Filter() primitive.M {
filter := bson.M{}
if q.ID != nil {
id, _ := primitive.ObjectIDFromHex(*q.ID)
filter["_id"] = id
}
if q.Status != nil {
filter["status"] = q.Status
}
if q.UID != nil {
filter["uid"] = q.UID
}
if q.SceneType != nil {
filter["sceneType"] = q.SceneType
}
return filter
}
type WebListRes struct {
Total int64 `json:"total"`
HasNext bool `json:"hasNext"`
List []aiimagetovideomod.AiImageToVideo `json:"list"`
}
// GetList 获取列表
func (q *WebListReq) GetList() (res WebListRes, err error) {
res.List, res.Total, res.HasNext, err = aiimagetovideomod.GetList(q.Filter(), int64(q.Skip()), int64(q.Limit()), q.GetSort())
return
}
type WebUpdateReq struct {
ID string `json:"id" binding:"required"` // ID
Status *int `json:"status"` // 状态
Remark *string `json:"remark"` // 备注
}
func (p *WebUpdateReq) UpdateCond() primitive.M {
data := make(map[string]interface{})
if p.Status != nil {
data["status"] = *p.Status
}
if p.Remark != nil {
data["remark"] = *p.Remark
}
data["updatedAt"] = time.Now()
return data
}
// Update 更新数据
func (p *WebUpdateReq) Update() error {
id, _ := primitive.ObjectIDFromHex(p.ID)
data, err := aiimagetovideomod.GetInfo(id)
if err != nil {
return err
}
if data.ID.IsZero() {
return errors.New("data is null")
}
if p.Status != nil {
if data.Status == int(aiimagetovideomod.StatusRefunded) || data.Status == int(aiimagetovideomod.StatusGenerationFailed) {
return errors.New("Please do not refund repeatedly.")
}
switch aiimagetovideomod.AiImageToVideoStatus(*p.Status) {
case aiimagetovideomod.StatusRefunded:
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
if _, err = aiimagetovideomod.UpdateByID(t, id, p.UpdateCond()); err != nil {
return err
}
// 退款
if data.DebitAmountCoin == 0 && data.DebitIncomeCoin == 0 { // 总金额为0则不需要退款
return nil
}
// 退款进入钱包余额
wallet, err := walletmod.ReturnAmountAndIncome(t, -data.DebitAmountCoin, -data.DebitIncomeCoin, data.UID)
if err != nil {
log.Error(fmt.Sprintf("Handle Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", data.UID))
return err
}
var tl []txnmod.TransactionLog
if data.DebitAmountCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: data.UID,
Amount: -data.DebitAmountCoin,
ActualAmount: float64(-data.DebitAmountCoin),
TranType: txnmod.AiImageToVideoDebitGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiImageToVideoDebitGoldReturn),
Desc: fmt.Sprintf("退还AI图生视频金币-%d", data.DebitAmountCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if data.DebitIncomeCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: data.UID,
Amount: -data.DebitIncomeCoin,
ActualAmount: float64(-data.DebitIncomeCoin),
TranType: txnmod.AiImageToVideoDebitIncomeGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiImageToVideoDebitIncomeGoldReturn),
Desc: fmt.Sprintf("退还AI图生视频收益金币-%d", data.DebitIncomeCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if len(tl) > 0 {
txnErr := txnmod.InsertManyTransactionLog(t, tl)
if txnErr != nil {
log.Error(fmt.Sprintf("Handle imagetovideo Edit txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", data.UID))
return stderr.ErrDbQueryError
}
}
return nil
}); err != nil {
if e, ok := err.(stderr.Code); ok {
return e
}
return stderr.ErrDbQueryError
}
default:
}
}
if _, err = aiimagetovideomod.UpdateByID(nil, id, p.UpdateCond()); err != nil {
return err
}
return nil
}
type WebDeleteReq struct {
ID primitive.ObjectID `json:"id" binding:"required"`
}
// Delete 删除数据
func (p *WebDeleteReq) Delete() error {
if err := aiimagetovideomod.DeleteByID(nil, p.ID); err != nil {
return err
}
return nil
}
// CallbackReq 换脸订单回调请求
type CallbackReq struct {
ImgUrl string `json:"imgUrl"` // AI图生视频图片地址
AppOrderNum string `json:"appOrderNum"` // app订单号
Status int `json:"status"` // 订单状态 1:成功,2:失败
Msg string `json:"msg"` // 消息
}
func (p *CallbackReq) Callback() error {
id, _ := primitive.ObjectIDFromHex(p.AppOrderNum)
// 查询该笔订单是否存在
data, err := aiimagetovideomod.GetInfo(id)
if err != nil {
return stderr.ErrDbQueryError
}
if data.ID.IsZero() {
return errors.New("ai imagetovideo data is null")
}
if data.Status != int(aiimagetovideomod.StatusSubmitted) {
log.Error("AI图生视频-重复回调或者状态不正确", log.Any("id", data.ID.Hex()), log.Any("status", data.Status))
return nil
}
var status = aiimagetovideomod.StatusGenerationSuccess
// 处理金币退款以及后续操作
set := bson.M{}
if p.ImgUrl != "" {
set["newImgUrl"] = strings.TrimSpace(p.ImgUrl)
}
if p.Status != 1 {
set["remark"] = p.Msg
set["newImgUrl"] = ""
status = aiimagetovideomod.StatusGenerationFailed
}
set["status"] = status
set["updatedAt"] = time.Now()
switch status {
case aiimagetovideomod.StatusGenerationSuccess:
if _, err = aiimagetovideomod.UpdateByID(nil, id, set); err != nil {
return stderr.ErrDbUpdateError
}
if data.ShareStatus == 1 {
common.Go(func() {
// 新增一个分享
alPlaza := aiplazamod.AiPlaza{
Type: 4,
OrderId: data.ID,
Template: "",
Uid: data.UID,
Title: data.ShareTitle,
OriginalImage: data.ImgUrl,
OriginalVideo: "",
OriginContent: "",
GenerateImage: p.ImgUrl,
GenerateVideo: "",
Status: aiplazamod.DefaultStatus,
}
_, err = aiplazamod.Insert(nil, alPlaza)
if err != nil {
log.Error("新增ai广场帖子失败", log.Any("alPlaza", alPlaza), log.E(err))
return
}
})
}
return nil
case aiimagetovideomod.StatusGenerationFailed: // 退款
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
if _, err = aiimagetovideomod.UpdateByID(t, id, set); err != nil {
return err
}
// 退款
if data.DebitAmountCoin == 0 && data.DebitIncomeCoin == 0 { // 总金额为0则不需要退款
return nil
}
// 退款进入钱包余额
wallet, err := walletmod.ReturnAmountAndIncome(t, -data.DebitAmountCoin, -data.DebitIncomeCoin, data.UID)
if err != nil {
log.Error(fmt.Sprintf("Handle Callback Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", data.UID))
return err
}
var tl []txnmod.TransactionLog
if data.DebitAmountCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: data.UID,
Amount: -data.DebitAmountCoin,
ActualAmount: float64(-data.DebitAmountCoin),
TranType: txnmod.AiImageToVideoDebitGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiImageToVideoDebitGoldReturn),
Desc: fmt.Sprintf("退还AI图生视频金币-%d", data.DebitAmountCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if data.DebitIncomeCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: data.UID,
Amount: -data.DebitIncomeCoin,
ActualAmount: float64(-data.DebitIncomeCoin),
TranType: txnmod.AiImageToVideoDebitIncomeGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiImageToVideoDebitIncomeGoldReturn),
Desc: fmt.Sprintf("退还AI图生视频收益金币-%d", data.DebitIncomeCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if len(tl) > 0 {
txnErr := txnmod.InsertManyTransactionLog(t, tl)
if txnErr != nil {
log.Error(fmt.Sprintf("Handle imagetovideo Callback txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", data.UID))
return stderr.ErrDbQueryError
}
}
return nil
}); err != nil {
if e, ok := err.(stderr.Code); ok {
return e
}
return stderr.ErrDbQueryError
}
return nil
default:
}
return nil
}