package ai_text_to_image_ser import ( "91porn-server/app/appg" "91porn-server/common" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/common/stderr" "91porn-server/middleware/ua" "91porn-server/models/cache/aitexttoimagedata" "91porn-server/models/cache/sysconfdata" "91porn-server/models/commod" "91porn-server/models/v/aichangefacevidmod" "91porn-server/models/v/aitexttoimagemod" "91porn-server/models/v/sysconfmod" "91porn-server/models/v/txnmod" "91porn-server/models/v/usermod" "91porn-server/models/v/walletmod" "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) type AppQueryListReq struct { Status int `json:"status" form:"status"` // 状态 1、排队中 2、生成成功 3、生成失败 UID uint64 `json:"-"` // 用户ID commod.Page } func (p *AppQueryListReq) Filter() primitive.M { filter := bson.M{} switch p.Status { case 1: filter["status"] = bson.M{"$in": []aitexttoimagemod.AiTextToImageStatus{aitexttoimagemod.StatusOrderSuccess, aitexttoimagemod.StatusSubmitted}} case 2: filter["status"] = aitexttoimagemod.StatusGenerationSuccess case 3: filter["status"] = bson.M{"$in": []aitexttoimagemod.AiTextToImageStatus{aitexttoimagemod.StatusGenerationFailed, aitexttoimagemod.StatusRefunded}} } filter["uid"] = p.UID filter["isHide"] = false return filter } type AppListRes struct { Total int64 `json:"total"` HasNext bool `json:"hasNext"` List []*aitexttoimagemod.AiTextToImageInfo `json:"list"` } // GetList 获取列表 func (p *AppQueryListReq) GetList() AppListRes { var res AppListRes var err error sort := bson.D{{"createdAt", -1}} // 获取列表 var data []aitexttoimagemod.AiTextToImage data, res.Total, res.HasNext, err = aitexttoimagemod.GetList(p.Filter(), int64(p.Skip()), int64(p.Limit()), sort) if err != nil { log.Error("获取AI绘图列表列表数据错误", log.Any("Params", *p), log.E(err)) return res } res.List = aitexttoimagedata.FormatAppDataList(data) // 获取所有的模版 cond := bson.M{"status": 1, "moduleType": 5} mods, err := aichangefacevidmod.GetAllModsByCond(cond) if err != nil { return res } if len(mods) > 0 { for i := range res.List { for _, m := range mods { if res.List[i].StyleType == m.StyleType { res.List[i].StyleUrl = m.Cover } } } } return res } type GenerateReq struct { Text string `json:"text"` // 绘图描述 StyleType int `json:"styleType"` // 绘图风格 AspectRatio string `json:"aspectRatio"` // 绘图比例 1:1,4:3,3:4,16:9,9:16 Coin int64 `json:"-"` // 此次脱衣金币个数 UID uint64 `json:"-"` // 用户ID ShareTitle string `json:"shareTitle"` // 分享标题 ShareStatus int `json:"shareStatus"` // 是否分享 0-不分享 1-分享 } func (p *GenerateReq) GenerateInfo(orderId primitive.ObjectID, orderCreatedAt time.Time, debitCoins, debitIncomeCoins int64) aitexttoimagemod.AiTextToImage { return aitexttoimagemod.AiTextToImage{ ID: orderId, Coin: debitIncomeCoins + debitCoins, DebitAmountCoin: debitCoins, DebitIncomeCoin: debitIncomeCoins, IsFreeTimes: false, Text: p.Text, StyleType: p.StyleType, AspectRatio: p.AspectRatio, UID: p.UID, Status: int(aitexttoimagemod.StatusOrderSuccess), IsHide: false, ShareTitle: p.ShareTitle, ShareStatus: p.ShareStatus, UpdatedAt: orderCreatedAt, CreatedAt: orderCreatedAt, } } // Generate 生成订单 func (p *GenerateReq) Generate(ua ua.UA, ip string) (stderr.Code, error) { // 获取用户信息 user, err := usermod.FindUserByUID(p.UID) if err != nil { return stderr.ErrDbQueryError, err } if user.ID.IsZero() { return stderr.UserIsNotExists, errors.New("user is null") } configure, _ := sysconfdata.GetAllFromCache() p.Coin = configure.GetInt(sysconfmod.VCodeAiTextToImagePrice) var debitAmountCoins, debitIncomeCoins int64 if p.Coin > 0 { // 获取用户钱包 w, err := walletmod.GetWallet(p.UID) if err != nil { return stderr.ErrDbQueryError, err } if w == nil { return stderr.InsufficientBalance, errors.New("Insufficient balance") } // 如果收费的部分余额不够支付 if p.Coin > (w.Amount + w.Income) { return stderr.InsufficientBalance, errors.New("Insufficient balance") } debitAmountCoins, debitIncomeCoins = TotalDebit(p.Coin, *w) } // 获取用户是否是复购 isRepurchase, err := txnmod.CheckRepurchaseByTransTypes(p.UID, []txnmod.TransType{ txnmod.AiTextToImageDebitGold, txnmod.AiTextToImageDebitInComeGold, }) if err != nil { log.Error("txnmod.CheckRepurchaseByTransTypes fail", log.E(err)) return stderr.ErrDbQueryError, err } var orderId primitive.ObjectID var orderCreatedAt time.Time if err = appg.VideoDB.Trans(func(tool *db.MongoTool) error { var tl []txnmod.TransactionLog if debitIncomeCoins > 0 || debitAmountCoins > 0 { // 扣除钱包余额 wallet, wErr := walletmod.DebitAmountAndIncome(tool, debitAmountCoins, debitIncomeCoins, p.UID) if wErr != nil { log.Error(fmt.Sprintf("Handle imagetovideo Generate walletmod.DebitAmount error:%+v:", wErr), log.Any("uid", p.UID)) return stderr.ErrDbQueryError } if debitAmountCoins > 0 { tl = append(tl, txnmod.TransactionLog{ TransNo: primitive.NewObjectID(), UID: p.UID, Amount: -debitAmountCoins, ActualAmount: float64(-debitAmountCoins), TranType: txnmod.AiTextToImageDebitGold.Key(), TranTypeInt: int64(txnmod.AiTextToImageDebitGold), Desc: fmt.Sprintf("生成AI绘图金币-%d", debitAmountCoins), RealAmount: walletmod.GetRealAmount(wallet), SysType: user.SysType, IsRepurchase: isRepurchase, }) } if debitIncomeCoins > 0 { tl = append(tl, txnmod.TransactionLog{ TransNo: primitive.NewObjectID(), UID: p.UID, Amount: -debitIncomeCoins, ActualAmount: float64(-debitIncomeCoins), TranType: txnmod.AiTextToImageDebitInComeGold.Key(), TranTypeInt: int64(txnmod.AiTextToImageDebitInComeGold), Desc: fmt.Sprintf("生成AI绘图收益金币-%d", debitIncomeCoins), RealAmount: walletmod.GetRealAmount(wallet), SysType: user.SysType, IsRepurchase: isRepurchase, }) } } if len(tl) > 0 { txnErr := txnmod.InsertManyTransactionLog(tool, tl) if txnErr != nil { log.Error(fmt.Sprintf("Handle imagetovideo Generate txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", p.UID)) return stderr.ErrDbQueryError } } // 新增AI图生视频记录 orderId = primitive.NewObjectID() orderCreatedAt = time.Now() order := p.GenerateInfo(orderId, orderCreatedAt, debitAmountCoins, debitIncomeCoins) if _, err = aitexttoimagemod.Insert(tool, order); err != nil { log.Error(fmt.Sprintf("Handle imagetovideo Generate InsertOnes error:%+v:", err), log.Any("uid", p.UID)) return stderr.ErrDbInsertError } return nil }); err != nil { log.Error(fmt.Sprintf("Handle imagetovideo Generate Trans error:%+v;uid:%v;", err, p.UID)) return stderr.ErrDbUpdateError, err } common.Go(func() { autoUploadOrder(orderId) }) return stderr.Success, nil } type AutoUploadReq struct { AppID int `json:"appId"` // 应用 ID UID uint64 `json:"uid"` // 用户 ID Text string `json:"text"` // 绘图描述 StyleType int `json:"styleType"` // 绘图风格 AspectRatio string `json:"aspectRatio"` // 绘图比例 1:1,4:3,3:4,16:9,9:16 AppOrderNum string `json:"appOrderNum"` // 应用订单号 NotifyURL string `json:"notifyUrl"` // 通知 URL } func autoUploadOrder(id primitive.ObjectID) error { item, err := aitexttoimagemod.GetInfo(id) if err != nil { return err } if item.ID.IsZero() { return errors.New(" aiimagetovideo order is null") } // 将请求参数编码为JSON requestBody := AutoUploadReq{ AppID: int(commod.KFK_APPID), UID: item.UID, Text: item.Text, AspectRatio: item.AspectRatio, StyleType: item.StyleType, AppOrderNum: item.ID.Hex(), NotifyURL: fmt.Sprintf("%v/api/web/admin/ai/text_to_image/callback", appg.Conf.URL.AiImageToVideoCallbackUrl), } jsonData, err := json.Marshal(requestBody) if err != nil { return err } apiURL := getAutoUploadUrl() // 创建请求对象 req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData)) if err != nil { return fmt.Errorf("创建请求失败: %v", err) } // 通过http.Client发送请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { return fmt.Errorf("请求失败: %v", err) } defer resp.Body.Close() // 读取响应内容 respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return fmt.Errorf("读取响应内容失败: %v", err) } // 如果返回状态码非200,可以考虑返回错误 if resp.StatusCode != http.StatusOK { return fmt.Errorf("请求失败,状态码:%d,内容:%s", resp.StatusCode, string(respBytes)) } // 更新订单 updateCond := bson.M{ "status": aitexttoimagemod.StatusSubmitted, "updatedAt": time.Now(), } _, err = aitexttoimagemod.UpdateByID(nil, id, updateCond) if err != nil { return err } return nil } func getAutoUploadUrl() string { return fmt.Sprintf("%v/api/comfyui/prd/create_text_job", appg.Conf.URL.AiImageToVideoUrl) } func TotalDebit(price int64, w walletmod.Wallet) (amountCoins, incomeCoins int64) { var ( debitAmountCoins int64 debitIncomeCoins int64 ) // 计算当日实际扣减的金额 debitCoins := price if w.Amount >= debitCoins { debitAmountCoins = debitCoins } else { debitAmountCoins = w.Amount debitIncomeCoins = debitCoins - w.Amount } return debitAmountCoins, debitIncomeCoins } type HideReq struct { ID string `json:"id"` // AI订单ID UID uint64 `json:"-"` // 用户ID } // Hide 删除订单 func (p *HideReq) Hide() error { oid, err := primitive.ObjectIDFromHex(p.ID) if err != nil { return err } item, err := aitexttoimagemod.GetInfo(oid) if err != nil { log.Error("获取AI绘图列表详情数据错误", log.Any("ID", p.ID), log.E(err)) return err } if item.ID.IsZero() { return errors.New("AI订单不存在") } if item.UID != p.UID { return errors.New("只能删除自己的订单") } if err = validateHideStatus(item.Status); err != nil { return err } if err = aitexttoimagemod.Hide(p.UID, oid); err != nil { return err } return nil } func validateHideStatus(status int) error { if status == int(aitexttoimagemod.StatusOrderSuccess) || status == int(aitexttoimagemod.StatusSubmitted) { return stderr.AiGenningDelForbidden } return nil }