Add OpenRouter dedicated images API support
Fetches /api/v1/images/models in parallel with /models and merges results
into the model picker. Image-only models (e.g. Sourceful, Seedream, Flux
via this endpoint) were previously invisible since they don't appear in the
standard /models endpoint.
Models from the images API get usesImagesAPI=true and route through a new
generateImageAPIResponse() path in ChatViewModel that POSTs to /api/v1/images
with {model, prompt} instead of the chat completions endpoint. The response's
b64_json data is decoded and displayed via the existing GeneratedImagesView.
Cost is taken directly from the usage.cost field in the images API response
(USD per image) via a new rawCostUSD field on ChatResponse.Usage, bypassing
the token-based calculateCost() path used for chat models.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -132,15 +132,19 @@ struct ChatResponse: Codable {
|
||||
let totalTokens: Int
|
||||
let cacheCreationInputTokens: Int?
|
||||
let cacheReadInputTokens: Int?
|
||||
/// Direct USD cost returned by the images API (bypasses token-based calculation).
|
||||
let rawCostUSD: Double?
|
||||
|
||||
init(promptTokens: Int, completionTokens: Int, totalTokens: Int, cacheCreationInputTokens: Int? = nil, cacheReadInputTokens: Int? = nil) {
|
||||
init(promptTokens: Int, completionTokens: Int, totalTokens: Int, cacheCreationInputTokens: Int? = nil, cacheReadInputTokens: Int? = nil, rawCostUSD: Double? = nil) {
|
||||
self.promptTokens = promptTokens
|
||||
self.completionTokens = completionTokens
|
||||
self.totalTokens = totalTokens
|
||||
self.cacheCreationInputTokens = cacheCreationInputTokens
|
||||
self.cacheReadInputTokens = cacheReadInputTokens
|
||||
self.rawCostUSD = rawCostUSD
|
||||
}
|
||||
|
||||
// rawCostUSD is set programmatically, never decoded from API responses
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case promptTokens = "prompt_tokens"
|
||||
case completionTokens = "completion_tokens"
|
||||
@@ -148,6 +152,16 @@ struct ChatResponse: Codable {
|
||||
case cacheCreationInputTokens = "cache_creation_input_tokens"
|
||||
case cacheReadInputTokens = "cache_read_input_tokens"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
promptTokens = try c.decode(Int.self, forKey: .promptTokens)
|
||||
completionTokens = try c.decode(Int.self, forKey: .completionTokens)
|
||||
totalTokens = try c.decode(Int.self, forKey: .totalTokens)
|
||||
cacheCreationInputTokens = try c.decodeIfPresent(Int.self, forKey: .cacheCreationInputTokens)
|
||||
cacheReadInputTokens = try c.decodeIfPresent(Int.self, forKey: .cacheReadInputTokens)
|
||||
rawCostUSD = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Codable since ToolCallInfo/generatedImages are not from API directly
|
||||
|
||||
Reference in New Issue
Block a user