330 lines
11 KiB
Go
330 lines
11 KiB
Go
package aiautoser
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common"
|
|
"91porn-server/common/db"
|
|
"91porn-server/common/httputil"
|
|
"91porn-server/common/log"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/models/v/aiUnDressmod"
|
|
"91porn-server/models/v/aichangefaceimgmod"
|
|
"91porn-server/models/v/aichangefacemod"
|
|
"91porn-server/models/v/backpackmod"
|
|
"91porn-server/models/v/txnmod"
|
|
"91porn-server/models/v/walletmod"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
const autoOperator = "AI_AUTO"
|
|
|
|
type changeFaceRequest struct {
|
|
AppID int `json:"app_id"`
|
|
OrderNumApp string `json:"order_num_app"`
|
|
Title string `json:"title"`
|
|
SourceImageURL string `json:"source_image_url"`
|
|
NotifyURL string `json:"notify_url"`
|
|
}
|
|
|
|
type changeFaceResponse struct {
|
|
Code int `json:"code"`
|
|
}
|
|
|
|
// SubmitVideo automatically approves and submits an AI video face-swap order.
|
|
// Submission failures are handled with the same refund policy as the existing
|
|
// Web callback flow.
|
|
func SubmitVideo(id primitive.ObjectID) error {
|
|
order, err := aichangefacemod.FindByID(nil, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aichangefacemod.TransitionStatus(nil, id, aichangefacemod.StatusGenning, aichangefacemod.StatusSubmit, bson.M{
|
|
"operator": autoOperator,
|
|
"remark": "已自动提交",
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
|
|
notifyURL, notifyErr := appg.AICallbackURL("/api/web/admin/ai/changeface/callback")
|
|
if notifyErr != nil || len(order.Pic) == 0 || order.Pic[0] == "" || appg.Conf.URL.AiServer == "" {
|
|
return refundVideo(id, "自动提交参数不完整")
|
|
}
|
|
req := changeFaceRequest{
|
|
AppID: int(commod.KFK_APPID),
|
|
OrderNumApp: id.Hex(),
|
|
Title: order.ModTitle,
|
|
SourceImageURL: order.Pic[0],
|
|
NotifyURL: notifyURL,
|
|
}
|
|
if err := postChangeFace(req); err != nil {
|
|
log.Error("AI视频换脸自动提交失败", log.Any("id", id.Hex()), log.E(err))
|
|
return refundVideo(id, err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SubmitImage automatically approves and submits an AI image face-swap order.
|
|
func SubmitImage(id primitive.ObjectID) error {
|
|
order, err := aichangefaceimgmod.FindByID(nil, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aichangefaceimgmod.TransitionStatus(nil, id, aichangefaceimgmod.Processing, aichangefaceimgmod.StatusSubmit, bson.M{
|
|
"updateAct": autoOperator,
|
|
"remark": "已自动提交",
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
|
|
notifyURL, notifyErr := appg.AICallbackURL("/api/web/admin/ai/change_face_img/callback")
|
|
if notifyErr != nil || order.OriginPic == "" || appg.Conf.URL.AiServer == "" {
|
|
return refundImage(id, "自动提交参数不完整")
|
|
}
|
|
req := changeFaceRequest{
|
|
AppID: int(commod.KFK_APPID),
|
|
OrderNumApp: id.Hex(),
|
|
Title: order.ModTitle,
|
|
SourceImageURL: order.OriginPic,
|
|
NotifyURL: notifyURL,
|
|
}
|
|
if err := postChangeFace(req); err != nil {
|
|
log.Error("AI图片换脸自动提交失败", log.Any("id", id.Hex()), log.E(err))
|
|
return refundImage(id, err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SubmitUndress automatically approves and submits an AI undress order.
|
|
func SubmitUndress(id primitive.ObjectID) error {
|
|
order, err := aiUnDressmod.FindByID(nil, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aiUnDressmod.TransitionStatus(nil, id, aiUnDressmod.Processing, aiUnDressmod.SubmitOrder, bson.M{
|
|
"updateAct": autoOperator,
|
|
"remark": "已自动提交",
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
|
|
notifyURL, notifyErr := appg.AICallbackURL("/api/web/admin/ai/undress/callback")
|
|
if notifyErr != nil || len(order.OriginPics) == 0 || appg.Conf.URL.AiUndressServer == "" {
|
|
return refundUndress(id, "自动提交参数不完整")
|
|
}
|
|
req := aiUnDressmod.AiUndressOrderReq{
|
|
AppId: int(commod.KFK_APPID),
|
|
FileUrl: order.OriginPics,
|
|
UserId: strconv.FormatUint(order.UID, 10),
|
|
AppOrderNum: id.Hex(),
|
|
NotifyUrl: notifyURL,
|
|
}
|
|
var resp aiUnDressmod.AiUndressOrderResp
|
|
statusCode, err := httputil.DefaultClientPostJsonWithResp(
|
|
&resp,
|
|
common.BindUrl(appg.Conf.URL.AiUndressServer, "/api/undress/prd/create_job"),
|
|
nil,
|
|
req,
|
|
)
|
|
if err != nil || statusCode != 200 {
|
|
if err == nil {
|
|
err = fmt.Errorf("third-party HTTP status %d", statusCode)
|
|
}
|
|
log.Error("AI脱衣自动提交失败", log.Any("id", id.Hex()), log.E(err))
|
|
return refundUndress(id, err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func postChangeFace(req changeFaceRequest) error {
|
|
var resp changeFaceResponse
|
|
statusCode, err := httputil.DefaultClientPostJsonWithResp(
|
|
&resp,
|
|
common.BindUrl(appg.Conf.URL.AiServer, "/api/changeface/prd/changeFaceByVideo"),
|
|
nil,
|
|
req,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if statusCode != 200 {
|
|
return fmt.Errorf("third-party HTTP status %d", statusCode)
|
|
}
|
|
if resp.Code == 40000 {
|
|
return errors.New("third-party template is unavailable")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func refundVideo(id primitive.ObjectID, remark string) error {
|
|
return appg.VideoDB.Trans(func(tool *db.MongoTool) error {
|
|
order, err := aichangefacemod.FindByID(tool, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aichangefacemod.TransitionStatus(tool, id, aichangefacemod.StatusSubmit, aichangefacemod.StatusRefund, bson.M{
|
|
"operator": autoOperator,
|
|
"remark": remark,
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
if len(order.Discount) > 0 {
|
|
if _, err = backpackmod.UnuseManyGoods(tool, order.Discount); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if order.Coin == 0 && order.IncomeCoin == 0 {
|
|
return nil
|
|
}
|
|
wallet, err := walletmod.ReturnAmountAndIncome(tool, -order.Coin, -order.IncomeCoin, order.Uid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
totalCoin := order.Coin + order.IncomeCoin
|
|
return txnmod.InsertTransactionLog(tool, &txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(),
|
|
UID: order.Uid,
|
|
Amount: totalCoin,
|
|
ActualAmount: float64(totalCoin),
|
|
TranType: txnmod.AiChangefaceDebitGoldReturn.Key(),
|
|
TranTypeInt: int64(txnmod.AiChangefaceDebitGoldReturn),
|
|
Desc: fmt.Sprintf("AI换脸金币退返-%d", totalCoin),
|
|
RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
})
|
|
}
|
|
|
|
func refundImage(id primitive.ObjectID, remark string) error {
|
|
return appg.VideoDB.Trans(func(tool *db.MongoTool) error {
|
|
order, err := aichangefaceimgmod.FindByID(tool, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aichangefaceimgmod.TransitionStatus(tool, id, aichangefaceimgmod.StatusSubmit, aichangefaceimgmod.REFUND, bson.M{
|
|
"updateAct": autoOperator,
|
|
"remark": remark,
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
return refundImageBalance(tool, order)
|
|
})
|
|
}
|
|
|
|
func refundImageBalance(tool *db.MongoTool, order *aichangefaceimgmod.AiChangeFaceImg) error {
|
|
logs := make([]txnmod.TransactionLog, 0, 3)
|
|
if order.Count > 0 || order.IsFreeTimes {
|
|
count := order.Count
|
|
if count == 0 {
|
|
count = 1
|
|
}
|
|
wallet, err := walletmod.DebitAiFreeTimes(tool, -count, order.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: count, ActualAmount: float64(count),
|
|
TranType: txnmod.AiChangeFaceImgDebitFreeTimesReturn.Key(), TranTypeInt: int64(txnmod.AiChangeFaceImgDebitFreeTimesReturn),
|
|
Desc: fmt.Sprintf("AI图片换脸免费次数退返[%d次]", count), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
if order.DebitAmountCoin > 0 || order.DebitIncomeCoin > 0 {
|
|
wallet, err := walletmod.ReturnAmountAndIncome(tool, -order.DebitAmountCoin, -order.DebitIncomeCoin, order.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if order.DebitIncomeCoin > 0 {
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: order.DebitIncomeCoin, ActualAmount: float64(order.DebitIncomeCoin),
|
|
TranType: txnmod.AiChangeFaceImgReturnIncomeGold.Key(), TranTypeInt: int64(txnmod.AiChangeFaceImgReturnIncomeGold),
|
|
Desc: fmt.Sprintf("AI图片换脸收益金币退返-%d", order.DebitIncomeCoin), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
if order.DebitAmountCoin > 0 {
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: order.DebitAmountCoin, ActualAmount: float64(order.DebitAmountCoin),
|
|
TranType: txnmod.AiChangeFaceImgReturnGold.Key(), TranTypeInt: int64(txnmod.AiChangeFaceImgReturnGold),
|
|
Desc: fmt.Sprintf("AI图片换脸金币退返-%d", order.DebitAmountCoin), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
}
|
|
if len(logs) == 0 {
|
|
return nil
|
|
}
|
|
return txnmod.InsertManyTransactionLog(tool, logs)
|
|
}
|
|
|
|
func refundUndress(id primitive.ObjectID, remark string) error {
|
|
return appg.VideoDB.Trans(func(tool *db.MongoTool) error {
|
|
order, err := aiUnDressmod.FindByID(tool, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
transitioned, err := aiUnDressmod.TransitionStatus(tool, id, aiUnDressmod.SubmitOrder, aiUnDressmod.REFUND, bson.M{
|
|
"updateAct": autoOperator,
|
|
"remark": remark,
|
|
})
|
|
if err != nil || !transitioned {
|
|
return err
|
|
}
|
|
return refundUndressBalance(tool, order)
|
|
})
|
|
}
|
|
|
|
func refundUndressBalance(tool *db.MongoTool, order *aiUnDressmod.AiUnDress) error {
|
|
logs := make([]txnmod.TransactionLog, 0, 3)
|
|
if order.Count > 0 || order.IsFreeTimes {
|
|
count := order.Count
|
|
if count == 0 {
|
|
count = 1
|
|
}
|
|
wallet, err := walletmod.DebitAiFreeTimes(tool, -count, order.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: count, ActualAmount: float64(count),
|
|
TranType: txnmod.AiUndressDebitFreeTimesReturn.Key(), TranTypeInt: int64(txnmod.AiUndressDebitFreeTimesReturn),
|
|
Desc: fmt.Sprintf("AI脱衣免费次数退返[%d次]", count), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
debitAmount := order.DebitAmountCoin
|
|
debitIncome := order.DebitIncomeCoin
|
|
if !order.IsFreeTimes && debitAmount == 0 && debitIncome == 0 {
|
|
debitAmount = order.Coin
|
|
}
|
|
if debitAmount > 0 || debitIncome > 0 {
|
|
wallet, err := walletmod.ReturnAmountAndIncome(tool, -debitAmount, -debitIncome, order.UID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if debitIncome > 0 {
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: debitIncome, ActualAmount: float64(debitIncome),
|
|
TranType: txnmod.AiUndressDebitIncomeGoldReturn.Key(), TranTypeInt: int64(txnmod.AiUndressDebitIncomeGoldReturn),
|
|
Desc: fmt.Sprintf("AI脱衣收益金币退返-%d", debitIncome), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
if debitAmount > 0 {
|
|
logs = append(logs, txnmod.TransactionLog{
|
|
TransNo: primitive.NewObjectID(), UID: order.UID, Amount: debitAmount, ActualAmount: float64(debitAmount),
|
|
TranType: txnmod.AiUndressDebitGoldReturn.Key(), TranTypeInt: int64(txnmod.AiUndressDebitGoldReturn),
|
|
Desc: fmt.Sprintf("AI脱衣金币退返-%d", debitAmount), RealAmount: walletmod.GetRealAmount(wallet),
|
|
})
|
|
}
|
|
}
|
|
if len(logs) == 0 {
|
|
return nil
|
|
}
|
|
return txnmod.InsertManyTransactionLog(tool, logs)
|
|
}
|