Skip to content

Add Submodel channel support#1804

Closed
danding5 wants to merge 8 commits into
QuantumNous:mainfrom
danding5:main
Closed

Add Submodel channel support#1804
danding5 wants to merge 8 commits into
QuantumNous:mainfrom
danding5:main

Conversation

@danding5
Copy link
Copy Markdown
Contributor

@danding5 danding5 commented Sep 15, 2025

Summary by CodeRabbit

  • New Features

    • Added SubModel channel support with adaptor integration.
    • New “SubModel” option and icon in the channel selector.
    • Preloaded model list for SubModel to simplify setup.
    • Default usage ratios configured for popular SubModel models.
  • Improvements

    • Clarified pricing display for extra services for consistency.
    • Minor UI/layout tweaks for audio pricing for better readability.

# Conflicts:
#	common/api_type.go
#	constant/api_type.go
#	constant/channel.go
#	relay/relay_adaptor.go
#	web/src/constants/channel.constants.js
# Conflicts:
#	relay/relay_adaptor.go
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 15, 2025

Walkthrough

Adds a new Submodel channel: constants (channel/API), base URL, adaptor implementation and wiring, model list and ratios, web UI option/icon and modal defaults; includes an unresolved merge conflict in relay adaptor import/merge area.

Changes

Cohort / File(s) Summary
API type mapping
common/api_type.go
Map ChannelTypeSubmodel to APITypeSubmodel in ChannelType2APIType (returns APITypeSubmodel, true).
Constants: API & Channel
constant/api_type.go, constant/channel.go
Add APITypeSubmodel and ChannelTypeSubmodel = 53; insert base URL https://llm.submodel.ai at index 53 in ChannelBaseURLs.
Submodel adaptor & metadata
relay/channel/submodel/adaptor.go, relay/channel/submodel/constants.go
New exported Adaptor with request URL/header setup, DoRequest/DoResponse, many Convert* methods (most returning endpoint-not-supported), plus ModelList and ChannelName = "submodel".
Relay wiring
relay/relay_adaptor.go
Import submodel package and return &submodel.Adaptor{} for APITypeSubmodel in GetAdaptor; merge-conflict markers present in this file.
Default model ratios
setting/ratio_setting/model_ratio.go
Add Submodel-related entries to defaultModelRatio for multiple model identifiers.
Web: channel option & icon
web/src/constants/channel.constants.js, web/src/helpers/render.jsx
Add CHANNEL_OPTIONS entry { value: 53, color: 'blue', label: 'SubModel' } and map channelType 53 to the SubModel icon; minor translation-wrapper adjustments in price rendering.
Web: edit modal defaults
web/src/components/table/channels/modals/EditTagModal.jsx
Seed inputs.models with a predefined Submodel list when type === 53 and models are empty; otherwise fall back to existing behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Relay as Relay (Submodel Adaptor)
  participant SubAPI as Submodel API

  Client->>Relay: OpenAI-style request (channelType=53)
  rect rgba(200,230,255,0.15)
    Relay->>Relay: ConvertOpenAIRequest (passthrough check)
    Relay->>Relay: GetRequestURL(baseUrl, path, channelType)
    Relay->>Relay: SetupRequestHeader (Authorization: Bearer)
  end
  Relay->>SubAPI: DoRequest (channel.DoApiRequest)
  alt Streaming (info.IsStream)
    SubAPI-->>Relay: stream chunks
    Relay-->>Client: OaiStreamHandler -> stream client
  else Non-stream
    SubAPI-->>Relay: JSON response
    Relay-->>Client: OpenaiHandler -> final response
  end
  note right of Relay: Unsupported endpoints return "endpoint not supported" errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • xyfacai

Poem

A twitch of whiskers, quickfoot cheer,
I wired a channel new and clear.
Keys and URLs, models to show,
Icons gleam where submodels go.
This bunny hops — the code will flow. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “Add Submodel channel support” succinctly captures the primary purpose of the changeset by announcing integration of the Submodel channel, aligning directly with the added constants, adaptor, routing logic, and UI adjustments described in the pull request. It's concise, uses clear wording without extraneous details, and conveys the core update for reviewers scanning the history. Therefore, it effectively summarizes the main change without being overly broad or vague.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (11)
web/src/components/table/channels/modals/EditTagModal.jsx (1)

121-123: Dead code path: switch(name==='type') never fires in this modal.

This modal doesn’t expose a "type" field, so case 53 won’t execute. Either remove the switch(name==='type') block from this component or source the list via getChannelModels(53) when initializing models for SubModel to avoid duplication.

Apply one of:

  • Remove the unused switch block from this component.
  • Or, on load for SubModel tags, set models from a single source (helpers/getChannelModels or backend) instead of hardcoding here.
web/src/helpers/render.jsx (2)

346-347: Channel icon mapping added — OK; comment label is misleading.

Case 53 is a channel, not “嵌入模型”. Suggest correcting the comment to “SubModel”.

-    case 53: // 嵌入模型:SubModel 
+    case 53: // SubModel
       return <SubModel size={iconSize} />;

1444-1464: Minor: keep i18n messages consistent with existing wording.

The updated sentence structure is fine; no functional change. Consider reusing shared fragments to reduce duplication.

setting/ratio_setting/model_ratio.go (1)

253-264: SubModel ratios added — OK; add CompletionRatio entries for namespaced models.
GetCompletionRatio does an exact lookup for names containing '/' and then falls back to hard-coded heuristics (commonly default 1). Add explicit CompletionRatio entries for the new namespaced models in setting/ratio_setting/model_ratio.go (submodel block ~lines 252–264) to avoid unintended defaults; see GetCompletionRatio implementation (~lines 459–476).

relay/channel/submodel/constants.go (2)

3-14: Make the model list private and immutable to callers.

Exported ModelList can be mutated by other packages and via GetModelList, which returns the backing slice. Make it unexported and return a copy from the adaptor.

Apply:

-var ModelList = []string{
+var modelList = []string{
 	"NousResearch/Hermes-4-405B-FP8",
 	"Qwen/Qwen3-235B-A22B-Thinking-2507",
 	"Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8",
 	"Qwen/Qwen3-235B-A22B-Instruct-2507",
 	"zai-org/GLM-4.5-FP8",
 	"openai/gpt-oss-120b",
 	"deepseek-ai/DeepSeek-R1-0528",
 	"deepseek-ai/DeepSeek-R1",
 	"deepseek-ai/DeepSeek-V3-0324",
 	"deepseek-ai/DeepSeek-V3.1",
 }

3-14: Model list will drift; consider configuration/override.

These identifiers change frequently. Recommend allowing override via DB/admin setting or env (comma‑separated) and documenting defaults here.

relay/channel/submodel/adaptor.go (5)

34-36: Cloudflare Gateway path handling gap.

GetFullRequestURL special‑cases OpenAI/Azure when base is gateway.ai.cloudflare.com but not Submodel. If this channel ever uses CF Gateway, requests may be misrouted. Either add a Submodel case in relay/common/relay_utils.go or ensure Submodel base URLs never use CF Gateway.


38-42: Don’t override Authorization if caller set a custom header.

DoApiRequest applies HeadersOverride before this, but this setter unconditionally clobbers it.

Apply:

 func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error {
 	channel.SetupApiRequestHeader(info, c, req)
-	req.Set("Authorization", "Bearer "+info.ApiKey)
+	if req.Get("Authorization") == "" {
+		req.Set("Authorization", "Bearer "+info.ApiKey)
+	}
 	return nil
 }

44-49: Minor: normalize stream flag (optional).

If upstream didn’t set info.IsStream, consider syncing from request.Stream to avoid mismatches.


19-29: Prefer typed, user‑facing errors.

Returning plain errors.New("endpoint not supported") may map to generic 500s. If available, use a channel‑agnostic error (e.g., types.NewError(..., ErrorCodeEndpointNotSupported)) for consistent status codes and client messaging.

Also applies to: 51-57


76-82: Return a copy of the model list.

Prevents external mutation of internal slice.

Apply:

 func (a *Adaptor) GetModelList() []string {
-	return ModelList
+	return append([]string(nil), modelList...)
 }
 
 func (a *Adaptor) GetChannelName() string {
 	return ChannelName
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f760a8 and 274872b.

📒 Files selected for processing (10)
  • common/api_type.go (1 hunks)
  • constant/api_type.go (1 hunks)
  • constant/channel.go (2 hunks)
  • relay/channel/submodel/adaptor.go (1 hunks)
  • relay/channel/submodel/constants.go (1 hunks)
  • relay/relay_adaptor.go (2 hunks)
  • setting/ratio_setting/model_ratio.go (1 hunks)
  • web/src/components/table/channels/modals/EditTagModal.jsx (1 hunks)
  • web/src/constants/channel.constants.js (1 hunks)
  • web/src/helpers/render.jsx (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 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/components/table/channels/modals/EditTagModal.jsx
📚 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/components/table/channels/modals/EditTagModal.jsx
📚 Learning: 2025-08-05T17:14:17.246Z
Learnt from: neotf
PR: QuantumNous/new-api#1511
File: setting/ratio_setting/model_ratio.go:118-123
Timestamp: 2025-08-05T17:14:17.246Z
Learning: Claude models handle "-thinking" variants differently from Gemini models. For Claude models, only the base model (without "-thinking") gets an entry in defaultModelRatio map. The "-thinking" variants rely on the Claude relay handler stripping the suffix using strings.TrimSuffix(textRequest.Model, "-thinking") before looking up the ratio, so they automatically use the base model's ratio.

Applied to files:

  • setting/ratio_setting/model_ratio.go
🧬 Code graph analysis (4)
common/api_type.go (2)
constant/channel.go (1)
  • ChannelTypeSubmodel (53-53)
constant/api_type.go (1)
  • APITypeSubmodel (36-36)
relay/channel/submodel/adaptor.go (10)
relay/common/relay_info.go (1)
  • RelayInfo (74-120)
dto/claude.go (1)
  • ClaudeRequest (187-203)
dto/audio.go (1)
  • AudioRequest (9-15)
relay/common/relay_utils.go (1)
  • GetFullRequestURL (22-34)
relay/channel/api_request.go (3)
  • SetupApiRequestHeader (25-37)
  • DoRequest (231-233)
  • DoApiRequest (39-72)
dto/openai_request.go (2)
  • GeneralOpenAIRequest (25-78)
  • OpenAIResponsesRequest (768-790)
dto/rerank.go (1)
  • RerankRequest (10-18)
dto/embedding.go (1)
  • EmbeddingRequest (21-32)
relay/channel/openai/relay-openai.go (2)
  • OaiStreamHandler (111-175)
  • OpenaiHandler (177-256)
relay/channel/submodel/constants.go (2)
  • ModelList (3-14)
  • ChannelName (16-16)
relay/relay_adaptor.go (3)
constant/api_type.go (1)
  • APITypeSubmodel (36-36)
relay/channel/submodel/adaptor.go (1)
  • Adaptor (16-17)
relay/channel/adapter.go (1)
  • Adaptor (13-30)
web/src/helpers/render.jsx (1)
web/src/hooks/model-pricing/useModelPricingData.jsx (1)
  • groupRatio (50-50)
🔇 Additional comments (9)
constant/channel.go (2)

53-57: New ChannelTypeSubmodel constant — OK.

Constant placement is correct (before ChannelTypeDummy). No issues.


113-114: Base URL added — confirm correctness and TLS/cert expectations.

"https://llm.submodel.ai" looks fine. Ensure adaptor builds paths correctly (e.g., v1 prefix if required) and that self-signed/corporate CAs aren’t needed in production.

web/src/helpers/render.jsx (2)

1604-1632: Claude price log strings — OK.

Templates look consistent with renderClaudeModelPrice math.


1197-1215: Translation strings added — verify locale coverage

New Chinese i18n keys introduced in web/src/helpers/render.jsx (lines ~1125, 1132, 1197, 1208). Ensure matching entries exist in your locale files (e.g. web/src/i18n/locales/zh.json and web/src/i18n/locales/en.json) or confirm you intentionally rely on string-as-key fallback.

common/api_type.go (1)

70-72: API mapping for SubModel — OK.

ChannelTypeSubmodel → APITypeSubmodel mapping added correctly.

web/src/constants/channel.constants.js (1)

162-166: Add SubModel option — ChannelTypeSubmodel = 53 confirmed in backend; E2E verification required.
constant/channel.go:53 — ChannelTypeSubmodel = 53. Ensure end-to-end consumers (DB, API mappings, clients/tests) recognize the new channel type.

relay/channel/submodel/constants.go (1)

16-16: Confirm channel display name casing.

Elsewhere UI uses “SubModel”. Verify "submodel" won’t lead to inconsistent labeling or i18n mismatches.

relay/channel/submodel/adaptor.go (2)

59-61: Responses API not supported — verify routing/UI.

UI or router may send /v1/responses for some models. If Submodel truly doesn’t support it, ensure it’s hidden/disabled for this channel to prevent 4xx.


67-74: Assumes OpenAI‑compatible responses.

OaiStreamHandler/OpenaiHandler expect OpenAI schema and SSE format. Confirm Submodel aligns (event names, deltas, usage fields). Also verify pricing/usage mapping exists for these models to avoid zero/incorrect billing.

Comment thread constant/api_type.go
Comment on lines +36 to 37
APITypeSubmodel
)
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.

💡 Verification agent

🧩 Analysis chain

Do not add after APITypeDummy — move APITypeSubmodel before Dummy.

APITypeDummy is a sentinel (“do not add any channel after this”). Adding Submodel after Dummy breaks that contract and may exclude it from counts/loops.

Apply this reordering:

  APITypeJimeng
- APITypeMoonshot // this one is only for count, do not add any channel after this
- APITypeDummy    // this one is only for count, do not add any channel after this
- APITypeSubmodel
+ APITypeMoonshot
+ APITypeSubmodel
+ APITypeDummy    // this one is only for count, do not add any channel after this

🏁 Script executed:

#!/bin/bash
# Check for places treating APITypeDummy as an upper bound
rg -nP '(APITypeDummy).*?do not add|for\s*\(.*<\s*constant\.APITypeDummy' -C2

Length of output: 317


Move APITypeSubmodel before APITypeDummy (constant/api_type.go:34-36)

APITypeDummy is a sentinel ("do not add any channel after this"); Submodel after it violates that contract and can be excluded from counts/loops.

  APITypeJimeng
- APITypeMoonshot // this one is only for count, do not add any channel after this
- APITypeDummy    // this one is only for count, do not add any channel after this
- APITypeSubmodel
+ APITypeMoonshot
+ APITypeSubmodel
+ APITypeDummy    // this one is only for count, do not add any channel after this
📝 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
APITypeSubmodel
)
APITypeJimeng
APITypeMoonshot
APITypeSubmodel
APITypeDummy // this one is only for count, do not add any channel after this
)
🤖 Prompt for AI Agents
In constant/api_type.go around lines 34 to 37, APITypeSubmodel is declared after
the sentinel APITypeDummy which breaks the sentinel contract; move the
APITypeSubmodel constant declaration so it appears before APITypeDummy (i.e.,
reorder the constants so APITypeDummy remains the final sentinel value), and
ensure any comments/documentation reflect that APITypeDummy is the terminal
sentinel and that Submodel is excluded from sentinel-based counts/loops.

Comment thread relay/relay_adaptor.go
Comment on lines +41 to +45
"one-api/relay/channel/submodel"
=======

"github.com/gin-gonic/gin"
>>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd
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

Unresolved merge conflict and missing imports — blocks build.

Conflict markers present; gin import is dropped; submodel import only on one side. Resolve and include both imports.

Apply this fix:

 import (
   "one-api/constant"
   "one-api/relay/channel"
   "one-api/relay/channel/ali"
@@
   "one-api/relay/channel/zhipu_4v"
   "strconv"
-<<<<<<< HEAD
-    "one-api/relay/channel/submodel"
-=======
-
-	"github.com/gin-gonic/gin"
->>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd
+  "github.com/gin-gonic/gin"
+  "one-api/relay/channel/submodel"
 )
📝 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
"one-api/relay/channel/submodel"
=======
"github.com/gin-gonic/gin"
>>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd
"github.com/gin-gonic/gin"
"one-api/relay/channel/submodel"
🤖 Prompt for AI Agents
In relay/relay_adaptor.go around lines 41 to 45, remove the unresolved git
conflict markers and restore a proper import block that includes both
"one-api/relay/channel/submodel" and "github.com/gin-gonic/gin"; ensure there
are no leftover <<<<<<<, =======, >>>>>>> lines, place both packages as separate
entries in the import section, run gofmt/goimports to fix formatting and then
rebuild to confirm the missing import and conflict errors are resolved.

Comment thread relay/relay_adaptor.go
Comment on lines +110 to 112
case constant.APITypeSubmodel:
return &submodel.Adaptor{}
}
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.

💡 Verification agent

🧩 Analysis chain

Adaptor wiring for SubModel — OK once imports are fixed.

Case is correct; will work after resolving imports.


🏁 Script executed:

#!/bin/bash
# Ensure no other conflict markers remain
rg -n '^(<{7}|={7}|>{7})' -S

Length of output: 147


Resolve git merge conflicts and fix imports in relay/relay_adaptor.go

Submodel adaptor case (lines 110–112) is correct, but relay/relay_adaptor.go contains unresolved git conflict markers at lines 40, 42, 45 — remove the conflict markers and fix imports so the file compiles.

🤖 Prompt for AI Agents
In relay/relay_adaptor.go around lines 40, 42, 45 and 110–112, there are
unresolved git conflict markers that must be removed and the import block fixed
so the file compiles; delete the conflict marker lines (e.g. <<<<<<<, =======,
>>>>>>>) at the referenced lines, ensure the import list includes the submodel
package import path used by the case constant.APITypeSubmodel and any other
packages referenced in the file, remove any duplicate or unused imports, and run
go build or go vet to confirm the file compiles cleanly.

Comment on lines +57 to 58
SubModel,
} from '@lobehub/icons';
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.

💡 Verification agent

🧩 Analysis chain

Verify SubModel icon export exists in @lobehub/icons.

Import compiles only if SubModel is exported in your installed version.


🌐 Web query:

Does @lobehub/icons export a SubModel icon component? Which package version includes it, and is the component name exactly "SubModel"?

💡 Result:

Short answer: No.

  • I couldn't find any exported component named "SubModel" in the @lobehub/icons package or its repository. [1][2].
  • The npm package pages and the lobe-icons GitHub repo/releases list show the package and recent versions, but there is no mention or file named SubModel in the source or changelog. [1][3].

If you want, I can search a specific package version tarball or list the package's exported names to double-check—which version should I inspect?

Sources:

  • @lobehub/icons (npm) package page. [1]
  • lobehub / lobe-icons repository (GitHub). [2]
  • lobe-icons releases / changelog (GitHub Releases). [3]

SubModel is not exported by @lobehub/icons — remove or replace import

The @lobehub/icons package does not export a component named "SubModel"; the import in web/src/helpers/render.jsx (lines 57–58) will fail to compile.

  • Remove "SubModel" from the import and use an available exported icon or add/point to the package version that provides it.
🤖 Prompt for AI Agents
In web/src/helpers/render.jsx around lines 57-58, the import includes "SubModel"
which is not exported by @lobehub/icons; remove "SubModel" from the import
statement and either replace its usage in this file with an icon that exists in
@lobehub/icons (search current exports and pick a suitable replacement) or
update/package.json to a version of @lobehub/icons that actually exports
SubModel and run npm/yarn install; ensure any JSX references to <SubModel /> are
updated to the chosen replacement component name.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
web/src/helpers/render.jsx (3)

1206-1213: Don’t use literal strings as i18n keys — add stable keys with defaultValue

Passing a full sentence (with spaces/Chinese) as the key makes it untranslatable and brittle. Define keys and use defaultValue for fallback text.

Example:

-  ? i18next.t(
-      ' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}',
-      { count: webSearchCallCount, price: webSearchPrice, ratio: groupRatio, ratioType: ratioLabel }
-    )
+  ? i18next.t('pricing.extra.webSearch', {
+      defaultValue: ' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}',
+      count: webSearchCallCount,
+      price: webSearchPrice,
+      ratio: groupRatio,
+      ratioType: ratioLabel,
+    })

And similarly for 文件搜索:

-  ? i18next.t(
-      ' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}',
-      { count: fileSearchCallCount, price: fileSearchPrice, ratio: groupRatio, ratioType: ratioLabel }
-    )
+  ? i18next.t('pricing.extra.fileSearch', {
+      defaultValue: ' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}',
+      count: fileSearchCallCount,
+      price: fileSearchPrice,
+      ratio: groupRatio,
+      ratioType: ratioLabel,
+    })

Please also add these keys to your locale files.

Also applies to: 1217-1224


1463-1483: Same i18n issue — replace literal-string keys with proper keys + defaultValue

These sentences should also use stable keys to be translatable and avoid treating the sentence as a lookup key.

Example pattern:

- i18next.t('文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + ... = ${{total}}', { ... })
+ i18next.t('pricing.text.detailWithCache', {
+   defaultValue: '文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}',
+   nonCacheInput, cacheInput, cachePrice, price: inputRatioPrice, completion: completionTokens, compPrice: completionRatioPrice, total: textPrice.toFixed(6),
+})

1623-1651: Repeat: convert literal i18n calls to keyed strings with defaultValue

Ensure these two branches use translation keys; avoid constructing entire sentences as keys.

Example:

- i18next.t('提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}', { ... })
+ i18next.t('pricing.claude.simple', {
+   defaultValue: '提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}',
+   input: inputTokens, price: inputRatioPrice, completion: completionTokens, compPrice: completionRatioPrice, ratio: groupRatio, ratioType: ratioLabel, total: price.toFixed(6),
+})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 274872b and 4c2979b.

📒 Files selected for processing (2)
  • setting/ratio_setting/model_ratio.go (1 hunks)
  • web/src/helpers/render.jsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • setting/ratio_setting/model_ratio.go
🔇 Additional comments (2)
web/src/helpers/render.jsx (2)

1404-1408: LGTM — formatting only

Line breaks in the multiplication chain don’t change semantics.


57-58: SubModel icon import will break build — remove named import and guard usage

The @lobehub/icons package doesn’t export SubModel in common versions; this named import will fail at compile time. Prefer feature-detecting via the namespace import you already have and fall back to a generic icon.

Apply:

-  Jimeng,
-  SubModel,
+  Jimeng,
 } from '@lobehub/icons';

Comment on lines +346 to +347
case 53: // 嵌入模型:SubModel
return <SubModel size={iconSize} />;
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 | 🟠 Major

Guard SubModel usage with feature-detect; provide fallback icon

Avoid hard dependency on a possibly-missing icon component. Use LobeIcons.SubModel if present, otherwise a generic Layers icon.

-    case 53: // 嵌入模型:SubModel 
-      return <SubModel size={iconSize} />;
+    case 53: { // 子模型 / SubModel
+      const Icon = LobeIcons.SubModel;
+      return Icon ? <Icon size={iconSize} /> : <Layers size={iconSize} />;
+    }
📝 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
case 53: // 嵌入模型:SubModel
return <SubModel size={iconSize} />;
case 53: { // 子模型 / SubModel
const Icon = LobeIcons.SubModel;
return Icon ? <Icon size={iconSize} /> : <Layers size={iconSize} />;
}
🤖 Prompt for AI Agents
In web/src/helpers/render.jsx around lines 346-347, the code unconditionally
returns <SubModel /> which can break if that icon component is missing; update
the return to guard feature-detect LobeIcons.SubModel and fall back to a generic
Layers icon: ensure LobeIcons (and the fallback Icons/Layers component) are in
scope, then replace the unconditional return with a conditional usage such as
using a local variable Component = (LobeIcons && LobeIcons.SubModel) ?
LobeIcons.SubModel : Icons.Layers and return <Component size={iconSize} /> so
the code safely uses the SubModel icon when available and a Layers icon
otherwise.

@seefs001
Copy link
Copy Markdown
Collaborator

编译不过呀

@danding5 danding5 closed this Sep 29, 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