relay_info.go 9.8 KB

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