mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-08 00:54:17 +00:00
优化透传图片意图判定复用
This commit is contained in:
1 parent
da85cc7e47
commit
92edda2f6e
3 files changed
+89
-2
No files matched your search
@@ -100,7 +100,8 @@ func (s *OpenAIGatewayService) forwardOpenAIPassthrough(
|
|||||||
body = updatedBody
|
body = updatedBody
|
||||||
|
|
||||||
apiKey := getAPIKeyFromContext(c)
|
apiKey := getAPIKeyFromContext(c)
|
||||||
if IsImageGenerationIntent(openAIResponsesEndpoint, reqModel, body) && !GroupAllowsImageGeneration(apiKeyGroup(apiKey)) {
|
imageIntent := IsImageGenerationIntent(openAIResponsesEndpoint, reqModel, body)
|
||||||
|
if imageIntent && !GroupAllowsImageGeneration(apiKeyGroup(apiKey)) {
|
||||||
MarkOpsClientBusinessLimited(c, OpsClientBusinessLimitedReasonLocalFeatureGate)
|
MarkOpsClientBusinessLimited(c, OpsClientBusinessLimitedReasonLocalFeatureGate)
|
||||||
c.JSON(http.StatusForbidden, gin.H{
|
c.JSON(http.StatusForbidden, gin.H{
|
||||||
"error": gin.H{
|
"error": gin.H{
|
||||||
@@ -113,7 +114,7 @@ func (s *OpenAIGatewayService) forwardOpenAIPassthrough(
|
|||||||
imageBillingModel := ""
|
imageBillingModel := ""
|
||||||
imageSizeTier := ""
|
imageSizeTier := ""
|
||||||
imageInputSize := ""
|
imageInputSize := ""
|
||||||
if IsImageGenerationIntent(openAIResponsesEndpoint, reqModel, body) {
|
if imageIntent {
|
||||||
var imageCfgErr error
|
var imageCfgErr error
|
||||||
imageCfg, imageCfgErr := resolveOpenAIResponsesImageBillingConfigDetailedFromBody(body, reqModel)
|
imageCfg, imageCfgErr := resolveOpenAIResponsesImageBillingConfigDetailedFromBody(body, reqModel)
|
||||||
if imageCfgErr != nil {
|
if imageCfgErr != nil {
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var passthroughImageIntentBenchmarkSink bool
|
||||||
|
|
||||||
|
func BenchmarkOpenAIPassthroughImageIntentReuse_LargeBody(b *testing.B) {
|
||||||
|
body := buildLargeOpenAIResponsesImageToolBody(32 << 20)
|
||||||
|
|
||||||
|
b.Run("Once", func(b *testing.B) {
|
||||||
|
b.SetBytes(int64(len(body)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
passthroughImageIntentBenchmarkSink = IsImageGenerationIntent(openAIResponsesEndpoint, "gpt-5.4", body)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("Twice", func(b *testing.B) {
|
||||||
|
b.SetBytes(int64(len(body)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
permissionIntent := IsImageGenerationIntent(openAIResponsesEndpoint, "gpt-5.4", body)
|
||||||
|
billingIntent := IsImageGenerationIntent(openAIResponsesEndpoint, "gpt-5.4", body)
|
||||||
|
passthroughImageIntentBenchmarkSink = permissionIntent && billingIntent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOpenAIGatewayService_APIKeyPassthrough_ImageIntentPreservesGateAndBilling(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
body := []byte(`{"model":"gpt-5.4","stream":false,"tools":[{"type":"image_generation","model":"gpt-image-2","size":"2048x1152"}],"input":"draw"}`)
|
||||||
|
|
||||||
|
t.Run("disabled group rejects before upstream", func(t *testing.T) {
|
||||||
|
upstream := &httpUpstreamRecorder{}
|
||||||
|
svc := newOpenAIImageGenerationControlTestService(upstream)
|
||||||
|
c, recorder := newOpenAIImageGenerationControlTestContext(false, "curl/8.0")
|
||||||
|
account := newOpenAIImageGenerationControlTestAccount()
|
||||||
|
account.Extra = map[string]any{"openai_passthrough": true}
|
||||||
|
|
||||||
|
result, err := svc.Forward(context.Background(), c, account, body)
|
||||||
|
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, result)
|
||||||
|
require.Equal(t, http.StatusForbidden, recorder.Code)
|
||||||
|
require.Equal(t, "permission_error", gjson.GetBytes(recorder.Body.Bytes(), "error.type").String())
|
||||||
|
require.Nil(t, upstream.lastReq)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("allowed group keeps image billing", func(t *testing.T) {
|
||||||
|
upstream := &httpUpstreamRecorder{resp: &http.Response{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
||||||
|
Body: io.NopCloser(strings.NewReader(
|
||||||
|
`{"output":[{"id":"ig_1","type":"image_generation_call","result":"final-image","size":"2048x1152"}],"usage":{"input_tokens":1,"output_tokens":2}}`,
|
||||||
|
)),
|
||||||
|
}}
|
||||||
|
svc := newOpenAIImageGenerationControlTestService(upstream)
|
||||||
|
c, _ := newOpenAIImageGenerationControlTestContext(true, "curl/8.0")
|
||||||
|
account := newOpenAIImageGenerationControlTestAccount()
|
||||||
|
account.Extra = map[string]any{"openai_passthrough": true}
|
||||||
|
|
||||||
|
result, err := svc.Forward(context.Background(), c, account, body)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
require.NotNil(t, upstream.lastReq)
|
||||||
|
require.Equal(t, body, upstream.lastBody)
|
||||||
|
require.Equal(t, 1, result.ImageCount)
|
||||||
|
require.Equal(t, "gpt-image-2", result.BillingModel)
|
||||||
|
require.Equal(t, "2K", result.ImageSize)
|
||||||
|
require.Equal(t, "2048x1152", result.ImageInputSize)
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in new issue
Block a user