mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
feat: add Gemini provider support for image generation
- Create centralized image generation models configuration in types package - Implement generateImage() method in Gemini provider for text-to-image and image-to-image - Add provider dropdown in UI settings to switch between OpenRouter and Gemini - Update generateImageTool to route requests to appropriate provider - Add settings persistence for Gemini API key and model selection - Translate all new UI strings across 18 supported languages - Fix settings state management to properly handle new image generation settings
This commit is contained in:
parent
a8f87d2b1d
commit
68a7c8390b
30 changed files with 653 additions and 89 deletions
|
|
@ -44,8 +44,11 @@ export const globalSettingsSchema = z.object({
|
|||
dismissedUpsells: z.array(z.string()).optional(),
|
||||
|
||||
// Image generation settings (experimental) - flattened for simplicity
|
||||
imageGenerationProvider: z.enum(["openrouter", "gemini"]).optional(),
|
||||
openRouterImageApiKey: z.string().optional(),
|
||||
openRouterImageGenerationSelectedModel: z.string().optional(),
|
||||
geminiImageApiKey: z.string().optional(),
|
||||
geminiImageGenerationSelectedModel: z.string().optional(),
|
||||
|
||||
condensingApiConfigId: z.string().optional(),
|
||||
customCondensingPrompt: z.string().optional(),
|
||||
|
|
@ -210,7 +213,8 @@ export const SECRET_STATE_KEYS = [
|
|||
|
||||
// Global secrets that are part of GlobalSettings (not ProviderSettings)
|
||||
export const GLOBAL_SECRET_KEYS = [
|
||||
"openRouterImageApiKey", // For image generation
|
||||
"openRouterImageApiKey", // For OpenRouter image generation
|
||||
"geminiImageApiKey", // For Gemini image generation
|
||||
] as const
|
||||
|
||||
// Type for the actual secret storage keys
|
||||
|
|
|
|||
75
packages/types/src/image-generation.ts
Normal file
75
packages/types/src/image-generation.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { z } from "zod"
|
||||
|
||||
/**
|
||||
* Image Generation Provider
|
||||
*/
|
||||
export const imageGenerationProviders = ["openrouter", "gemini"] as const
|
||||
export const imageGenerationProviderSchema = z.enum(imageGenerationProviders)
|
||||
export type ImageGenerationProvider = z.infer<typeof imageGenerationProviderSchema>
|
||||
|
||||
/**
|
||||
* Image Generation Model Info
|
||||
*/
|
||||
export interface ImageGenerationModelInfo {
|
||||
provider: ImageGenerationProvider
|
||||
modelId: string
|
||||
label: string
|
||||
supportsEditMode?: boolean // Whether the model supports image editing (text + image input)
|
||||
maxInputSize?: number // Maximum input image size in MB
|
||||
outputFormats?: string[] // Supported output formats
|
||||
}
|
||||
|
||||
/**
|
||||
* Image Generation Models by Provider
|
||||
*/
|
||||
export const IMAGE_GENERATION_MODELS: Record<ImageGenerationProvider, ImageGenerationModelInfo[]> = {
|
||||
openrouter: [
|
||||
{
|
||||
provider: "openrouter",
|
||||
modelId: "google/gemini-2.5-flash-image-preview",
|
||||
label: "Gemini 2.5 Flash Image Preview",
|
||||
supportsEditMode: true,
|
||||
outputFormats: ["png", "jpeg"],
|
||||
},
|
||||
{
|
||||
provider: "openrouter",
|
||||
modelId: "google/gemini-2.5-flash-image-preview:free",
|
||||
label: "Gemini 2.5 Flash Image Preview (Free)",
|
||||
supportsEditMode: true,
|
||||
outputFormats: ["png", "jpeg"],
|
||||
},
|
||||
],
|
||||
gemini: [
|
||||
{
|
||||
provider: "gemini",
|
||||
modelId: "gemini-2.5-flash-image-preview",
|
||||
label: "Gemini 2.5 Flash Image Preview",
|
||||
supportsEditMode: true,
|
||||
outputFormats: ["png", "jpeg"],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all models for a specific provider
|
||||
*/
|
||||
export function getImageGenerationModelsForProvider(provider: ImageGenerationProvider): ImageGenerationModelInfo[] {
|
||||
return IMAGE_GENERATION_MODELS[provider] || []
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get all available image generation models
|
||||
*/
|
||||
export function getAllImageGenerationModels(): ImageGenerationModelInfo[] {
|
||||
return Object.values(IMAGE_GENERATION_MODELS).flat()
|
||||
}
|
||||
|
||||
/**
|
||||
* Image Generation Result
|
||||
*/
|
||||
export interface ImageGenerationResult {
|
||||
success: boolean
|
||||
imageData?: string // Base64 encoded image data URL
|
||||
imageFormat?: string // Format of the generated image (png, jpeg, etc.)
|
||||
error?: string
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ export * from "./experiment.js"
|
|||
export * from "./followup.js"
|
||||
export * from "./global-settings.js"
|
||||
export * from "./history.js"
|
||||
export * from "./image-generation.js"
|
||||
export * from "./ipc.js"
|
||||
export * from "./marketplace.js"
|
||||
export * from "./mcp.js"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,13 @@ import {
|
|||
} from "@google/genai"
|
||||
import type { JWTInput } from "google-auth-library"
|
||||
|
||||
import { type ModelInfo, type GeminiModelId, geminiDefaultModelId, geminiModels } from "@roo-code/types"
|
||||
import {
|
||||
type ModelInfo,
|
||||
type GeminiModelId,
|
||||
geminiDefaultModelId,
|
||||
geminiModels,
|
||||
type ImageGenerationResult,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ApiHandlerOptions } from "../../shared/api"
|
||||
import { safeJsonParse } from "../../shared/safeJsonParse"
|
||||
|
|
@ -335,4 +341,139 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
|
||||
return totalCost
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an image using Gemini's image generation API
|
||||
* @param prompt The text prompt for image generation
|
||||
* @param model The model to use for generation
|
||||
* @param apiKey The Gemini API key (if not using vertex)
|
||||
* @param inputImage Optional base64 encoded input image data URL for editing
|
||||
* @returns The generated image data and format, or an error
|
||||
*/
|
||||
async generateImage(
|
||||
prompt: string,
|
||||
model: string,
|
||||
apiKey?: string,
|
||||
inputImage?: string,
|
||||
): Promise<ImageGenerationResult> {
|
||||
try {
|
||||
// Create a temporary client with the provided API key if needed
|
||||
let client: GoogleGenAI
|
||||
if (apiKey && !this.options.vertexProjectId) {
|
||||
// Use provided API key for standard Gemini
|
||||
client = new GoogleGenAI({ apiKey })
|
||||
} else {
|
||||
// Use existing client (either vertex or standard with already configured key)
|
||||
client = this.client
|
||||
}
|
||||
|
||||
// Prepare the content for generation
|
||||
const contents: any[] = []
|
||||
|
||||
if (inputImage) {
|
||||
// For image editing mode, include both text and image
|
||||
const base64Match = inputImage.match(/^data:image\/(png|jpeg|jpg);base64,(.+)$/)
|
||||
if (!base64Match) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Invalid input image format. Expected base64 data URL.",
|
||||
}
|
||||
}
|
||||
|
||||
const mimeType = base64Match[1] === "jpg" ? "image/jpeg" : `image/${base64Match[1]}`
|
||||
const base64Data = base64Match[2]
|
||||
|
||||
contents.push({
|
||||
role: "user",
|
||||
parts: [
|
||||
{ text: prompt },
|
||||
{
|
||||
inlineData: {
|
||||
mimeType,
|
||||
data: base64Data,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
} else {
|
||||
// For text-to-image mode
|
||||
contents.push({
|
||||
role: "user",
|
||||
parts: [{ text: prompt }],
|
||||
})
|
||||
}
|
||||
|
||||
const config: GenerateContentConfig = {
|
||||
httpOptions: this.options.googleGeminiBaseUrl
|
||||
? { baseUrl: this.options.googleGeminiBaseUrl }
|
||||
: undefined,
|
||||
temperature: 1.0, // Higher temperature for more creative image generation
|
||||
}
|
||||
|
||||
const params: GenerateContentParameters = {
|
||||
model,
|
||||
contents,
|
||||
config,
|
||||
}
|
||||
|
||||
const result = await client.models.generateContent(params)
|
||||
|
||||
// Extract the generated image from the response
|
||||
if (!result.candidates || result.candidates.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
error: "No candidates returned in the response",
|
||||
}
|
||||
}
|
||||
|
||||
const candidate = result.candidates[0]
|
||||
if (!candidate.content || !candidate.content.parts) {
|
||||
return {
|
||||
success: false,
|
||||
error: "No content parts in the response",
|
||||
}
|
||||
}
|
||||
|
||||
// Find the image part in the response
|
||||
let imageData: string | undefined
|
||||
let imageFormat = "png" // Default format
|
||||
|
||||
for (const part of candidate.content.parts) {
|
||||
if (part.inlineData) {
|
||||
const mimeType = part.inlineData.mimeType
|
||||
const data = part.inlineData.data
|
||||
|
||||
if (mimeType?.startsWith("image/")) {
|
||||
// Extract format from mime type
|
||||
imageFormat = mimeType.replace("image/", "").replace("jpeg", "jpg")
|
||||
|
||||
// Convert to data URL format
|
||||
imageData = `data:${mimeType};base64,${data}`
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageData) {
|
||||
return {
|
||||
success: false,
|
||||
error: "No image data found in the response",
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
imageData,
|
||||
imageFormat,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"
|
||||
console.error("Gemini image generation error:", errorMessage)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: `Failed to generate image: ${errorMessage}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,8 @@ import { getReadablePath } from "../../utils/path"
|
|||
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
import { OpenRouterHandler } from "../../api/providers/openrouter"
|
||||
|
||||
// Hardcoded list of image generation models for now
|
||||
const IMAGE_GENERATION_MODELS = ["google/gemini-2.5-flash-image", "openai/gpt-5-image", "openai/gpt-5-image-mini"]
|
||||
import { GeminiHandler } from "../../api/providers/gemini"
|
||||
import { ImageGenerationProvider, getImageGenerationModelsForProvider } from "@roo-code/types"
|
||||
|
||||
export async function generateImageTool(
|
||||
cline: Task,
|
||||
|
|
@ -128,25 +127,60 @@ export async function generateImageTool(
|
|||
// Check if file is write-protected
|
||||
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false
|
||||
|
||||
// Get OpenRouter API key from global settings (experimental image generation)
|
||||
const openRouterApiKey = state?.openRouterImageApiKey
|
||||
// Get the selected provider from settings (default to openrouter)
|
||||
const selectedProvider = (state?.imageGenerationProvider || "openrouter") as ImageGenerationProvider
|
||||
|
||||
if (!openRouterApiKey) {
|
||||
await cline.say(
|
||||
"error",
|
||||
"OpenRouter API key is required for image generation. Please configure it in the Image Generation experimental settings.",
|
||||
)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
// Get selected model from settings based on provider
|
||||
let selectedModel: string
|
||||
let apiKey: string | undefined
|
||||
|
||||
if (selectedProvider === "openrouter") {
|
||||
apiKey = state?.openRouterImageApiKey
|
||||
if (!apiKey) {
|
||||
await cline.say(
|
||||
"error",
|
||||
"OpenRouter API key is required for image generation. Please configure it in the Image Generation experimental settings.",
|
||||
),
|
||||
)
|
||||
)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
"OpenRouter API key is required for image generation. Please configure it in the Image Generation experimental settings.",
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
// Get selected model or use default for OpenRouter
|
||||
const models = getImageGenerationModelsForProvider("openrouter")
|
||||
selectedModel =
|
||||
state?.openRouterImageGenerationSelectedModel ||
|
||||
(models[0]?.modelId ?? "google/gemini-2.5-flash-image-preview")
|
||||
} else if (selectedProvider === "gemini") {
|
||||
// For Gemini, we can use the existing Gemini API key from the provider settings
|
||||
// Check for a dedicated image generation API key first, then fall back to the provider's API key
|
||||
apiKey =
|
||||
state?.geminiImageApiKey ||
|
||||
(state?.apiConfiguration?.apiProvider === "gemini" ? state?.apiConfiguration?.geminiApiKey : undefined)
|
||||
if (!apiKey) {
|
||||
await cline.say(
|
||||
"error",
|
||||
"Gemini API key is required for image generation. Please configure it in the Image Generation experimental settings or in the Gemini provider settings.",
|
||||
)
|
||||
pushToolResult(
|
||||
formatResponse.toolError(
|
||||
"Gemini API key is required for image generation. Please configure it in the Image Generation experimental settings or in the Gemini provider settings.",
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
// Get selected model or use default for Gemini
|
||||
const models = getImageGenerationModelsForProvider("gemini")
|
||||
selectedModel =
|
||||
state?.geminiImageGenerationSelectedModel || (models[0]?.modelId ?? "gemini-2.5-flash-image-preview")
|
||||
} else {
|
||||
await cline.say("error", `Unsupported image generation provider: ${selectedProvider}`)
|
||||
pushToolResult(formatResponse.toolError(`Unsupported image generation provider: ${selectedProvider}`))
|
||||
return
|
||||
}
|
||||
|
||||
// Get selected model from settings or use default
|
||||
const selectedModel = state?.openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODELS[0]
|
||||
|
||||
// Determine if the path is outside the workspace
|
||||
const fullPath = path.resolve(cline.cwd, removeClosingTag("path", relPath))
|
||||
const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
|
||||
|
|
@ -176,16 +210,28 @@ export async function generateImageTool(
|
|||
return
|
||||
}
|
||||
|
||||
// Create a temporary OpenRouter handler with minimal options
|
||||
const openRouterHandler = new OpenRouterHandler({} as any)
|
||||
// Generate image based on provider
|
||||
let result
|
||||
|
||||
// Call the generateImage method with the explicit API key and optional input image
|
||||
const result = await openRouterHandler.generateImage(
|
||||
prompt,
|
||||
selectedModel,
|
||||
openRouterApiKey,
|
||||
inputImageData,
|
||||
)
|
||||
if (selectedProvider === "openrouter") {
|
||||
// Create a temporary OpenRouter handler with minimal options
|
||||
const openRouterHandler = new OpenRouterHandler({} as any)
|
||||
|
||||
// Call the generateImage method with the explicit API key and optional input image
|
||||
result = await openRouterHandler.generateImage(prompt, selectedModel, apiKey!, inputImageData)
|
||||
} else if (selectedProvider === "gemini") {
|
||||
// Create a temporary Gemini handler with minimal options
|
||||
const geminiHandler = new GeminiHandler({ geminiApiKey: apiKey } as any)
|
||||
|
||||
// Call the generateImage method with the optional input image
|
||||
result = await geminiHandler.generateImage(prompt, selectedModel, apiKey, inputImageData)
|
||||
} else {
|
||||
// This should not happen due to earlier check, but for type safety
|
||||
result = {
|
||||
success: false,
|
||||
error: `Unsupported provider: ${selectedProvider}`,
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.success) {
|
||||
await cline.say("error", result.error || "Failed to generate image")
|
||||
|
|
|
|||
|
|
@ -1811,8 +1811,11 @@ export class ClineProvider
|
|||
includeTaskHistoryInEnhance,
|
||||
taskSyncEnabled,
|
||||
remoteControlEnabled,
|
||||
imageGenerationProvider,
|
||||
openRouterImageApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
geminiImageApiKey,
|
||||
geminiImageGenerationSelectedModel,
|
||||
openRouterUseMiddleOutTransform,
|
||||
featureRoomoteControlEnabled,
|
||||
} = await this.getState()
|
||||
|
|
@ -1960,8 +1963,11 @@ export class ClineProvider
|
|||
includeTaskHistoryInEnhance: includeTaskHistoryInEnhance ?? true,
|
||||
taskSyncEnabled,
|
||||
remoteControlEnabled,
|
||||
imageGenerationProvider,
|
||||
openRouterImageApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
geminiImageApiKey,
|
||||
geminiImageGenerationSelectedModel,
|
||||
openRouterUseMiddleOutTransform,
|
||||
featureRoomoteControlEnabled,
|
||||
}
|
||||
|
|
@ -2181,8 +2187,11 @@ export class ClineProvider
|
|||
return false
|
||||
}
|
||||
})(),
|
||||
imageGenerationProvider: stateValues.imageGenerationProvider,
|
||||
openRouterImageApiKey: stateValues.openRouterImageApiKey,
|
||||
openRouterImageGenerationSelectedModel: stateValues.openRouterImageGenerationSelectedModel,
|
||||
geminiImageApiKey: stateValues.geminiImageApiKey,
|
||||
geminiImageGenerationSelectedModel: stateValues.geminiImageGenerationSelectedModel,
|
||||
featureRoomoteControlEnabled: (() => {
|
||||
try {
|
||||
const userSettings = CloudService.instance.getUserSettings()
|
||||
|
|
|
|||
|
|
@ -1578,6 +1578,21 @@ export const webviewMessageHandler = async (
|
|||
await provider.contextProxy.setValue("openRouterImageGenerationSelectedModel", message.text)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "imageGenerationProvider":
|
||||
await provider.contextProxy.setValue(
|
||||
"imageGenerationProvider",
|
||||
message.text as "openrouter" | "gemini" | undefined,
|
||||
)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "geminiImageApiKey":
|
||||
await provider.contextProxy.setValue("geminiImageApiKey", message.text)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "geminiImageGenerationSelectedModel":
|
||||
await provider.contextProxy.setValue("geminiImageGenerationSelectedModel", message.text)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "showRooIgnoredFiles":
|
||||
await updateGlobalState("showRooIgnoredFiles", message.bool ?? false)
|
||||
await provider.postStateToWebview()
|
||||
|
|
|
|||
|
|
@ -343,6 +343,9 @@ export type ExtensionState = Pick<
|
|||
profileThresholds: Record<string, number>
|
||||
hasOpenedModeSelector: boolean
|
||||
openRouterImageApiKey?: string
|
||||
imageGenerationProvider?: "openrouter" | "gemini"
|
||||
geminiImageApiKey?: string
|
||||
geminiImageGenerationSelectedModel?: string
|
||||
openRouterUseMiddleOutTransform?: boolean
|
||||
messageQueue?: QueuedMessage[]
|
||||
lastShownAnnouncementId?: string
|
||||
|
|
|
|||
|
|
@ -224,6 +224,9 @@ export interface WebviewMessage {
|
|||
| "imageGenerationSettings"
|
||||
| "openRouterImageApiKey"
|
||||
| "openRouterImageGenerationSelectedModel"
|
||||
| "imageGenerationProvider"
|
||||
| "geminiImageApiKey"
|
||||
| "geminiImageGenerationSelectedModel"
|
||||
| "queueMessage"
|
||||
| "removeQueuedMessage"
|
||||
| "editQueuedMessage"
|
||||
|
|
|
|||
|
|
@ -21,8 +21,13 @@ type ExperimentalSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
setApiConfigurationField?: any
|
||||
openRouterImageApiKey?: string
|
||||
openRouterImageGenerationSelectedModel?: string
|
||||
imageGenerationProvider?: string
|
||||
geminiImageApiKey?: string
|
||||
geminiImageGenerationSelectedModel?: string
|
||||
setOpenRouterImageApiKey?: (apiKey: string) => void
|
||||
setImageGenerationSelectedModel?: (model: string) => void
|
||||
setImageGenerationProvider?: (provider: "gemini" | "openrouter" | undefined) => void
|
||||
setGeminiImageApiKey?: (apiKey: string) => void
|
||||
}
|
||||
|
||||
export const ExperimentalSettings = ({
|
||||
|
|
@ -32,8 +37,13 @@ export const ExperimentalSettings = ({
|
|||
setApiConfigurationField,
|
||||
openRouterImageApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
imageGenerationProvider,
|
||||
geminiImageApiKey,
|
||||
geminiImageGenerationSelectedModel,
|
||||
setOpenRouterImageApiKey,
|
||||
setImageGenerationSelectedModel,
|
||||
setImageGenerationProvider,
|
||||
setGeminiImageApiKey,
|
||||
className,
|
||||
...props
|
||||
}: ExperimentalSettingsProps) => {
|
||||
|
|
@ -78,8 +88,13 @@ export const ExperimentalSettings = ({
|
|||
}
|
||||
openRouterImageApiKey={openRouterImageApiKey}
|
||||
openRouterImageGenerationSelectedModel={openRouterImageGenerationSelectedModel}
|
||||
imageGenerationProvider={imageGenerationProvider as any}
|
||||
geminiApiKey={geminiImageApiKey}
|
||||
geminiImageGenerationSelectedModel={geminiImageGenerationSelectedModel}
|
||||
setOpenRouterImageApiKey={setOpenRouterImageApiKey}
|
||||
setImageGenerationSelectedModel={setImageGenerationSelectedModel}
|
||||
setImageGenerationProvider={setImageGenerationProvider}
|
||||
setGeminiApiKey={setGeminiImageApiKey}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,118 @@
|
|||
import React, { useState, useEffect } from "react"
|
||||
import { VSCodeCheckbox, VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { getImageGenerationModelsForProvider, type ImageGenerationProvider } from "@roo-code/types"
|
||||
|
||||
interface ImageGenerationSettingsProps {
|
||||
enabled: boolean
|
||||
onChange: (enabled: boolean) => void
|
||||
openRouterImageApiKey?: string
|
||||
geminiApiKey?: string
|
||||
openRouterImageGenerationSelectedModel?: string
|
||||
geminiImageGenerationSelectedModel?: string
|
||||
imageGenerationProvider?: ImageGenerationProvider
|
||||
setOpenRouterImageApiKey: (apiKey: string) => void
|
||||
setGeminiApiKey?: (apiKey: string) => void
|
||||
setImageGenerationSelectedModel: (model: string) => void
|
||||
setImageGenerationProvider?: (provider: ImageGenerationProvider | undefined) => void
|
||||
}
|
||||
|
||||
// Hardcoded list of image generation models
|
||||
const IMAGE_GENERATION_MODELS = [
|
||||
{ value: "google/gemini-2.5-flash-image", label: "Gemini 2.5 Flash Image" },
|
||||
{ value: "openai/gpt-5-image", label: "GPT-5 Image" },
|
||||
{ value: "openai/gpt-5-image-mini", label: "GPT-5 Image Mini" },
|
||||
// Add more models as they become available
|
||||
]
|
||||
|
||||
export const ImageGenerationSettings = ({
|
||||
enabled,
|
||||
onChange,
|
||||
openRouterImageApiKey,
|
||||
geminiApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
geminiImageGenerationSelectedModel,
|
||||
imageGenerationProvider = "openrouter",
|
||||
setOpenRouterImageApiKey,
|
||||
setGeminiApiKey,
|
||||
setImageGenerationSelectedModel,
|
||||
setImageGenerationProvider,
|
||||
}: ImageGenerationSettingsProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const [apiKey, setApiKey] = useState(openRouterImageApiKey || "")
|
||||
const [selectedModel, setSelectedModel] = useState(
|
||||
openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODELS[0].value,
|
||||
)
|
||||
const [provider, setProvider] = useState<ImageGenerationProvider>(imageGenerationProvider)
|
||||
const [openRouterApiKeyLocal, setOpenRouterApiKeyLocal] = useState(openRouterImageApiKey || "")
|
||||
const [geminiApiKeyLocal, setGeminiApiKeyLocal] = useState(geminiApiKey || "")
|
||||
|
||||
// Get models for current provider
|
||||
const availableModels = getImageGenerationModelsForProvider(provider)
|
||||
|
||||
// Get default model for provider
|
||||
const getDefaultModel = (provider: ImageGenerationProvider) => {
|
||||
const models = getImageGenerationModelsForProvider(provider)
|
||||
return models.length > 0 ? models[0].modelId : ""
|
||||
}
|
||||
|
||||
// Get current selected model based on provider
|
||||
const getCurrentSelectedModel = () => {
|
||||
if (provider === "openrouter") {
|
||||
return openRouterImageGenerationSelectedModel || getDefaultModel("openrouter")
|
||||
} else {
|
||||
return geminiImageGenerationSelectedModel || getDefaultModel("gemini")
|
||||
}
|
||||
}
|
||||
|
||||
const [selectedModel, setSelectedModel] = useState(getCurrentSelectedModel())
|
||||
|
||||
// Update local state when props change (e.g., when switching profiles)
|
||||
useEffect(() => {
|
||||
setApiKey(openRouterImageApiKey || "")
|
||||
setSelectedModel(openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODELS[0].value)
|
||||
}, [openRouterImageApiKey, openRouterImageGenerationSelectedModel])
|
||||
setOpenRouterApiKeyLocal(openRouterImageApiKey || "")
|
||||
setGeminiApiKeyLocal(geminiApiKey || "")
|
||||
setProvider(imageGenerationProvider || "openrouter")
|
||||
// Calculate selected model directly in the effect
|
||||
const newSelectedModel =
|
||||
provider === "openrouter"
|
||||
? openRouterImageGenerationSelectedModel || getDefaultModel("openrouter")
|
||||
: geminiImageGenerationSelectedModel || getDefaultModel("gemini")
|
||||
setSelectedModel(newSelectedModel)
|
||||
}, [
|
||||
openRouterImageApiKey,
|
||||
geminiApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
geminiImageGenerationSelectedModel,
|
||||
imageGenerationProvider,
|
||||
provider,
|
||||
])
|
||||
|
||||
// Handle provider change
|
||||
const handleProviderChange = (value: ImageGenerationProvider) => {
|
||||
setProvider(value)
|
||||
if (setImageGenerationProvider) {
|
||||
setImageGenerationProvider(value as ImageGenerationProvider | undefined)
|
||||
}
|
||||
|
||||
// Set default model for new provider
|
||||
const defaultModel = getDefaultModel(value)
|
||||
setSelectedModel(defaultModel)
|
||||
setImageGenerationSelectedModel(defaultModel)
|
||||
}
|
||||
|
||||
// Handle API key changes
|
||||
const handleApiKeyChange = (value: string) => {
|
||||
setApiKey(value)
|
||||
const handleOpenRouterApiKeyChange = (value: string) => {
|
||||
setOpenRouterApiKeyLocal(value)
|
||||
setOpenRouterImageApiKey(value)
|
||||
}
|
||||
|
||||
const handleGeminiApiKeyChange = (value: string) => {
|
||||
setGeminiApiKeyLocal(value)
|
||||
if (setGeminiApiKey) {
|
||||
setGeminiApiKey(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle model selection changes
|
||||
const handleModelChange = (value: string) => {
|
||||
setSelectedModel(value)
|
||||
setImageGenerationSelectedModel(value)
|
||||
}
|
||||
|
||||
// Get current API key based on provider
|
||||
const getCurrentApiKey = () => {
|
||||
return provider === "openrouter" ? openRouterApiKeyLocal : geminiApiKeyLocal
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
|
|
@ -67,30 +128,78 @@ export const ImageGenerationSettings = ({
|
|||
|
||||
{enabled && (
|
||||
<div className="ml-2 space-y-3">
|
||||
{/* API Key Configuration */}
|
||||
{/* Provider Selection */}
|
||||
<div>
|
||||
<label className="block font-medium mb-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.openRouterApiKeyLabel")}
|
||||
{t("settings:experimental.IMAGE_GENERATION.providerLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={apiKey}
|
||||
onInput={(e: any) => handleApiKeyChange(e.target.value)}
|
||||
placeholder={t("settings:experimental.IMAGE_GENERATION.openRouterApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
type="password"
|
||||
/>
|
||||
<VSCodeDropdown
|
||||
value={provider}
|
||||
onChange={(e: any) => handleProviderChange(e.target.value as ImageGenerationProvider)}
|
||||
className="w-full">
|
||||
<VSCodeOption value="openrouter" className="py-2 px-3">
|
||||
OpenRouter
|
||||
</VSCodeOption>
|
||||
<VSCodeOption value="gemini" className="py-2 px-3">
|
||||
Gemini
|
||||
</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
<p className="text-vscode-descriptionForeground text-xs mt-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.getApiKeyText")}{" "}
|
||||
<a
|
||||
href="https://openrouter.ai/keys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground">
|
||||
openrouter.ai/keys
|
||||
</a>
|
||||
{t("settings:experimental.IMAGE_GENERATION.providerDescription")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* API Key Configuration based on provider */}
|
||||
{provider === "openrouter" && (
|
||||
<div>
|
||||
<label className="block font-medium mb-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.openRouterApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={openRouterApiKeyLocal}
|
||||
onInput={(e: any) => handleOpenRouterApiKeyChange(e.target.value)}
|
||||
placeholder={t("settings:experimental.IMAGE_GENERATION.openRouterApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
type="password"
|
||||
/>
|
||||
<p className="text-vscode-descriptionForeground text-xs mt-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.getApiKeyText")}{" "}
|
||||
<a
|
||||
href="https://openrouter.ai/keys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground">
|
||||
openrouter.ai/keys
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{provider === "gemini" && (
|
||||
<div>
|
||||
<label className="block font-medium mb-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.geminiApiKeyLabel")}
|
||||
</label>
|
||||
<VSCodeTextField
|
||||
value={geminiApiKeyLocal}
|
||||
onInput={(e: any) => handleGeminiApiKeyChange(e.target.value)}
|
||||
placeholder={t("settings:experimental.IMAGE_GENERATION.geminiApiKeyPlaceholder")}
|
||||
className="w-full"
|
||||
type="password"
|
||||
/>
|
||||
<p className="text-vscode-descriptionForeground text-xs mt-1">
|
||||
{t("settings:experimental.IMAGE_GENERATION.geminiGetApiKeyText")}{" "}
|
||||
<a
|
||||
href="https://aistudio.google.com/app/apikey"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground">
|
||||
Google AI Studio
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Model Selection */}
|
||||
<div>
|
||||
<label className="block font-medium mb-1">
|
||||
|
|
@ -100,8 +209,8 @@ export const ImageGenerationSettings = ({
|
|||
value={selectedModel}
|
||||
onChange={(e: any) => handleModelChange(e.target.value)}
|
||||
className="w-full">
|
||||
{IMAGE_GENERATION_MODELS.map((model) => (
|
||||
<VSCodeOption key={model.value} value={model.value} className="py-2 px-3">
|
||||
{availableModels.map((model) => (
|
||||
<VSCodeOption key={model.modelId} value={model.modelId} className="py-2 px-3">
|
||||
{model.label}
|
||||
</VSCodeOption>
|
||||
))}
|
||||
|
|
@ -112,13 +221,15 @@ export const ImageGenerationSettings = ({
|
|||
</div>
|
||||
|
||||
{/* Status Message */}
|
||||
{enabled && !apiKey && (
|
||||
{enabled && !getCurrentApiKey() && (
|
||||
<div className="p-2 bg-vscode-editorWarning-background text-vscode-editorWarning-foreground rounded text-sm">
|
||||
{t("settings:experimental.IMAGE_GENERATION.warningMissingKey")}
|
||||
{provider === "openrouter"
|
||||
? t("settings:experimental.IMAGE_GENERATION.warningMissingKey")
|
||||
: t("settings:experimental.IMAGE_GENERATION.warningMissingGeminiKey")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{enabled && apiKey && (
|
||||
{enabled && getCurrentApiKey() && (
|
||||
<div className="p-2 bg-vscode-editorInfo-background text-vscode-editorInfo-foreground rounded text-sm">
|
||||
{t("settings:experimental.IMAGE_GENERATION.successConfigured")}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -195,6 +195,9 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
openRouterImageApiKey,
|
||||
openRouterImageGenerationSelectedModel,
|
||||
reasoningBlockCollapsed,
|
||||
imageGenerationProvider,
|
||||
geminiImageApiKey,
|
||||
geminiImageGenerationSelectedModel,
|
||||
} = cachedState
|
||||
|
||||
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
|
||||
|
|
@ -292,11 +295,28 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
|
||||
const setImageGenerationSelectedModel = useCallback((model: string) => {
|
||||
setCachedState((prevState) => {
|
||||
// Only set change detected if value actually changed
|
||||
if (prevState.openRouterImageGenerationSelectedModel !== model) {
|
||||
setChangeDetected(true)
|
||||
setChangeDetected(true)
|
||||
// Update the appropriate model field based on the current provider
|
||||
const provider = prevState.imageGenerationProvider || "openrouter"
|
||||
if (provider === "openrouter") {
|
||||
return { ...prevState, openRouterImageGenerationSelectedModel: model }
|
||||
} else {
|
||||
return { ...prevState, geminiImageGenerationSelectedModel: model }
|
||||
}
|
||||
return { ...prevState, openRouterImageGenerationSelectedModel: model }
|
||||
})
|
||||
}, [])
|
||||
|
||||
const setImageGenerationProvider = useCallback((provider: "gemini" | "openrouter" | undefined) => {
|
||||
setCachedState((prevState) => {
|
||||
setChangeDetected(true)
|
||||
return { ...prevState, imageGenerationProvider: provider }
|
||||
})
|
||||
}, [])
|
||||
|
||||
const setGeminiImageApiKey = useCallback((apiKey: string) => {
|
||||
setCachedState((prevState) => {
|
||||
setChangeDetected(true)
|
||||
return { ...prevState, geminiImageApiKey: apiKey }
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
|
@ -392,6 +412,12 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
type: "openRouterImageGenerationSelectedModel",
|
||||
text: openRouterImageGenerationSelectedModel,
|
||||
})
|
||||
vscode.postMessage({ type: "imageGenerationProvider", text: imageGenerationProvider })
|
||||
vscode.postMessage({ type: "geminiImageApiKey", text: geminiImageApiKey })
|
||||
vscode.postMessage({
|
||||
type: "geminiImageGenerationSelectedModel",
|
||||
text: geminiImageGenerationSelectedModel,
|
||||
})
|
||||
setChangeDetected(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -797,8 +823,15 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
openRouterImageGenerationSelectedModel={
|
||||
openRouterImageGenerationSelectedModel as string | undefined
|
||||
}
|
||||
imageGenerationProvider={imageGenerationProvider as string | undefined}
|
||||
geminiImageApiKey={geminiImageApiKey as string | undefined}
|
||||
geminiImageGenerationSelectedModel={
|
||||
geminiImageGenerationSelectedModel as string | undefined
|
||||
}
|
||||
setOpenRouterImageApiKey={setOpenRouterImageApiKey}
|
||||
setImageGenerationSelectedModel={setImageGenerationSelectedModel}
|
||||
setImageGenerationProvider={setImageGenerationProvider}
|
||||
setGeminiImageApiKey={setGeminiImageApiKey}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/ca/settings.json
generated
8
webview-ui/src/i18n/locales/ca/settings.json
generated
|
|
@ -749,7 +749,13 @@
|
|||
"modelSelectionLabel": "Model de generació d'imatges",
|
||||
"modelSelectionDescription": "Selecciona el model per a la generació d'imatges",
|
||||
"warningMissingKey": "⚠️ La clau API d'OpenRouter és necessària per a la generació d'imatges. Si us plau, configura-la a dalt.",
|
||||
"successConfigured": "✓ La generació d'imatges està configurada i llesta per utilitzar"
|
||||
"successConfigured": "✓ La generació d'imatges està configurada i llesta per utilitzar",
|
||||
"providerLabel": "Proveïdor de generació d'imatges",
|
||||
"providerDescription": "Tria el proveïdor per a la generació d'imatges",
|
||||
"geminiApiKeyLabel": "Clau API de Gemini",
|
||||
"geminiApiKeyPlaceholder": "Introdueix la teva clau API de Gemini",
|
||||
"geminiGetApiKeyText": "Obté la teva clau API de",
|
||||
"warningMissingGeminiKey": "⚠️ La clau API de Gemini és necessària per a la generació d'imatges. Si us plau, configura-la a dalt."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Habilitar comandes de barra diagonal iniciades pel model",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/de/settings.json
generated
8
webview-ui/src/i18n/locales/de/settings.json
generated
|
|
@ -749,7 +749,13 @@
|
|||
"modelSelectionLabel": "Bildgenerierungsmodell",
|
||||
"modelSelectionDescription": "Wähle das Modell für die Bildgenerierung aus",
|
||||
"warningMissingKey": "⚠️ OpenRouter API-Schlüssel ist für Bildgenerierung erforderlich. Bitte konfiguriere ihn oben.",
|
||||
"successConfigured": "✓ Bildgenerierung ist konfiguriert und einsatzbereit"
|
||||
"successConfigured": "✓ Bildgenerierung ist konfiguriert und einsatzbereit",
|
||||
"providerLabel": "Bildgenerierungs-Anbieter",
|
||||
"providerDescription": "Wähle den Anbieter für die Bildgenerierung",
|
||||
"geminiApiKeyLabel": "Gemini API-Schlüssel",
|
||||
"geminiApiKeyPlaceholder": "Gib deinen Gemini API-Schlüssel ein",
|
||||
"geminiGetApiKeyText": "Hol dir deinen API-Schlüssel von",
|
||||
"warningMissingGeminiKey": "⚠️ Gemini API-Schlüssel ist für Bildgenerierung erforderlich. Bitte konfiguriere ihn oben."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Modellinitierte Slash-Befehle aktivieren",
|
||||
|
|
|
|||
|
|
@ -754,7 +754,13 @@
|
|||
"modelSelectionLabel": "Image Generation Model",
|
||||
"modelSelectionDescription": "Select the model to use for image generation",
|
||||
"warningMissingKey": "⚠️ OpenRouter API key is required for image generation. Please configure it above.",
|
||||
"successConfigured": "✓ Image generation is configured and ready to use"
|
||||
"successConfigured": "✓ Image generation is configured and ready to use",
|
||||
"providerLabel": "Image Generation Provider",
|
||||
"providerDescription": "Choose the provider for image generation",
|
||||
"geminiApiKeyLabel": "Gemini API Key",
|
||||
"geminiApiKeyPlaceholder": "Enter your Gemini API key",
|
||||
"geminiGetApiKeyText": "Get your API key from",
|
||||
"warningMissingGeminiKey": "⚠️ Gemini API key is required for image generation. Please configure it above."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Enable model-initiated slash commands",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/es/settings.json
generated
8
webview-ui/src/i18n/locales/es/settings.json
generated
|
|
@ -749,7 +749,13 @@
|
|||
"modelSelectionLabel": "Modelo de generación de imágenes",
|
||||
"modelSelectionDescription": "Selecciona el modelo para la generación de imágenes",
|
||||
"warningMissingKey": "⚠️ La clave API de OpenRouter es requerida para la generación de imágenes. Por favor, configúrala arriba.",
|
||||
"successConfigured": "✓ La generación de imágenes está configurada y lista para usar"
|
||||
"successConfigured": "✓ La generación de imágenes está configurada y lista para usar",
|
||||
"providerLabel": "Proveedor de generación de imágenes",
|
||||
"providerDescription": "Elige el proveedor para la generación de imágenes",
|
||||
"geminiApiKeyLabel": "Clave API de Gemini",
|
||||
"geminiApiKeyPlaceholder": "Introduce tu clave API de Gemini",
|
||||
"geminiGetApiKeyText": "Obtén tu clave API de",
|
||||
"warningMissingGeminiKey": "⚠️ La clave API de Gemini es requerida para la generación de imágenes. Por favor, configúrala arriba."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Habilitar comandos slash iniciados por el modelo",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/fr/settings.json
generated
8
webview-ui/src/i18n/locales/fr/settings.json
generated
|
|
@ -749,7 +749,13 @@
|
|||
"modelSelectionLabel": "Modèle de génération d'images",
|
||||
"modelSelectionDescription": "Sélectionnez le modèle pour la génération d'images",
|
||||
"warningMissingKey": "⚠️ Une clé API OpenRouter est requise pour la génération d'images. Veuillez la configurer ci-dessus.",
|
||||
"successConfigured": "✓ La génération d'images est configurée et prête à utiliser"
|
||||
"successConfigured": "✓ La génération d'images est configurée et prête à utiliser",
|
||||
"providerLabel": "Fournisseur de génération d'images",
|
||||
"providerDescription": "Choisissez le fournisseur pour la génération d'images",
|
||||
"geminiApiKeyLabel": "Clé API Gemini",
|
||||
"geminiApiKeyPlaceholder": "Entrez votre clé API Gemini",
|
||||
"geminiGetApiKeyText": "Obtenez votre clé API depuis",
|
||||
"warningMissingGeminiKey": "⚠️ Une clé API Gemini est requise pour la génération d'images. Veuillez la configurer ci-dessus."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Activer les commandes slash initiées par le modèle",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/hi/settings.json
generated
8
webview-ui/src/i18n/locales/hi/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "छवि निर्माण मॉडल",
|
||||
"modelSelectionDescription": "छवि निर्माण के लिए उपयोग करने वाला मॉडल चुनें",
|
||||
"warningMissingKey": "⚠️ छवि निर्माण के लिए OpenRouter API कुंजी आवश्यक है। कृपया इसे ऊपर कॉन्फ़िगर करें।",
|
||||
"successConfigured": "✓ छवि निर्माण कॉन्फ़िगर है और उपयोग के लिए तैयार है"
|
||||
"successConfigured": "✓ छवि निर्माण कॉन्फ़िगर है और उपयोग के लिए तैयार है",
|
||||
"providerLabel": "छवि निर्माण प्रदाता",
|
||||
"providerDescription": "छवि निर्माण के लिए प्रदाता चुनें",
|
||||
"geminiApiKeyLabel": "Gemini API कुंजी",
|
||||
"geminiApiKeyPlaceholder": "अपनी Gemini API कुंजी दर्ज करें",
|
||||
"geminiGetApiKeyText": "अपनी API कुंजी प्राप्त करें",
|
||||
"warningMissingGeminiKey": "⚠️ छवि निर्माण के लिए Gemini API कुंजी आवश्यक है। कृपया इसे ऊपर कॉन्फ़िगर करें।"
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "मॉडल द्वारा शुरू किए गए स्लैश कमांड सक्षम करें",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/id/settings.json
generated
8
webview-ui/src/i18n/locales/id/settings.json
generated
|
|
@ -779,7 +779,13 @@
|
|||
"modelSelectionLabel": "Model Pembuatan Gambar",
|
||||
"modelSelectionDescription": "Pilih model untuk pembuatan gambar",
|
||||
"warningMissingKey": "⚠️ Kunci API OpenRouter diperlukan untuk pembuatan gambar. Silakan konfigurasi di atas.",
|
||||
"successConfigured": "✓ Pembuatan gambar dikonfigurasi dan siap digunakan"
|
||||
"successConfigured": "✓ Pembuatan gambar dikonfigurasi dan siap digunakan",
|
||||
"providerLabel": "Penyedia pembuatan gambar",
|
||||
"providerDescription": "Pilih penyedia untuk pembuatan gambar",
|
||||
"geminiApiKeyLabel": "Kunci API Gemini",
|
||||
"geminiApiKeyPlaceholder": "Masukkan kunci API Gemini Anda",
|
||||
"geminiGetApiKeyText": "Dapatkan kunci API Anda dari",
|
||||
"warningMissingGeminiKey": "⚠️ Kunci API Gemini diperlukan untuk pembuatan gambar. Silakan konfigurasi di atas."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Aktifkan perintah slash yang dimulai model",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/it/settings.json
generated
8
webview-ui/src/i18n/locales/it/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Modello di generazione immagini",
|
||||
"modelSelectionDescription": "Seleziona il modello per la generazione di immagini",
|
||||
"warningMissingKey": "⚠️ La chiave API OpenRouter è richiesta per la generazione di immagini. Configurala sopra.",
|
||||
"successConfigured": "✓ La generazione di immagini è configurata e pronta per l'uso"
|
||||
"successConfigured": "✓ La generazione di immagini è configurata e pronta per l'uso",
|
||||
"providerLabel": "Provider di generazione immagini",
|
||||
"providerDescription": "Scegli il provider per la generazione di immagini",
|
||||
"geminiApiKeyLabel": "Chiave API Gemini",
|
||||
"geminiApiKeyPlaceholder": "Inserisci la tua chiave API Gemini",
|
||||
"geminiGetApiKeyText": "Ottieni la tua chiave API da",
|
||||
"warningMissingGeminiKey": "⚠️ La chiave API Gemini è richiesta per la generazione di immagini. Configurala sopra."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Abilita comandi slash avviati dal modello",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/ja/settings.json
generated
8
webview-ui/src/i18n/locales/ja/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "画像生成モデル",
|
||||
"modelSelectionDescription": "画像生成に使用するモデルを選択",
|
||||
"warningMissingKey": "⚠️ 画像生成にはOpenRouter APIキーが必要です。上記で設定してください。",
|
||||
"successConfigured": "✓ 画像生成が設定され、使用準備完了です"
|
||||
"successConfigured": "✓ 画像生成が設定され、使用準備完了です",
|
||||
"providerLabel": "画像生成プロバイダー",
|
||||
"providerDescription": "画像生成のプロバイダーを選択",
|
||||
"geminiApiKeyLabel": "Gemini APIキー",
|
||||
"geminiApiKeyPlaceholder": "Gemini APIキーを入力してください",
|
||||
"geminiGetApiKeyText": "APIキーを取得する場所",
|
||||
"warningMissingGeminiKey": "⚠️ 画像生成にはGemini APIキーが必要です。上記で設定してください。"
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "モデル開始スラッシュコマンドを有効にする",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/ko/settings.json
generated
8
webview-ui/src/i18n/locales/ko/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "이미지 생성 모델",
|
||||
"modelSelectionDescription": "이미지 생성에 사용할 모델을 선택하세요",
|
||||
"warningMissingKey": "⚠️ 이미지 생성에는 OpenRouter API 키가 필요합니다. 위에서 설정해주세요.",
|
||||
"successConfigured": "✓ 이미지 생성이 구성되었으며 사용할 준비가 되었습니다"
|
||||
"successConfigured": "✓ 이미지 생성이 구성되었으며 사용할 준비가 되었습니다",
|
||||
"providerLabel": "이미지 생성 제공자",
|
||||
"providerDescription": "이미지 생성 제공자를 선택하세요",
|
||||
"geminiApiKeyLabel": "Gemini API 키",
|
||||
"geminiApiKeyPlaceholder": "Gemini API 키를 입력하세요",
|
||||
"geminiGetApiKeyText": "API 키를 받을 곳",
|
||||
"warningMissingGeminiKey": "⚠️ 이미지 생성에는 Gemini API 키가 필요합니다. 위에서 설정해주세요."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "모델 시작 슬래시 명령 활성화",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/nl/settings.json
generated
8
webview-ui/src/i18n/locales/nl/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Afbeeldingsgeneratiemodel",
|
||||
"modelSelectionDescription": "Selecteer het model voor afbeeldingsgeneratie",
|
||||
"warningMissingKey": "⚠️ OpenRouter API-sleutel is vereist voor afbeeldingsgeneratie. Configureer deze hierboven.",
|
||||
"successConfigured": "✓ Afbeeldingsgeneratie is geconfigureerd en klaar voor gebruik"
|
||||
"successConfigured": "✓ Afbeeldingsgeneratie is geconfigureerd en klaar voor gebruik",
|
||||
"providerLabel": "Afbeeldingsgeneratie provider",
|
||||
"providerDescription": "Kies de provider voor afbeeldingsgeneratie",
|
||||
"geminiApiKeyLabel": "Gemini API-sleutel",
|
||||
"geminiApiKeyPlaceholder": "Voer je Gemini API-sleutel in",
|
||||
"geminiGetApiKeyText": "Haal je API-sleutel op van",
|
||||
"warningMissingGeminiKey": "⚠️ Gemini API-sleutel is vereist voor afbeeldingsgeneratie. Configureer deze hierboven."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Model-geïnitieerde slash-commando's inschakelen",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/pl/settings.json
generated
8
webview-ui/src/i18n/locales/pl/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Model generowania obrazów",
|
||||
"modelSelectionDescription": "Wybierz model do generowania obrazów",
|
||||
"warningMissingKey": "⚠️ Klucz API OpenRouter jest wymagany do generowania obrazów. Skonfiguruj go powyżej.",
|
||||
"successConfigured": "✓ Generowanie obrazów jest skonfigurowane i gotowe do użycia"
|
||||
"successConfigured": "✓ Generowanie obrazów jest skonfigurowane i gotowe do użycia",
|
||||
"providerLabel": "Dostawca generowania obrazów",
|
||||
"providerDescription": "Wybierz dostawcę do generowania obrazów",
|
||||
"geminiApiKeyLabel": "Klucz API Gemini",
|
||||
"geminiApiKeyPlaceholder": "Wprowadź swój klucz API Gemini",
|
||||
"geminiGetApiKeyText": "Uzyskaj swój klucz API od",
|
||||
"warningMissingGeminiKey": "⚠️ Klucz API Gemini jest wymagany do generowania obrazów. Skonfiguruj go powyżej."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Włącz polecenia slash inicjowane przez model",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/pt-BR/settings.json
generated
8
webview-ui/src/i18n/locales/pt-BR/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Modelo de Geração de Imagens",
|
||||
"modelSelectionDescription": "Selecione o modelo para geração de imagens",
|
||||
"warningMissingKey": "⚠️ A chave de API do OpenRouter é necessária para geração de imagens. Configure-a acima.",
|
||||
"successConfigured": "✓ A geração de imagens está configurada e pronta para uso"
|
||||
"successConfigured": "✓ A geração de imagens está configurada e pronta para uso",
|
||||
"providerLabel": "Provedor de geração de imagens",
|
||||
"providerDescription": "Escolha o provedor para geração de imagens",
|
||||
"geminiApiKeyLabel": "Chave de API do Gemini",
|
||||
"geminiApiKeyPlaceholder": "Digite sua chave de API do Gemini",
|
||||
"geminiGetApiKeyText": "Obtenha sua chave de API de",
|
||||
"warningMissingGeminiKey": "⚠️ A chave de API do Gemini é necessária para geração de imagens. Configure-a acima."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Ativar comandos slash iniciados pelo modelo",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/ru/settings.json
generated
8
webview-ui/src/i18n/locales/ru/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Модель генерации изображений",
|
||||
"modelSelectionDescription": "Выберите модель для генерации изображений",
|
||||
"warningMissingKey": "⚠️ API-ключ OpenRouter необходим для генерации изображений. Настройте его выше.",
|
||||
"successConfigured": "✓ Генерация изображений настроена и готова к использованию"
|
||||
"successConfigured": "✓ Генерация изображений настроена и готова к использованию",
|
||||
"providerLabel": "Провайдер генерации изображений",
|
||||
"providerDescription": "Выберите провайдера для генерации изображений",
|
||||
"geminiApiKeyLabel": "API-ключ Gemini",
|
||||
"geminiApiKeyPlaceholder": "Введите ваш API-ключ Gemini",
|
||||
"geminiGetApiKeyText": "Получите ваш API-ключ от",
|
||||
"warningMissingGeminiKey": "⚠️ API-ключ Gemini необходим для генерации изображений. Настройте его выше."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Включить слэш-команды, инициированные моделью",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/tr/settings.json
generated
8
webview-ui/src/i18n/locales/tr/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Görüntü Üretim Modeli",
|
||||
"modelSelectionDescription": "Görüntü üretimi için kullanılacak modeli seçin",
|
||||
"warningMissingKey": "⚠️ Görüntü üretimi için OpenRouter API anahtarı gereklidir. Lütfen yukarıda yapılandırın.",
|
||||
"successConfigured": "✓ Görüntü üretimi yapılandırılmış ve kullanıma hazır"
|
||||
"successConfigured": "✓ Görüntü üretimi yapılandırılmış ve kullanıma hazır",
|
||||
"providerLabel": "Görüntü üretim sağlayıcısı",
|
||||
"providerDescription": "Görüntü üretimi için sağlayıcıyı seçin",
|
||||
"geminiApiKeyLabel": "Gemini API Anahtarı",
|
||||
"geminiApiKeyPlaceholder": "Gemini API anahtarınızı girin",
|
||||
"geminiGetApiKeyText": "API anahtarınızı alın",
|
||||
"warningMissingGeminiKey": "⚠️ Görüntü üretimi için Gemini API anahtarı gereklidir. Lütfen yukarıda yapılandırın."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Model tarafından başlatılan slash komutlarını etkinleştir",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/vi/settings.json
generated
8
webview-ui/src/i18n/locales/vi/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "Mô hình tạo hình ảnh",
|
||||
"modelSelectionDescription": "Chọn mô hình để sử dụng cho việc tạo hình ảnh",
|
||||
"warningMissingKey": "⚠️ Khóa API OpenRouter là bắt buộc để tạo hình ảnh. Vui lòng cấu hình ở trên.",
|
||||
"successConfigured": "✓ Tạo hình ảnh đã được cấu hình và sẵn sàng sử dụng"
|
||||
"successConfigured": "✓ Tạo hình ảnh đã được cấu hình và sẵn sàng sử dụng",
|
||||
"providerLabel": "Nhà cung cấp tạo hình ảnh",
|
||||
"providerDescription": "Chọn nhà cung cấp cho việc tạo hình ảnh",
|
||||
"geminiApiKeyLabel": "Khóa API Gemini",
|
||||
"geminiApiKeyPlaceholder": "Nhập khóa API Gemini của bạn",
|
||||
"geminiGetApiKeyText": "Lấy khóa API của bạn từ",
|
||||
"warningMissingGeminiKey": "⚠️ Khóa API Gemini là bắt buộc để tạo hình ảnh. Vui lòng cấu hình ở trên."
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "Bật lệnh slash do mô hình khởi tạo",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/zh-CN/settings.json
generated
8
webview-ui/src/i18n/locales/zh-CN/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "图像生成模型",
|
||||
"modelSelectionDescription": "选择用于图像生成的模型",
|
||||
"warningMissingKey": "⚠️ 图像生成需要 OpenRouter API 密钥。请在上方配置。",
|
||||
"successConfigured": "✓ 图像生成已配置完成,可以使用"
|
||||
"successConfigured": "✓ 图像生成已配置完成,可以使用",
|
||||
"providerLabel": "图像生成提供商",
|
||||
"providerDescription": "选择图像生成的提供商",
|
||||
"geminiApiKeyLabel": "Gemini API 密钥",
|
||||
"geminiApiKeyPlaceholder": "输入您的 Gemini API 密钥",
|
||||
"geminiGetApiKeyText": "获取您的 API 密钥",
|
||||
"warningMissingGeminiKey": "⚠️ 图像生成需要 Gemini API 密钥。请在上方配置。"
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "启用模型发起的斜杠命令",
|
||||
|
|
|
|||
8
webview-ui/src/i18n/locales/zh-TW/settings.json
generated
8
webview-ui/src/i18n/locales/zh-TW/settings.json
generated
|
|
@ -750,7 +750,13 @@
|
|||
"modelSelectionLabel": "圖像生成模型",
|
||||
"modelSelectionDescription": "選擇用於圖像生成的模型",
|
||||
"warningMissingKey": "⚠️ 圖像生成需要 OpenRouter API 金鑰。請在上方設定。",
|
||||
"successConfigured": "✓ 圖像生成已設定完成並準備使用"
|
||||
"successConfigured": "✓ 圖像生成已設定完成並準備使用",
|
||||
"providerLabel": "圖像生成供應商",
|
||||
"providerDescription": "選擇圖像生成的供應商",
|
||||
"geminiApiKeyLabel": "Gemini API 金鑰",
|
||||
"geminiApiKeyPlaceholder": "輸入您的 Gemini API 金鑰",
|
||||
"geminiGetApiKeyText": "取得您的 API 金鑰從",
|
||||
"warningMissingGeminiKey": "⚠️ 圖像生成需要 Gemini API 金鑰。請在上方設定。"
|
||||
},
|
||||
"RUN_SLASH_COMMAND": {
|
||||
"name": "啟用模型啟動的斜線命令",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue