Skip to content

feats: better group setting - #2812

Closed
nekohy wants to merge 4968 commits into
QuantumNous:mainfrom
nekohy:feats-better-group
Closed

feats: better group setting#2812
nekohy wants to merge 4968 commits into
QuantumNous:mainfrom
nekohy:feats-better-group

Conversation

@nekohy

@nekohy nekohy commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features
    • Added per-model group configuration support, allowing users to customize group mappings for individual models within channels.
    • Introduced a dedicated model group mapping editor in the channel configuration UI.
    • Extended multi-language support with new interface labels for group configuration management.

feitianbubu and others added 30 commits November 26, 2025 21:56
…-i2v

Gemini Veo3.1[AI Studio]增加图生视频支持
Ensure image file is closed using defer after opening.
…edit

Gemini Image系列支持图像编辑
…d-oai

feat: 视频下载和界面预览统一使用OAI标准接口
…-err-code

fix(aws): extract HTTP status code from AWS SDK errors
…na-err

fix: nano-banana not compatible imageSize
…nce-playground-debugging

feat(playground): enhance SSE debugging and add image paste support with i18n
fix: nano banana pro 4k(StreamScannerMaxBufferMB env)
feat: glm coding plan && kimi coding plan
fix(i18n): fill missing translations in i18n.
…ix-gemini-ImageConfig

Revert "fix: gemini image correct generationConfig"
…emini-veo3.1-i2v

Revert "Gemini Veo3.1[AI Studio]增加图生视频支持"
…emini-image-edit

Revert "Gemini Image系列支持图像编辑"
…ix-nano-banana-err

Revert "fix: nano-banana not compatible imageSize"
seefs001 and others added 25 commits January 5, 2026 23:36
问题描述:
- 使用 auto 分组的令牌调用 /v1/videos 等 Task 接口时,虽然任务能成功创建,
  但使用日志不显示记录,且不会扣费

根本原因:
- Distribute 中间件在选择渠道后,会将实际选中的分组存储在 ContextKeyAutoGroup 中
- 但 RelayTaskSubmit 函数没有从 context 中读取这个值来更新 info.UsingGroup
- 导致 info.UsingGroup 始终是 "auto" 而不是实际选中的分组(如 "sora2逆")
- 当 auto 分组的倍率配置为 0 时,quota 计算结果为 0
- 日志记录条件 "if quota != 0" 不满足,导致日志不记录、不扣费

修复方案:
- 在 RelayTaskSubmit 函数中计算分组倍率之前,添加从 ContextKeyAutoGroup
  获取实际分组的逻辑
- 使用安全的类型断言,避免潜在的 panic 风险

影响范围:
- 仅影响 Task Relay 流程(/v1/videos, /suno, /kling 等接口)
- 不影响使用具体分组令牌的调用
- 不影响其他 Relay 类型(chat/completions 等已有类似处理逻辑)
…task-logging

fix(task): 修复使用 auto 分组时 Task Relay 不记录日志和不扣费的问题
Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible
path when listing models for Gemini channels, improving compatibility with
third-party Gemini-format providers that don't implement OpenAI routes.

- Add paginated model listing with timeout and optional proxy support
- Select an enabled key for multi-key Gemini channels
…etchModels

fix: remove Minimax from FETCHABLE channels
…tchModels

fix(gemini): fetch model list via native v1beta/models endpoint
* feat: /v1/chat/completion -> /v1/response
…-auto-disable

feat: status code auto-disable configuration
* fix: setting ui

* fix: rm global.chat_completions_to_responses_policy

* fix: rm global.chat_completions_to_responses_policy
…Names

fix: clean propertyNames for gemini function
…t-param-override

feat: channel testing supports parameter overriding
* feat: codex channel

* feat: codex channel

* feat: codex oauth flow

* feat: codex refresh cred

* feat: codex usage

* fix: codex err message detail

* fix: codex setting ui

* feat: codex refresh cred task

* fix: import err

* fix: codex store must be false

* fix: chat -> responses tool call

* fix: chat -> responses tool call
…sing Claude's rendering logs, the two approaches handle input rendering differently.
@coderabbitai

coderabbitai Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This change introduces per-model group configuration for channels. The backend adds a ModelGroupMapping field and getter method to resolve model-specific groups, updating ability creation/update logic accordingly. The frontend introduces a new ModelGroupMappingEditor component integrated into the channel edit modal, with English and Chinese i18n support.

Changes

Cohort / File(s) Summary
Backend Model Grouping
model/ability.go, model/channel.go
Added ModelGroupMapping field with JSON storage and GetModelGroupMapping() method. Updated ability resolution in both AddAbilities and UpdateAbilities to use per-model groups when available, falling back to channel defaults.
Frontend Editor Component
web/src/components/table/channels/ModelGroupMappingEditor.jsx
New React component for managing per-model group configurations with model selector, multi-select group editor, and delete actions. Renders table with configured models and their assigned groups.
Modal Integration
web/src/components/table/channels/modals/EditChannelModal.jsx
Integrated ModelGroupMappingEditor into channel edit flow with state management for modelGroupConfig, parsing of model_group_mapping on load, and serialization during submission.
Internationalization
web/src/i18n/locales/en.json, web/src/i18n/locales/zh.json
Added six translation keys (Chinese and English) for model group configuration UI labels, descriptions, and empty states.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • seefs001

Poem

🐰 Per-model groups now dance with glee,
Each model picks its own destiny,
The editor lets us map with care,
While translations float in the air—
A feature fluffy, precise, and fair! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'feats: better group setting' is vague and does not clearly convey the specific implementation of per-model group configurations. It lacks concrete details about the core change. Consider using a more descriptive title like 'feat: add per-model group configuration support' to clearly communicate the primary change to reviewers scanning PR history.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
model/ability.go (1)

146-176: ⚠️ Potential issue | 🟡 Minor

Trim and skip empty group names when generating abilities.

Whitespace or empty entries in default/custom groups can create invalid group records and mismatched routing.

🧹 Suggested normalization in both AddAbilities and UpdateAbilities
-		for _, group := range groups {
+		for _, group := range groups {
+			group = strings.TrimSpace(group)
+			if group == "" {
+				continue
+			}
 			key := group + "|" + model
 			if _, exists := abilitySet[key]; exists {
 				continue
 			}
-		for _, group := range groups {
+		for _, group := range groups {
+			group = strings.TrimSpace(group)
+			if group == "" {
+				continue
+			}
 			key := group + "|" + model
 			if _, exists := abilitySet[key]; exists {
 				continue
 			}

Also applies to: 226-256

🤖 Fix all issues with AI agents
In `@model/channel.go`:
- Around line 106-122: GetModelGroupMapping currently swallows JSON unmarshal
errors; update it to log the invalid JSON and the error before returning nil so
misconfigurations are visible. In the GetModelGroupMapping method, when
common.Unmarshal returns an error, emit a log entry (e.g., using the standard
log package or your package logger) that includes the error and the raw
*channel.ModelGroupMapping string for context, then continue to return nil; keep
the rest of the function (cleaning empty keys and returning mapping) unchanged.

In `@web/src/components/table/channels/modals/EditChannelModal.jsx`:
- Around line 1392-1395: The model_group_mapping currently serializes all
modelGroupConfig.specificRules, including stale entries for removed models;
update the logic around localInputs.model_group_mapping (in
EditChannelModal.jsx) to first prune specificRules by keeping only keys present
in normalizedModels (i.e., filter modelGroupConfig.specificRules by
normalizedModels set), then JSON.stringify that pruned object and omit (delete
or set to undefined/empty) model_group_mapping when the pruned object is empty
so no empty/stale overrides are submitted.
🧹 Nitpick comments (1)
web/src/components/table/channels/modals/EditChannelModal.jsx (1)

566-582: Normalize parsed model_group_mapping before storing.

If persisted data contains arrays or non-array values, the editor state can become inconsistent. Consider filtering to a plain object of string arrays.

♻️ Suggested normalization
-          if (mgMap && typeof mgMap === 'object') {
-            // 直接使用 model_group_mapping 的内容作为 specificRules,不做过滤
-            mgConfig.specificRules = mgMap;
-          }
+          if (mgMap && typeof mgMap === 'object' && !Array.isArray(mgMap)) {
+            const cleanedRules = {};
+            Object.entries(mgMap).forEach(([model, groups]) => {
+              if (Array.isArray(groups)) {
+                cleanedRules[model] = groups
+                  .map((g) => String(g).trim())
+                  .filter(Boolean);
+              }
+            });
+            mgConfig.specificRules = cleanedRules;
+          }

Comment thread model/channel.go
Comment on lines +106 to +122
// GetModelGroupMapping 解析模型分组映射,返回 map[model][]groups
func (channel *Channel) GetModelGroupMapping() map[string][]string {
if channel.ModelGroupMapping == nil || *channel.ModelGroupMapping == "" {
return nil
}
var mapping map[string][]string
if err := common.Unmarshal([]byte(*channel.ModelGroupMapping), &mapping); err != nil {
return nil
}
// 清理空值
for model, groups := range mapping {
if model == "" || len(groups) == 0 {
delete(mapping, model)
}
}
return mapping
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Log invalid model_group_mapping JSON to avoid silent fallback.

Right now a malformed JSON silently disables the feature. Emitting a log makes misconfigurations actionable.

🛠️ Proposed fix
-	if err := common.Unmarshal([]byte(*channel.ModelGroupMapping), &mapping); err != nil {
-		return nil
-	}
+	if err := common.Unmarshal([]byte(*channel.ModelGroupMapping), &mapping); err != nil {
+		common.SysLog(fmt.Sprintf("failed to unmarshal model_group_mapping: channel_id=%d, error=%v", channel.Id, err))
+		return nil
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// GetModelGroupMapping 解析模型分组映射,返回 map[model][]groups
func (channel *Channel) GetModelGroupMapping() map[string][]string {
if channel.ModelGroupMapping == nil || *channel.ModelGroupMapping == "" {
return nil
}
var mapping map[string][]string
if err := common.Unmarshal([]byte(*channel.ModelGroupMapping), &mapping); err != nil {
return nil
}
// 清理空值
for model, groups := range mapping {
if model == "" || len(groups) == 0 {
delete(mapping, model)
}
}
return mapping
}
// GetModelGroupMapping 解析模型分组映射,返回 map[model][]groups
func (channel *Channel) GetModelGroupMapping() map[string][]string {
if channel.ModelGroupMapping == nil || *channel.ModelGroupMapping == "" {
return nil
}
var mapping map[string][]string
if err := common.Unmarshal([]byte(*channel.ModelGroupMapping), &mapping); err != nil {
common.SysLog(fmt.Sprintf("failed to unmarshal model_group_mapping: channel_id=%d, error=%v", channel.Id, err))
return nil
}
// 清理空值
for model, groups := range mapping {
if model == "" || len(groups) == 0 {
delete(mapping, model)
}
}
return mapping
}
🤖 Prompt for AI Agents
In `@model/channel.go` around lines 106 - 122, GetModelGroupMapping currently
swallows JSON unmarshal errors; update it to log the invalid JSON and the error
before returning nil so misconfigurations are visible. In the
GetModelGroupMapping method, when common.Unmarshal returns an error, emit a log
entry (e.g., using the standard log package or your package logger) that
includes the error and the raw *channel.ModelGroupMapping string for context,
then continue to return nil; keep the rest of the function (cleaning empty keys
and returning mapping) unchanged.

Comment on lines +1392 to +1395
// Build model_group_mapping from modelGroupConfig.specificRules only
// model_group_mapping 只存储有单独配置的模型
localInputs.model_group_mapping = JSON.stringify(modelGroupConfig.specificRules || {});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prune mappings for models that were removed.

Stale overrides remain hidden in the editor but still get serialized, so they can reappear if a model is re-added. Filter to normalizedModels before stringify and omit when empty.

🧹 Suggested pruning before submit
-    localInputs.model_group_mapping = JSON.stringify(modelGroupConfig.specificRules || {});
+    const modelGroupMapping = Object.fromEntries(
+      Object.entries(modelGroupConfig.specificRules || {}).filter(([model]) =>
+        normalizedModels.includes(model),
+      ),
+    );
+    localInputs.model_group_mapping =
+      Object.keys(modelGroupMapping).length > 0
+        ? JSON.stringify(modelGroupMapping)
+        : '';
🤖 Prompt for AI Agents
In `@web/src/components/table/channels/modals/EditChannelModal.jsx` around lines
1392 - 1395, The model_group_mapping currently serializes all
modelGroupConfig.specificRules, including stale entries for removed models;
update the logic around localInputs.model_group_mapping (in
EditChannelModal.jsx) to first prune specificRules by keeping only keys present
in normalizedModels (i.e., filter modelGroupConfig.specificRules by
normalizedModels set), then JSON.stringify that pruned object and omit (delete
or set to undefined/empty) model_group_mapping when the pruned object is empty
so no empty/stale overrides are submitted.

@nekohy
nekohy deleted the feats-better-group branch May 22, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.