channel.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package controller
  2. import (
  3. "fmt"
  4. "maps"
  5. "net/http"
  6. "slices"
  7. "strconv"
  8. "strings"
  9. "github.com/gin-gonic/gin"
  10. "github.com/labring/aiproxy/core/controller/utils"
  11. "github.com/labring/aiproxy/core/middleware"
  12. "github.com/labring/aiproxy/core/model"
  13. "github.com/labring/aiproxy/core/monitor"
  14. "github.com/labring/aiproxy/core/relay/adaptors"
  15. log "github.com/sirupsen/logrus"
  16. )
  17. // ChannelTypeMetas godoc
  18. //
  19. // @Summary Get channel type metadata
  20. // @Description Returns metadata for all channel types
  21. // @Tags channels
  22. // @Produce json
  23. // @Security ApiKeyAuth
  24. // @Success 200 {object} middleware.APIResponse{data=map[int]adaptors.AdaptorMeta}
  25. // @Router /api/channels/type_metas [get]
  26. func ChannelTypeMetas(c *gin.Context) {
  27. middleware.SuccessResponse(c, adaptors.ChannelMetas)
  28. }
  29. // GetChannels godoc
  30. //
  31. // @Summary Get channels with pagination
  32. // @Description Returns a paginated list of channels with optional filters
  33. // @Tags channels
  34. // @Produce json
  35. // @Security ApiKeyAuth
  36. // @Param page query int false "Page number"
  37. // @Param per_page query int false "Items per page"
  38. // @Param id query int false "Filter by id"
  39. // @Param name query string false "Filter by name"
  40. // @Param key query string false "Filter by key"
  41. // @Param channel_type query int false "Filter by channel type"
  42. // @Param base_url query string false "Filter by base URL"
  43. // @Param order query string false "Order by field"
  44. // @Success 200 {object} middleware.APIResponse{data=map[string]any{channels=[]model.Channel,total=int}}
  45. // @Router /api/channels/ [get]
  46. func GetChannels(c *gin.Context) {
  47. page, perPage := utils.ParsePageParams(c)
  48. id, _ := strconv.Atoi(c.Query("id"))
  49. name := c.Query("name")
  50. key := c.Query("key")
  51. channelType, _ := strconv.Atoi(c.Query("channel_type"))
  52. baseURL := c.Query("base_url")
  53. order := c.Query("order")
  54. channels, total, err := model.GetChannels(
  55. page,
  56. perPage,
  57. id,
  58. name,
  59. key,
  60. channelType,
  61. baseURL,
  62. order,
  63. )
  64. if err != nil {
  65. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  66. return
  67. }
  68. middleware.SuccessResponse(c, gin.H{
  69. "channels": channels,
  70. "total": total,
  71. })
  72. }
  73. // GetAllChannels godoc
  74. //
  75. // @Summary Get all channels
  76. // @Description Returns a list of all channels without pagination
  77. // @Tags channels
  78. // @Produce json
  79. // @Security ApiKeyAuth
  80. // @Success 200 {object} middleware.APIResponse{data=[]model.Channel}
  81. // @Router /api/channels/all [get]
  82. func GetAllChannels(c *gin.Context) {
  83. channels, err := model.GetAllChannels()
  84. if err != nil {
  85. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  86. return
  87. }
  88. middleware.SuccessResponse(c, channels)
  89. }
  90. // AddChannels godoc
  91. //
  92. // @Summary Add multiple channels
  93. // @Description Adds multiple channels in a batch operation
  94. // @Tags channels
  95. // @Accept json
  96. // @Produce json
  97. // @Security ApiKeyAuth
  98. // @Param channels body []AddChannelRequest true "Channel information"
  99. // @Success 200 {object} middleware.APIResponse
  100. // @Router /api/channels/ [post]
  101. func AddChannels(c *gin.Context) {
  102. channels := make([]*AddChannelRequest, 0)
  103. err := c.ShouldBindJSON(&channels)
  104. if err != nil {
  105. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  106. return
  107. }
  108. _channels := make([]*model.Channel, 0, len(channels))
  109. for _, channel := range channels {
  110. channels, err := channel.ToChannels()
  111. if err != nil {
  112. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  113. return
  114. }
  115. _channels = append(_channels, channels...)
  116. }
  117. err = model.BatchInsertChannels(_channels)
  118. if err != nil {
  119. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  120. return
  121. }
  122. middleware.SuccessResponse(c, nil)
  123. }
  124. // SearchChannels godoc
  125. //
  126. // @Summary Search channels
  127. // @Description Search channels with keyword and optional filters
  128. // @Tags channels
  129. // @Produce json
  130. // @Security ApiKeyAuth
  131. // @Param keyword query string true "Search keyword"
  132. // @Param page query int false "Page number"
  133. // @Param per_page query int false "Items per page"
  134. // @Param id query int false "Filter by id"
  135. // @Param name query string false "Filter by name"
  136. // @Param key query string false "Filter by key"
  137. // @Param channel_type query int false "Filter by channel type"
  138. // @Param base_url query string false "Filter by base URL"
  139. // @Param order query string false "Order by field"
  140. // @Success 200 {object} middleware.APIResponse{data=map[string]any{channels=[]model.Channel,total=int}}
  141. // @Router /api/channels/search [get]
  142. func SearchChannels(c *gin.Context) {
  143. keyword := c.Query("keyword")
  144. page, perPage := utils.ParsePageParams(c)
  145. id, _ := strconv.Atoi(c.Query("id"))
  146. name := c.Query("name")
  147. key := c.Query("key")
  148. channelType, _ := strconv.Atoi(c.Query("channel_type"))
  149. baseURL := c.Query("base_url")
  150. order := c.Query("order")
  151. channels, total, err := model.SearchChannels(
  152. keyword,
  153. page,
  154. perPage,
  155. id,
  156. name,
  157. key,
  158. channelType,
  159. baseURL,
  160. order,
  161. )
  162. if err != nil {
  163. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  164. return
  165. }
  166. middleware.SuccessResponse(c, gin.H{
  167. "channels": channels,
  168. "total": total,
  169. })
  170. }
  171. // GetChannel godoc
  172. //
  173. // @Summary Get a channel by ID
  174. // @Description Returns detailed information about a specific channel
  175. // @Tags channel
  176. // @Produce json
  177. // @Security ApiKeyAuth
  178. // @Param id path int true "Channel ID"
  179. // @Success 200 {object} middleware.APIResponse{data=model.Channel}
  180. // @Router /api/channel/{id} [get]
  181. func GetChannel(c *gin.Context) {
  182. id, err := strconv.Atoi(c.Param("id"))
  183. if err != nil {
  184. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  185. return
  186. }
  187. channel, err := model.GetChannelByID(id)
  188. if err != nil {
  189. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  190. return
  191. }
  192. middleware.SuccessResponse(c, channel)
  193. }
  194. // AddChannelRequest represents the request body for adding a channel
  195. type AddChannelRequest struct {
  196. ModelMapping map[string]string `json:"model_mapping"`
  197. Configs model.ChannelConfigs `json:"configs"`
  198. Name string `json:"name"`
  199. Key string `json:"key"`
  200. BaseURL string `json:"base_url"`
  201. Models []string `json:"models"`
  202. Type model.ChannelType `json:"type"`
  203. Priority int32 `json:"priority"`
  204. Status int `json:"status"`
  205. Sets []string `json:"sets"`
  206. }
  207. func (r *AddChannelRequest) ToChannel() (*model.Channel, error) {
  208. a, ok := adaptors.GetAdaptor(r.Type)
  209. if !ok {
  210. return nil, fmt.Errorf("invalid channel type: %d", r.Type)
  211. }
  212. metadata := a.Metadata()
  213. if validator := adaptors.GetKeyValidator(a); validator != nil {
  214. err := validator.ValidateKey(r.Key)
  215. if err != nil {
  216. keyHelp := metadata.KeyHelp
  217. if keyHelp == "" {
  218. return nil, fmt.Errorf(
  219. "%s [%s(%d)] invalid key: %w",
  220. r.Name,
  221. r.Type.String(),
  222. r.Type,
  223. err,
  224. )
  225. }
  226. return nil, fmt.Errorf(
  227. "%s [%s(%d)] invalid key: %w, %s",
  228. r.Name,
  229. r.Type.String(),
  230. r.Type,
  231. err,
  232. keyHelp,
  233. )
  234. }
  235. }
  236. if r.Configs != nil {
  237. if metadata.ConfigTemplates.Validator != nil {
  238. if err := metadata.ConfigTemplates.Validator(r.Configs); err != nil {
  239. return nil, fmt.Errorf("config validate faild: %w", err)
  240. }
  241. }
  242. }
  243. return &model.Channel{
  244. Type: r.Type,
  245. Name: r.Name,
  246. Key: r.Key,
  247. BaseURL: r.BaseURL,
  248. Models: slices.Clone(r.Models),
  249. ModelMapping: maps.Clone(r.ModelMapping),
  250. Priority: r.Priority,
  251. Status: r.Status,
  252. Configs: r.Configs,
  253. Sets: slices.Clone(r.Sets),
  254. }, nil
  255. }
  256. func (r *AddChannelRequest) ToChannels() ([]*model.Channel, error) {
  257. keys := strings.Split(r.Key, "\n")
  258. channels := make([]*model.Channel, 0, len(keys))
  259. for _, key := range keys {
  260. if key == "" {
  261. continue
  262. }
  263. c, err := r.ToChannel()
  264. if err != nil {
  265. return nil, err
  266. }
  267. c.Key = key
  268. channels = append(channels, c)
  269. }
  270. if len(channels) == 0 {
  271. ch, err := r.ToChannel()
  272. if err != nil {
  273. return nil, err
  274. }
  275. return []*model.Channel{ch}, nil
  276. }
  277. return channels, nil
  278. }
  279. // AddChannel godoc
  280. //
  281. // @Summary Add a single channel
  282. // @Description Adds a new channel to the system
  283. // @Tags channel
  284. // @Accept json
  285. // @Produce json
  286. // @Security ApiKeyAuth
  287. // @Param channel body AddChannelRequest true "Channel information"
  288. // @Success 200 {object} middleware.APIResponse
  289. // @Router /api/channel/ [post]
  290. func AddChannel(c *gin.Context) {
  291. channel := AddChannelRequest{}
  292. err := c.ShouldBindJSON(&channel)
  293. if err != nil {
  294. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  295. return
  296. }
  297. channels, err := channel.ToChannels()
  298. if err != nil {
  299. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  300. return
  301. }
  302. err = model.BatchInsertChannels(channels)
  303. if err != nil {
  304. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  305. return
  306. }
  307. middleware.SuccessResponse(c, nil)
  308. }
  309. // DeleteChannel godoc
  310. //
  311. // @Summary Delete a channel
  312. // @Description Deletes a channel by its ID
  313. // @Tags channel
  314. // @Produce json
  315. // @Security ApiKeyAuth
  316. // @Param id path int true "Channel ID"
  317. // @Success 200 {object} middleware.APIResponse
  318. // @Router /api/channel/{id} [delete]
  319. func DeleteChannel(c *gin.Context) {
  320. id, _ := strconv.Atoi(c.Param("id"))
  321. err := model.DeleteChannelByID(id)
  322. if err != nil {
  323. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  324. return
  325. }
  326. middleware.SuccessResponse(c, nil)
  327. }
  328. // DeleteChannels godoc
  329. //
  330. // @Summary Delete multiple channels
  331. // @Description Deletes multiple channels by their IDs
  332. // @Tags channels
  333. // @Accept json
  334. // @Produce json
  335. // @Security ApiKeyAuth
  336. // @Param ids body []int true "Channel IDs"
  337. // @Success 200 {object} middleware.APIResponse
  338. // @Router /api/channels/batch_delete [post]
  339. func DeleteChannels(c *gin.Context) {
  340. ids := []int{}
  341. err := c.ShouldBindJSON(&ids)
  342. if err != nil {
  343. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  344. return
  345. }
  346. err = model.DeleteChannelsByIDs(ids)
  347. if err != nil {
  348. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  349. return
  350. }
  351. middleware.SuccessResponse(c, nil)
  352. }
  353. // UpdateChannel godoc
  354. //
  355. // @Summary Update a channel
  356. // @Description Updates an existing channel by its ID
  357. // @Tags channel
  358. // @Accept json
  359. // @Produce json
  360. // @Security ApiKeyAuth
  361. // @Param id path int true "Channel ID"
  362. // @Param channel body AddChannelRequest true "Updated channel information"
  363. // @Success 200 {object} middleware.APIResponse{data=model.Channel}
  364. // @Router /api/channel/{id} [put]
  365. func UpdateChannel(c *gin.Context) {
  366. idStr := c.Param("id")
  367. if idStr == "" {
  368. middleware.ErrorResponse(c, http.StatusBadRequest, "id is required")
  369. return
  370. }
  371. id, err := strconv.Atoi(idStr)
  372. if err != nil {
  373. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  374. return
  375. }
  376. channel := AddChannelRequest{}
  377. err = c.ShouldBindJSON(&channel)
  378. if err != nil {
  379. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  380. return
  381. }
  382. ch, err := channel.ToChannel()
  383. if err != nil {
  384. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  385. return
  386. }
  387. ch.ID = id
  388. err = model.UpdateChannel(ch)
  389. if err != nil {
  390. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  391. return
  392. }
  393. err = monitor.ClearChannelAllModelErrors(c.Request.Context(), id)
  394. if err != nil {
  395. log.Errorf("failed to clear channel all model errors: %+v", err)
  396. }
  397. middleware.SuccessResponse(c, ch)
  398. }
  399. // UpdateChannelStatusRequest represents the request body for updating a channel's status
  400. type UpdateChannelStatusRequest struct {
  401. Status int `json:"status"`
  402. }
  403. // UpdateChannelStatus godoc
  404. //
  405. // @Summary Update channel status
  406. // @Description Updates the status of a channel by its ID
  407. // @Tags channel
  408. // @Accept json
  409. // @Produce json
  410. // @Security ApiKeyAuth
  411. // @Param id path int true "Channel ID"
  412. // @Param status body UpdateChannelStatusRequest true "Status information"
  413. // @Success 200 {object} middleware.APIResponse
  414. // @Router /api/channel/{id}/status [post]
  415. func UpdateChannelStatus(c *gin.Context) {
  416. id, _ := strconv.Atoi(c.Param("id"))
  417. status := UpdateChannelStatusRequest{}
  418. err := c.ShouldBindJSON(&status)
  419. if err != nil {
  420. middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
  421. return
  422. }
  423. err = model.UpdateChannelStatusByID(id, status.Status)
  424. if err != nil {
  425. middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
  426. return
  427. }
  428. err = monitor.ClearChannelAllModelErrors(c.Request.Context(), id)
  429. if err != nil {
  430. log.Errorf("failed to clear channel all model errors: %+v", err)
  431. }
  432. middleware.SuccessResponse(c, nil)
  433. }