Files
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

343 lines
10 KiB
Go
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package ai_text_to_novel_ser
import (
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/cache/aitexttonoveldata"
"91porn-server/models/commod"
"91porn-server/models/v/aitexttonovelmod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/walletmod"
"91porn-server/web/webg"
"errors"
"fmt"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type WebListReq struct {
ID *string `json:"id" form:"id"` // ID
UID *uint64 `json:"uid" form:"uid"` // 用户ID
Status *int `json:"status" form:"status"` // 状态
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
}
return filter
}
func (q *WebListReq) Sort() primitive.D {
return bson.D{{Key: "createdAt", Value: -1}}
}
type WebListRes struct {
Total int64 `json:"total"`
HasNext bool `json:"hasNext"`
List []aitexttonovelmod.AiTextToNovel `json:"list"`
}
// GetList 获取列表
func (q *WebListReq) GetList() (res WebListRes, err error) {
res.List, res.Total, res.HasNext, err = aitexttonovelmod.GetList(q.Filter(), int64(q.Skip()), int64(q.Limit()), q.Sort())
return
}
type WebUpdateReq struct {
ID primitive.ObjectID `json:"id" binding:"required"`
UID *uint64 `json:"uid"` // 用户ID
Background *string `json:"background"` // 小说人物设定/故事背景等
Scene *string `json:"scene"` // 地点场景
Text *string `json:"text"` // 故事情节描述
Other *string `json:"other"` // 小说其他要求
ModelType *string `json:"modelType"` // AI小说模型 12
Content *string `json:"content"` // AI生成小说正文
Status *int `json:"status"` // 状态
Coin *int64 `json:"coin"` // AI小说金币个数
DebitAmountCoin *int64 `json:"debitAmountCoin"` // 此次AI小说扣除金币个数
DebitIncomeCoin *int64 `json:"debitIncomeCoin"` // 此次AI小说扣除收益金币个数
IsFreeTimes *bool `json:"isFreeTimes"` // 是否使用免费次数
IsHide *bool `json:"isHide"` // 是否被用户隐藏
Remark *string `json:"remark"` // 备注
IsDelete *bool `json:"isDelete"` // 是否删除
}
// Update 更新数据
func (p *WebUpdateReq) Update() error {
info, err := aitexttonovelmod.GetInfo(p.ID)
if err != nil {
return err
}
if info.ID.IsZero() {
return errors.New("data is null")
}
data := make(map[string]interface{})
if p.UID != nil {
data["uid"] = *p.UID
}
if p.Background != nil {
data["background"] = *p.Background
}
if p.Scene != nil {
data["scene"] = *p.Scene
}
if p.Text != nil {
data["text"] = *p.Text
}
if p.Other != nil {
data["other"] = *p.Other
}
if p.ModelType != nil {
data["modelType"] = *p.ModelType
}
if p.Content != nil {
data["content"] = *p.Content
}
if p.Status != nil {
data["status"] = *p.Status
}
if p.Coin != nil {
data["coin"] = *p.Coin
}
if p.DebitAmountCoin != nil {
data["debitAmountCoin"] = *p.DebitAmountCoin
}
if p.DebitIncomeCoin != nil {
data["debitIncomeCoin"] = *p.DebitIncomeCoin
}
if p.IsFreeTimes != nil {
data["isFreeTimes"] = *p.IsFreeTimes
}
if p.IsHide != nil {
data["isHide"] = *p.IsHide
}
if p.Remark != nil {
data["remark"] = *p.Remark
}
if p.IsDelete != nil {
data["isDelete"] = *p.IsDelete
}
data["updatedAt"] = time.Now()
if p.Status != nil && *p.Status == 5 {
if info.Status == int(aitexttonovelmod.StatusRefunded) || info.Status == int(aitexttonovelmod.StatusGenerationFailed) {
return errors.New("Please do not refund repeatedly.")
}
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
if _, err = aitexttonovelmod.UpdateByID(t, info.ID, data); err != nil {
return err
}
// 退款
if info.DebitAmountCoin == 0 && info.DebitIncomeCoin == 0 { // 总金额为0则不需要退款
return nil
}
// 退款进入钱包余额
wallet, err := walletmod.ReturnAmountAndIncome(t, -info.DebitAmountCoin, -info.DebitIncomeCoin, info.UID)
if err != nil {
log.Error(fmt.Sprintf("Handle text to novel Edit walletmod.DebitAmount error:%+v:", err), log.Any("uid", info.UID))
return err
}
var tl []txnmod.TransactionLog
if info.DebitAmountCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: info.UID,
Amount: info.DebitAmountCoin,
ActualAmount: float64(info.DebitAmountCoin),
TranType: txnmod.AiTextToNovelDebitGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiTextToNovelDebitGoldReturn),
Desc: fmt.Sprintf("退还AI小说金币-%d", info.DebitAmountCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if info.DebitIncomeCoin > 0 {
tl = append(tl, txnmod.TransactionLog{
TransNo: primitive.NewObjectID(),
UID: info.UID,
Amount: info.DebitIncomeCoin,
ActualAmount: float64(info.DebitIncomeCoin),
TranType: txnmod.AiTextToNovelDebitIncomeGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiTextToNovelDebitIncomeGoldReturn),
Desc: fmt.Sprintf("退还AI小说收益金币-%d", info.DebitIncomeCoin),
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if len(tl) > 0 {
txnErr := txnmod.InsertManyTransactionLog(t, tl)
if txnErr != nil {
log.Error(fmt.Sprintf("Handle ai text to novel txnmod.InsertTransactionLog error:%+v:", txnErr), log.Any("uid", info.UID))
return stderr.ErrDbQueryError
}
}
return nil
}); err != nil {
if e, ok := err.(stderr.Code); ok {
return e
}
return stderr.ErrDbQueryError
}
return nil
} else {
if _, err = aitexttonoveldata.UpdateData(nil, p.ID.Hex(), data); err != nil {
}
return err
}
}
type WebDeleteReq struct {
ID primitive.ObjectID `json:"id" binding:"required"`
}
// Delete 删除数据
func (p *WebDeleteReq) Delete() error {
data, err := aitexttonovelmod.GetInfo(p.ID)
if err != nil {
return err
}
if err = validateDeleteStatus(data.Status); err != nil {
return err
}
if err := aitexttonoveldata.DeleteData(nil, p.ID); err != nil {
return err
}
return nil
}
func validateDeleteStatus(status int) error {
if status == int(aitexttonovelmod.StatusOrderSuccess) ||
status == int(aitexttonovelmod.StatusSubmitted) {
return stderr.AiGenningDelForbidden
}
return nil
}
// CallbackReq 换脸订单回调请求
type CallbackReq struct {
Content string `json:"content"` // 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 := aitexttonovelmod.GetInfo(id)
if err != nil {
return stderr.ErrDbQueryError
}
if data.ID.IsZero() {
return errors.New("ai text to novel data is null")
}
if data.Status != int(aitexttonovelmod.StatusSubmitted) {
log.Error("AI小说-重复回调或者状态不正确", log.Any("id", data.ID.Hex()), log.Any("status", data.Status))
return nil
}
var status = aitexttonovelmod.StatusGenerationSuccess
// 处理金币退款以及后续操作
set := bson.M{}
if p.Content != "" {
set["content"] = strings.TrimSpace(p.Content)
}
if p.Status != 1 {
set["remark"] = p.Msg
set["content"] = ""
status = aitexttonovelmod.StatusGenerationFailed
}
set["status"] = status
set["updatedAt"] = time.Now()
switch status {
case aitexttonovelmod.StatusGenerationSuccess:
if _, err = aitexttonovelmod.UpdateByID(nil, id, set); err != nil {
return stderr.ErrDbUpdateError
}
return nil
case aitexttonovelmod.StatusGenerationFailed: // 退款
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
if _, err = aitexttonovelmod.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.AiTextToNovelDebitGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiTextToNovelDebitGoldReturn),
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.AiTextToNovelDebitIncomeGoldReturn.Key(),
TranTypeInt: int64(txnmod.AiTextToNovelDebitIncomeGoldReturn),
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 ai text to image 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
}