Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
3decb33
feat(AliAdaptor): enhance video input structure and add PixVerse support
Fankouzu Apr 9, 2026
f4afb2d
Merge pull request #1 from Fankouzu/custom/pixverse-billing
Fankouzu Apr 9, 2026
9579270
chore(web): bump @lobehub/icons, VisActor vchart, add antd peer
Fankouzu Apr 9, 2026
e321282
Merge pull request #2 from Fankouzu:chore/bump-lobehub-icons-visactor…
Fankouzu Apr 9, 2026
2bfc9c3
fix(doubao): preserve draft_task id in video content items
Fankouzu Apr 11, 2026
3aaedc2
Merge pull request #3 from Fankouzu/feat/doubao-seedance-draft-task-c…
Fankouzu Apr 11, 2026
6162fdb
Merge branch 'QuantumNous:main' into main
Fankouzu Apr 11, 2026
6b33a38
fix(doubao): skip appending prompt text when content uses draft_task
Fankouzu Apr 11, 2026
49a3baa
Merge pull request #4 from Fankouzu/fix/doubao-seedance-draft-no-text…
Fankouzu Apr 11, 2026
137cd7f
Merge upstream/main into main: resolve web deps (keep visactor v2, an…
Fankouzu Apr 15, 2026
4bac883
feat(channel): add PingXingShiJie async task channel (fork of task/do…
Fankouzu Apr 15, 2026
80a1ef3
feat(pingxingshijie): align channel 58 with /v2 APIs, envelope, and a…
Fankouzu Apr 15, 2026
fe9ea68
fix(relay): use Distribute relay_mode for GET /v1/images/generations/…
Fankouzu Apr 15, 2026
f1fb6f0
fix(pingxingshijie): map image task done status and data[].url for Se…
Fankouzu Apr 15, 2026
8809ba3
fix(task): image result_url recovery, upstream_kind in API, admin ima…
Fankouzu Apr 15, 2026
0328b85
fix(relay): accept image field as string or URL array in TaskSubmitReq
Fankouzu Apr 15, 2026
9fa4128
fix(pingxingshijie): avoid empty envelope data breaking ConvertToOpen…
Fankouzu Apr 15, 2026
49ba8f5
feat(pingxingshijie): pass full upstream JSON via metadata.upstream /…
Fankouzu Apr 15, 2026
35cbcb0
fix(pingxingshijie): extract video create task id from task_id and ne…
Fankouzu Apr 15, 2026
0771812
fix(pingxingshijie): Seedance 1.5 Pro draft_task upscale forwarding a…
Fankouzu Apr 16, 2026
ee071b8
Merge pull request #5 from Fankouzu/feature/channel-pingxingshijie-task
Fankouzu Apr 16, 2026
cb72e2e
feat(pingxingshijie): map channel 58 to Volc relay for chat, unwrap e…
Fankouzu Apr 16, 2026
7288053
fix(pingxingshijie): use /v1/chat/completions upstream for channel 58…
Fankouzu Apr 16, 2026
d077cd7
fix(pingxingshijie): update upstream path for channel 58 to /v2/chat/…
Fankouzu Apr 16, 2026
f4b3c52
Merge pull request #6 from Fankouzu/feature/pingxingshijie-text-chann…
Fankouzu Apr 17, 2026
9f26d60
Merge upstream/main
Fankouzu Apr 28, 2026
1ee1935
Merge origin/main
Fankouzu Apr 28, 2026
8caca48
feat: add comprehensive Token Management API reference documentation
Fankouzu Apr 28, 2026
e89b74c
feat: add Kie task adaptor
Fankouzu Apr 28, 2026
cd369ae
feat: register Kie channel type
Fankouzu Apr 28, 2026
2deeaf9
feat: wire Kie task relay
Fankouzu Apr 28, 2026
490e869
feat: expose Kie models in registry
Fankouzu Apr 28, 2026
ab34e53
feat: add Kie channel option
Fankouzu Apr 28, 2026
e6a6b51
feat: add Kie channel logo
Fankouzu Apr 29, 2026
9965d31
fix: stabilize task billing ratios
Fankouzu Apr 30, 2026
6105339
fix: preserve task provider metadata
Fankouzu Apr 30, 2026
ed4cc98
fix: sync PingXingShiJie task adapter
Fankouzu Apr 30, 2026
cdece92
fix: align PingXingShiJie image endpoint
Fankouzu Apr 30, 2026
0d5f32b
fix: scale Kie image billing by resolution
Fankouzu Apr 30, 2026
63f898e
fix: preserve task request metadata fields
Fankouzu Apr 30, 2026
cf2ac39
Merge pull request #7 from Fankouzu/sync/pingxingshijie-upstream
Fankouzu Apr 30, 2026
9a7e171
Merge origin/main into feature/kie-ai-channel
Fankouzu Apr 30, 2026
56db688
Merge pull request #8 from Fankouzu/feature/kie-ai-channel
Fankouzu Apr 30, 2026
9927a1f
Merge upstream/main into main
Fankouzu Apr 30, 2026
03064d2
fix(ui): add default channel labels for PingXingShiJie and KieAI
Fankouzu Apr 30, 2026
699b7f0
fix(ui): render external channel logo URLs
Fankouzu Apr 30, 2026
c1faa38
Merge pull request #9 from Fankouzu/fix/default-channel-58-59-logos
Fankouzu Apr 30, 2026
08d6d03
feat(logs): extract task media results
Fankouzu Apr 30, 2026
a53db1f
feat(logs): add task media results dialog
Fankouzu Apr 30, 2026
b925361
feat(logs): show task media results in table
Fankouzu Apr 30, 2026
4e1ca77
feat(i18n): add task media result labels
Fankouzu Apr 30, 2026
f039ab0
feat(i18n): add task media result translations
Fankouzu Apr 30, 2026
620aea3
Merge pull request #10 from Fankouzu/feat/default-task-media-results
Fankouzu Apr 30, 2026
ccb29df
feat(distributor): update default model to use taskpxsj.AssetPlacehol…
Fankouzu May 1, 2026
bd7e62c
feat(image-edits): pass JSON requests through to OpenAI
Fankouzu May 4, 2026
b0a34d7
fix(image): add images field to ImageRequest for JSON edits
Fankouzu May 4, 2026
eb2413d
feat(image-edits): stream SSE responses to prevent proxy timeout
Fankouzu May 4, 2026
e5fa07e
fix(image): uncomment Stream field in ImageRequest
Fankouzu May 4, 2026
c1831f6
fix(image-edits): return empty usage instead of nil to prevent panic
Fankouzu May 4, 2026
324b78b
fix(image-edits): parse usage from last data: line in SSE
Fankouzu May 4, 2026
ca265f3
fix(build): use lastDataLine instead of undefined dataLine
Fankouzu May 4, 2026
7648a73
Merge pull request #11 from Fankouzu/feat/image-edits-json-support
Fankouzu May 5, 2026
1094ebe
feat(channel): add fal.ai async task channel
Fankouzu May 5, 2026
e5385ee
fix(frontend): register FalAI(60) in channel type picker
Fankouzu May 5, 2026
6a5acd7
fix(frontend): register FalAI(60) in classic theme channel picker
Fankouzu May 5, 2026
ae019f8
fix(frontend): add Fal.ai(60) channel display in both default and cla…
Fankouzu May 5, 2026
28873b3
fix(frontend): use Fal.Color component from @lobehub/icons/es/Fal for…
Fankouzu May 5, 2026
5d3b07c
fix(fal): 6x3 pricing matrix replaces single quality multipliers
Fankouzu May 5, 2026
32ea6df
docs: add fal.ai channel usage guide with complete pricing matrix
Fankouzu May 5, 2026
be21cff
Merge pull request #12 from Fankouzu/feat/fal-ai-channel
Fankouzu May 8, 2026
e1a8aa9
fix(fal): detect error responses and stop polling on failure
Fankouzu May 9, 2026
8c345ae
fix(fal): handle array format in detail field from FastAPI errors
Fankouzu May 9, 2026
8fea1ac
fix(fal): skip transient detail messages (in progress, in queue) from…
Fankouzu May 9, 2026
e0f8d59
Merge pull request #13 from Fankouzu/fix/fal-ai-error-polling
Fankouzu May 9, 2026
ac3911d
Route long GPT image jobs through async Sub2API
Fankouzu May 11, 2026
91f868f
Expose Sub2API async in the classic channel picker
Fankouzu May 11, 2026
8efe079
Expose Sub2API async models to channel metadata
Fankouzu May 11, 2026
f467125
Prevent classic channel picker from rendering an undefined icon
Fankouzu May 11, 2026
e5d621c
Register async image route with the main relay router
Fankouzu May 11, 2026
7c544aa
Target Sub2API async image endpoint
Fankouzu May 11, 2026
7c7f340
Bridge Sub2API sync images behind async tasks
Fankouzu May 11, 2026
7970e29
Avoid inline image payloads in Sub2API task fetch
Fankouzu May 11, 2026
b61529a
Return Sub2API image base64 from task fetch
Fankouzu May 11, 2026
f43fc80
Shape Sub2API image task results like OpenAI images
Fankouzu May 11, 2026
b14ade7
Add pricing tables for t2i and i2i image generation models
Fankouzu May 11, 2026
0510b7d
Preview Sub2API base64 image task results
Fankouzu May 11, 2026
43767e8
Address async channel review risks
Fankouzu May 11, 2026
041f99f
Merge upstream main to clear PR conflicts
Fankouzu May 11, 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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ data/
.gomodcache/
.gocache-temp
.gopath
.test
token_estimator_test.go
# Local copy of vendor API doc; not tracked (example URLs may trip GitHub push protection)
Pingxingshijie-AI接口.md
.test
skills-lock.json
9 changes: 9 additions & 0 deletions common/api_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ func ChannelType2APIType(channelType int) (int, bool) {
apiType = constant.APITypeMokaAI
case constant.ChannelTypeVolcEngine:
apiType = constant.APITypeVolcEngine
case constant.ChannelTypePingXingShiJie:
// Text/embed/rerank/image sync: same HTTP paths as Volcengine Ark (/api/v3/*). Async tasks still use task/pingxingshijie.
apiType = constant.APITypeVolcEngine
case constant.ChannelTypeKieAI:
// KieAI currently exposes async Market jobs through task/kie; sync calls fall back to OpenAI-compatible handling when used.
apiType = constant.APITypeOpenAI
case constant.ChannelTypeSub2APIAsync:
// Sub2API-async is task-only for async image jobs; keep API type OpenAI-compatible for channel metadata.
apiType = constant.APITypeOpenAI
case constant.ChannelTypeBaiduV2:
apiType = constant.APITypeBaiduV2
case constant.ChannelTypeOpenRouter:
Expand Down
17 changes: 17 additions & 0 deletions common/api_type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package common

import (
"testing"

"github.com/QuantumNous/new-api/constant"
)

func TestChannelType2APITypeMapsSub2APIAsyncToOpenAI(t *testing.T) {
apiType, ok := ChannelType2APIType(constant.ChannelTypeSub2APIAsync)
if !ok {
t.Fatal("expected Sub2API-async channel type to be known")
}
if apiType != constant.APITypeOpenAI {
t.Fatalf("api type = %d, want %d", apiType, constant.APITypeOpenAI)
}
}
12 changes: 12 additions & 0 deletions constant/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const (
ChannelTypeSora = 55
ChannelTypeReplicate = 56
ChannelTypeCodex = 57
ChannelTypePingXingShiJie = 58
ChannelTypeKieAI = 59
ChannelTypeFalAI = 60
ChannelTypeSub2APIAsync = 61
ChannelTypeDummy // this one is only for count, do not add any channel after this

)
Expand Down Expand Up @@ -118,6 +122,10 @@ var ChannelBaseURLs = []string{
"https://api.openai.com", //55
"https://api.replicate.com", //56
"https://chatgpt.com", //57
"https://api.pingxingshijie.cn", //58 PingXingShiJie
"https://api.kie.ai", //59 KieAI
"https://queue.fal.run", //60 FalAI
"https://api.sub2api.com", //61 Sub2API-async
}

var ChannelTypeNames = map[int]string{
Expand Down Expand Up @@ -175,6 +183,10 @@ var ChannelTypeNames = map[int]string{
ChannelTypeSora: "Sora",
ChannelTypeReplicate: "Replicate",
ChannelTypeCodex: "Codex",
ChannelTypePingXingShiJie: "PingXingShiJie",
ChannelTypeKieAI: "KieAI",
ChannelTypeFalAI: "FalAI",
ChannelTypeSub2APIAsync: "Sub2API-async",
}

func GetChannelTypeName(channelType int) string {
Expand Down
11 changes: 10 additions & 1 deletion controller/channel-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
requestPath = "/v1/images/generations"
}

// PingXingShiJie: sync image models use OpenAI image relay; text uses chat (Volc-style upstream via adaptor mapping).
if channel.Type == constant.ChannelTypePingXingShiJie && strings.Contains(strings.ToLower(testModel), "seedream") {
requestPath = "/v1/images/generations"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// responses-only models
if strings.Contains(strings.ToLower(testModel), "codex") {
requestPath = "/v1/responses"
Expand All @@ -135,6 +140,10 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
if strings.HasPrefix(requestPath, "/v1/responses/compact") {
testModel = ratio_setting.WithCompactModelSuffix(testModel)
}
effectiveEndpointType := endpointType
if effectiveEndpointType == "" && requestPath == "/v1/images/generations" {
effectiveEndpointType = string(constant.EndpointTypeImageGeneration)
}

c.Request = &http.Request{
Method: "POST",
Expand Down Expand Up @@ -219,7 +228,7 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
}
}

request := buildTestRequest(testModel, endpointType, channel, isStream)
request := buildTestRequest(testModel, effectiveEndpointType, channel, isStream)

info, err := relaycommon.GenRelayInfo(c, relayFormat, request, nil)

Expand Down
23 changes: 23 additions & 0 deletions controller/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"github.com/QuantumNous/new-api/relay/channel/lingyiwanwu"
"github.com/QuantumNous/new-api/relay/channel/minimax"
"github.com/QuantumNous/new-api/relay/channel/moonshot"
taskkie "github.com/QuantumNous/new-api/relay/channel/task/kie"
taskpxsj "github.com/QuantumNous/new-api/relay/channel/task/pingxingshijie"
tasksub2apiasync "github.com/QuantumNous/new-api/relay/channel/task/sub2api_async"
relaycommon "github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/service"
Expand Down Expand Up @@ -79,6 +82,14 @@ func init() {
OwnedBy: minimax.ChannelName,
})
}
for _, modelName := range taskkie.ModelList {
openAIModels = append(openAIModels, dto.OpenAIModels{
Id: modelName,
Object: "model",
Created: 1626777600,
OwnedBy: taskkie.ChannelName,
})
}
for modelName, _ := range constant.MidjourneyModel2Action {
openAIModels = append(openAIModels, dto.OpenAIModels{
Id: modelName,
Expand All @@ -93,6 +104,18 @@ func init() {
}
channelId2Models = make(map[int][]string)
for i := 1; i <= constant.ChannelTypeDummy; i++ {
if i == constant.ChannelTypePingXingShiJie {
channelId2Models[i] = append([]string(nil), taskpxsj.ModelList...)
continue
}
if i == constant.ChannelTypeKieAI {
channelId2Models[i] = append([]string(nil), taskkie.ModelList...)
continue
}
if i == constant.ChannelTypeSub2APIAsync {
channelId2Models[i] = append([]string(nil), tasksub2apiasync.ModelList...)
continue
}
apiType, success := common.ChannelType2APIType(i)
if !success || apiType == constant.APITypeAIProxyLibrary {
continue
Expand Down
14 changes: 14 additions & 0 deletions controller/model_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/dto"
"github.com/QuantumNous/new-api/model"
taskkie "github.com/QuantumNous/new-api/relay/channel/task/kie"
tasksub2apiasync "github.com/QuantumNous/new-api/relay/channel/task/sub2api_async"
"github.com/QuantumNous/new-api/setting/config"
"github.com/QuantumNous/new-api/setting/operation_setting"
"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -210,6 +212,18 @@ func TestListModelsIncludesTieredBillingModel(t *testing.T) {
require.Empty(t, missingExprPricing.BillingExpr)
}

func TestKieModelsAppearInGlobalModelRegistry(t *testing.T) {
for _, modelName := range taskkie.ModelList {
aiModel, ok := openAIModelsMap[modelName]
require.True(t, ok, "missing Kie model %s", modelName)
require.Equal(t, taskkie.ChannelName, aiModel.OwnedBy)
}
}

func TestSub2APIAsyncModelsAppearInChannelModelRegistry(t *testing.T) {
require.Equal(t, tasksub2apiasync.ModelList, channelId2Models[constant.ChannelTypeSub2APIAsync])
}

func TestListModelsTokenLimitIncludesTieredBillingModel(t *testing.T) {
withSelfUseModeDisabled(t)
withTieredBillingConfig(t, map[string]string{
Expand Down
4 changes: 4 additions & 0 deletions controller/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/QuantumNous/new-api/model"
perfmetrics "github.com/QuantumNous/new-api/pkg/perf_metrics"
"github.com/QuantumNous/new-api/relay"
taskpxsj "github.com/QuantumNous/new-api/relay/channel/task/pingxingshijie"
relaycommon "github.com/QuantumNous/new-api/relay/common"
relayconstant "github.com/QuantumNous/new-api/relay/constant"
"github.com/QuantumNous/new-api/relay/helper"
Expand Down Expand Up @@ -578,6 +579,7 @@ func RelayTask(c *gin.Context) {

task := model.InitTask(result.Platform, relayInfo)
task.PrivateData.UpstreamTaskID = result.UpstreamTaskID
task.PrivateData.UpstreamKind = taskpxsj.UpstreamKindFromPath(c.Request.URL.Path)
task.PrivateData.BillingSource = relayInfo.BillingSource
task.PrivateData.SubscriptionId = relayInfo.SubscriptionId
task.PrivateData.TokenId = relayInfo.TokenId
Expand All @@ -594,6 +596,8 @@ func RelayTask(c *gin.Context) {
task.Action = relayInfo.Action
if insertErr := task.Insert(); insertErr != nil {
common.SysError("insert task error: " + insertErr.Error())
} else if relayInfo.TaskRelayInfo != nil && relayInfo.AfterTaskInserted != nil {
relayInfo.AfterTaskInserted(task.ID)
}
}

Expand Down
Loading