Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
184 commits
Select commit Hold shift + click to select a range
69de99e
支持即梦2.0的全能提示词
xuanyustudio Apr 19, 2026
0c194c6
1
xuanyustudio Apr 22, 2026
805d5fd
轮询使用原始data
xuanyustudio Apr 22, 2026
6253847
2
xuanyustudio Apr 22, 2026
f61cc74
xai
xuanyustudio Apr 24, 2026
a523a60
修改bug
xuanyustudio Apr 24, 2026
cc0126d
11
xuanyustudio Apr 27, 2026
f311fde
增加链接
xuanyustudio Apr 30, 2026
60ea930
gemini tts
xuanyustudio May 6, 2026
e5d54b3
增加token日志
xuanyustudio May 13, 2026
388782b
Merge remote-tracking branch 'upstream/main'
xuanyustudio May 15, 2026
5074ba8
bun的配置
xuanyustudio May 15, 2026
b79e385
金额问题
xuanyustudio May 15, 2026
a897e44
音频适配
xuanyustudio May 15, 2026
4812ced
增加两个渠道,和按秒计费
xuanyustudio May 20, 2026
2b18ce3
首页统计bug
xuanyustudio May 21, 2026
48c1b36
火山协议自定义
xuanyustudio May 23, 2026
621bb49
草稿字段
xuanyustudio May 25, 2026
592d8fb
豆包特殊中转站
xuanyustudio May 26, 2026
eafa416
1
xuanyustudio May 26, 2026
95c8c32
修改视频异步退款和改余额冲突的bug
xuanyustudio May 28, 2026
beca8bf
手工改令牌额度做记录
xuanyustudio May 28, 2026
58aecba
针对seedance2的视频输入这个特殊功能做了价格折扣的选项
xuanyustudio Jun 6, 2026
e3afadf
增加agnes模型的支持
xuanyustudio Jun 15, 2026
e00b48b
agnes
xuanyustudio Jun 16, 2026
a4a2eb8
预览视频
xuanyustudio Jun 21, 2026
fca17ff
前端修改
xuanyustudio Jun 21, 2026
9acbc0b
增加模型vyroseedance
xuanyustudio Jun 25, 2026
10a8086
agens的bug
xuanyustudio Jun 28, 2026
2c4420f
vyro 的新模型支持
xuanyustudio Jul 1, 2026
4103302
增强
xuanyustudio Jul 2, 2026
0878d57
image images
xuanyustudio Jul 2, 2026
9247b31
增加83zi厂商
xuanyustudio Jul 2, 2026
55198b7
轮询误判的错误
xuanyustudio Jul 2, 2026
b24da75
改名
xuanyustudio Jul 2, 2026
b43f4b0
接入7tai渠道
xuanyustudio Jul 3, 2026
fb47700
模型限制的查询权限
xuanyustudio Jul 8, 2026
7e39560
不同分辨率不同价格
xuanyustudio Jul 10, 2026
9ec5829
前端
xuanyustudio Jul 10, 2026
48eb9a2
做了测试用例和文档。
xuanyustudio Jul 10, 2026
cfa1622
docs: add XunhuPay (虎皮椒) top-up design spec
xuanyustudio Jul 10, 2026
c20deab
增加支付
xuanyustudio Jul 10, 2026
f66f143
修bug
xuanyustudio Jul 10, 2026
001d35d
bug
xuanyustudio Jul 10, 2026
a348bd0
修bug
xuanyustudio Jul 11, 2026
e3091ac
修改bug
xuanyustudio Jul 11, 2026
7e0c3a3
修改bug
xuanyustudio Jul 11, 2026
e3fd48e
计费bug修改
xuanyustudio Jul 12, 2026
f84a97c
格式转换
xuanyustudio Jul 12, 2026
b1a20dd
480-》720
xuanyustudio Jul 12, 2026
3a4f3f6
强化图片的bug
xuanyustudio Jul 12, 2026
1c3bf07
修改了83zi厂商的格式。
xuanyustudio Jul 13, 2026
52ddf2f
文档修改
xuanyustudio Jul 14, 2026
3ef86ef
热更
xuanyustudio Jul 14, 2026
1c55941
multipart 覆盖模型名变了
xuanyustudio Jul 15, 2026
6867ad1
docs: add Seedance asset management API design
xuanyustudio Jul 15, 2026
074cde8
docs: add Seedance asset APIs implementation plan
xuanyustudio Jul 15, 2026
767aad1
认证
xuanyustudio Jul 15, 2026
dad56d1
增加文件
xuanyustudio Jul 15, 2026
5cd8055
增加渠道管理
xuanyustudio Jul 17, 2026
978ce72
调试信息修改
xuanyustudio Jul 17, 2026
bdabcc8
bug
xuanyustudio Jul 17, 2026
a01c86e
模型
xuanyustudio Jul 18, 2026
19150df
过人脸
xuanyustudio Jul 18, 2026
d350e21
网址
xuanyustudio Jul 18, 2026
1d1f5e9
模型调试
xuanyustudio Jul 20, 2026
88e54e3
增加渠道
xuanyustudio Jul 20, 2026
6fe74a9
docs: add MegaByAI video channel design spec
xuanyustudio Jul 20, 2026
429c2ff
docs: add MegaByAI video channel implementation plan
xuanyustudio Jul 20, 2026
46ba45d
test: megabyai create-body field mapping
xuanyustudio Jul 20, 2026
ba5bdaa
feat: register megabyai channel type 65
xuanyustudio Jul 20, 2026
4eb0e54
feat: megabyai Sora-based video task adaptor
xuanyustudio Jul 20, 2026
f39fff7
feat(web): add megabyai channel type in default UI
xuanyustudio Jul 20, 2026
12b55f1
feat(web): add megabyai channel type in classic UI
xuanyustudio Jul 20, 2026
cfd7532
test
xuanyustudio Jul 20, 2026
724c5ac
改bug
xuanyustudio Jul 20, 2026
bd758ff
docs: add MegaByAI channel face-pass design
xuanyustudio Jul 21, 2026
db1c1e3
docs: megabyai face-pass local 1600 WebP preprocess
xuanyustudio Jul 21, 2026
1f07b30
feat: megabyai channel face-pass with local 1600 WebP preprocess
xuanyustudio Jul 21, 2026
6412471
修改
xuanyustudio Jul 21, 2026
04fad77
1
xuanyustudio Jul 21, 2026
e47a841
fix: megabyai face-pass use both-eyes full-face mask for upstream
xuanyustudio Jul 21, 2026
43b2ce9
0
xuanyustudio Jul 21, 2026
38733bf
11
xuanyustudio Jul 21, 2026
8f2d8f5
1
xuanyustudio Jul 21, 2026
9ba7237
docs: seedance-debug UX polish design (assets, help, auth probe)
xuanyustudio Jul 21, 2026
4552cdf
22
xuanyustudio Jul 22, 2026
68ae643
docs: OpenAI/Sora channel face-pass design
xuanyustudio Jul 22, 2026
4bcd77f
改人脸
xuanyustudio Jul 22, 2026
92b5e90
修复
xuanyustudio Jul 23, 2026
18f5844
docs: Sora2U async video channel design
xuanyustudio Jul 24, 2026
7c1819c
docs: Sora2U channel implementation plan
xuanyustudio Jul 24, 2026
f4c1c98
docs: point Sora2U design at versioned plan path
xuanyustudio Jul 24, 2026
2186986
feat: sora2u normalize and task parse helpers
xuanyustudio Jul 24, 2026
5d1fb15
feat: register sora2u channel type 66 and task adaptor
xuanyustudio Jul 24, 2026
cbe44d3
feat(web): add Sora2U channel type in default and classic UI
xuanyustudio Jul 24, 2026
15f031f
优化首页
xuanyustudio Jul 28, 2026
c5e4589
音频支持
xuanyustudio Jul 29, 2026
bdcb70d
22
xuanyustudio Jul 29, 2026
314c34e
22
xuanyustudio Aug 2, 2026
fe53bff
111
xuanyustudio Aug 2, 2026
8648045
333
xuanyustudio Aug 2, 2026
3446112
11
xuanyustudio Aug 2, 2026
53b7e47
预扣价格调整。
xuanyustudio Aug 2, 2026
f32ddb6
修复suceess没url的bug
xuanyustudio Aug 4, 2026
12cb559
minimax h3
xuanyustudio Aug 4, 2026
4b647ba
调试页
xuanyustudio Aug 4, 2026
ede4511
改
xuanyustudio Aug 5, 2026
05e4afb
Add design for admin failed-request error logs.
xuanyustudio Aug 7, 2026
6c105d1
Add implementation plan for admin error logs.
xuanyustudio Aug 7, 2026
b2f0f7c
feat(error-log): default-on ErrorLogEnabled and error_category constants
xuanyustudio Aug 7, 2026
7e644b6
feat(error-log): add ErrorLogEnabled system setting toggle
xuanyustudio Aug 7, 2026
bf960d1
feat(error-log): add RecordRequestErrorLog helper and wire upstream path
xuanyustudio Aug 7, 2026
aeceeca
feat(error-log): record auth, rate_limit, and channel middleware fail…
xuanyustudio Aug 7, 2026
d54d888
feat(error-log): cover relay early exits, quota, and task/MJ failures
xuanyustudio Aug 7, 2026
13f0a29
feat(error-log): admin GET /api/error-log and hide errors from user logs
xuanyustudio Aug 7, 2026
200433e
feat(error-log): admin Error Logs page with category filters
xuanyustudio Aug 7, 2026
9196b04
chore(i18n): translations for admin error logs
xuanyustudio Aug 7, 2026
31a594a
feat(error-log): add Classic admin Error Logs page and settings
xuanyustudio Aug 7, 2026
961c890
fix(error-log): include errorLog in classic personal sidebar modules
xuanyustudio Aug 7, 2026
b6e8dd3
滚滚滚
xuanyustudio Aug 7, 2026
01d3dbb
docs: add Seedance official asset direct-connect design
xuanyustudio Aug 8, 2026
86f1364
方法
xuanyustudio Aug 8, 2026
9c6af40
22
xuanyustudio Aug 8, 2026
bc5328e
方法
xuanyustudio Aug 8, 2026
a9a4001
33
xuanyustudio Aug 8, 2026
e21db73
方法
xuanyustudio Aug 8, 2026
426cf12
3333
xuanyustudio Aug 8, 2026
987ae0b
44
xuanyustudio Aug 8, 2026
d58194e
333
xuanyustudio Aug 8, 2026
4c56614
4444
xuanyustudio Aug 8, 2026
3332da5
333
xuanyustudio Aug 10, 2026
25f28f6
极简
xuanyustudio Aug 10, 2026
24cc7e3
发发发
xuanyustudio Aug 10, 2026
6b684b0
docs: add mao Seedance adaptive resolution channel design
xuanyustudio Aug 11, 2026
daf4f3d
docs: add mao Seedance adaptive channel implementation plan
xuanyustudio Aug 11, 2026
d778cf8
test: mao resolution tier and upstream model mapping
xuanyustudio Aug 11, 2026
7a95ed8
fix: mao normalizeTier prefer resolution and model error list
xuanyustudio Aug 11, 2026
d2b5601
test: mao create and poll response parsing
xuanyustudio Aug 11, 2026
39fe5fe
feat: mao upstream payload builder with adaptive model
xuanyustudio Aug 11, 2026
de67495
feat: register mao channel type 68 and task adaptor
xuanyustudio Aug 11, 2026
9275a12
feat: add mao channel UI options in default and classic
xuanyustudio Aug 11, 2026
716435b
i18n: add classic zh mao_key_prompt for channel 68
xuanyustudio Aug 11, 2026
3773636
docs: add mao async failure same-channel retry design
xuanyustudio Aug 11, 2026
75b1bd7
docs: add mao async same-channel retry implementation plan
xuanyustudio Aug 11, 2026
a935a3c
feat: mao async retry helpers and TaskPrivateData fields
xuanyustudio Aug 11, 2026
b8cd039
feat: persist mao upstream request body for async retry
xuanyustudio Aug 11, 2026
26b2bce
feat: mao TryResubmitOnFailure same-channel resubmit
xuanyustudio Aug 11, 2026
2feea0d
feat: short-circuit video poll refund when async resubmit succeeds
xuanyustudio Aug 11, 2026
fbba473
33
xuanyustudio Aug 11, 2026
df8f071
fix: mao async retry stop after 3 failures (no 4th attempt)
xuanyustudio Aug 11, 2026
bdc13dc
docs: add mao Volc official content normalize design
xuanyustudio Aug 11, 2026
cedca9a
docs: add mao volc official content normalize plan
xuanyustudio Aug 11, 2026
abf3001
feat: mao volc official content normalize helpers
xuanyustudio Aug 11, 2026
92f27c3
feat: wire mao volc normalize into BuildRequestBody
xuanyustudio Aug 11, 2026
097fc1e
fix: mao merge top-level camera_fixed into metadata
xuanyustudio Aug 11, 2026
25a3274
333
xuanyustudio Aug 11, 2026
4236621
发发发
xuanyustudio Aug 11, 2026
16891ed
docs: add async task cross-channel failover design
xuanyustudio Aug 12, 2026
82f898a
docs: add async task cross-channel failover implementation plan
xuanyustudio Aug 12, 2026
58f3601
feat: classify async task fail reasons for failover
xuanyustudio Aug 12, 2026
782af88
feat: add task failover system options
xuanyustudio Aug 12, 2026
35c0d0c
feat: resolve ordered channel candidates for task failover
xuanyustudio Aug 12, 2026
4139735
feat: snapshot failover state and use ordered channels on task submit
xuanyustudio Aug 12, 2026
e59bcc9
feat: orchestrate async failure same-channel retry via failover service
xuanyustudio Aug 12, 2026
35846d8
feat: recreate failed async tasks on next failover channel
xuanyustudio Aug 12, 2026
cbcb313
refactor: align mao async retry with shared failover classification
xuanyustudio Aug 12, 2026
2bd0e3a
feat(web): task failover toggles and model channel order settings
xuanyustudio Aug 12, 2026
a659f51
feat(classic): task failover settings and drag-order channel list
xuanyustudio Aug 12, 2026
f195a8e
天天天天
xuanyustudio Aug 12, 2026
423d054
docs: add yk-video (KYY model-center) channel design
xuanyustudio Aug 12, 2026
6855dbd
方法
xuanyustudio Aug 12, 2026
45ac3e6
天天
xuanyustudio Aug 12, 2026
5ee4f1b
00
xuanyustudio Aug 13, 2026
f021fa8
个
xuanyustudio Aug 13, 2026
fcad02e
个
xuanyustudio Aug 13, 2026
ce25b76
docs: add yk-sd channel design with forced Seedance assets
xuanyustudio Aug 13, 2026
4af3454
增加渠道
xuanyustudio Aug 13, 2026
dbb839a
吧
xuanyustudio Aug 13, 2026
30f02e9
方法
xuanyustudio Aug 13, 2026
6e92f21
对的
xuanyustudio Aug 13, 2026
a03b305
33
xuanyustudio Aug 13, 2026
d06859d
yk-sd参考视频按上游每秒单价计费,结算只补不退
xuanyustudio Oct 19, 2026
da2e57e
sfg
xuanyustudio Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ data/
.gocache-temp
.gopath

token_estimator_test.go
token_estimator_test.go
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
...
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
8 changes: 8 additions & 0 deletions controller/channel-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
requestPath = "/v1/images/generations"
}

// VolcEngine 视频生成模型
if channel.Type == constant.ChannelTypeVolcEngine && strings.Contains(testModel, "seedance") {
requestPath = "/v1/imagegen/video"
}

// responses-only models
if strings.Contains(strings.ToLower(testModel), "codex") {
requestPath = "/v1/responses"
Expand Down Expand Up @@ -201,6 +206,9 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
if c.Request.URL.Path == "/v1/images/generations" {
relayFormat = types.RelayFormatOpenAIImage
}
if c.Request.URL.Path == "/v1/imagegen/video" {
relayFormat = types.RelayFormatOpenAIImage
}
if c.Request.URL.Path == "/v1/messages" {
relayFormat = types.RelayFormatClaude
}
Expand Down
3 changes: 1 addition & 2 deletions controller/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,8 +568,6 @@ func RelayTask(c *gin.Context) {
if settleErr := service.SettleBilling(c, relayInfo, result.Quota); settleErr != nil {
common.SysError("settle task billing error: " + settleErr.Error())
}
service.LogTaskConsumption(c, relayInfo)

task := model.InitTask(result.Platform, relayInfo)
task.PrivateData.UpstreamTaskID = result.UpstreamTaskID
task.PrivateData.BillingSource = relayInfo.BillingSource
Expand All @@ -586,6 +584,7 @@ func RelayTask(c *gin.Context) {
task.Quota = result.Quota
task.Data = result.TaskData
task.Action = relayInfo.Action
service.LogTaskConsumption(c, relayInfo, task.TaskID)
if insertErr := task.Insert(); insertErr != nil {
common.SysError("insert task error: " + insertErr.Error())
}
Expand Down
2 changes: 2 additions & 0 deletions controller/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,11 @@ func AddToken(c *gin.Context) {
common.ApiError(c, err)
return
}
// 创建成功时返回完整 key(仅此一次),供外部系统(如 Webman 渠道注册)保存为 API Token。
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "",
"data": cleanToken.GetFullKey(),
})
}

Expand Down
17 changes: 17 additions & 0 deletions controller/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,19 @@ func GetAffCode(c *gin.Context) {
return
}

func GetAffInvitees(c *gin.Context) {
inviterId := c.GetInt("id")
pageInfo := common.GetPageQuery(c)
invitees, total, err := model.GetInviteesByInviterId(inviterId, pageInfo)
if err != nil {
common.ApiError(c, err)
return
}
pageInfo.SetTotal(int(total))
pageInfo.SetItems(invitees)
common.ApiSuccess(c, pageInfo)
}

func GetSelf(c *gin.Context) {
id := c.GetInt("id")
userRole := c.GetInt("role")
Expand All @@ -378,6 +391,10 @@ func GetSelf(c *gin.Context) {
common.ApiError(c, err)
return
}
inviteeCount, countErr := model.GetInviteeCountByInviterId(id)
if countErr == nil {
user.AffCount = int(inviteeCount)
}
// Hide admin remarks: set to empty to trigger omitempty tag, ensuring the remark field is not included in JSON returned to regular users
user.Remark = ""

Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/QuantumNous/new-api

// +heroku goVersion go1.18
go 1.25.1
go 1.25.0

require (
github.com/Calcium-Ion/go-epay v0.0.4
Expand Down Expand Up @@ -49,11 +49,11 @@ require (
github.com/waffo-com/waffo-go v1.3.1
github.com/yapingcat/gomedia v0.0.0-20240906162731-17feea57090c
golang.org/x/crypto v0.45.0
golang.org/x/image v0.38.0
golang.org/x/image v0.36.0
golang.org/x/net v0.47.0
golang.org/x/sync v0.20.0
golang.org/x/sync v0.19.0
golang.org/x/sys v0.38.0
golang.org/x/text v0.35.0
golang.org/x/text v0.34.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.4.3
gorm.io/driver/postgres v1.5.2
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -325,14 +325,19 @@ golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -353,9 +358,12 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
96 changes: 75 additions & 21 deletions model/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/QuantumNous/new-api/common"
Expand Down Expand Up @@ -253,15 +254,17 @@ func RecordConsumeLog(c *gin.Context, userId int, params RecordConsumeLogParams)
}

type RecordTaskBillingLogParams struct {
UserId int
LogType int
Content string
ChannelId int
ModelName string
Quota int
TokenId int
Group string
Other map[string]interface{}
UserId int
LogType int
Content string
ChannelId int
ModelName string
Quota int
TokenId int
Group string
Other map[string]interface{}
PromptTokens int
CompletionTokens int
}

func RecordTaskBillingLog(params RecordTaskBillingLogParams) {
Expand All @@ -276,25 +279,76 @@ func RecordTaskBillingLog(params RecordTaskBillingLogParams) {
}
}
log := &Log{
UserId: params.UserId,
Username: username,
CreatedAt: common.GetTimestamp(),
Type: params.LogType,
Content: params.Content,
TokenName: tokenName,
ModelName: params.ModelName,
Quota: params.Quota,
ChannelId: params.ChannelId,
TokenId: params.TokenId,
Group: params.Group,
Other: common.MapToJsonStr(params.Other),
UserId: params.UserId,
Username: username,
CreatedAt: common.GetTimestamp(),
Type: params.LogType,
Content: params.Content,
TokenName: tokenName,
ModelName: params.ModelName,
Quota: params.Quota,
PromptTokens: params.PromptTokens,
CompletionTokens: params.CompletionTokens,
ChannelId: params.ChannelId,
TokenId: params.TokenId,
Group: params.Group,
Other: common.MapToJsonStr(params.Other),
}
err := LOG_DB.Create(log).Error
if err != nil {
common.SysLog("failed to record task billing log: " + err.Error())
}
}

func logOtherIsTaskFlag(v any) bool {
switch t := v.(type) {
case bool:
return t
case float64:
return t != 0
case string:
return t == "true" || t == "1"
default:
return false
}
}

// TryPatchTaskConsumeLogTokens 将任务完成后的 token 用量写回提交时记录的消费日志(匹配 other.public_task_id)。
func TryPatchTaskConsumeLogTokens(userId int, publicTaskID string, promptTokens, completionTokens int) bool {
if publicTaskID == "" || (promptTokens <= 0 && completionTokens <= 0) {
return false
}
var logs []Log
err := LOG_DB.Where("user_id = ? AND type = ?", userId, LogTypeConsume).
Order("id desc").Limit(80).Find(&logs).Error
if err != nil {
return false
}
for i := range logs {
otherMap, e := common.StrToMap(logs[i].Other)
if e != nil || otherMap == nil {
continue
}
if !logOtherIsTaskFlag(otherMap["is_task"]) {
continue
}
ptid := ""
if v, ok := otherMap["public_task_id"]; ok && v != nil {
ptid = strings.TrimSpace(fmt.Sprint(v))
}
if ptid != publicTaskID {
continue
}
errUp := LOG_DB.Model(&Log{}).Where("id = ?", logs[i].Id).
Updates(map[string]any{
"prompt_tokens": promptTokens,
"completion_tokens": completionTokens,
}).Error
return errUp == nil
}
return false
}

func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int, group string, requestId string) (logs []*Log, total int64, err error) {
var tx *gorm.DB
if logType == LogTypeUnknown {
Expand Down
54 changes: 52 additions & 2 deletions model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ type User struct {
StripeCustomer string `json:"stripe_customer" gorm:"type:varchar(64);column:stripe_customer;index"`
}

type InviteeSummary struct {
Id int `json:"id"`
Username string `json:"username"`
DisplayName string `json:"display_name"`
Email string `json:"email"`
Quota int `json:"quota"`
UsedQuota int `json:"used_quota"`
}

func (user *User) ToBaseUser() *UserBase {
cache := &UserBase{
Id: user.Id,
Expand Down Expand Up @@ -312,6 +321,47 @@ func GetUserIdByAffCode(affCode string) (int, error) {
return user.Id, err
}

func GetInviteesByInviterId(inviterId int, pageInfo *common.PageInfo) (invitees []*InviteeSummary, total int64, err error) {
tx := DB.Begin()
if tx.Error != nil {
return nil, 0, tx.Error
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

query := tx.Model(&User{}).Where("inviter_id = ?", inviterId)

err = query.Count(&total).Error
if err != nil {
tx.Rollback()
return nil, 0, err
}

err = query.Select("id", "username", "display_name", "email", "quota", "used_quota").
Order("id desc").
Limit(pageInfo.GetPageSize()).
Offset(pageInfo.GetStartIdx()).
Find(&invitees).Error
if err != nil {
tx.Rollback()
return nil, 0, err
}

if err = tx.Commit().Error; err != nil {
return nil, 0, err
}

return invitees, total, nil
}

func GetInviteeCountByInviterId(inviterId int) (count int64, err error) {
err = DB.Model(&User{}).Where("inviter_id = ?", inviterId).Count(&count).Error
return count, err
}

func DeleteUserById(id int) (err error) {
if id == 0 {
return errors.New("id 为空!")
Expand Down Expand Up @@ -426,8 +476,8 @@ func (user *User) Insert(inviterId int) error {
if common.QuotaForInviter > 0 {
//_ = IncreaseUserQuota(inviterId, common.QuotaForInviter)
RecordLog(inviterId, LogTypeSystem, fmt.Sprintf("邀请用户赠送 %s", logger.LogQuota(common.QuotaForInviter)))
_ = inviteUser(inviterId)
}
_ = inviteUser(inviterId)
}
return nil
}
Expand Down Expand Up @@ -486,8 +536,8 @@ func (user *User) FinalizeOAuthUserCreation(inviterId int) {
}
if common.QuotaForInviter > 0 {
RecordLog(inviterId, LogTypeSystem, fmt.Sprintf("邀请用户赠送 %s", logger.LogQuota(common.QuotaForInviter)))
_ = inviteUser(inviterId)
}
_ = inviteUser(inviterId)
}
}

Expand Down
3 changes: 3 additions & 0 deletions relay/channel/gemini/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func (a *Adaptor) ConvertGeminiRequest(c *gin.Context, info *relaycommon.RelayIn
}
}
}
if isGeminiPreviewTTSModel(info.UpstreamModelName) {
applyGeminiPreviewTTSGenerationDefaults(&request.GenerationConfig)
}
return request, nil
}

Expand Down
1 change: 1 addition & 0 deletions relay/channel/gemini/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var ModelList = []string{
"gemini-2.5-flash-native-audio-latest",
// preview version
"gemini-2.5-flash-preview-tts", "gemini-2.5-pro-preview-tts",
"gemini-3.1-flash-tts-preview",
"gemini-2.5-flash-image", "gemini-2.5-flash-lite-preview-09-2025",
"gemini-3-pro-preview", "gemini-3-flash-preview", "gemini-3.1-pro-preview",
"gemini-3.1-pro-preview-customtools", "gemini-3.1-flash-lite-preview",
Expand Down
Loading