From d6e43d5324b065d683e58bcb734b0bac02f6e458 Mon Sep 17 00:00:00 2001 From: shiyue <935732994@qq.com> Date: Thu, 5 Feb 2026 17:46:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E4=B8=BA=20grok=20=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 12 ---- .kilocode/mcp.json | 14 ++++ .roo/mcp.json | 1 + config.json | 46 +++++++------ index.html | 43 +++++++----- script.js | 127 ++++++++++++++++++++++-------------- 6 files changed, 145 insertions(+), 98 deletions(-) delete mode 100644 .claude/settings.local.json create mode 100644 .kilocode/mcp.json create mode 100644 .roo/mcp.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 6719964..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(mkdir:*)" - ], - "deny": [] - }, - "env": { - "ANTHROPIC_AUTH_TOKEN": "sk-zpZrOa1KqxkLCBH0eMMiIxvyLONJ9SAglhktSGKNNjCuKQQn", - "ANTHROPIC_BASE_URL":"https://instcopilot-api.com" - } -} \ No newline at end of file diff --git a/.kilocode/mcp.json b/.kilocode/mcp.json new file mode 100644 index 0000000..4f09235 --- /dev/null +++ b/.kilocode/mcp.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "superdesign": { + "command": "node", + "args": [ + "E:/我的项目/superdesign-mcp-claude-code/dist/index.js" + ], + "env": {}, + "alwaysAllow": [ + "superdesign_generate" + ] + } + } +} \ No newline at end of file diff --git a/.roo/mcp.json b/.roo/mcp.json new file mode 100644 index 0000000..6b0a486 --- /dev/null +++ b/.roo/mcp.json @@ -0,0 +1 @@ +{"mcpServers":{}} \ No newline at end of file diff --git a/config.json b/config.json index 1b5a386..d6489d6 100644 --- a/config.json +++ b/config.json @@ -1,23 +1,28 @@ { "app": { - "name": "OpenRouter Image Generator", - "version": "1.0.0", - "description": "基于OpenRouter API的图像生成Web应用", + "name": "Grok Image Generator", + "version": "2.0.0", + "description": "基于 Grok API 的图像生成 Web 应用", "author": "OVINC CN", "license": "MIT" }, "api": { - "default_base_url": "https://openrouter.ai/api/v1", + "default_base_url": "", "default_timeout": 600, - "default_model": "google/gemini-2.5-flash-image-preview:free", + "default_model": "grok-imagine-1.0", + "default_response_format": "b64_json", + "default_n": 1, "supported_models": [ { - "id": "google/gemini-2.5-flash-image-preview:free", - "name": "Google Gemini 2.5 Flash Image Preview", - "description": "免费的Google Gemini模型,支持图像生成和视觉理解", - "pricing": "free" + "id": "grok-imagine-1.0", + "name": "Grok Imagine 1.0", + "description": "Grok 图像生成模型,支持文本到图像生成", + "pricing": "paid", + "capabilities": ["text-to-image"] } - ] + ], + "supported_response_formats": ["url", "b64_json"], + "max_images_per_request": 10 }, "ui": { "theme": { @@ -42,22 +47,23 @@ } }, "storage": { - "settings_key": "openRouterSettings", - "chat_history_key": "openRouterChatHistory", - "generated_images_key": "openRouterGeneratedImages" + "settings_key": "grokImageSettings", + "chat_history_key": "grokImageChatHistory", + "generated_images_key": "grokGeneratedImages" }, "endpoints": { - "models": "/models", - "chat_completions": "/chat/completions", - "image_generation": "/images/generations" + "models": "/v1/models", + "image_generation": "/v1/images/generations" }, "error_messages": { - "no_api_key": "请先输入API Key", - "connection_failed": "连接失败,请检查网络和API设置", - "invalid_response": "API响应格式错误", + "no_api_key": "请先输入 API Key", + "no_base_url": "请先配置 API 地址", + "connection_failed": "连接失败,请检查网络和 API 设置", + "invalid_response": "API 响应格式错误", "image_generation_failed": "图像生成失败", "file_too_large": "文件大小超过限制", "unsupported_format": "不支持的文件格式", - "upload_failed": "文件上传失败" + "upload_failed": "文件上传失败", + "image_edit_not_supported": "当前 API 不支持图像编辑,仅支持文本生成图像" } } \ No newline at end of file diff --git a/index.html b/index.html index ce87810..be9f169 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - OpenRouter Image Generator + Grok Image Generator @@ -16,9 +16,9 @@

- OpenRouter Image Generator + Grok Image Generator

-

基于OpenRouter API的智能图像生成工具

+

基于 Grok API 的智能图像生成工具

@@ -35,30 +35,39 @@
- +
- - + +
-
+
-
+
+
+ + +
+
+
-
+
@@ -84,17 +93,17 @@
- +
-
上传参考图像
+
上传参考图像 暂不支持
-
+
-

拖拽图像到此处或点击选择文件 (最多10张)

- -
diff --git a/script.js b/script.js index 9ee33e4..7f33c19 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,4 @@ -// OpenRouter Image Generator - 主要JavaScript逻辑 +// Grok Image Generator - 主要JavaScript逻辑 // 全局变量 let uploadedImages = []; @@ -6,10 +6,12 @@ let chatHistory = []; let generatedImages = []; let currentSettings = { apiKey: '', - baseUrl: 'https://openrouter.ai/api/v1', - model: 'google/gemini-2.5-flash-image-preview:free', + baseUrl: '', + model: 'grok-imagine-1.0', timeout: 600, - proxy: '' + proxy: '', + responseFormat: 'b64_json', + n: 1 }; let currentImageIndex = 0; // 当前查看的图像索引 let currentModalInstance = null; // 当前模态框实例 @@ -22,12 +24,12 @@ const CONFIG = { MAX_CHAT_HISTORY: 50, // 减少聊天历史记录数量以节省存储空间 MAX_GENERATED_IMAGES: 600, // 减少存储的图像数量以防止存储空间溢出 STORAGE_KEYS: { - SETTINGS: 'openRouterSettings', - CHAT_HISTORY: 'openRouterChatHistory', - GENERATED_IMAGES: 'openRouterGeneratedImages' + SETTINGS: 'grokImageSettings', + CHAT_HISTORY: 'grokImageChatHistory', + GENERATED_IMAGES: 'grokGeneratedImages' }, INDEXED_DB: { - NAME: 'OpenRouterImageDB', + NAME: 'GrokImageDB', VERSION: 1, STORES: { SETTINGS: 'settings', @@ -39,13 +41,15 @@ const CONFIG = { // 错误消息 const ERROR_MESSAGES = { - NO_API_KEY: '请先输入API Key', - CONNECTION_FAILED: '连接失败,请检查网络和API设置', - INVALID_RESPONSE: 'API响应格式错误', + NO_API_KEY: '请先输入 API Key', + NO_BASE_URL: '请先配置 API 地址', + CONNECTION_FAILED: '连接失败,请检查网络和 API 设置', + INVALID_RESPONSE: 'API 响应格式错误', IMAGE_GENERATION_FAILED: '图像生成失败', FILE_TOO_LARGE: '文件大小超过限制', UNSUPPORTED_FORMAT: '不支持的文件格式', - UPLOAD_FAILED: '文件上传失败' + UPLOAD_FAILED: '文件上传失败', + IMAGE_EDIT_NOT_SUPPORTED: '当前 API 不支持图像编辑,仅支持文本生成图像' }; // 工具函数 @@ -698,35 +702,24 @@ const apiService = { // 生成图像 generateImage: async function(message, images, settings) { - const messages = [ - { - role: 'user', - content: [ - { type: 'text', text: message } - ] - } - ]; - - // 添加上传的图像 - images.forEach(img => { - messages[0].content.push({ - type: 'image_url', - image_url: { url: img.data } - }); - }); + // 检查是否有上传的图像,如果有则提示不支持 + if (images && images.length > 0) { + console.warn('当前 API 不支持图像编辑,将忽略上传的图像'); + } + // 构建请求 payload(符合 OpenAI 图像生成 API 格式) const payload = { model: settings.model, - messages: messages, - stream: false, - "modalities": ["image","text"] + prompt: message, + n: settings.n || 1, + response_format: settings.responseFormat || 'b64_json' }; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), settings.timeout * 1000); try { - const response = await fetch(`${settings.baseUrl}/chat/completions`, { + const response = await fetch(`${settings.baseUrl}/v1/images/generations`, { method: 'POST', headers: { 'Authorization': `Bearer ${settings.apiKey}`, @@ -739,31 +732,50 @@ const apiService = { clearTimeout(timeoutId); if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`); } const data = await response.json(); - - // 解析响应 - const choice = data.choices[0]; - const messageContent = choice.message.content; + + // 解析响应(OpenAI 图像生成 API 格式) const images = []; - - // 提取图像数据并转换为Blob URL,但保留原始base64数据 - if (choice.message.images) { - choice.message.images.forEach(img => { - // 确保原始数据是base64格式 - const originalBase64 = img.image_url.url; - const blobUrl = utils.base64ToBlobUrl(originalBase64); - images.push(blobUrl); + let hasError = false; + + if (data.data && Array.isArray(data.data)) { + data.data.forEach(item => { + if (item.b64_json) { + // 检测 API 返回的错误标记 + if (item.b64_json === 'error' || item.b64_json === 'Error') { + hasError = true; + return; + } + // base64 格式响应 + const base64Data = `data:image/png;base64,${item.b64_json}`; + const blobUrl = utils.base64ToBlobUrl(base64Data); + images.push(blobUrl); + } else if (item.url) { + // 检测 URL 格式的错误标记 + if (item.url === 'error' || item.url === 'Error') { + hasError = true; + return; + } + // URL 格式响应 + images.push(item.url); + } }); } + // 如果检测到错误标记,抛出错误以触发重试 + if (hasError) { + throw new Error('API 返回错误标记,需要重试'); + } + return { success: true, - content: messageContent, + content: `已生成 ${images.length} 张图像`, images: images, - usage: data.usage + usage: data.usage || null }; } catch (error) { clearTimeout(timeoutId); @@ -1578,6 +1590,7 @@ const uiController = { document.getElementById('model').value = currentSettings.model; document.getElementById('timeout').value = currentSettings.timeout; document.getElementById('proxy').value = currentSettings.proxy; + document.getElementById('responseFormat').value = currentSettings.responseFormat || 'b64_json'; // 加载聊天历史 const indexedChatHistory = await indexedDBStorage.getChatHistory(); @@ -1756,7 +1769,8 @@ const uiController = { currentSettings.model = document.getElementById('model').value; currentSettings.timeout = parseInt(document.getElementById('timeout').value); currentSettings.proxy = document.getElementById('proxy').value; - + currentSettings.responseFormat = document.getElementById('responseFormat').value; + const saved = await indexedDBStorage.saveSettings(currentSettings); if (!saved) { console.error('IndexedDB 保存设置失败'); @@ -1856,7 +1870,7 @@ const app = { // 初始化"全部下载"按钮的可见性 uiController.updateDownloadAllButtonVisibility(); - console.log('OpenRouter Image Generator initialized'); + console.log('Grok Image Generator initialized'); }, // 初始化事件监听器 @@ -1969,6 +1983,21 @@ const app = { return; } + // 检查 API 地址是否已配置 + const baseUrl = document.getElementById('baseUrl').value; + if (!baseUrl) { + utils.showNotification(ERROR_MESSAGES.NO_BASE_URL, 'warning'); + return; + } + + // 检查是否有上传的图像,如果有则提示不支持 + if (uploadedImages && uploadedImages.length > 0) { + utils.showNotification(ERROR_MESSAGES.IMAGE_EDIT_NOT_SUPPORTED, 'warning'); + // 清空上传的图像 + uploadedImages = []; + uiController.updateUploadedImagesDisplay(); + } + // 隐藏传统加载状态,使用占位图像代替 uiController.hideTraditionalLoading();