541 lines
16 KiB
Go
541 lines
16 KiB
Go
package ai_changeface_ser
|
|
|
|
import (
|
|
"91porn-server/common"
|
|
"91porn-server/common/db"
|
|
"91porn-server/common/httputil"
|
|
"91porn-server/common/log"
|
|
"91porn-server/common/stderr"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/models/v/aichangefacemod"
|
|
"91porn-server/models/v/aichangefacevidmod"
|
|
"91porn-server/models/v/aiplazamod"
|
|
"91porn-server/models/v/backpackmod"
|
|
"91porn-server/models/v/txnmod"
|
|
"91porn-server/models/v/walletmod"
|
|
"91porn-server/web/proto"
|
|
"91porn-server/web/webg"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
func List(id *primitive.ObjectID, req *aichangefacemod.ListRequest) ([]aichangefacemod.AiChangeFaceWebResp, int64, bool, error) {
|
|
limit := req.Limit()
|
|
acfs, count, err := aichangefacemod.WebList(id, req.Uid, req.Status, req.VidID, int(req.Skip()), int(limit+1))
|
|
if err != nil {
|
|
return nil, 0, false, err
|
|
}
|
|
hasNext := false
|
|
if len(acfs) > int(limit) {
|
|
acfs = acfs[:limit]
|
|
hasNext = true
|
|
}
|
|
acfsLen := len(acfs)
|
|
acfwrs := make([]aichangefacemod.AiChangeFaceWebResp, acfsLen)
|
|
for i, v := range acfs {
|
|
acfwrs[i] = aichangefacemod.AiChangeFaceWebResp{
|
|
ID: v.ID,
|
|
Uid: v.Uid,
|
|
Pic: v.Pic,
|
|
ModId: v.VidID,
|
|
ModUrl: v.ModVideo,
|
|
ModTitle: v.ModTitle,
|
|
Coin: v.Coin,
|
|
IncomeCoin: v.IncomeCoin,
|
|
Status: v.Status,
|
|
Cover: v.Cover,
|
|
Url: v.Url,
|
|
Remark: v.Remark,
|
|
Operator: v.Operator,
|
|
CreatedAt: v.CreatedAt,
|
|
UpdatedAt: v.UpdatedAt,
|
|
}
|
|
}
|
|
return acfwrs, count, hasNext, nil
|
|
}
|
|
|
|
func Update(act string, req *aichangefacemod.EditAiChangeFace) stderr.Code {
|
|
// 获取Ai记录
|
|
data, err := aichangefacemod.FindByID(nil, req.ID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
|
|
// 如果已经退款,直接返回,避免重复扣款
|
|
if *req.Status == aichangefacemod.StatusRefund && data.Status == aichangefacemod.StatusRefund {
|
|
return stderr.Success
|
|
}
|
|
|
|
switch *req.Status {
|
|
case aichangefacemod.StatusGenning: // 未完成或完成
|
|
if err = aichangefacemod.Update(nil, req.ID, req.Update(act)); err != nil {
|
|
return stderr.ErrDbUpdateError
|
|
}
|
|
return stderr.Success
|
|
case aichangefacemod.StatusComplete:
|
|
if req.Url == nil || *req.Url == "" {
|
|
return stderr.ChangeFaceSuccessWithoutUrl
|
|
}
|
|
if err = aichangefacemod.Update(nil, req.ID, req.Update(act)); err != nil {
|
|
return stderr.ErrDbUpdateError
|
|
}
|
|
return stderr.Success
|
|
case aichangefacemod.StatusRefund: // 退款
|
|
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
|
|
var tl []txnmod.TransactionLog
|
|
updateSet, _ := req.Update(act)["$set"].(bson.M)
|
|
transitioned, transitionErr := aichangefacemod.TransitionStatus(t, req.ID, data.Status, aichangefacemod.StatusRefund, updateSet)
|
|
if transitionErr != nil {
|
|
return transitionErr
|
|
}
|
|
if !transitioned {
|
|
return nil
|
|
}
|
|
|
|
// 折扣券返还
|
|
if len(data.Discount) > 0 {
|
|
if _, err = backpackmod.UnuseManyGoods(t, data.Discount); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if data.Coin > 0 || data.IncomeCoin > 0 {
|
|
// 退款进入钱包余额
|
|
wallet, err := walletmod.ReturnAmountAndIncome(t, -data.Coin, -data.IncomeCoin, data.Uid)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("Handle AiUnDress Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", data.Uid))
|
|
return err
|
|
}
|
|
|
|
if data.Coin > 0 {
|
|
tl = append(tl, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: data.Uid,
|
|
Amount: data.Coin,
|
|
ActualAmount: float64(data.Coin),
|
|
TranType: txnmod.AiChangefaceDebitGoldReturn.Key(),
|
|
TranTypeInt: int64(txnmod.AiChangefaceDebitGoldReturn),
|
|
Desc: fmt.Sprintf("AI换脸金币退返-%d", data.Coin),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
|
|
if data.IncomeCoin > 0 {
|
|
tl = append(tl, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: data.Uid,
|
|
Amount: data.IncomeCoin,
|
|
ActualAmount: float64(data.IncomeCoin),
|
|
TranType: txnmod.AiChangefaceDebitIncomeGoldReturn.Key(),
|
|
TranTypeInt: int64(txnmod.AiChangefaceDebitIncomeGoldReturn),
|
|
Desc: fmt.Sprintf("AI换收益金币退返-%d", data.IncomeCoin),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
}
|
|
|
|
if len(tl) > 0 {
|
|
txnErr := txnmod.InsertManyTransactionLog(t, tl)
|
|
if txnErr != nil {
|
|
log.Error(fmt.Sprintf("Handle AiChangeface Generate txnmod.InsertManyTransactionLog 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 stderr.Success
|
|
default:
|
|
return stderr.ErrParamError
|
|
}
|
|
}
|
|
|
|
func UpdateNew(act string, req *aichangefacemod.EditAiChangeFace) stderr.Code {
|
|
// 获取Ai记录
|
|
data, err := aichangefacemod.FindByID(nil, req.ID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
if *req.Status == aichangefacemod.StatusSubmit && data.Status == aichangefacemod.StatusSubmit {
|
|
return stderr.Success
|
|
}
|
|
if *req.Status == aichangefacemod.StatusRefund && data.Status == aichangefacemod.StatusRefund {
|
|
return stderr.Success
|
|
}
|
|
set := bson.M{}
|
|
set["status"] = req.Status
|
|
if req.Cover != nil {
|
|
set["cover"] = strings.TrimSpace(*req.Cover)
|
|
}
|
|
if req.Url != nil {
|
|
set["url"] = strings.TrimSpace(*req.Url)
|
|
}
|
|
if req.Remark != nil {
|
|
set["remark"] = *req.Remark
|
|
}
|
|
if len(set) == 0 { // 没有做任何修改
|
|
return stderr.Success
|
|
}
|
|
set["operator"] = act // 记录操作员
|
|
set["updatedAt"] = time.Now()
|
|
switch *req.Status {
|
|
case aichangefacemod.StatusGenning: // 未完成或完成
|
|
if err = aichangefacemod.Update(nil, req.ID, bson.M{"$set": set}); err != nil {
|
|
return stderr.ErrDbUpdateError
|
|
}
|
|
case aichangefacemod.StatusSubmit:
|
|
//提交订单到第三方
|
|
notifyURL, notifyErr := webg.AICallbackURL("/api/web/admin/ai/changeface/callback")
|
|
if notifyErr != nil {
|
|
log.Error("AI视频换脸回调地址配置异常", log.E(notifyErr))
|
|
return stderr.Failure
|
|
}
|
|
httpReq := proto.AiChangeFaceReq{
|
|
AppId: int(commod.KFK_APPID),
|
|
OrderNumAPP: data.ID.Hex(),
|
|
Title: data.ModTitle,
|
|
SourceImageUrl: data.Pic[0],
|
|
NotifyUrl: notifyURL,
|
|
}
|
|
url := webg.Conf.URL.AiServer + "/api/changeface/prd/changeFaceByVideo"
|
|
//第三方请求地址
|
|
var resp proto.AiChangeFaceResp
|
|
codeJ, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, httpReq)
|
|
if err != nil {
|
|
log.Error("CreateChangeFace httputil.DefaultClientPostJsonWithResp err", log.E(err))
|
|
return stderr.Failure
|
|
}
|
|
if codeJ != 200 {
|
|
log.Error("CreateChangeFace req http code error", log.Any("code", codeJ))
|
|
return stderr.Failure
|
|
}
|
|
if resp.Code == 40000 {
|
|
return stderr.ChangeFaceNoModule
|
|
}
|
|
if err = aichangefacemod.Update(nil, req.ID, bson.M{"$set": set}); err != nil {
|
|
return stderr.ErrDbUpdateError
|
|
}
|
|
case aichangefacemod.StatusRefund: // 退款
|
|
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
|
|
transitioned, transitionErr := aichangefacemod.TransitionStatus(t, req.ID, data.Status, aichangefacemod.StatusRefund, set)
|
|
if transitionErr != nil {
|
|
return transitionErr
|
|
}
|
|
if !transitioned {
|
|
return nil
|
|
}
|
|
// 折扣券返还
|
|
if len(data.Discount) > 0 {
|
|
if _, err = backpackmod.UnuseManyGoods(t, data.Discount); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// 退款
|
|
if data.Coin == 0 && data.IncomeCoin == 0 { // 总金额为0则不需要退款
|
|
return nil
|
|
}
|
|
// 退款进入钱包余额
|
|
wallet, err := walletmod.ReturnAmountAndIncome(t, -data.Coin, -data.IncomeCoin, data.Uid)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("Handle AiUnDress Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", data.Uid))
|
|
return err
|
|
}
|
|
// 添加退款记录
|
|
totalCoin := data.Coin + data.IncomeCoin
|
|
if err = txnmod.InsertTransactionLog(t, &txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: data.Uid,
|
|
Amount: totalCoin,
|
|
ActualAmount: float64(totalCoin),
|
|
TranType: txnmod.AiChangefaceDebitGoldReturn.Key(),
|
|
TranTypeInt: int64(txnmod.AiChangefaceDebitGoldReturn),
|
|
Desc: fmt.Sprintf("AI换脸金币退返-%d", totalCoin),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
}); err != nil {
|
|
log.Error(fmt.Sprintf("Handle AiChangeface Edit txnmod.InsertTransactionLog error:%+v:", err), log.Any("uid", data.Uid))
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
if e, ok := err.(stderr.Code); ok {
|
|
return e
|
|
}
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
default:
|
|
return stderr.ErrParamError
|
|
}
|
|
return stderr.Success
|
|
}
|
|
|
|
func AddMod(acfv aichangefacevidmod.AddAiChangeFaceVidReq) error {
|
|
now := time.Now()
|
|
return aichangefacevidmod.AddAiChangeFaceVid(aichangefacevidmod.AiChangeFaceVidMod{
|
|
Title: acfv.Title,
|
|
SourceURL: acfv.SourceURL,
|
|
Status: acfv.Status,
|
|
PlayTime: acfv.PlayTime,
|
|
Cover: acfv.Cover,
|
|
Type: acfv.Type,
|
|
NewUrl: acfv.NewUrl,
|
|
Coin: acfv.Coin,
|
|
VipCoin: acfv.VipCoin,
|
|
StyleType: acfv.StyleType,
|
|
ModuleType: acfv.ModuleType,
|
|
HotMark: acfv.HotMark,
|
|
HotValue: acfv.HotValue,
|
|
Sort: acfv.Sort,
|
|
SceneType: acfv.SceneType,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
})
|
|
}
|
|
|
|
func UpdateMod(eacfv aichangefacevidmod.EditAiChangeFaceVid) error {
|
|
set := bson.M{}
|
|
if eacfv.Title != nil {
|
|
set["title"] = *eacfv.Title
|
|
}
|
|
if eacfv.SourceURL != nil {
|
|
set["sourceURL"] = *eacfv.SourceURL
|
|
}
|
|
if eacfv.Status != nil {
|
|
set["status"] = *eacfv.Status
|
|
}
|
|
if eacfv.NewUrl != nil {
|
|
set["newUrl"] = *eacfv.NewUrl
|
|
}
|
|
if eacfv.PlayTime != nil {
|
|
set["playTime"] = *eacfv.PlayTime
|
|
}
|
|
if eacfv.Cover != nil {
|
|
set["cover"] = *eacfv.Cover
|
|
}
|
|
if eacfv.Type != nil {
|
|
set["type"] = *eacfv.Type
|
|
}
|
|
if eacfv.Coin != nil {
|
|
set["coin"] = *eacfv.Coin
|
|
}
|
|
if eacfv.VipCoin != nil {
|
|
set["vipCoin"] = *eacfv.VipCoin
|
|
}
|
|
if eacfv.ModuleType != nil {
|
|
set["moduleType"] = *eacfv.ModuleType
|
|
}
|
|
if eacfv.HotValue != nil {
|
|
set["hotValue"] = *eacfv.HotValue
|
|
}
|
|
if eacfv.HotMark != nil {
|
|
set["hotMark"] = *eacfv.HotMark
|
|
}
|
|
if eacfv.Sort != nil {
|
|
set["sort"] = *eacfv.Sort
|
|
}
|
|
if eacfv.SceneType != nil {
|
|
set["sceneType"] = *eacfv.SceneType
|
|
}
|
|
if len(set) == 0 {
|
|
return nil
|
|
}
|
|
set["updatedAt"] = time.Now()
|
|
return aichangefacevidmod.UpdateAiChangeFaceVid(eacfv.ID, bson.M{"$set": set})
|
|
}
|
|
|
|
func ModList(req *aichangefacevidmod.WebListRequest) (interface{}, stderr.Code) {
|
|
var (
|
|
data = map[string]interface{}{
|
|
"list": []interface{}{},
|
|
"count": 0,
|
|
}
|
|
err error
|
|
)
|
|
|
|
if err != nil {
|
|
return nil, stderr.ErrParamError
|
|
}
|
|
count, err := aichangefacevidmod.CountDocument(req.Filter())
|
|
if err != nil {
|
|
return nil, stderr.ErrDbQueryError
|
|
}
|
|
if count == 0 {
|
|
return data, stderr.Success
|
|
}
|
|
list, err := aichangefacevidmod.QueryAllDocument(req.Filter(), req.Options())
|
|
if err != nil {
|
|
return data, stderr.ErrDbQueryError
|
|
}
|
|
data["count"] = count
|
|
data["list"] = list
|
|
return data, stderr.Success
|
|
}
|
|
|
|
func CallBackOrder(req *aichangefacevidmod.CallbackReq) stderr.Code {
|
|
//根据订单号更新ai换脸订单
|
|
id, _ := primitive.ObjectIDFromHex(req.AppOrderNum)
|
|
//查询该笔订单是否存在
|
|
aichangeFaceInfo, err := aichangefacemod.FindByID(nil, id)
|
|
if aichangeFaceInfo == nil || err != nil {
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
oldOrderTime := time.Date(2025, 9, 15, 0, 0, 0, 0, time.Local)
|
|
if aichangeFaceInfo.CreatedAt.Before(oldOrderTime) &&
|
|
(aichangeFaceInfo.Status == aichangefacemod.StatusComplete || aichangeFaceInfo.Status == aichangefacemod.StatusRefund) {
|
|
// 以前的单子如果处理过了就新下资源和状态
|
|
set := bson.M{"url": strings.TrimSpace(req.ImgUrl)}
|
|
if req.Msg == "操作成功" {
|
|
set["status"] = aichangefacemod.StatusComplete
|
|
} else {
|
|
set["remark"] = req.Msg
|
|
set["status"] = aichangefacemod.StatusRefund
|
|
}
|
|
_ = aichangefacemod.Update(nil, id, bson.M{"$set": set})
|
|
|
|
return stderr.Success
|
|
}
|
|
if aichangeFaceInfo.Status != aichangefacemod.StatusSubmit {
|
|
log.Error("AI视频换脸-重复回调或者状态不正确", log.Any("id", aichangeFaceInfo.ID.Hex()), log.Any("status", aichangeFaceInfo.Status))
|
|
return stderr.Success
|
|
}
|
|
|
|
var status = aichangefacemod.StatusComplete
|
|
//处理金币退款以及后续操作
|
|
set := bson.M{}
|
|
if req.ImgUrl != "" {
|
|
set["url"] = strings.TrimSpace(req.ImgUrl)
|
|
}
|
|
if req.Msg != "操作成功" {
|
|
set["remark"] = req.Msg
|
|
status = aichangefacemod.StatusRefund
|
|
}
|
|
set["status"] = status
|
|
set["updatedAt"] = time.Now()
|
|
switch status {
|
|
case aichangefacemod.StatusComplete:
|
|
transitioned, updateErr := aichangefacemod.TransitionStatus(nil, id, aichangefacemod.StatusSubmit, aichangefacemod.StatusComplete, set)
|
|
if updateErr != nil {
|
|
return stderr.ErrDbUpdateError
|
|
}
|
|
if !transitioned {
|
|
return stderr.Success
|
|
}
|
|
common.Go(func() {
|
|
if aichangeFaceInfo.ShareStatus != 1 {
|
|
return
|
|
}
|
|
// 新增一个分享
|
|
alPlaza := aiplazamod.AiPlaza{
|
|
Type: 2,
|
|
OrderId: aichangeFaceInfo.ID,
|
|
Template: aichangeFaceInfo.VidID.Hex(),
|
|
Uid: aichangeFaceInfo.Uid,
|
|
Title: aichangeFaceInfo.ShareTitle,
|
|
OriginalImage: "",
|
|
OriginalVideo: aichangeFaceInfo.ModVideo,
|
|
OriginalVideoCover: aichangeFaceInfo.ModCover,
|
|
OriginContent: "",
|
|
GenerateVideo: req.ImgUrl,
|
|
GenerateVideoCover: aichangeFaceInfo.Pic[0],
|
|
Status: aiplazamod.DefaultStatus,
|
|
}
|
|
if len(aichangeFaceInfo.Pic) > 0 {
|
|
alPlaza.GenerateVideoCover = aichangeFaceInfo.Pic[0]
|
|
}
|
|
_, err = aiplazamod.Insert(nil, alPlaza)
|
|
if err != nil {
|
|
log.Error("新增ai广场帖子失败", log.Any("alPlaza", alPlaza), log.E(err))
|
|
return
|
|
}
|
|
})
|
|
return stderr.Success
|
|
case aichangefacemod.StatusRefund: // 退款
|
|
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
|
|
transitioned, transitionErr := aichangefacemod.TransitionStatus(t, id, aichangefacemod.StatusSubmit, aichangefacemod.StatusRefund, set)
|
|
if transitionErr != nil {
|
|
return transitionErr
|
|
}
|
|
if !transitioned {
|
|
return nil
|
|
}
|
|
// 折扣券返还
|
|
if len(aichangeFaceInfo.Discount) > 0 {
|
|
if _, err = backpackmod.UnuseManyGoods(t, aichangeFaceInfo.Discount); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// 退款
|
|
if aichangeFaceInfo.Coin == 0 && aichangeFaceInfo.IncomeCoin == 0 { // 总金额为0则不需要退款
|
|
return nil
|
|
}
|
|
// 退款进入钱包余额
|
|
wallet, err := walletmod.ReturnAmountAndIncome(t, -aichangeFaceInfo.Coin, -aichangeFaceInfo.IncomeCoin, aichangeFaceInfo.Uid)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("Handle AiUnDress Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", aichangeFaceInfo.Uid))
|
|
return err
|
|
}
|
|
// 添加退款记录
|
|
totalCoin := aichangeFaceInfo.Coin + aichangeFaceInfo.IncomeCoin
|
|
if err = txnmod.InsertTransactionLog(t, &txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: aichangeFaceInfo.Uid,
|
|
Amount: totalCoin,
|
|
ActualAmount: float64(totalCoin),
|
|
TranType: txnmod.AiChangefaceDebitGoldReturn.Key(),
|
|
TranTypeInt: int64(txnmod.AiChangefaceDebitGoldReturn),
|
|
Desc: fmt.Sprintf("AI换脸金币退返-%d", totalCoin),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
}); err != nil {
|
|
log.Error(fmt.Sprintf("Handle AiChangeface Edit txnmod.InsertTransactionLog error:%+v:", err), log.Any("uid", aichangeFaceInfo.Uid))
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
if e, ok := err.(stderr.Code); ok {
|
|
return e
|
|
}
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
return stderr.Success
|
|
default:
|
|
return stderr.ErrParamError
|
|
}
|
|
}
|
|
|
|
type BatchUpdateReq struct {
|
|
IDS []string `json:"ids" bson:"ids"` // AI模版IDS
|
|
MID string `json:"mid" bson:"mid"` // 模块ID
|
|
}
|
|
|
|
func (q *BatchUpdateReq) Filter() primitive.M {
|
|
filter := bson.M{}
|
|
var ids []primitive.ObjectID
|
|
for _, id := range q.IDS {
|
|
objectID, _ := primitive.ObjectIDFromHex(id)
|
|
ids = append(ids, objectID)
|
|
}
|
|
|
|
if len(ids) > 0 {
|
|
filter["_id"] = bson.M{"$in": ids}
|
|
}
|
|
return filter
|
|
}
|
|
|
|
func (q *BatchUpdateReq) UpdateCond() primitive.M {
|
|
cond := bson.M{}
|
|
cond["mid"] = q.MID
|
|
cond["updatedAt"] = time.Now()
|
|
return cond
|
|
}
|
|
|
|
func (q *BatchUpdateReq) BatchUpdateMod() error {
|
|
return aichangefacevidmod.UpdateManyByCond(q.Filter(), bson.M{"$set": q.UpdateCond()})
|
|
}
|