relay_info.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. package common
  2. import (
  3. "one-api/common"
  4. "one-api/constant"
  5. "one-api/dto"
  6. relayconstant "one-api/relay/constant"
  7. "strings"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/gorilla/websocket"
  11. )
  12. type ThinkingContentInfo struct {
  13. IsFirstThinkingContent bool
  14. SendLastThinkingContent bool
  15. HasSentThinkingContent bool
  16. }
  17. const (
  18. LastMessageTypeNone = "none"
  19. LastMessageTypeText = "text"
  20. LastMessageTypeTools = "tools"
  21. LastMessageTypeThinking = "thinking"
  22. )
  23. type ClaudeConvertInfo struct {
  24. LastMessagesType string
  25. Index int
  26. Usage *dto.Usage
  27. FinishReason string
  28. Done bool
  29. }
  30. const (
  31. RelayFormatOpenAI = "openai"
  32. RelayFormatClaude = "claude"
  33. RelayFormatGemini = "gemini"
  34. RelayFormatOpenAIResponses = "openai_responses"
  35. RelayFormatOpenAIAudio = "openai_audio"
  36. RelayFormatOpenAIImage = "openai_image"
  37. RelayFormatRerank = "rerank"
  38. RelayFormatEmbedding = "embedding"
  39. )
  40. type RerankerInfo struct {
  41. Documents []any
  42. ReturnDocuments bool
  43. }
  44. type BuildInToolInfo struct {
  45. ToolName string
  46. CallCount int
  47. SearchContextSize string
  48. }
  49. type ResponsesUsageInfo struct {
  50. BuiltInTools map[string]*BuildInToolInfo
  51. }
  52. type RelayInfo struct {
  53. ChannelType int
  54. ChannelId int
  55. ChannelIsMultiKey bool // 是否多密钥
  56. ChannelMultiKeyIndex int // 多密钥索引
  57. TokenId int
  58. TokenKey string
  59. UserId int
  60. UsingGroup string // 使用的分组
  61. UserGroup string // 用户所在分组
  62. TokenUnlimited bool
  63. StartTime time.Time
  64. FirstResponseTime time.Time
  65. isFirstResponse bool
  66. //SendLastReasoningResponse bool
  67. ApiType int
  68. IsStream bool
  69. IsGeminiBatchEmbedding bool
  70. IsPlayground bool
  71. UsePrice bool
  72. RelayMode int
  73. UpstreamModelName string
  74. OriginModelName string
  75. //RecodeModelName string
  76. RequestURLPath string
  77. ApiVersion string
  78. PromptTokens int
  79. ApiKey string
  80. Organization string
  81. BaseUrl string
  82. SupportStreamOptions bool
  83. ShouldIncludeUsage bool
  84. DisablePing bool // 是否禁止向下游发送自定义 Ping
  85. IsModelMapped bool
  86. ClientWs *websocket.Conn
  87. TargetWs *websocket.Conn
  88. InputAudioFormat string
  89. OutputAudioFormat string
  90. RealtimeTools []dto.RealTimeTool
  91. IsFirstRequest bool
  92. AudioUsage bool
  93. ReasoningEffort string
  94. ChannelSetting dto.ChannelSettings
  95. ChannelOtherSettings dto.ChannelOtherSettings
  96. ParamOverride map[string]interface{}
  97. UserSetting dto.UserSetting
  98. UserEmail string
  99. UserQuota int
  100. RelayFormat string
  101. SendResponseCount int
  102. ChannelCreateTime int64
  103. ThinkingContentInfo
  104. *ClaudeConvertInfo
  105. *RerankerInfo
  106. *ResponsesUsageInfo
  107. }
  108. // 定义支持流式选项的通道类型
  109. var streamSupportedChannels = map[int]bool{
  110. constant.ChannelTypeOpenAI: true,
  111. constant.ChannelTypeAnthropic: true,
  112. constant.ChannelTypeAws: true,
  113. constant.ChannelTypeGemini: true,
  114. constant.ChannelCloudflare: true,
  115. constant.ChannelTypeAzure: true,
  116. constant.ChannelTypeVolcEngine: true,
  117. constant.ChannelTypeOllama: true,
  118. constant.ChannelTypeXai: true,
  119. constant.ChannelTypeDeepSeek: true,
  120. constant.ChannelTypeBaiduV2: true,
  121. }
  122. func GenRelayInfoWs(c *gin.Context, ws *websocket.Conn) *RelayInfo {
  123. info := GenRelayInfo(c)
  124. info.ClientWs = ws
  125. info.InputAudioFormat = "pcm16"
  126. info.OutputAudioFormat = "pcm16"
  127. info.IsFirstRequest = true
  128. return info
  129. }
  130. func GenRelayInfoClaude(c *gin.Context) *RelayInfo {
  131. info := GenRelayInfo(c)
  132. info.RelayFormat = RelayFormatClaude
  133. info.ShouldIncludeUsage = false
  134. info.ClaudeConvertInfo = &ClaudeConvertInfo{
  135. LastMessagesType: LastMessageTypeNone,
  136. }
  137. return info
  138. }
  139. func GenRelayInfoRerank(c *gin.Context, req *dto.RerankRequest) *RelayInfo {
  140. info := GenRelayInfo(c)
  141. info.RelayMode = relayconstant.RelayModeRerank
  142. info.RelayFormat = RelayFormatRerank
  143. info.RerankerInfo = &RerankerInfo{
  144. Documents: req.Documents,
  145. ReturnDocuments: req.GetReturnDocuments(),
  146. }
  147. return info
  148. }
  149. func GenRelayInfoOpenAIAudio(c *gin.Context) *RelayInfo {
  150. info := GenRelayInfo(c)
  151. info.RelayFormat = RelayFormatOpenAIAudio
  152. return info
  153. }
  154. func GenRelayInfoEmbedding(c *gin.Context) *RelayInfo {
  155. info := GenRelayInfo(c)
  156. info.RelayFormat = RelayFormatEmbedding
  157. return info
  158. }
  159. func GenRelayInfoResponses(c *gin.Context, req *dto.OpenAIResponsesRequest) *RelayInfo {
  160. info := GenRelayInfo(c)
  161. info.RelayMode = relayconstant.RelayModeResponses
  162. info.RelayFormat = RelayFormatOpenAIResponses
  163. info.SupportStreamOptions = false
  164. info.ResponsesUsageInfo = &ResponsesUsageInfo{
  165. BuiltInTools: make(map[string]*BuildInToolInfo),
  166. }
  167. if len(req.Tools) > 0 {
  168. for _, tool := range req.Tools {
  169. toolType := common.Interface2String(tool["type"])
  170. info.ResponsesUsageInfo.BuiltInTools[toolType] = &BuildInToolInfo{
  171. ToolName: toolType,
  172. CallCount: 0,
  173. }
  174. switch toolType {
  175. case dto.BuildInToolWebSearchPreview:
  176. searchContextSize := common.Interface2String(tool["search_context_size"])
  177. if searchContextSize == "" {
  178. searchContextSize = "medium"
  179. }
  180. info.ResponsesUsageInfo.BuiltInTools[toolType].SearchContextSize = searchContextSize
  181. }
  182. }
  183. }
  184. info.IsStream = req.Stream
  185. return info
  186. }
  187. func GenRelayInfoGemini(c *gin.Context) *RelayInfo {
  188. info := GenRelayInfo(c)
  189. info.RelayFormat = RelayFormatGemini
  190. info.ShouldIncludeUsage = false
  191. return info
  192. }
  193. func GenRelayInfoImage(c *gin.Context) *RelayInfo {
  194. info := GenRelayInfo(c)
  195. info.RelayFormat = RelayFormatOpenAIImage
  196. return info
  197. }
  198. func GenRelayInfo(c *gin.Context) *RelayInfo {
  199. channelType := common.GetContextKeyInt(c, constant.ContextKeyChannelType)
  200. channelId := common.GetContextKeyInt(c, constant.ContextKeyChannelId)
  201. paramOverride := common.GetContextKeyStringMap(c, constant.ContextKeyChannelParamOverride)
  202. tokenId := common.GetContextKeyInt(c, constant.ContextKeyTokenId)
  203. tokenKey := common.GetContextKeyString(c, constant.ContextKeyTokenKey)
  204. userId := common.GetContextKeyInt(c, constant.ContextKeyUserId)
  205. tokenUnlimited := common.GetContextKeyBool(c, constant.ContextKeyTokenUnlimited)
  206. startTime := common.GetContextKeyTime(c, constant.ContextKeyRequestStartTime)
  207. if startTime.IsZero() {
  208. startTime = time.Now()
  209. }
  210. // firstResponseTime = time.Now() - 1 second
  211. apiType, _ := common.ChannelType2APIType(channelType)
  212. info := &RelayInfo{
  213. UserQuota: common.GetContextKeyInt(c, constant.ContextKeyUserQuota),
  214. UserEmail: common.GetContextKeyString(c, constant.ContextKeyUserEmail),
  215. isFirstResponse: true,
  216. RelayMode: relayconstant.Path2RelayMode(c.Request.URL.Path),
  217. BaseUrl: common.GetContextKeyString(c, constant.ContextKeyChannelBaseUrl),
  218. RequestURLPath: c.Request.URL.String(),
  219. ChannelType: channelType,
  220. ChannelId: channelId,
  221. TokenId: tokenId,
  222. TokenKey: tokenKey,
  223. UserId: userId,
  224. UsingGroup: common.GetContextKeyString(c, constant.ContextKeyUsingGroup),
  225. UserGroup: common.GetContextKeyString(c, constant.ContextKeyUserGroup),
  226. TokenUnlimited: tokenUnlimited,
  227. StartTime: startTime,
  228. FirstResponseTime: startTime.Add(-time.Second),
  229. OriginModelName: common.GetContextKeyString(c, constant.ContextKeyOriginalModel),
  230. UpstreamModelName: common.GetContextKeyString(c, constant.ContextKeyOriginalModel),
  231. //RecodeModelName: c.GetString("original_model"),
  232. IsModelMapped: false,
  233. ApiType: apiType,
  234. ApiVersion: c.GetString("api_version"),
  235. ApiKey: common.GetContextKeyString(c, constant.ContextKeyChannelKey),
  236. Organization: c.GetString("channel_organization"),
  237. ChannelCreateTime: c.GetInt64("channel_create_time"),
  238. ParamOverride: paramOverride,
  239. RelayFormat: RelayFormatOpenAI,
  240. ThinkingContentInfo: ThinkingContentInfo{
  241. IsFirstThinkingContent: true,
  242. SendLastThinkingContent: false,
  243. },
  244. ChannelIsMultiKey: common.GetContextKeyBool(c, constant.ContextKeyChannelIsMultiKey),
  245. ChannelMultiKeyIndex: common.GetContextKeyInt(c, constant.ContextKeyChannelMultiKeyIndex),
  246. }
  247. if strings.HasPrefix(c.Request.URL.Path, "/pg") {
  248. info.IsPlayground = true
  249. info.RequestURLPath = strings.TrimPrefix(info.RequestURLPath, "/pg")
  250. info.RequestURLPath = "/v1" + info.RequestURLPath
  251. }
  252. if info.BaseUrl == "" {
  253. info.BaseUrl = constant.ChannelBaseURLs[channelType]
  254. }
  255. if info.ChannelType == constant.ChannelTypeAzure {
  256. info.ApiVersion = GetAPIVersion(c)
  257. }
  258. if info.ChannelType == constant.ChannelTypeVertexAi {
  259. info.ApiVersion = c.GetString("region")
  260. }
  261. if streamSupportedChannels[info.ChannelType] {
  262. info.SupportStreamOptions = true
  263. }
  264. channelSetting, ok := common.GetContextKeyType[dto.ChannelSettings](c, constant.ContextKeyChannelSetting)
  265. if ok {
  266. info.ChannelSetting = channelSetting
  267. }
  268. channelOtherSettings, ok := common.GetContextKeyType[dto.ChannelOtherSettings](c, constant.ContextKeyChannelOtherSetting)
  269. if ok {
  270. info.ChannelOtherSettings = channelOtherSettings
  271. }
  272. userSetting, ok := common.GetContextKeyType[dto.UserSetting](c, constant.ContextKeyUserSetting)
  273. if ok {
  274. info.UserSetting = userSetting
  275. }
  276. return info
  277. }
  278. func (info *RelayInfo) SetPromptTokens(promptTokens int) {
  279. info.PromptTokens = promptTokens
  280. }
  281. func (info *RelayInfo) SetIsStream(isStream bool) {
  282. info.IsStream = isStream
  283. }
  284. func (info *RelayInfo) SetFirstResponseTime() {
  285. if info.isFirstResponse {
  286. info.FirstResponseTime = time.Now()
  287. info.isFirstResponse = false
  288. }
  289. }
  290. func (info *RelayInfo) HasSendResponse() bool {
  291. return info.FirstResponseTime.After(info.StartTime)
  292. }
  293. type TaskRelayInfo struct {
  294. *RelayInfo
  295. Action string
  296. OriginTaskID string
  297. ConsumeQuota bool
  298. }
  299. func GenTaskRelayInfo(c *gin.Context) *TaskRelayInfo {
  300. info := &TaskRelayInfo{
  301. RelayInfo: GenRelayInfo(c),
  302. }
  303. return info
  304. }
  305. type TaskSubmitReq struct {
  306. Prompt string `json:"prompt"`
  307. Model string `json:"model,omitempty"`
  308. Mode string `json:"mode,omitempty"`
  309. Image string `json:"image,omitempty"`
  310. Size string `json:"size,omitempty"`
  311. Duration int `json:"duration,omitempty"`
  312. Metadata map[string]interface{} `json:"metadata,omitempty"`
  313. }
  314. type TaskInfo struct {
  315. Code int `json:"code"`
  316. TaskID string `json:"task_id"`
  317. Status string `json:"status"`
  318. Reason string `json:"reason,omitempty"`
  319. Url string `json:"url,omitempty"`
  320. Progress string `json:"progress,omitempty"`
  321. }