Skip to content

fix: openai responses api 未统计图像生成调用计费 - #1813

Merged
Calcium-Ion merged 2 commits into
mainfrom
fix1797
Sep 16, 2025
Merged

fix: openai responses api 未统计图像生成调用计费#1813
Calcium-Ion merged 2 commits into
mainfrom
fix1797

Conversation

@creamlike1024

@creamlike1024 creamlike1024 commented Sep 16, 2025

Copy link
Copy Markdown
Collaborator

Close #1797
wechat_2025-09-16_124635_770

Summary by CodeRabbit

  • New Features

    • Added support for image-generation calls including quality and size metadata.
    • Per-call pricing for image generation is now calculated by quality and size and included in billing.
    • UI displays image-generation call cost and includes it in total price breakdown.
    • Usage logs now record image-generation call presence and price for auditing.
  • Bug Fixes

    • Improved reliability of streaming usage handling, with safer null-checks and capture of cached token details.

@coderabbitai

coderabbitai Bot commented Sep 16, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds detection and metadata extraction for image_generation_call outputs, propagates quality/size through relay handlers, introduces GPT Image 1 per-call pricing and lookup, integrates image-call billing into postConsumeQuota and logging, surfaces the charge in web UI/usage logs, and refines streaming usage handling to include cached input tokens.

Changes

Cohort / File(s) Summary
DTO: Responses output extensions
dto/openai_response.go
Adds ResponsesOutputTypeImageGenerationCall constant, Quality and Size fields to ResponsesOutput, and methods HasImageGenerationCall(), GetQuality(), GetSize() on OpenAIResponsesResponse.
Relay: Responses propagation & streaming usage
relay/channel/openai/relay_responses.go
Sets context flags image_generation_call, image_generation_call_quality, image_generation_call_size for non-stream and stream completions; restructures null-safe streaming usage checks and captures InputTokensDetails.cached_tokens into usage.
Billing: Quota computation update
relay/compatible_handler.go
Adds image-generation-call quota/price handling in postConsumeQuota using context flags and GetGPTImage1PriceOnceCall; includes calculated quota in total and logs image_generation_call and image_generation_call_price when applicable.
Pricing: GPT Image 1 per-call
setting/operation_setting/tools.go
Adds nine exported GPT Image 1 per-call price constants (quality × size) and GetGPTImage1PriceOnceCall(quality, size) float64 lookup with fallback.
Web UI: Price rendering
web/src/helpers/render.jsx
Extends renderModelPrice signature with imageGenerationCall and imageGenerationCallPrice; includes image-call price in total and renders an extra line and breakdown when enabled.
Web: Usage logs integration
web/src/hooks/usage-logs/useUsageLogsData.jsx
Passes image_generation_call and image_generation_call_price from logs[i].other into renderModelPrice call sites (defaults applied when absent).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Relay as Relay Handler
  participant Resp as Responses DTO
  participant Ctx as Request Context
  participant Billing as postConsumeQuota
  participant Pricing as GetGPTImage1PriceOnceCall
  participant UI as Web UI / Logs

  Client->>Relay: /v1/responses (may stream)
  Relay->>Resp: parse outputs
  Resp-->>Relay: HasImageGenerationCall? (quality,size)
  Relay->>Ctx: set image_generation_call, quality, size
  Relay->>Ctx: set usage (incl. input_tokens_details.cached_tokens)
  Relay->>Billing: postConsumeQuota invoked
  Billing->>Ctx: read image_generation_call, quality, size
  Billing->>Pricing: lookup price(quality,size)
  Pricing-->>Billing: per-call price
  Billing->>Billing: add image-call quota/price to totals
  Billing->>UI: log image_generation_call and price
  UI-->>Client: render totals (includes image-call line)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • xyfacai

Poem

A nibble of bytes, a whisker of light,
I hop through responses, pricing now right.
Quality, size—each carrot I count,
Images billed fair, totals amount.
Thump-thump—patch delivered, wallet delight! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: openai responses api 未统计图像生成调用计费" concisely and accurately states the primary intent — to fix missing image-generation billing for the OpenAI /v1/responses API — and it directly matches the changes in the diff that add detection, metadata propagation, pricing, and billing logic for image-generation calls. The title is specific and clear enough for teammates scanning PR history.
Linked Issues Check ✅ Passed Issue #1797 reported that image-generation calls via /v1/responses were not billed; the PR implements the coding fixes: it introduces detection and accessors for image_generation_call outputs, propagates image_generation_call and its quality/size from response handlers into the billing context, adds GPT-Image1 pricing constants and GetGPTImage1PriceOnceCall, and charges the computed price in compatible_handler while exposing price in logs and the UI. These code-level changes directly address the linked issue's primary requirement to include image-generation charges in billing.
Out of Scope Changes Check ✅ Passed All substantive changes are focused on implementing image-generation billing and related telemetry/UI; the only additional modifications are safer null-checking and capturing of input_tokens_details in streaming usage handling, which appear to be targeted robustness improvements rather than unrelated feature work. No large or unrelated out-of-scope changes were detected in the provided summaries.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix1797

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11cf70e and 17be7c3.

📒 Files selected for processing (1)
  • web/src/helpers/render.jsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/src/helpers/render.jsx

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.

@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 (8)
dto/openai_response.go (2)

292-315: Name clarity and robustness for quality/size getters.

  • Consider more explicit names (GetImageGenerationQuality/GetImageGenerationSize).
  • Normalize strings (lowercase/trim) at source to reduce downstream case bugs.

Want me to push a follow-up that adds normalized getters and uses them across the call sites?


320-328: Avoid emitting empty fields when marshalling.

Add omitempty to Quality/Size to prevent empty strings being serialized for non-image outputs.

 type ResponsesOutput struct {
@@
-  Quality string                   `json:"quality"`
-  Size    string                   `json:"size"`
+  Quality string                   `json:"quality,omitempty"`
+  Size    string                   `json:"size,omitempty"`
 }
relay/compatible_handler.go (1)

441-444: Record more context in logs for observability.

Include quality/size/count to aid audits and UI display.

 if !dImageGenerationCallQuota.IsZero() {
   other["image_generation_call"] = true
   other["image_generation_call_price"] = imageGenerationCallPrice
+  if v := ctx.GetInt("image_generation_call_count"); v > 0 { other["image_generation_call_count"] = v }
+  if q := ctx.GetString("image_generation_call_quality"); q != "" { other["image_generation_call_quality"] = q }
+  if s := ctx.GetString("image_generation_call_size"); s != "" { other["image_generation_call_size"] = s }
 }
relay/channel/openai/relay_responses.go (2)

36-40: Also pass image-generation call count (non-stream).

Count calls so billing can multiply by N.

 if responsesResponse.HasImageGenerationCall() {
   c.Set("image_generation_call", true)
   c.Set("image_generation_call_quality", responsesResponse.GetQuality())
   c.Set("image_generation_call_size", responsesResponse.GetSize())
+  if cnt := responsesResponse.CountImageGenerationCalls(); cnt > 0 {
+    c.Set("image_generation_call_count", cnt)
+  }
 }

89-108: Streaming: set usage safely (good), but also capture image-call count.

Increment count on item-done events to avoid relying solely on the final snapshot.

Apply these diffs:

 case "response.completed":
   if streamResponse.Response != nil {
     if streamResponse.Response.Usage != nil {
@@
     }
-    if streamResponse.Response.HasImageGenerationCall() {
+    if streamResponse.Response.HasImageGenerationCall() {
       c.Set("image_generation_call", true)
       c.Set("image_generation_call_quality", streamResponse.Response.GetQuality())
       c.Set("image_generation_call_size", streamResponse.Response.GetSize())
+      if cnt := streamResponse.Response.CountImageGenerationCalls(); cnt > 0 {
+        c.Set("image_generation_call_count", cnt)
+      }
     }
   }
@@
 case dto.ResponsesOutputTypeItemDone:
   // 函数调用处理
   if streamResponse.Item != nil {
     switch streamResponse.Item.Type {
     case dto.BuildInCallWebSearchCall:
       info.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolWebSearchPreview].CallCount++
+    case dto.ResponsesOutputTypeImageGenerationCall:
+      // Increment count as items complete; capture last seen quality/size for logging.
+      current := c.GetInt("image_generation_call_count")
+      c.Set("image_generation_call_count", current+1)
+      if streamResponse.Item.Quality != "" { c.Set("image_generation_call_quality", streamResponse.Item.Quality) }
+      if streamResponse.Item.Size != "" { c.Set("image_generation_call_size", streamResponse.Item.Size) }
     }
   }

If the stream never reaches “completed”, the per-item path still captures the count.

setting/operation_setting/tools.go (1)

13-23: Add 'last verified' comment and consider externalizing GPT-Image-1 prices

Constants in setting/operation_setting/tools.go (lines 13–23) match OpenAI gpt-image-1 pricing as of September 16, 2025: 1024×1024 — low $0.011 / medium $0.042 / high $0.167; 1024×1536 & 1536×1024 — low $0.016 / medium $0.063 / high $0.25.

  • Add an inline comment above these constants: "last verified: 2025-09-16 — OpenAI pricing docs" (include source reference).
  • Optional: move these values to config/DB/env to avoid rebuilds when prices change.
web/src/helpers/render.jsx (2)

1137-1143: UI: show call count when >1

Currently always renders “/ 1次”. If multiple calls occur, display the count for clarity.

-          {imageGenerationCall && imageGenerationCallPrice > 0 && (
+          {imageGenerationCall && imageGenerationCallPrice > 0 && (
             <p>
-              {i18next.t('图片生成调用:${{price}} / 1次', {
-                price: imageGenerationCallPrice,
-              })}
+              {i18next.t('图片生成调用:${{price}} / 1次{{times}}', {
+                price: imageGenerationCallPrice,
+                times:
+                  (imageGenerationCalls ?? 0) > 1
+                    ? ` × ${imageGenerationCalls}`
+                    : '',
+              })}
             </p>
           )}

Note: uses imageGenerationCalls from the previous comment.


1223-1232: Breakdown string: include image call count for transparency

Extra services summary omits the number of image calls.

-                imageGenerationCall && imageGenerationCallPrice > 0
+                imageGenerationCall && imageGenerationCallPrice > 0
                   ? i18next.t(
-                      ' + 图片生成调用 ${{price}} / 1次 * {{ratioType}} {{ratio}}',
+                      ' + 图片生成调用 {{count}}次 / 1次 * ${{price}} * {{ratioType}} {{ratio}}',
                       {
-                        price: imageGenerationCallPrice,
+                        count: imageGenerationCalls ?? (imageGenerationCall ? 1 : 0),
+                        price: imageGenerationCallPrice,
                         ratio: groupRatio,
                         ratioType: ratioLabel,
                       },
                     )
                   : '',
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 18a385f and 11cf70e.

📒 Files selected for processing (6)
  • dto/openai_response.go (3 hunks)
  • relay/channel/openai/relay_responses.go (2 hunks)
  • relay/compatible_handler.go (3 hunks)
  • setting/operation_setting/tools.go (2 hunks)
  • web/src/helpers/render.jsx (4 hunks)
  • web/src/hooks/usage-logs/useUsageLogsData.jsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
relay/compatible_handler.go (1)
setting/operation_setting/tools.go (1)
  • GetGPTImage1PriceOnceCall (81-107)
relay/channel/openai/relay_responses.go (1)
dto/openai_response.go (1)
  • Usage (221-234)
web/src/helpers/render.jsx (1)
web/src/hooks/model-pricing/useModelPricingData.jsx (1)
  • groupRatio (50-50)
🔇 Additional comments (4)
relay/compatible_handler.go (1)

342-344: LGTM on quota aggregation hook.

Image-generation quota is now included in the final total.

dto/openai_response.go (1)

9-11: No change required — upstream output[].type is "image_generation_call"
Verified against OpenAI Responses examples and Azure Responses references.

web/src/hooks/usage-logs/useUsageLogsData.jsx (1)

450-452: renderModelPrice signature updated; call sites verified.
Definition includes the new params imageGenerationCall and imageGenerationCallPrice (web/src/helpers/render.jsx:1008); the only call site found (web/src/hooks/usage-logs/useUsageLogsData.jsx:428–452) already passes both args — no other call sites located.

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

1030-1032: New args added to renderModelPrice — usage-logs call site relies on defaults; confirm forwarding of image flags

Search found a single invocation at web/src/hooks/usage-logs/useUsageLogsData.jsx:428 calling renderModelPrice(logs[i].prompt_tokens, logs[i].completion_tokens, other?.model_ratio) — it does not pass imageGenerationCall or imageGenerationCallPrice. renderModelPrice is exported at web/src/helpers/render.jsx:1008 and supplies defaults for those params. If usage logs can include image-generation metadata, forward those fields into this call; otherwise relying on the defaults is acceptable.

Comment thread dto/openai_response.go
Comment on lines +280 to +290
func (o *OpenAIResponsesResponse) HasImageGenerationCall() bool {
if len(o.Output) == 0 {
return false
}
for _, output := range o.Output {
if output.Type == ResponsesOutputTypeImageGenerationCall {
return true
}
}
return 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

Only detects presence; no support for multiple image-generation calls.

If a single Responses object includes multiple image-generation calls, billing will undercount. Provide a count API.

Apply this diff to expose a count helper:

 func (o *OpenAIResponsesResponse) HasImageGenerationCall() bool {
@@
 }
 
+// CountImageGenerationCalls returns how many image-generation calls are present.
+func (o *OpenAIResponsesResponse) CountImageGenerationCalls() int {
+  if len(o.Output) == 0 {
+    return 0
+  }
+  count := 0
+  for _, output := range o.Output {
+    if output.Type == ResponsesOutputTypeImageGenerationCall {
+      count++
+    }
+  }
+  return count
+}
📝 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
func (o *OpenAIResponsesResponse) HasImageGenerationCall() bool {
if len(o.Output) == 0 {
return false
}
for _, output := range o.Output {
if output.Type == ResponsesOutputTypeImageGenerationCall {
return true
}
}
return false
}
func (o *OpenAIResponsesResponse) HasImageGenerationCall() bool {
if len(o.Output) == 0 {
return false
}
for _, output := range o.Output {
if output.Type == ResponsesOutputTypeImageGenerationCall {
return true
}
}
return false
}
// CountImageGenerationCalls returns how many image-generation calls are present.
func (o *OpenAIResponsesResponse) CountImageGenerationCalls() int {
if len(o.Output) == 0 {
return 0
}
count := 0
for _, output := range o.Output {
if output.Type == ResponsesOutputTypeImageGenerationCall {
count++
}
}
return count
}
🤖 Prompt for AI Agents
In dto/openai_response.go around lines 280 to 290, the current
HasImageGenerationCall only detects existence of image-generation outputs and
therefore undercounts when multiple image-generation calls exist; add a new
method (e.g., CountImageGenerationCalls) on OpenAIResponsesResponse that
iterates over o.Output, increments a counter for each output with Type ==
ResponsesOutputTypeImageGenerationCall, and returns the total count as an int so
callers can bill correctly for multiple image-generation calls.

Comment on lines +279 to 286
var dImageGenerationCallQuota decimal.Decimal
var imageGenerationCallPrice float64
if ctx.GetBool("image_generation_call") {
imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(ctx.GetString("image_generation_call_quality"), ctx.GetString("image_generation_call_size"))
dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).Mul(dGroupRatio).Mul(dQuotaPerUnit)
extraContent += fmt.Sprintf("Image Generation Call 花费 %s", dImageGenerationCallQuota.String())
}

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

Under-billing when multiple image-generation calls occur.

You bill as a single call; if N calls happen, only 1× price is charged.

Apply this minimal diff (count defaulting to 1 for backward compatibility):

 var dImageGenerationCallQuota decimal.Decimal
 var imageGenerationCallPrice float64
 if ctx.GetBool("image_generation_call") {
-  imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(ctx.GetString("image_generation_call_quality"), ctx.GetString("image_generation_call_size"))
-  dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).Mul(dGroupRatio).Mul(dQuotaPerUnit)
-  extraContent += fmt.Sprintf("Image Generation Call 花费 %s", dImageGenerationCallQuota.String())
+  imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(
+    ctx.GetString("image_generation_call_quality"),
+    ctx.GetString("image_generation_call_size"),
+  )
+  callCount := ctx.GetInt("image_generation_call_count")
+  if callCount <= 0 {
+    callCount = 1
+  }
+  dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).
+    Mul(decimal.NewFromInt(int64(callCount))).
+    Mul(dGroupRatio).Mul(dQuotaPerUnit)
+  extraContent += fmt.Sprintf("Image Generation Call %d 次,花费 %s", callCount, dImageGenerationCallQuota.String())
 }

Note: Best is summing per-call prices when qualities/sizes differ; see suggestions in openai/relay_responses.go.

📝 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
var dImageGenerationCallQuota decimal.Decimal
var imageGenerationCallPrice float64
if ctx.GetBool("image_generation_call") {
imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(ctx.GetString("image_generation_call_quality"), ctx.GetString("image_generation_call_size"))
dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).Mul(dGroupRatio).Mul(dQuotaPerUnit)
extraContent += fmt.Sprintf("Image Generation Call 花费 %s", dImageGenerationCallQuota.String())
}
var dImageGenerationCallQuota decimal.Decimal
var imageGenerationCallPrice float64
if ctx.GetBool("image_generation_call") {
imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(
ctx.GetString("image_generation_call_quality"),
ctx.GetString("image_generation_call_size"),
)
callCount := ctx.GetInt("image_generation_call_count")
if callCount <= 0 {
callCount = 1
}
dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).
Mul(decimal.NewFromInt(int64(callCount))).
Mul(dGroupRatio).Mul(dQuotaPerUnit)
extraContent += fmt.Sprintf("Image Generation Call %d 次,花费 %s", callCount, dImageGenerationCallQuota.String())
}
🤖 Prompt for AI Agents
In relay/compatible_handler.go around lines 279-286, the image-generation cost
is only billed once even if multiple calls occur; read an integer count from the
context (e.g., "image_generation_call_count"), default it to 1 for backward
compatibility if missing or zero, then multiply the per-call price/decimal quota
by that count (use decimal.NewFromInt(int64(count)) when updating
dImageGenerationCallQuota or multiply the float price by float64(count)). Also
update the extraContent string to reflect the count and total cost (e.g., "Image
Generation Call xN 花费 ...").

Comment on lines +81 to +107
func GetGPTImage1PriceOnceCall(quality string, size string) float64 {
prices := map[string]map[string]float64{
"low": {
"1024x1024": GPTImage1Low1024x1024,
"1024x1536": GPTImage1Low1024x1536,
"1536x1024": GPTImage1Low1536x1024,
},
"medium": {
"1024x1024": GPTImage1Medium1024x1024,
"1024x1536": GPTImage1Medium1024x1536,
"1536x1024": GPTImage1Medium1536x1024,
},
"high": {
"1024x1024": GPTImage1High1024x1024,
"1024x1536": GPTImage1High1024x1536,
"1536x1024": GPTImage1High1536x1024,
},
}

if qualityMap, exists := prices[quality]; exists {
if price, exists := qualityMap[size]; exists {
return price
}
}

return GPTImage1High1024x1024
}

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

Normalize inputs and avoid per-call map allocation.

  • Current lookup is case-sensitive; unknown inputs fall back to the highest price (overbilling). Lowercase/trim inputs.
  • Hoist the prices map to a package-level var to avoid allocating it on every call.

Apply these diffs:

+var gptImage1Prices = map[string]map[string]float64{
+  "low": {
+    "1024x1024": GPTImage1Low1024x1024,
+    "1024x1536": GPTImage1Low1024x1536,
+    "1536x1024": GPTImage1Low1536x1024,
+  },
+  "medium": {
+    "1024x1024": GPTImage1Medium1024x1024,
+    "1024x1536": GPTImage1Medium1024x1536,
+    "1536x1024": GPTImage1Medium1536x1024,
+  },
+  "high": {
+    "1024x1024": GPTImage1High1024x1024,
+    "1024x1536": GPTImage1High1024x1536,
+    "1536x1024": GPTImage1High1536x1024,
+  },
+}
+
 func GetGPTImage1PriceOnceCall(quality string, size string) float64 {
-  prices := map[string]map[string]float64{
-    "low": { ... },
-    "medium": { ... },
-    "high": { ... },
-  }
-
-  if qualityMap, exists := prices[quality]; exists {
-    if price, exists := qualityMap[size]; exists {
+  q := strings.ToLower(strings.TrimSpace(quality))
+  s := strings.ToLower(strings.TrimSpace(size))
+  if qualityMap, exists := gptImage1Prices[q]; exists {
+    if price, exists := qualityMap[s]; exists {
       return price
     }
   }
 
   return GPTImage1High1024x1024
 }

Optionally, support common synonyms ("standard"→"medium", "hd"→"high"). I can add a small alias map if desired.

🤖 Prompt for AI Agents
In setting/operation_setting/tools.go around lines 81 to 107, the function
allocates the prices map on every call and performs a case-sensitive lookup that
can overbill on unknown inputs; move the nested prices map to a package-level
variable (and an alias map for synonyms like "standard"→"medium", "hd"→"high"),
then in GetGPTImage1PriceOnceCall normalize inputs with strings.TrimSpace and
strings.ToLower, map any synonym to its canonical key, perform the lookup
against the package-level map, and if not found return a safe default (e.g., the
"low" 1024x1024 price) instead of the highest price to avoid overbilling.

Comment thread web/src/helpers/render.jsx
@Calcium-Ion
Calcium-Ion merged commit 752dc11 into main Sep 16, 2025
1 check passed
@Calcium-Ion
Calcium-Ion deleted the fix1797 branch October 11, 2025 03:06
x22x22 pushed a commit to x22x22/new-api that referenced this pull request Apr 24, 2026
fix: openai responses api 未统计图像生成调用计费
jiutubaba pushed a commit to jiutubaba/fx-api that referenced this pull request May 17, 2026
…ai-image-handling

fix: openai image request handling
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.

/v1/responses API 中通过 tools 调用 gpt-image-1 创建图片,未计算生图的费用(严重计费问题)

2 participants