package ai_undress_server import ( "91porn-server/app/appg" "91porn-server/app/service/aiautoser" "91porn-server/common" "91porn-server/common/constant/redisconst" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/common/stderr" "91porn-server/middleware/ua" "91porn-server/models/cache/sysconfdata" "91porn-server/models/v/advanceordermod" "91porn-server/models/v/aiUnDressmod" "91porn-server/models/v/sysconfmod" "91porn-server/models/v/txnmod" "91porn-server/models/v/usermod" "91porn-server/models/v/walletmod" "fmt" "strconv" "time" "github.com/go-redis/redis" carbon "github.com/golang-module/carbon/v2" "github.com/shopspring/decimal" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" ) func List(uid uint64, req *aiUnDressmod.ListRequest) (interface{}, stderr.Code) { var data = map[string]interface{}{ "list": []interface{}{}, "count": 0, } count, err := aiUnDressmod.CountDocument(req.Filter(uid)) if err != nil { return nil, stderr.ErrDbQueryError } if count == 0 { return data, stderr.Success } opts := options.Find().SetSkip(int64(req.Skip())).SetLimit(int64(req.Limit() + 1)).SetSort(bson.M{"updatedAt": -1}) list, err := aiUnDressmod.QueryAllDocument(req.Filter(uid), opts) if err != nil { return data, stderr.ErrDbQueryError } hasNext := false if len(list) > int(req.Limit()) { list = list[:req.Limit()] hasNext = true } data["count"] = count // 兼容旧版本 data["hasNext"] = hasNext data["list"] = list return data, stderr.Success } func Generate(uid uint64, req *aiUnDressmod.GenerateRequest, ua ua.UA, ip string) stderr.Code { if req.OriginPic == nil || len(req.OriginPic) == 0 { return stderr.ErrParamError } // 获取用户信息 user, err := usermod.FindUserByUID(uid) if err != nil { return stderr.ErrDbQueryError } if user.ID.IsZero() { return stderr.UserIsNotExists } configure, _ := sysconfdata.GetAllFromCache() req.Coin = configure.GetInt(sysconfmod.VCodeAiUndressPrice) picCount := int64(len(req.OriginPic)) privilegeFreeCount := int64(0) // 获取用户是否是复购 isRepurchase, err := txnmod.CheckRepurchaseByTransTypes(uid, []txnmod.TransType{ txnmod.AiUndressDebitFreeTimes, txnmod.AiUndressDebitGold, txnmod.AiUndressDebitIncomeGold, }) if err != nil { log.Error("txnmod.CheckRepurchaseByTransTypes fail", log.E(err)) return stderr.ErrDbQueryError } hasPrivilege, advance := advanceordermod.GetUserValidOrder(uid) if hasPrivilege { // 获取可用免费次数 validCount := advance.PrepaidPrivilege.AiUndressLimitPerDay - advance.TodayUse.AiUndressCount if validCount >= picCount { // 扣除免费次数 debitPlan := advanceordermod.DebitPlan{} debitPlan.AiUndressCount = &picCount if err := advanceordermod.Debit(nil, uid, debitPlan); err != nil { return stderr.ErrDbUpdateError } privilegeFreeCount = picCount picCount = 0 } else if validCount > 0 { // 扣除免费次数 debitPlan := advanceordermod.DebitPlan{} debitPlan.AiUndressCount = &validCount if err := advanceordermod.Debit(nil, uid, debitPlan); err != nil { return stderr.ErrDbUpdateError } privilegeFreeCount = validCount picCount -= validCount } if validCount > 0 { l := &txnmod.TransactionLog{ TransNo: primitive.NewObjectID(), UID: uid, Amount: 1, ActualAmount: float64(-1), TranType: txnmod.AiUndressDebitFreeTimes.Key(), TranTypeInt: int64(txnmod.AiUndressDebitFreeTimes), Desc: fmt.Sprintf("生成AI脱衣扣除免费次数[%d次]", privilegeFreeCount), RealAmount: decimal.Decimal{}, SysType: user.SysType, IsRepurchase: isRepurchase, } txnErr := txnmod.InsertTransactionLog(nil, l) if txnErr != nil { log.Error(fmt.Sprintf("Handle AiUnDress Generate txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", uid)) return stderr.ErrDbQueryError } } } var debitFreeCount, debitAmountCoins, debitIncomeCoins int64 if picCount > 0 { // 获取用户钱包 w, err := walletmod.GetWallet(uid) if err != nil { return stderr.ErrDbQueryError } // 校验用户余额 if w == nil || !CheckBalance(req.Coin, picCount, *w) { return stderr.InsufficientBalance } debitFreeCount, debitAmountCoins, debitIncomeCoins = TotalDebit(req.Coin, picCount, *w) if w.AiUndressFreeTimes > 0 { req.IsFreeTimes = true } } var orderId primitive.ObjectID var orderCreatedAt time.Time if err = appg.VideoDB.Trans(func(tool *db.MongoTool) error { var tl []txnmod.TransactionLog if debitFreeCount > 0 { expire := carbon.Tomorrow().StartOfDay().StdTime().Sub(time.Now()) // 累加次数 appg.Redis.IncrBy(redisconst.AiFreeUndressTodayUseTimesKey(uid), debitFreeCount, expire) // 扣除钱剩余次数 wallet, wErr := walletmod.DebitAiFreeTimes(tool, debitFreeCount, uid) if wErr != nil { log.Error(fmt.Sprintf("Handle AiUnDress Generate walletmod.DebitAiFreeTimes error:%+v:", wErr), log.Any("uid", uid)) return stderr.ErrDbQueryError } tl = append(tl, txnmod.TransactionLog{ TransNo: primitive.NewObjectID(), UID: uid, Amount: 1, ActualAmount: float64(-1), TranType: txnmod.AiUndressDebitFreeTimes.Key(), TranTypeInt: int64(txnmod.AiUndressDebitFreeTimes), Desc: fmt.Sprintf("生成AI脱衣扣除免费次数[%d次]", debitFreeCount), RealAmount: walletmod.GetRealAmount(wallet), SysType: user.SysType, IsRepurchase: isRepurchase, }) } if debitIncomeCoins > 0 || debitAmountCoins > 0 { // 扣除钱包余额 wallet, wErr := walletmod.DebitAmountAndIncome(tool, debitAmountCoins, debitIncomeCoins, uid) if wErr != nil { log.Error(fmt.Sprintf("Handle AiUnDress Generate walletmod.DebitAmount error:%+v:", wErr), log.Any("uid", uid)) return stderr.ErrDbQueryError } if debitAmountCoins > 0 { tl = append(tl, txnmod.TransactionLog{ TransNo: primitive.NewObjectID(), UID: uid, Amount: -debitAmountCoins, ActualAmount: float64(-debitAmountCoins), TranType: txnmod.AiUndressDebitGold.Key(), TranTypeInt: int64(txnmod.AiUndressDebitGold), 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: uid, Amount: -debitIncomeCoins, ActualAmount: float64(-debitIncomeCoins), TranType: txnmod.AiUndressDebitIncomeGold.Key(), TranTypeInt: int64(txnmod.AiUndressDebitIncomeGold), 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 AiUnDress Generate txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", uid)) return stderr.ErrDbQueryError } } // 新增AI脱衣记录 orderId = primitive.NewObjectID() orderCreatedAt = time.Now() if err := aiUnDressmod.InsertMany(tool, req.GenerateMany(orderId, orderCreatedAt, uid, privilegeFreeCount, debitFreeCount, debitAmountCoins, debitIncomeCoins, req.Coin, req.ShareTitle, req.ShareStatus)); err != nil { log.Error(fmt.Sprintf("Handle AiUnDress Generate InsertOnes error:%+v:", err), log.Any("uid", uid)) return stderr.ErrDbInsertError } return nil }); err != nil { log.Error(fmt.Sprintf("Handle AiUnDress Generate Trans error:%+v;uid:%v;", err, uid)) return stderr.ErrDbUpdateError } common.Go(func() { if err := aiautoser.SubmitUndress(orderId); err != nil { log.Error("AI脱衣自动处理失败", log.Any("id", orderId.Hex()), log.E(err)) } }) return stderr.Success } func AiUndressHide(uid uint64, req *aiUnDressmod.DelRequest) stderr.Code { acf, err := aiUnDressmod.FindByID(nil, req.ID) if err != nil { return stderr.ErrDbQueryError } if acf.ID.IsZero() { return stderr.CodeEmptyData } if acf.UID != uid { return stderr.Failure } if acf.Status == aiUnDressmod.Processing || acf.Status == aiUnDressmod.SubmitOrder { return stderr.AiGenningDelForbidden } if err = aiUnDressmod.Edit(nil, req.Filter(), req.Update()); err != nil { return stderr.ErrDbQueryError } return stderr.Success } func TotalDebit(price int64, count int64, w walletmod.Wallet) (fCount, amountCoins, incomeCoins int64) { var ( debitFreeTimes int64 debitAmountCoins int64 debitIncomeCoins int64 ) // 当日剩余ai免费脱衣次数 todayAiUndressFreeTimes := GetTodayRemainingAiFreeUndressTimes(w) // 实际使用的免费脱衣次数 if todayAiUndressFreeTimes >= count { return count, 0, 0 } debitFreeTimes = todayAiUndressFreeTimes // 计算当日实际扣减的金额 debitCoins := (count - debitFreeTimes) * price if w.Amount >= debitCoins { debitAmountCoins = debitCoins } else { debitAmountCoins = w.Amount debitIncomeCoins = debitCoins - w.Amount } return debitFreeTimes, debitAmountCoins, debitIncomeCoins } // GetTodayRemainingAiFreeUndressTimes 获取当日剩余的免费ai脱衣的次数 func GetTodayRemainingAiFreeUndressTimes(w walletmod.Wallet) (num int64) { var todayUseAiUndressFreeTimes int // 当日已使用的免费ai脱衣次数 //获取当日已经使用的ai免费脱衣次数 str, err := appg.Redis.Get(redisconst.AiFreeUndressTodayUseTimesKey(w.UID)) if err != nil && err != redis.Nil { log.Error(fmt.Sprintf("get AiUndressTodayUseTimes err%v", err)) // redis报错返回已经当日最大限制次数,避免被刷 todayUseAiUndressFreeTimes = 0 } else if str != nil { todayUseAiUndressFreeTimes, _ = strconv.Atoi(*str) } num = int64(appg.Conf.AiFreeUnDressDailyLimit - todayUseAiUndressFreeTimes) // 如果用户剩余的免费次数不足,以剩余次数为准 if num >= w.AiUndressFreeTimes { num = w.AiUndressFreeTimes } if num < 0 { num = 0 } return } func CheckBalance(price int64, count int64, w walletmod.Wallet) bool { var checkStats bool var totalCoins = w.Amount if w.Income != 0 { totalCoins += w.Income } if w.AiUndressFreeTimes > 0 && w.AiUndressFreeTimes >= count { checkStats = true } if w.AiUndressFreeTimes > 0 && w.AiUndressFreeTimes < count && totalCoins >= price*(count-w.AiUndressFreeTimes) { checkStats = true } if w.AiUndressFreeTimes <= 0 && totalCoins >= price*count { checkStats = true } return checkStats }