Skip to content

alpha -> main - #1910

Merged
seefs001 merged 15 commits into
QuantumNous:mainfrom
seefs001:fix/volcengine_default_baseurl
Sep 29, 2025
Merged

alpha -> main#1910
seefs001 merged 15 commits into
QuantumNous:mainfrom
seefs001:fix/volcengine_default_baseurl

Conversation

@seefs001

@seefs001 seefs001 commented Sep 29, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features
    • Enable promotion codes during Stripe Checkout (configurable in payment settings).
    • Optional Umami analytics injection when environment variables are set.
    • Support URL context tool for Gemini channels.
    • Enhanced task log modal: video playback with loading state, error fallback, and open/copy URL actions.
  • Improvements
    • Channel editor: default base URL for type 45; key deduplication action for batch inputs; layout refinements.
  • Localization
    • Added EN/ZH translations for the new Stripe promotion code option.

@coderabbitai

coderabbitai Bot commented Sep 29, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds Stripe promotion code support via a new setting, integrates Umami analytics injection into the index page, introduces Gemini urlContext tool support, enhances video handling in task log modal, adds key deduplication and defaults in channel edit modal, and updates settings/UI and i18n accordingly.

Changes

Cohort / File(s) Summary
Stripe promotion codes support
controller/topup_stripe.go, model/option.go, setting/payment_stripe.go, web/src/pages/Setting/Payment/SettingsPaymentGatewayStripe.jsx, web/src/components/settings/PaymentSetting.jsx, web/src/i18n/locales/en.json, web/src/i18n/locales/zh.json
Adds a feature flag (StripePromotionCodesEnabled) surfaced in settings/UI and i18n; passes AllowPromotionCodes to Stripe Checkout session when enabled; persists option in model/setting.
Gemini urlContext tool
dto/gemini.go, relay/channel/gemini/relay-gemini.go
Extends GeminiChatTool with URLContext and builds Gemini tool list by detecting "urlContext" tool, attaching URLContext payload.
Analytics injection (Umami)
main.go, web/index.html
Inserts placeholder in HTML and injects Umami script at runtime based on env vars (UMAMI_WEBSITE_ID, UMAMI_SCRIPT_URL).
Task logs video modal
web/src/components/table/task-logs/modals/ContentModal.jsx
Adds async video loading, error handling, spinner, and actions (open in new tab, copy URL); refactors rendering logic.
Channel edit enhancements
web/src/components/table/channels/modals/EditChannelModal.jsx
Sets default base_url for type 45; adds JSON key dedup for type 41 with user feedback; UI layout tweaks and handling updates.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant FE as Frontend
  participant BE as Server
  participant Stripe as Stripe API
  Note over FE,BE: Stripe Checkout with promotion codes
  FE->>BE: Request Stripe checkout session
  BE->>BE: Read setting StripePromotionCodesEnabled
  BE->>Stripe: Create Checkout Session<br/>(AllowPromotionCodes = setting)
  Stripe-->>BE: Session
  BE-->>FE: Session URL
Loading
sequenceDiagram
  autonumber
  participant Client
  participant Relay as Gemini Relay
  participant Gemini
  Note over Client,Relay: urlContext tool handling
  Client->>Relay: Request with Tools (includes "urlContext")
  Relay->>Relay: Build Gemini tools list<br/>(attach URLContext payload)
  Relay->>Gemini: Send content + tools
  Gemini-->>Relay: Response
  Relay-->>Client: Transformed response
Loading
sequenceDiagram
  autonumber
  participant UI as Task Logs UI
  participant Modal as ContentModal
  participant Net as Browser Loader
  Note over UI,Modal: Video preview flow
  UI->>Modal: Open with video URL
  Modal->>Modal: isLoading=true
  Modal->>Net: Load video
  alt Load success
    Net-->>Modal: loadedmetadata
    Modal->>Modal: isLoading=false
  else Load error
    Net-->>Modal: error
    Modal->>Modal: videoError=true, isLoading=false
    Modal-->>UI: Show error actions (open, copy)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • creamlike1024
  • Calcium-Ion

Poem

A nibble of flags, a sprinkle of code,
Promotion codes hop down the checkout road.
Umami tracks with tiny feet,
Gemini brings URLs to meet.
Videos spin, keys align—no fuss!
Ship it quick—thump-thump—trust us. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title “alpha → main” does not describe any of the functional changes in this pull request and simply reflects a branch merge rather than summarizing the key updates such as Stripe promotion code support, URLContext enhancements, analytics injection, and related UI modifications. As a result, it fails to meet the requirement for a concise, clear title that conveys the main change from the developer’s perspective. Please rename the pull request to a concise, specific title that highlights the primary functionality added (for example, “Add Stripe promotion codes support and URLContext for Gemini tools with analytics injection and UI updates”).
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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

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

@seefs001
seefs001 merged commit a91f3e7 into QuantumNous:main Sep 29, 2025
1 check was pending

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

🧹 Nitpick comments (2)
web/src/components/table/channels/modals/EditChannelModal.jsx (2)

349-351: Avoid overwriting a previously chosen base_url when switching types.

Only set the default for type 45 if base_url is empty to preserve user choice.

Apply this diff:

-        case 45:
-          localModels = getChannelModels(value);
-          setInputs((prevInputs) => ({ ...prevInputs, base_url: 'https://ark.cn-beijing.volces.com' }));
+        case 45:
+          localModels = getChannelModels(value);
+          setInputs((prev) => ({
+            ...prev,
+            base_url:
+              typeof prev.base_url === 'string' && prev.base_url.trim()
+                ? prev.base_url
+                : 'https://ark.cn-beijing.volces.com',
+          }));

967-1016: Harden key dedup to handle CRLF and mixed newlines.

Use a newline-agnostic split to avoid stray “\r” on Windows inputs.

-    const keyLines = currentKey.split('\n');
+    const keyLines = currentKey.split(/\r?\n/);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2b5efb and bf9a5f5.

📒 Files selected for processing (13)
  • controller/topup_stripe.go (1 hunks)
  • dto/gemini.go (1 hunks)
  • main.go (3 hunks)
  • model/option.go (2 hunks)
  • relay/channel/gemini/relay-gemini.go (3 hunks)
  • setting/payment_stripe.go (1 hunks)
  • web/index.html (1 hunks)
  • web/src/components/settings/PaymentSetting.jsx (1 hunks)
  • web/src/components/table/channels/modals/EditChannelModal.jsx (8 hunks)
  • web/src/components/table/task-logs/modals/ContentModal.jsx (1 hunks)
  • web/src/i18n/locales/en.json (1 hunks)
  • web/src/i18n/locales/zh.json (1 hunks)
  • web/src/pages/Setting/Payment/SettingsPaymentGatewayStripe.jsx (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 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/EditChannelModal.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 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/EditChannelModal.jsx
🧬 Code graph analysis (6)
web/src/pages/Setting/Payment/SettingsPaymentGatewayStripe.jsx (1)
web/src/components/settings/PaymentSetting.jsx (1)
  • inputs (30-49)
model/option.go (2)
common/constants.go (1)
  • OptionMap (36-36)
setting/payment_stripe.go (1)
  • StripePromotionCodesEnabled (8-8)
controller/topup_stripe.go (1)
setting/payment_stripe.go (1)
  • StripePromotionCodesEnabled (8-8)
relay/channel/gemini/relay-gemini.go (1)
dto/gemini.go (1)
  • GeminiChatTool (249-255)
web/src/components/table/task-logs/modals/ContentModal.jsx (2)
web/src/components/table/task-logs/TaskLogsActions.jsx (1)
  • Typography (25-25)
web/src/hooks/task-logs/useTaskLogsData.js (2)
  • isModalOpen (67-67)
  • modalContent (68-68)
web/src/components/table/channels/modals/EditChannelModal.jsx (1)
web/src/helpers/utils.jsx (2)
  • showInfo (161-163)
  • showSuccess (157-159)
🔇 Additional comments (8)
controller/topup_stripe.go (1)

228-230: Promotion codes flag is cleanly threaded through

AllowPromotionCodes only toggles when the new setting flips on, matching Stripe’s expectations while leaving existing sessions untouched. Nice surgical change.

model/option.go (1)

85-86: Option plumbing stays consistent

Appreciate that you registered StripePromotionCodesEnabled in both the initializer and the runtime update switch—this keeps the flag aligned across in-memory settings and persisted options.

Also applies to: 334-335

web/src/components/table/channels/modals/EditChannelModal.jsx (6)

458-465: Good fallback for Volcengine Ark base_url when loading channels.

This guards empty base_url for type 45 cleanly.


1112-1146: Batch UI refinements look correct.

Nice addition of “密钥聚合模式” and dedup action gating (hidden for Vertex).


1348-1351: Persisting vertex_key_type via settings is correct.

Keeps top-level UI state while serializing to settings for backend.


1371-1372: Conditional rendering for Vertex JSON/manual vs upload is clear and consistent.

Good separation of batch/file-only vs single/manual paths.

Also applies to: 1436-1437


848-851: Correct serialization of Vertex keys before submit.

JSON-stringifying array vs single item matches the expected payload shape.


1946-1966: Make the base_url Select fully form-controlled and extensible.

  • Remove defaultValue and bind the select to the form state:
    - defaultValue='https://ark.cn-beijing.volces.com'
    + value={inputs.base_url}
  • Enable custom entries for future regions:
    + allowAdditions
  • Centralize the two official endpoints into a shared constant:
    export const API_BASE_URLS = [
      'https://ark.cn-beijing.volces.com',       // VolcEngine Ark Beijing (per VolcEngine docs)
      'https://ark.ap-southeast.bytepluses.com'  // BytePlus ModelArk AP-Southeast (per BytePlus docs)
    ];

Comment thread main.go
Comment on lines +166 to +167
indexPage = bytes.ReplaceAll(indexPage, []byte("<analytics></analytics>\n"), []byte(analyticsInject))

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

Don’t hardcode newline in the analytics placeholder replacement

bytes.ReplaceAll currently searches for <analytics></analytics>\n. If the built index.html uses \r\n (common on Windows) or the bundler strips the trailing newline, the placeholder never matches, so the Umami script is never injected even when UMAMI_WEBSITE_ID is set. Please match the tag without assuming a specific line ending (and append a newline only when you actually inject the script) to keep the feature reliable across build environments.

-	analyticsInject := analyticsInjectBuilder.String()
-	indexPage = bytes.ReplaceAll(indexPage, []byte("<analytics></analytics>\n"), []byte(analyticsInject))
+	analyticsInject := analyticsInjectBuilder.String()
+	placeholder := []byte("<analytics></analytics>")
+	replacement := []byte(analyticsInject)
+	if analyticsInject != "" {
+		replacement = append(replacement, '\n')
+	}
+	indexPage = bytes.ReplaceAll(indexPage, placeholder, replacement)
📝 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
indexPage = bytes.ReplaceAll(indexPage, []byte("<analytics></analytics>\n"), []byte(analyticsInject))
analyticsInject := analyticsInjectBuilder.String()
placeholder := []byte("<analytics></analytics>")
replacement := []byte(analyticsInject)
if analyticsInject != "" {
replacement = append(replacement, '\n')
}
indexPage = bytes.ReplaceAll(indexPage, placeholder, replacement)
🤖 Prompt for AI Agents
In main.go around lines 166-167, the replacement currently matches
"<analytics></analytics>\n" which fails on CRLF or when the trailing newline is
absent; change the logic to search for the tag without assuming a line ending
(e.g. match "<analytics></analytics>"), or normalize CRLF to LF first, then
perform bytes.ReplaceAll on the tag-only byte sequence; when you actually inject
the analytics script, append a single '\n' to the injected bytes so the output
keeps a newline only when injection occurs.

Comment on lines +35 to +40
useEffect(() => {
if (isModalOpen && isVideo) {
setVideoError(false);
setIsLoading(true);
}
}, [isModalOpen, isVideo]);

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

Reset the error state when changing sources. The effect never reruns when a new modalContent is shown while the modal stays open, so a prior failure leaves videoError === true and short-circuits rendering of the <video> element for the new source. Users remain stuck on the fallback even though the next URL might be playable. Please re-trigger the reset when modalContent changes.

-  }, [isModalOpen, isVideo]);
+  }, [isModalOpen, isVideo, modalContent]);
📝 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
useEffect(() => {
if (isModalOpen && isVideo) {
setVideoError(false);
setIsLoading(true);
}
}, [isModalOpen, isVideo]);
useEffect(() => {
if (isModalOpen && isVideo) {
setVideoError(false);
setIsLoading(true);
}
}, [isModalOpen, isVideo, modalContent]);
🤖 Prompt for AI Agents
In web/src/components/table/task-logs/modals/ContentModal.jsx around lines 35 to
40, the effect that resets videoError and sets loading only depends on
isModalOpen and isVideo, so when a new modalContent is shown while the modal
stays open a prior videoError can persist; update the effect to also depend on
modalContent and when isModalOpen && isVideo is true reset videoError to false
and setIsLoading(true) (so new sources clear previous error state and attempt to
load).

Comment on lines +117 to +126
<video
src={modalContent}
controls
style={{ width: '100%' }}
autoPlay
crossOrigin="anonymous"
onError={handleVideoError}
onLoadedData={handleVideoLoaded}
onLoadStart={() => setIsLoading(true)}
/>

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 | 🔴 Critical

Don’t force crossOrigin="anonymous" on every video. Adding this attribute makes the browser issue a CORS fetch; providers that don’t send Access-Control-Allow-Origin (many CDN/S3 links) now fail to load and always hit your error state, breaking previously working videos. Please drop the attribute or gate it behind an opt-in.

         <video 
           src={modalContent} 
           controls 
           style={{ width: '100%' }} 
           autoPlay
-          crossOrigin="anonymous"
           onError={handleVideoError}
           onLoadedData={handleVideoLoaded}
           onLoadStart={() => setIsLoading(true)}
         />
📝 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
<video
src={modalContent}
controls
style={{ width: '100%' }}
autoPlay
crossOrigin="anonymous"
onError={handleVideoError}
onLoadedData={handleVideoLoaded}
onLoadStart={() => setIsLoading(true)}
/>
<video
src={modalContent}
controls
style={{ width: '100%' }}
autoPlay
onError={handleVideoError}
onLoadedData={handleVideoLoaded}
onLoadStart={() => setIsLoading(true)}
/>
🤖 Prompt for AI Agents
In web/src/components/table/task-logs/modals/ContentModal.jsx around lines 117
to 126, the video element currently forces crossOrigin="anonymous" which
triggers CORS fetches and breaks sources that don't send
Access-Control-Allow-Origin; remove the hardcoded crossOrigin attribute or make
it opt-in by adding a prop/flag (e.g., allowCrossOrigin or crossoriginEnabled)
to the component and only set the crossOrigin attribute when that prop is true;
update the component’s prop types/defaults and callers to pass the flag where
CORS-enabled sources are expected.

Comment on lines +67 to 71
StripePromotionCodesEnabled:
props.options.StripePromotionCodesEnabled !== undefined
? props.options.StripePromotionCodesEnabled
: false,
};

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

Coerce StripePromotionCodesEnabled to a boolean

props.options.StripePromotionCodesEnabled arrives as a persisted string ('true'/'false'). Passing that through as-is makes the switch render “on” even when the stored value is 'false', because any non-empty string is truthy and Semi UI’s checked prop expects an actual boolean.(semi.design)

Fix by normalizing the option to a boolean before seeding state:

-        StripePromotionCodesEnabled:
-          props.options.StripePromotionCodesEnabled !== undefined
-            ? props.options.StripePromotionCodesEnabled
-            : false,
+        StripePromotionCodesEnabled:
+          props.options.StripePromotionCodesEnabled !== undefined
+            ? ['true', true].includes(props.options.StripePromotionCodesEnabled)
+            : false,
📝 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
StripePromotionCodesEnabled:
props.options.StripePromotionCodesEnabled !== undefined
? props.options.StripePromotionCodesEnabled
: false,
};
StripePromotionCodesEnabled:
props.options.StripePromotionCodesEnabled !== undefined
? ['true', true].includes(props.options.StripePromotionCodesEnabled)
: false,
};
🤖 Prompt for AI Agents
In web/src/pages/Setting/Payment/SettingsPaymentGatewayStripe.jsx around lines
67 to 71, props.options.StripePromotionCodesEnabled is coming in as a string
('true'/'false') so the switch renders incorrectly; normalize it to a real
boolean when seeding state by checking if the value is the boolean true or the
string 'true' (e.g. value === true || value === 'true') and use that result
instead of the raw prop.

@coderabbitai coderabbitai Bot mentioned this pull request Oct 20, 2025
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
jiutubaba pushed a commit to jiutubaba/fx-api that referenced this pull request May 17, 2026
fix(openai): 修复 Codex 工具调用 call_id 处理
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.

6 participants