Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const maxOpenAIImageDimensionProbeBytes int64 = 1 << 20
|
||||
|
||||
func detectOpenAIImageResultSize(encoded string) string {
|
||||
payload := strings.TrimSpace(encoded)
|
||||
if strings.HasPrefix(strings.ToLower(payload), "data:") {
|
||||
comma := strings.IndexByte(payload, ',')
|
||||
if comma < 0 || comma+1 >= len(payload) {
|
||||
return ""
|
||||
}
|
||||
payload = strings.TrimSpace(payload[comma+1:])
|
||||
}
|
||||
if payload == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, encoding := range []*base64.Encoding{base64.StdEncoding, base64.RawStdEncoding} {
|
||||
decoded := base64.NewDecoder(encoding, strings.NewReader(payload))
|
||||
buffered := bufio.NewReader(io.LimitReader(decoded, maxOpenAIImageDimensionProbeBytes))
|
||||
prefix, _ := buffered.Peek(30)
|
||||
if width, height, ok := detectOpenAIWebPDimensions(prefix); ok {
|
||||
return fmt.Sprintf("%dx%d", width, height)
|
||||
}
|
||||
cfg, _, err := image.DecodeConfig(buffered)
|
||||
if err != nil || cfg.Width <= 0 || cfg.Height <= 0 {
|
||||
continue
|
||||
}
|
||||
return fmt.Sprintf("%dx%d", cfg.Width, cfg.Height)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func detectOpenAIWebPDimensions(header []byte) (int, int, bool) {
|
||||
if len(header) < 16 || string(header[:4]) != "RIFF" || string(header[8:12]) != "WEBP" {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
switch string(header[12:16]) {
|
||||
case "VP8X":
|
||||
if len(header) < 30 {
|
||||
return 0, 0, false
|
||||
}
|
||||
width := 1 + int(header[24]) + int(header[25])<<8 + int(header[26])<<16
|
||||
height := 1 + int(header[27]) + int(header[28])<<8 + int(header[29])<<16
|
||||
return width, height, width > 0 && height > 0
|
||||
case "VP8 ":
|
||||
if len(header) < 30 || string(header[23:26]) != "\x9d\x01\x2a" {
|
||||
return 0, 0, false
|
||||
}
|
||||
width := int(binary.LittleEndian.Uint16(header[26:28]) & 0x3fff)
|
||||
height := int(binary.LittleEndian.Uint16(header[28:30]) & 0x3fff)
|
||||
return width, height, width > 0 && height > 0
|
||||
case "VP8L":
|
||||
if len(header) < 25 || header[20] != 0x2f {
|
||||
return 0, 0, false
|
||||
}
|
||||
width := 1 + int(header[21]) + int(header[22]&0x3f)<<8
|
||||
height := 1 + int(header[22]>>6) + int(header[23])<<2 + int(header[24]&0x0f)<<10
|
||||
return width, height, width > 0 && height > 0
|
||||
default:
|
||||
return 0, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func reconcileOpenAIResponsesImageResultSizes(results []openAIResponsesImageResult, firstMeta *openAIResponsesImageResult) {
|
||||
for i := range results {
|
||||
// ChatGPT OAuth can normalize requested controls to "auto". The final
|
||||
// image bytes are authoritative for response metadata and tier billing.
|
||||
if actualSize := detectOpenAIImageResultSize(results[i].Result); actualSize != "" {
|
||||
results[i].Size = actualSize
|
||||
}
|
||||
}
|
||||
if firstMeta == nil || len(results) == 0 {
|
||||
return
|
||||
}
|
||||
if size := strings.TrimSpace(results[0].Size); size != "" {
|
||||
firstMeta.Size = size
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user