Skip to content

Commit 2998696

Browse files
committed
feat: 添加图像生成API支持,包括请求和响应结构
1 parent 1282fb5 commit 2998696

8 files changed

Lines changed: 699 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ tools/authenticator/.proxies.txt.swp
1313
/logs/
1414
/target/
1515
/bin/
16+
.gocache

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@ curl --location 'http://你的服务器ip:8080/v1/audio/speech' \
7474
}' \
7575
--output speech.mp3
7676
```
77+
78+
### 图片生成
79+
80+
```bash
81+
curl --location 'http://你的服务器ip:8080/v1/images/generations' \
82+
--header 'Content-Type: application/json' \
83+
--header 'Authorization: Bearer access_token' \
84+
--data '{
85+
"model": "gpt-image-2",
86+
"prompt": "A cute orange cat wearing sunglasses, digital art",
87+
"n": 1,
88+
"size": "1024x1024",
89+
"response_format": "url"
90+
}'
91+
```
92+
93+
如需返回 base64,将 `response_format` 改为 `b64_json`
94+
7795
## 高级设置
7896

7997
默认情况不需要设置,除非你有需求
@@ -106,4 +124,4 @@ MIT License
106124

107125
- [linux.do](https://linux.do/)
108126
- [xiaozhou26](https://github.com/xiaozhou26)
109-
- [aurorax-neo](https://github.com/aurorax-neo)
127+
- [aurorax-neo](https://github.com/aurorax-neo)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.7
1+
2.2.8

initialize/handlers.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
chatgpt_types "aurora/typings/chatgpt"
1010
officialtypes "aurora/typings/official"
1111
"aurora/util"
12+
"encoding/base64"
1213
"io"
1314
"os"
1415
"strings"
@@ -377,6 +378,137 @@ func (h *Handler) responses(c *gin.Context) {
377378
c.String(200, "data: [DONE]\n\n")
378379
}
379380

381+
func (h *Handler) imageGenerations(c *gin.Context) {
382+
var imageRequest officialtypes.ImageGenerationRequest
383+
err := c.BindJSON(&imageRequest)
384+
if err != nil {
385+
c.JSON(400, gin.H{"error": gin.H{
386+
"message": "Request must be proper JSON",
387+
"type": "invalid_request_error",
388+
"param": nil,
389+
"code": err.Error(),
390+
}})
391+
return
392+
}
393+
if imageRequest.Prompt == "" {
394+
c.JSON(400, gin.H{"error": gin.H{
395+
"message": "Missing required parameter: prompt",
396+
"type": "invalid_request_error",
397+
"param": "prompt",
398+
"code": "missing_required_parameter",
399+
}})
400+
return
401+
}
402+
if imageRequest.N <= 0 {
403+
imageRequest.N = 1
404+
}
405+
if imageRequest.N > 10 {
406+
imageRequest.N = 10
407+
}
408+
if imageRequest.ResponseFormat == "" {
409+
imageRequest.ResponseFormat = "b64_json"
410+
}
411+
412+
proxyUrl := h.proxy.GetProxyIP()
413+
secret := h.token.GetPaidSecret()
414+
authHeader := c.GetHeader("Authorization")
415+
if authHeader != "" {
416+
customAccessToken := strings.Replace(authHeader, "Bearer ", "", 1)
417+
if strings.HasPrefix(customAccessToken, "eyJhbGciOiJSUzI1NiI") {
418+
secret = h.token.GenerateTempToken(customAccessToken)
419+
}
420+
}
421+
if secret == nil || secret.Token == "" {
422+
c.JSON(400, gin.H{"error": "Images API requires a logged-in ChatGPT access token."})
423+
c.Abort()
424+
return
425+
}
426+
if secret.IsFree {
427+
c.JSON(403, gin.H{"error": "Images API does not support free/noauth accounts. Use a ChatGPT access token."})
428+
return
429+
}
430+
431+
client := bogdanfinn.NewStdClient()
432+
client.SetCookies("https://chatgpt.com", chatgpt.BasicCookies)
433+
turnStile, status, err := chatgpt.InitTurnStile(client, secret, proxyUrl)
434+
if err != nil {
435+
c.JSON(status, gin.H{
436+
"message": err.Error(),
437+
"type": "InitTurnStile_request_error",
438+
"param": err,
439+
"code": status,
440+
})
441+
return
442+
}
443+
444+
var data []officialtypes.ImageGenerationData
445+
for i := 0; i < imageRequest.N; i++ {
446+
imageResults, upstreamText, err := chatgpt.GeneratePictureConversationImages(client, secret, turnStile, imageRequest.Prompt, imageRequest.Model, proxyUrl)
447+
if err != nil {
448+
c.JSON(500, gin.H{"error": gin.H{
449+
"message": err.Error(),
450+
"type": "image_generation_error",
451+
"param": nil,
452+
"code": "image_generation_error",
453+
}})
454+
return
455+
}
456+
for _, imageResult := range imageResults {
457+
item := officialtypes.ImageGenerationData{
458+
RevisedPrompt: imageRequest.Prompt,
459+
}
460+
if imageRequest.ResponseFormat == "b64_json" {
461+
if imageResult.B64JSON != "" {
462+
item.B64JSON = imageResult.B64JSON
463+
} else if imageResult.URL != "" {
464+
imageBytes, err := chatgpt.DownloadImageBytes(client, imageResult.URL, secret.Token, secret.PUID)
465+
if err != nil {
466+
c.JSON(500, gin.H{"error": gin.H{
467+
"message": err.Error(),
468+
"type": "image_download_error",
469+
"param": nil,
470+
"code": "image_download_error",
471+
}})
472+
return
473+
}
474+
item.B64JSON = base64.StdEncoding.EncodeToString(imageBytes)
475+
}
476+
} else {
477+
item.URL = imageResult.URL
478+
if item.URL == "" && imageResult.B64JSON != "" {
479+
item.B64JSON = imageResult.B64JSON
480+
}
481+
}
482+
data = append(data, item)
483+
if len(data) >= imageRequest.N {
484+
break
485+
}
486+
}
487+
if len(imageResults) == 0 && upstreamText != "" {
488+
c.JSON(500, gin.H{"error": gin.H{
489+
"message": "No image result found in response: " + upstreamText,
490+
"type": "image_generation_error",
491+
"param": nil,
492+
"code": "image_generation_error",
493+
}})
494+
return
495+
}
496+
if len(data) >= imageRequest.N {
497+
break
498+
}
499+
}
500+
if len(data) == 0 {
501+
c.JSON(500, gin.H{"error": gin.H{
502+
"message": "No image result found in response",
503+
"type": "image_generation_error",
504+
"param": nil,
505+
"code": "image_generation_error",
506+
}})
507+
return
508+
}
509+
c.JSON(200, officialtypes.NewImageGenerationResponse(data))
510+
}
511+
380512
func (h *Handler) engines(c *gin.Context) {
381513
type ResData struct {
382514
ID string `json:"id"`

initialize/router.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ func RegisterRouter() *gin.Engine {
3434
router.POST("/auth/refresh", handler.refresh)
3535
router.OPTIONS("/v1/chat/completions", optionsHandler)
3636
router.OPTIONS("/v1/responses", optionsHandler)
37+
router.OPTIONS("/v1/images/generations", optionsHandler)
3738

3839
authGroup := router.Group("").Use(middlewares.Authorization)
3940
authGroup.POST("/v1/chat/completions", handler.nightmare)
4041
authGroup.POST("/v1/responses", handler.responses)
4142
authGroup.GET("/v1/models", handler.engines)
4243
authGroup.POST("/backend-api/conversation", handler.chatgptConversation)
44+
authGroup.POST("/v1/images/generations", handler.imageGenerations)
4345
authGroup.OPTIONS("/v1/audio/speech", optionsHandler)
4446
authGroup.POST("/v1/audio/speech", handler.tts)
4547
return router

0 commit comments

Comments
 (0)