openai_messages_dispatch.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package service
  2. import (
  3. "strings"
  4. "github.com/Wei-Shaw/sub2api/internal/pkg/xai"
  5. )
  6. const (
  7. defaultOpenAIMessagesDispatchOpusMappedModel = "gpt-5.4"
  8. defaultOpenAIMessagesDispatchSonnetMappedModel = "gpt-5.3-codex"
  9. defaultOpenAIMessagesDispatchHaikuMappedModel = "gpt-5.4-mini"
  10. )
  11. func normalizeOpenAIMessagesDispatchMappedModel(model string) string {
  12. model = NormalizeOpenAICompatRequestedModel(strings.TrimSpace(model))
  13. return strings.TrimSpace(model)
  14. }
  15. func normalizeOpenAIMessagesDispatchModelConfig(cfg OpenAIMessagesDispatchModelConfig) OpenAIMessagesDispatchModelConfig {
  16. out := OpenAIMessagesDispatchModelConfig{
  17. OpusMappedModel: normalizeOpenAIMessagesDispatchMappedModel(cfg.OpusMappedModel),
  18. SonnetMappedModel: normalizeOpenAIMessagesDispatchMappedModel(cfg.SonnetMappedModel),
  19. HaikuMappedModel: normalizeOpenAIMessagesDispatchMappedModel(cfg.HaikuMappedModel),
  20. }
  21. if len(cfg.ExactModelMappings) > 0 {
  22. out.ExactModelMappings = make(map[string]string, len(cfg.ExactModelMappings))
  23. for requestedModel, mappedModel := range cfg.ExactModelMappings {
  24. requestedModel = strings.TrimSpace(requestedModel)
  25. mappedModel = normalizeOpenAIMessagesDispatchMappedModel(mappedModel)
  26. if requestedModel == "" || mappedModel == "" {
  27. continue
  28. }
  29. out.ExactModelMappings[requestedModel] = mappedModel
  30. }
  31. if len(out.ExactModelMappings) == 0 {
  32. out.ExactModelMappings = nil
  33. }
  34. }
  35. return out
  36. }
  37. func claudeMessagesDispatchFamily(model string) string {
  38. normalized := strings.ToLower(strings.TrimSpace(model))
  39. if !strings.HasPrefix(normalized, "claude") {
  40. return ""
  41. }
  42. switch {
  43. case strings.Contains(normalized, "opus"):
  44. return "opus"
  45. case strings.Contains(normalized, "sonnet"):
  46. return "sonnet"
  47. case strings.Contains(normalized, "haiku"):
  48. return "haiku"
  49. default:
  50. return ""
  51. }
  52. }
  53. func (g *Group) ResolveMessagesDispatchModel(requestedModel string) string {
  54. if g == nil {
  55. return ""
  56. }
  57. requestedModel = strings.TrimSpace(requestedModel)
  58. if requestedModel == "" {
  59. return ""
  60. }
  61. if g.Platform == PlatformGrok {
  62. if claudeMessagesDispatchFamily(requestedModel) == "" {
  63. return ""
  64. }
  65. opts := xai.RuntimeModelMappingOptions()
  66. if !opts.EnableCrossClientMap {
  67. return ""
  68. }
  69. return xai.ModelMappingWithOptions(opts)["claude-*"]
  70. }
  71. // 国产供应商分组:调度级模型映射不适用(其配置被 sanitize 置空,且下方的
  72. // gpt-5.x 默认值是 openai 专属,发给 CN 上游必错)。模型改写完全交给账号级
  73. // model_mapping;anthropic 协议上游本身接受 claude-* 模型名。
  74. if IsCNProvider(g.Platform) {
  75. return ""
  76. }
  77. cfg := normalizeOpenAIMessagesDispatchModelConfig(g.MessagesDispatchModelConfig)
  78. if mappedModel := strings.TrimSpace(cfg.ExactModelMappings[requestedModel]); mappedModel != "" {
  79. return mappedModel
  80. }
  81. switch claudeMessagesDispatchFamily(requestedModel) {
  82. case "opus":
  83. if mappedModel := strings.TrimSpace(cfg.OpusMappedModel); mappedModel != "" {
  84. return mappedModel
  85. }
  86. return defaultOpenAIMessagesDispatchOpusMappedModel
  87. case "sonnet":
  88. if mappedModel := strings.TrimSpace(cfg.SonnetMappedModel); mappedModel != "" {
  89. return mappedModel
  90. }
  91. return defaultOpenAIMessagesDispatchSonnetMappedModel
  92. case "haiku":
  93. if mappedModel := strings.TrimSpace(cfg.HaikuMappedModel); mappedModel != "" {
  94. return mappedModel
  95. }
  96. return defaultOpenAIMessagesDispatchHaikuMappedModel
  97. default:
  98. return ""
  99. }
  100. }
  101. func sanitizeGroupMessagesDispatchFields(g *Group) {
  102. if g == nil || g.Platform == PlatformOpenAI {
  103. return
  104. }
  105. if g.Platform != PlatformComposite {
  106. g.AllowMessagesDispatch = false
  107. }
  108. g.DefaultMappedModel = ""
  109. g.MessagesDispatchModelConfig = OpenAIMessagesDispatchModelConfig{}
  110. }