mirror of
				https://github.com/songquanpeng/one-api.git
				synced 2025-11-04 15:53:42 +08:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			v0.6.7-alp
			...
			v0.6.7-alp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9321427c6e | ||
| 
						 | 
					ceea4c6d4a | 
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							@@ -384,14 +384,17 @@ graph LR
 | 
				
			|||||||
    + `TIKTOKEN_CACHE_DIR`:默认程序启动时会联网下载一些通用的词元的编码,如:`gpt-3.5-turbo`,在一些网络环境不稳定,或者离线情况,可能会导致启动有问题,可以配置此目录缓存数据,可迁移到离线环境。
 | 
					    + `TIKTOKEN_CACHE_DIR`:默认程序启动时会联网下载一些通用的词元的编码,如:`gpt-3.5-turbo`,在一些网络环境不稳定,或者离线情况,可能会导致启动有问题,可以配置此目录缓存数据,可迁移到离线环境。
 | 
				
			||||||
    + `DATA_GYM_CACHE_DIR`:目前该配置作用与 `TIKTOKEN_CACHE_DIR` 一致,但是优先级没有它高。
 | 
					    + `DATA_GYM_CACHE_DIR`:目前该配置作用与 `TIKTOKEN_CACHE_DIR` 一致,但是优先级没有它高。
 | 
				
			||||||
17. `RELAY_TIMEOUT`:中继超时设置,单位为秒,默认不设置超时时间。
 | 
					17. `RELAY_TIMEOUT`:中继超时设置,单位为秒,默认不设置超时时间。
 | 
				
			||||||
18. `SQLITE_BUSY_TIMEOUT`:SQLite 锁等待超时设置,单位为毫秒,默认 `3000`。
 | 
					18. `RELAY_PROXY`:设置后使用该代理来请求 API。
 | 
				
			||||||
19. `GEMINI_SAFETY_SETTING`:Gemini 的安全设置,默认 `BLOCK_NONE`。
 | 
					19. `USER_CONTENT_REQUEST_TIMEOUT`:用户上传内容下载超时时间,单位为秒。
 | 
				
			||||||
20. `GEMINI_VERSION`:One API 所使用的 Gemini 版本,默认为 `v1`。
 | 
					20. `USER_CONTENT_REQUEST_PROXY`:设置后使用该代理来请求用户上传的内容,例如图片。
 | 
				
			||||||
21. `THEME`:系统的主题设置,默认为 `default`,具体可选值参考[此处](./web/README.md)。
 | 
					21. `SQLITE_BUSY_TIMEOUT`:SQLite 锁等待超时设置,单位为毫秒,默认 `3000`。
 | 
				
			||||||
22. `ENABLE_METRIC`:是否根据请求成功率禁用渠道,默认不开启,可选值为 `true` 和 `false`。
 | 
					22. `GEMINI_SAFETY_SETTING`:Gemini 的安全设置,默认 `BLOCK_NONE`。
 | 
				
			||||||
23. `METRIC_QUEUE_SIZE`:请求成功率统计队列大小,默认为 `10`。
 | 
					23. `GEMINI_VERSION`:One API 所使用的 Gemini 版本,默认为 `v1`。
 | 
				
			||||||
24. `METRIC_SUCCESS_RATE_THRESHOLD`:请求成功率阈值,默认为 `0.8`。
 | 
					24. `THEME`:系统的主题设置,默认为 `default`,具体可选值参考[此处](./web/README.md)。
 | 
				
			||||||
25. `INITIAL_ROOT_TOKEN`:如果设置了该值,则在系统首次启动时会自动创建一个值为该环境变量值的 root 用户令牌。
 | 
					25. `ENABLE_METRIC`:是否根据请求成功率禁用渠道,默认不开启,可选值为 `true` 和 `false`。
 | 
				
			||||||
 | 
					26. `METRIC_QUEUE_SIZE`:请求成功率统计队列大小,默认为 `10`。
 | 
				
			||||||
 | 
					27. `METRIC_SUCCESS_RATE_THRESHOLD`:请求成功率阈值,默认为 `0.8`。
 | 
				
			||||||
 | 
					28. `INITIAL_ROOT_TOKEN`:如果设置了该值,则在系统首次启动时会自动创建一个值为该环境变量值的 root 用户令牌。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 命令行参数
 | 
					### 命令行参数
 | 
				
			||||||
1. `--port <port_number>`: 指定服务器监听的端口号,默认为 `3000`。
 | 
					1. `--port <port_number>`: 指定服务器监听的端口号,默认为 `3000`。
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										60
									
								
								common/client/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								common/client/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					package client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/config"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/logger"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var HTTPClient *http.Client
 | 
				
			||||||
 | 
					var ImpatientHTTPClient *http.Client
 | 
				
			||||||
 | 
					var UserContentRequestHTTPClient *http.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Init() {
 | 
				
			||||||
 | 
						if config.UserContentRequestProxy != "" {
 | 
				
			||||||
 | 
							logger.SysLog(fmt.Sprintf("using %s as proxy to fetch user content", config.UserContentRequestProxy))
 | 
				
			||||||
 | 
							proxyURL, err := url.Parse(config.UserContentRequestProxy)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logger.FatalLog(fmt.Sprintf("USER_CONTENT_REQUEST_PROXY set but invalid: %s", config.UserContentRequestProxy))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							transport := &http.Transport{
 | 
				
			||||||
 | 
								Proxy: http.ProxyURL(proxyURL),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							UserContentRequestHTTPClient = &http.Client{
 | 
				
			||||||
 | 
								Transport: transport,
 | 
				
			||||||
 | 
								Timeout:   time.Second * time.Duration(config.UserContentRequestTimeout),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							UserContentRequestHTTPClient = &http.Client{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var transport http.RoundTripper
 | 
				
			||||||
 | 
						if config.RelayProxy != "" {
 | 
				
			||||||
 | 
							logger.SysLog(fmt.Sprintf("using %s as api relay proxy", config.RelayProxy))
 | 
				
			||||||
 | 
							proxyURL, err := url.Parse(config.RelayProxy)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logger.FatalLog(fmt.Sprintf("USER_CONTENT_REQUEST_PROXY set but invalid: %s", config.UserContentRequestProxy))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							transport = &http.Transport{
 | 
				
			||||||
 | 
								Proxy: http.ProxyURL(proxyURL),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if config.RelayTimeout == 0 {
 | 
				
			||||||
 | 
							HTTPClient = &http.Client{
 | 
				
			||||||
 | 
								Transport: transport,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							HTTPClient = &http.Client{
 | 
				
			||||||
 | 
								Timeout:   time.Duration(config.RelayTimeout) * time.Second,
 | 
				
			||||||
 | 
								Transport: transport,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ImpatientHTTPClient = &http.Client{
 | 
				
			||||||
 | 
							Timeout:   5 * time.Second,
 | 
				
			||||||
 | 
							Transport: transport,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -144,3 +144,7 @@ var MetricFailChanSize = env.Int("METRIC_FAIL_CHAN_SIZE", 128)
 | 
				
			|||||||
var InitialRootToken = os.Getenv("INITIAL_ROOT_TOKEN")
 | 
					var InitialRootToken = os.Getenv("INITIAL_ROOT_TOKEN")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var GeminiVersion = env.String("GEMINI_VERSION", "v1")
 | 
					var GeminiVersion = env.String("GEMINI_VERSION", "v1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var RelayProxy = env.String("RELAY_PROXY", "")
 | 
				
			||||||
 | 
					var UserContentRequestProxy = env.String("USER_CONTENT_REQUEST_PROXY", "")
 | 
				
			||||||
 | 
					var UserContentRequestTimeout = env.Int("USER_CONTENT_REQUEST_TIMEOUT", 30)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package image
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/base64"
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"image"
 | 
						"image"
 | 
				
			||||||
	_ "image/gif"
 | 
						_ "image/gif"
 | 
				
			||||||
	_ "image/jpeg"
 | 
						_ "image/jpeg"
 | 
				
			||||||
@@ -19,7 +20,7 @@ import (
 | 
				
			|||||||
var dataURLPattern = regexp.MustCompile(`data:image/([^;]+);base64,(.*)`)
 | 
					var dataURLPattern = regexp.MustCompile(`data:image/([^;]+);base64,(.*)`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func IsImageUrl(url string) (bool, error) {
 | 
					func IsImageUrl(url string) (bool, error) {
 | 
				
			||||||
	resp, err := http.Head(url)
 | 
						resp, err := client.UserContentRequestHTTPClient.Head(url)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, err
 | 
							return false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -34,7 +35,7 @@ func GetImageSizeFromUrl(url string) (width int, height int, err error) {
 | 
				
			|||||||
	if !isImage {
 | 
						if !isImage {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resp, err := http.Get(url)
 | 
						resp, err := client.UserContentRequestHTTPClient.Get(url)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,12 +4,12 @@ import (
 | 
				
			|||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/config"
 | 
						"github.com/songquanpeng/one-api/common/config"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
						"github.com/songquanpeng/one-api/common/logger"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/model"
 | 
						"github.com/songquanpeng/one-api/model"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/monitor"
 | 
						"github.com/songquanpeng/one-api/monitor"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/channeltype"
 | 
						"github.com/songquanpeng/one-api/relay/channeltype"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/client"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"github.com/gin-contrib/sessions/cookie"
 | 
						"github.com/gin-contrib/sessions/cookie"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common"
 | 
						"github.com/songquanpeng/one-api/common"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/config"
 | 
						"github.com/songquanpeng/one-api/common/config"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
						"github.com/songquanpeng/one-api/common/logger"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/controller"
 | 
						"github.com/songquanpeng/one-api/controller"
 | 
				
			||||||
@@ -94,6 +95,7 @@ func main() {
 | 
				
			|||||||
		logger.SysLog("metric enabled, will disable channel if too much request failed")
 | 
							logger.SysLog("metric enabled, will disable channel if too much request failed")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	openai.InitTokenEncoders()
 | 
						openai.InitTokenEncoders()
 | 
				
			||||||
 | 
						client.Init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Initialize HTTP server
 | 
						// Initialize HTTP server
 | 
				
			||||||
	server := gin.New()
 | 
						server := gin.New()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,9 +7,9 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common"
 | 
						"github.com/songquanpeng/one-api/common"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
						"github.com/songquanpeng/one-api/common/logger"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/adaptor/openai"
 | 
						"github.com/songquanpeng/one-api/relay/adaptor/openai"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/client"
 | 
					 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/constant"
 | 
						"github.com/songquanpeng/one-api/relay/constant"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/model"
 | 
						"github.com/songquanpeng/one-api/relay/model"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import (
 | 
				
			|||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/client"
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/meta"
 | 
						"github.com/songquanpeng/one-api/relay/meta"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"github.com/songquanpeng/one-api/relay/adaptor/openai"
 | 
						"github.com/songquanpeng/one-api/relay/adaptor/openai"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/meta"
 | 
						"github.com/songquanpeng/one-api/relay/meta"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/model"
 | 
						"github.com/songquanpeng/one-api/relay/model"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/relay/relaymode"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Adaptor struct {
 | 
					type Adaptor struct {
 | 
				
			||||||
@@ -24,7 +25,14 @@ func (a *Adaptor) Init(meta *meta.Meta) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 | 
					func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 | 
				
			||||||
	version := helper.AssignOrDefault(meta.Config.APIVersion, config.GeminiVersion)
 | 
						version := helper.AssignOrDefault(meta.Config.APIVersion, config.GeminiVersion)
 | 
				
			||||||
	action := "generateContent"
 | 
						action := ""
 | 
				
			||||||
 | 
						switch meta.Mode {
 | 
				
			||||||
 | 
						case relaymode.Embeddings:
 | 
				
			||||||
 | 
							action = "batchEmbedContents"
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							action = "generateContent"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if meta.IsStream {
 | 
						if meta.IsStream {
 | 
				
			||||||
		action = "streamGenerateContent?alt=sse"
 | 
							action = "streamGenerateContent?alt=sse"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -41,7 +49,14 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G
 | 
				
			|||||||
	if request == nil {
 | 
						if request == nil {
 | 
				
			||||||
		return nil, errors.New("request is nil")
 | 
							return nil, errors.New("request is nil")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ConvertRequest(*request), nil
 | 
						switch relayMode {
 | 
				
			||||||
 | 
						case relaymode.Embeddings:
 | 
				
			||||||
 | 
							geminiEmbeddingRequest := ConvertEmbeddingRequest(*request)
 | 
				
			||||||
 | 
							return geminiEmbeddingRequest, nil
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							geminiRequest := ConvertRequest(*request)
 | 
				
			||||||
 | 
							return geminiRequest, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
 | 
					func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
 | 
				
			||||||
@@ -61,7 +76,12 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Met
 | 
				
			|||||||
		err, responseText = StreamHandler(c, resp)
 | 
							err, responseText = StreamHandler(c, resp)
 | 
				
			||||||
		usage = openai.ResponseText2Usage(responseText, meta.ActualModelName, meta.PromptTokens)
 | 
							usage = openai.ResponseText2Usage(responseText, meta.ActualModelName, meta.PromptTokens)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		err, usage = Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
 | 
							switch meta.Mode {
 | 
				
			||||||
 | 
							case relaymode.Embeddings:
 | 
				
			||||||
 | 
								err, usage = EmbeddingHandler(c, resp)
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								err, usage = Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,5 +4,5 @@ package gemini
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var ModelList = []string{
 | 
					var ModelList = []string{
 | 
				
			||||||
	"gemini-pro", "gemini-1.0-pro-001", "gemini-1.5-pro",
 | 
						"gemini-pro", "gemini-1.0-pro-001", "gemini-1.5-pro",
 | 
				
			||||||
	"gemini-pro-vision", "gemini-1.0-pro-vision-001",
 | 
						"gemini-pro-vision", "gemini-1.0-pro-vision-001", "embedding-001", "text-embedding-004",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,6 +134,29 @@ func ConvertRequest(textRequest model.GeneralOpenAIRequest) *ChatRequest {
 | 
				
			|||||||
	return &geminiRequest
 | 
						return &geminiRequest
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ConvertEmbeddingRequest(request model.GeneralOpenAIRequest) *BatchEmbeddingRequest {
 | 
				
			||||||
 | 
						inputs := request.ParseInput()
 | 
				
			||||||
 | 
						requests := make([]EmbeddingRequest, len(inputs))
 | 
				
			||||||
 | 
						model := fmt.Sprintf("models/%s", request.Model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, input := range inputs {
 | 
				
			||||||
 | 
							requests[i] = EmbeddingRequest{
 | 
				
			||||||
 | 
								Model: model,
 | 
				
			||||||
 | 
								Content: ChatContent{
 | 
				
			||||||
 | 
									Parts: []Part{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Text: input,
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &BatchEmbeddingRequest{
 | 
				
			||||||
 | 
							Requests: requests,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ChatResponse struct {
 | 
					type ChatResponse struct {
 | 
				
			||||||
	Candidates     []ChatCandidate    `json:"candidates"`
 | 
						Candidates     []ChatCandidate    `json:"candidates"`
 | 
				
			||||||
	PromptFeedback ChatPromptFeedback `json:"promptFeedback"`
 | 
						PromptFeedback ChatPromptFeedback `json:"promptFeedback"`
 | 
				
			||||||
@@ -230,6 +253,23 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *ChatResponse) *openai.ChatC
 | 
				
			|||||||
	return &response
 | 
						return &response
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func embeddingResponseGemini2OpenAI(response *EmbeddingResponse) *openai.EmbeddingResponse {
 | 
				
			||||||
 | 
						openAIEmbeddingResponse := openai.EmbeddingResponse{
 | 
				
			||||||
 | 
							Object: "list",
 | 
				
			||||||
 | 
							Data:   make([]openai.EmbeddingResponseItem, 0, len(response.Embeddings)),
 | 
				
			||||||
 | 
							Model:  "gemini-embedding",
 | 
				
			||||||
 | 
							Usage:  model.Usage{TotalTokens: 0},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, item := range response.Embeddings {
 | 
				
			||||||
 | 
							openAIEmbeddingResponse.Data = append(openAIEmbeddingResponse.Data, openai.EmbeddingResponseItem{
 | 
				
			||||||
 | 
								Object:    `embedding`,
 | 
				
			||||||
 | 
								Index:     0,
 | 
				
			||||||
 | 
								Embedding: item.Values,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &openAIEmbeddingResponse
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, string) {
 | 
					func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, string) {
 | 
				
			||||||
	responseText := ""
 | 
						responseText := ""
 | 
				
			||||||
	scanner := bufio.NewScanner(resp.Body)
 | 
						scanner := bufio.NewScanner(resp.Body)
 | 
				
			||||||
@@ -337,3 +377,39 @@ func Handler(c *gin.Context, resp *http.Response, promptTokens int, modelName st
 | 
				
			|||||||
	_, err = c.Writer.Write(jsonResponse)
 | 
						_, err = c.Writer.Write(jsonResponse)
 | 
				
			||||||
	return nil, &usage
 | 
						return nil, &usage
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func EmbeddingHandler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatusCode, *model.Usage) {
 | 
				
			||||||
 | 
						var geminiEmbeddingResponse EmbeddingResponse
 | 
				
			||||||
 | 
						responseBody, err := io.ReadAll(resp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return openai.ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = resp.Body.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = json.Unmarshal(responseBody, &geminiEmbeddingResponse)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return openai.ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if geminiEmbeddingResponse.Error != nil {
 | 
				
			||||||
 | 
							return &model.ErrorWithStatusCode{
 | 
				
			||||||
 | 
								Error: model.Error{
 | 
				
			||||||
 | 
									Message: geminiEmbeddingResponse.Error.Message,
 | 
				
			||||||
 | 
									Type:    "gemini_error",
 | 
				
			||||||
 | 
									Param:   "",
 | 
				
			||||||
 | 
									Code:    geminiEmbeddingResponse.Error.Code,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								StatusCode: resp.StatusCode,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fullTextResponse := embeddingResponseGemini2OpenAI(&geminiEmbeddingResponse)
 | 
				
			||||||
 | 
						jsonResponse, err := json.Marshal(fullTextResponse)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return openai.ErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.Writer.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
 | 
						c.Writer.WriteHeader(resp.StatusCode)
 | 
				
			||||||
 | 
						_, err = c.Writer.Write(jsonResponse)
 | 
				
			||||||
 | 
						return nil, &fullTextResponse.Usage
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,33 @@ type ChatRequest struct {
 | 
				
			|||||||
	Tools            []ChatTools          `json:"tools,omitempty"`
 | 
						Tools            []ChatTools          `json:"tools,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmbeddingRequest struct {
 | 
				
			||||||
 | 
						Model                string      `json:"model"`
 | 
				
			||||||
 | 
						Content              ChatContent `json:"content"`
 | 
				
			||||||
 | 
						TaskType             string      `json:"taskType,omitempty"`
 | 
				
			||||||
 | 
						Title                string      `json:"title,omitempty"`
 | 
				
			||||||
 | 
						OutputDimensionality int         `json:"outputDimensionality,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BatchEmbeddingRequest struct {
 | 
				
			||||||
 | 
						Requests []EmbeddingRequest `json:"requests"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmbeddingData struct {
 | 
				
			||||||
 | 
						Values []float64 `json:"values"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmbeddingResponse struct {
 | 
				
			||||||
 | 
						Embeddings []EmbeddingData `json:"embeddings"`
 | 
				
			||||||
 | 
						Error      *Error          `json:"error,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Error struct {
 | 
				
			||||||
 | 
						Code    int    `json:"code,omitempty"`
 | 
				
			||||||
 | 
						Message string `json:"message,omitempty"`
 | 
				
			||||||
 | 
						Status  string `json:"status,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type InlineData struct {
 | 
					type InlineData struct {
 | 
				
			||||||
	MimeType string `json:"mimeType"`
 | 
						MimeType string `json:"mimeType"`
 | 
				
			||||||
	Data     string `json:"data"`
 | 
						Data     string `json:"data"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +0,0 @@
 | 
				
			|||||||
package client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/config"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var HTTPClient *http.Client
 | 
					 | 
				
			||||||
var ImpatientHTTPClient *http.Client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	if config.RelayTimeout == 0 {
 | 
					 | 
				
			||||||
		HTTPClient = &http.Client{}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		HTTPClient = &http.Client{
 | 
					 | 
				
			||||||
			Timeout: time.Duration(config.RelayTimeout) * time.Second,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ImpatientHTTPClient = &http.Client{
 | 
					 | 
				
			||||||
		Timeout: 5 * time.Second,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/gin-gonic/gin"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common"
 | 
						"github.com/songquanpeng/one-api/common"
 | 
				
			||||||
 | 
						"github.com/songquanpeng/one-api/common/client"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/config"
 | 
						"github.com/songquanpeng/one-api/common/config"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/ctxkey"
 | 
						"github.com/songquanpeng/one-api/common/ctxkey"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
						"github.com/songquanpeng/one-api/common/logger"
 | 
				
			||||||
@@ -17,7 +18,6 @@ import (
 | 
				
			|||||||
	"github.com/songquanpeng/one-api/relay/billing"
 | 
						"github.com/songquanpeng/one-api/relay/billing"
 | 
				
			||||||
	billingratio "github.com/songquanpeng/one-api/relay/billing/ratio"
 | 
						billingratio "github.com/songquanpeng/one-api/relay/billing/ratio"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/channeltype"
 | 
						"github.com/songquanpeng/one-api/relay/channeltype"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/client"
 | 
					 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/meta"
 | 
						"github.com/songquanpeng/one-api/relay/meta"
 | 
				
			||||||
	relaymodel "github.com/songquanpeng/one-api/relay/model"
 | 
						relaymodel "github.com/songquanpeng/one-api/relay/model"
 | 
				
			||||||
	"github.com/songquanpeng/one-api/relay/relaymode"
 | 
						"github.com/songquanpeng/one-api/relay/relaymode"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user