Skip to content

feat: 自动将渠道重定向中的模型名加入到模型列表 - #1707

Closed
StageDog wants to merge 1 commit into
QuantumNous:alphafrom
StageDog:feat/auto_add_redirect
Closed

feat: 自动将渠道重定向中的模型名加入到模型列表#1707
StageDog wants to merge 1 commit into
QuantumNous:alphafrom
StageDog:feat/auto_add_redirect

Conversation

@StageDog

@StageDog StageDog commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

PR 类型

  • Bug 修复
  • 新功能
  • 文档更新
  • 其他

PR 是否包含破坏性更新?

PR 描述

如图所示,保存时将自动填入重定向里的模型 image

Summary by CodeRabbit

  • New Features

    • Edit Channel: Model mapping JSON is now auto-parsed and normalized; keys are added to selected models, which are deduplicated and sorted. Submission enforces at least one model and shows clear errors for invalid JSON. The UI no longer blocks submission when the models field is empty, reducing manual steps and improving reliability.
  • Chores

    • Added lodash dependency to the web app.

@coderabbitai

coderabbitai Bot commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds lodash dependency in web/package.json. Updates EditChannel submit logic to parse and normalize JSON model_mapping, merge mapping keys into models, sort/deduplicate models, enforce at least one model at submit, and surface JSON parse errors. Removes prior verifyJSON usage and UI-required rule for models.

Changes

Cohort / File(s) Summary of Changes
Dependency update
web/package.json
Added lodash dependency (^4.17.21). No other dependency/script/API changes.
Channel edit submit handling
web/src/pages/Channel/EditChannel.js
Submit flow now parses model_mapping JSON, normalizes to sorted key-value JSON, merges mapping keys into models, sorts and deduplicates models, aborts with error on parse failure, and ensures at least one model exists. Removed prior verifyJSON path and UI required rule for models.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant EC as EditChannel Page
  participant SH as Submit Handler
  participant VM as Validator/Mapper
  participant UI as UI Feedback

  U->>EC: Click "Save"/Submit
  EC->>SH: onSubmit(localInputs)

  alt model_mapping provided
    SH->>VM: JSON.parse(localInputs.model_mapping)
    alt Parse fails
      VM-->>SH: Error
      SH->>UI: Show error "Invalid JSON"
      SH-->>EC: Abort submission
    else Parse succeeds
      VM-->>SH: mapping object
      SH->>SH: Normalize mapping (sort keys)
      SH->>SH: Merge mapping keys into models
      SH->>SH: Deduplicate + sort models
    end
  else no model_mapping
    SH->>SH: Use existing models
  end

  alt models empty
    SH->>UI: Show error "At least one model required"
    SH-->>EC: Abort submission
  else
    SH-->>EC: Proceed with save request
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I thump my paw—new maps to parse,
Keys hop into models, crisp and sparse.
JSON burrows neat and clean,
No stray twigs in the evergreen.
With lodash in my satchel tight,
I bound through forms—everything right.
Hippity, submit—good night! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
web/src/pages/Channel/EditChannel.js (1)

267-299: Avoid mutating React state arrays when aggregating models.

models references inputs.models; push mutates state. Clone first to keep state immutable.

-    const models = inputs['models'] || [];
+    const models = [...(inputs['models'] || [])];
@@
-        models.push(...res.data.data);
+        models.push(...(res.data.data || []));
@@
-          if (res && res.data && res.data.success) {
-            models.push(...res.data.data);
+          if (res && res.data && res.data.success) {
+            models.push(...(res.data.data || []));
🧹 Nitpick comments (3)
web/package.json (1)

21-21: Consider avoiding full lodash; use native or lodash-es to keep bundle lean.

For the current sorting/dedup use case, native APIs suffice. If a utility lib is preferred, import from lodash-es per-function to enable tree-shaking.

Optional removal if switching to native code:

-    "lodash": "^4.17.21",
web/src/pages/Channel/EditChannel.js (2)

28-28: Drop default lodash import (or switch to per-function from lodash-es).

If adopting native code below, remove this import. If keeping lodash, prefer import { toPairs, orderBy, fromPairs, keys } from 'lodash-es'.

-import _ from 'lodash';

224-230: Defensive parse for model_mapping from backend to prevent UI crash.

A bad value from server will throw. Wrap in try/catch and degrade gracefully.

-      if (data.model_mapping !== '') {
-        data.model_mapping = JSON.stringify(
-          JSON.parse(data.model_mapping),
-          null,
-          2,
-        );
-      }
+      if (data.model_mapping !== '') {
+        try {
+          data.model_mapping = JSON.stringify(
+            JSON.parse(data.model_mapping),
+            null,
+            2,
+          );
+        } catch {
+          showError(t('后端返回的模型映射不是有效 JSON,已忽略'));
+          data.model_mapping = '';
+        }
+      }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5cfc133 and 8851f7b.

⛔ Files ignored due to path filters (1)
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • web/package.json (1 hunks)
  • web/src/pages/Channel/EditChannel.js (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the applyModelMapping function transforms the models list by replacing original model names (mapping values) with display names (mapping keys). The database stores this transformed list containing mapped keys. On channel load, data.models contains these mapped display names, making the initialization filter if (data.models.includes(key)) correct.
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the applyModelMapping function transforms the models list by replacing original model names (mapping values) with display names (mapping keys). The database stores this transformed list containing mapped keys. On channel load, data.models contains these mapped display names, making the initialization filter if (data.models.includes(key)) correct.

Applied to files:

  • web/src/pages/Channel/EditChannel.js
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.

Applied to files:

  • web/src/pages/Channel/EditChannel.js
🧬 Code graph analysis (1)
web/src/pages/Channel/EditChannel.js (1)
web/src/helpers/utils.js (1)
  • showInfo (133-135)
🔇 Additional comments (1)
web/src/pages/Channel/EditChannel.js (1)

1249-1293: UX parity check: models no longer required at UI level; runtime will auto-fill from mapping keys.

Please verify flows where the user supplies only model_mapping: submit should succeed and models should persist the mapping keys (as stored/display names).

Suggested manual check:

  • New channel: clear “模型” list, set model_mapping to {"foo":"bar"}. Submit.
  • Confirm payload models contains "foo" only, and DB shows "foo" (mapped key) per previous behavior.

Comment on lines +550 to +568
let model_mapping = {};
if (localInputs.model_mapping && localInputs.model_mapping !== '') {
try {
model_mapping = _(JSON.parse(localInputs.model_mapping))
.toPairs()
.orderBy([0], ['asc'])
.fromPairs()
.value();
} catch (error) {
showInfo(t('模型映射必须是合法的 JSON 格式!'));
return;
}
}
localInputs.model_mapping = _.isEmpty(model_mapping) ? '' : JSON.stringify(model_mapping);
localInputs.models = _(localInputs.models)
.concat(_.keys(model_mapping))
.sort()
.sortedUniq()
.value();

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.

🛠️ Refactor suggestion

Harden model_mapping handling: validate object shape, trim keys/values, sort deterministically, dedup models; also treat JSON errors as errors.

Current code accepts arrays and uses lodash where native APIs suffice.

-    let model_mapping = {};
-    if (localInputs.model_mapping && localInputs.model_mapping !== '') {
-      try {
-        model_mapping = _(JSON.parse(localInputs.model_mapping))
-          .toPairs()
-          .orderBy([0], ['asc'])
-          .fromPairs()
-          .value();
-      } catch (error) {
-        showInfo(t('模型映射必须是合法的 JSON 格式!'));
-        return;
-      }
-    }
-    localInputs.model_mapping = _.isEmpty(model_mapping) ? '' : JSON.stringify(model_mapping);
-    localInputs.models = _(localInputs.models)
-      .concat(_.keys(model_mapping))
-      .sort()
-      .sortedUniq()
-      .value();
+    let model_mapping = {};
+    if (localInputs.model_mapping && localInputs.model_mapping.trim() !== '') {
+      try {
+        const raw = JSON.parse(localInputs.model_mapping);
+        if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
+          showError(t('模型映射必须是一个对象(形如 {"from":"to"})!'));
+          return;
+        }
+        const entries = Object.entries(raw)
+          .map(([k, v]) => [String(k).trim(), typeof v === 'string' ? v.trim() : String(v)])
+          .filter(([k, v]) => k.length > 0 && v.length > 0);
+        entries.sort((a, b) => a[0].localeCompare(b[0]));
+        model_mapping = Object.fromEntries(entries);
+      } catch {
+        showError(t('模型映射必须是合法的 JSON 格式!'));
+        return;
+      }
+    }
+    localInputs.model_mapping = Object.keys(model_mapping).length === 0 ? '' : JSON.stringify(model_mapping);
+    const currentModels = Array.isArray(localInputs.models) ? localInputs.models : [];
+    localInputs.models = Array.from(
+      new Set([
+        ...currentModels.map((m) => (m || '').trim()),
+        ...Object.keys(model_mapping),
+      ])
+    ).sort((a, b) => a.localeCompare(b));
📝 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
let model_mapping = {};
if (localInputs.model_mapping && localInputs.model_mapping !== '') {
try {
model_mapping = _(JSON.parse(localInputs.model_mapping))
.toPairs()
.orderBy([0], ['asc'])
.fromPairs()
.value();
} catch (error) {
showInfo(t('模型映射必须是合法的 JSON 格式!'));
return;
}
}
localInputs.model_mapping = _.isEmpty(model_mapping) ? '' : JSON.stringify(model_mapping);
localInputs.models = _(localInputs.models)
.concat(_.keys(model_mapping))
.sort()
.sortedUniq()
.value();
let model_mapping = {};
if (localInputs.model_mapping && localInputs.model_mapping.trim() !== '') {
try {
const raw = JSON.parse(localInputs.model_mapping);
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
showError(t('模型映射必须是一个对象(形如 {"from":"to"})!'));
return;
}
const entries = Object.entries(raw)
.map(([k, v]) => [String(k).trim(), typeof v === 'string' ? v.trim() : String(v)])
.filter(([k, v]) => k.length > 0 && v.length > 0);
entries.sort((a, b) => a[0].localeCompare(b[0]));
model_mapping = Object.fromEntries(entries);
} catch {
showError(t('模型映射必须是合法的 JSON 格式!'));
return;
}
}
localInputs.model_mapping = Object.keys(model_mapping).length === 0 ? '' : JSON.stringify(model_mapping);
const currentModels = Array.isArray(localInputs.models) ? localInputs.models : [];
localInputs.models = Array.from(
new Set([
...currentModels.map((m) => (m || '').trim()),
...Object.keys(model_mapping),
])
).sort((a, b) => a.localeCompare(b));
🤖 Prompt for AI Agents
In web/src/pages/Channel/EditChannel.js around lines 550-568, tighten
model_mapping handling: parse localInputs.model_mapping with JSON.parse inside
try/catch and on parse error call showInfo(...) and return; assert parsed value
is a plain object (not array/null), then build a new mapping by iterating
Object.entries(parsed), trimming key and value (String(value).trim()), skipping
entries with empty keys or values, and collecting keys into a Set; create a
deterministically ordered mapping by sorting keys lexicographically and
constructing a new object in that order; set localInputs.model_mapping to '' if
the resulting mapping is empty or to JSON.stringify(orderedMapping) otherwise;
ensure localInputs.models is an array (default to []), merge it with the
collected keys, deduplicate (using a Set), sort the final array, and assign back
to localInputs.models; avoid unnecessary lodash usage and rely on native
Array/Object/Set methods.

@qingchunyy

Copy link
Copy Markdown

是否与 #1658 重复?

@StageDog

Copy link
Copy Markdown
Contributor Author

😱做其他部分顺手做了忘了查

@StageDog StageDog closed this Aug 31, 2025
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.

2 participants