改为 grok 了

This commit is contained in:
2026-02-05 17:46:08 +08:00
parent b69b7782e5
commit d6e43d5324
6 changed files with 145 additions and 98 deletions

View File

@@ -1,12 +0,0 @@
{
"permissions": {
"allow": [
"Bash(mkdir:*)"
],
"deny": []
},
"env": {
"ANTHROPIC_AUTH_TOKEN": "sk-zpZrOa1KqxkLCBH0eMMiIxvyLONJ9SAglhktSGKNNjCuKQQn",
"ANTHROPIC_BASE_URL":"https://instcopilot-api.com"
}
}

14
.kilocode/mcp.json Normal file
View File

@@ -0,0 +1,14 @@
{
"mcpServers": {
"superdesign": {
"command": "node",
"args": [
"E:/我的项目/superdesign-mcp-claude-code/dist/index.js"
],
"env": {},
"alwaysAllow": [
"superdesign_generate"
]
}
}
}

1
.roo/mcp.json Normal file
View File

@@ -0,0 +1 @@
{"mcpServers":{}}

View File

@@ -1,23 +1,28 @@
{ {
"app": { "app": {
"name": "OpenRouter Image Generator", "name": "Grok Image Generator",
"version": "1.0.0", "version": "2.0.0",
"description": "基于OpenRouter API的图像生成Web应用", "description": "基于 Grok API 的图像生成 Web 应用",
"author": "OVINC CN", "author": "OVINC CN",
"license": "MIT" "license": "MIT"
}, },
"api": { "api": {
"default_base_url": "https://openrouter.ai/api/v1", "default_base_url": "",
"default_timeout": 600, "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": [ "supported_models": [
{ {
"id": "google/gemini-2.5-flash-image-preview:free", "id": "grok-imagine-1.0",
"name": "Google Gemini 2.5 Flash Image Preview", "name": "Grok Imagine 1.0",
"description": "免费的Google Gemini模型,支持图像生成和视觉理解", "description": "Grok 图像生成模型,支持文本到图像生成",
"pricing": "free" "pricing": "paid",
"capabilities": ["text-to-image"]
} }
] ],
"supported_response_formats": ["url", "b64_json"],
"max_images_per_request": 10
}, },
"ui": { "ui": {
"theme": { "theme": {
@@ -42,22 +47,23 @@
} }
}, },
"storage": { "storage": {
"settings_key": "openRouterSettings", "settings_key": "grokImageSettings",
"chat_history_key": "openRouterChatHistory", "chat_history_key": "grokImageChatHistory",
"generated_images_key": "openRouterGeneratedImages" "generated_images_key": "grokGeneratedImages"
}, },
"endpoints": { "endpoints": {
"models": "/models", "models": "/v1/models",
"chat_completions": "/chat/completions", "image_generation": "/v1/images/generations"
"image_generation": "/images/generations"
}, },
"error_messages": { "error_messages": {
"no_api_key": "请先输入API Key", "no_api_key": "请先输入 API Key",
"connection_failed": "连接失败请检查网络和API设置", "no_base_url": "请先配置 API 地址",
"invalid_response": "API响应格式错误", "connection_failed": "连接失败,请检查网络和 API 设置",
"invalid_response": "API 响应格式错误",
"image_generation_failed": "图像生成失败", "image_generation_failed": "图像生成失败",
"file_too_large": "文件大小超过限制", "file_too_large": "文件大小超过限制",
"unsupported_format": "不支持的文件格式", "unsupported_format": "不支持的文件格式",
"upload_failed": "文件上传失败" "upload_failed": "文件上传失败",
"image_edit_not_supported": "当前 API 不支持图像编辑,仅支持文本生成图像"
} }
} }

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenRouter Image Generator</title> <title>Grok Image Generator</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="styles.css" rel="stylesheet"> <link href="styles.css" rel="stylesheet">
@@ -16,9 +16,9 @@
<div class="card-header"> <div class="card-header">
<h1 class="mb-0"> <h1 class="mb-0">
<i class="fas fa-image me-2"></i> <i class="fas fa-image me-2"></i>
OpenRouter Image Generator Grok Image Generator
</h1> </h1>
<p class="mb-0 mt-2">基于OpenRouter API的智能图像生成工具</p> <p class="mb-0 mt-2">基于 Grok API 的智能图像生成工具</p>
</div> </div>
<div class="card-body"> <div class="card-body">
<!-- 设置面板 --> <!-- 设置面板 -->
@@ -35,30 +35,39 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="mb-3">
<label for="apiKey" class="form-label">API Key</label> <label for="apiKey" class="form-label">API Key</label>
<input type="password" class="form-control" id="apiKey" placeholder="输入您的OpenRouter API Key"> <input type="password" class="form-control" id="apiKey" placeholder="输入您的 API Key">
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="mb-3"> <div class="mb-3">
<label for="baseUrl" class="form-label">Base URL</label> <label for="baseUrl" class="form-label">API 地址</label>
<input type="url" class="form-control" id="baseUrl" value="https://openrouter.ai/api/v1"> <input type="url" class="form-control" id="baseUrl" placeholder="输入 API 地址,如 http://localhost:8000">
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-3">
<div class="mb-3"> <div class="mb-3">
<label for="model" class="form-label">模型</label> <label for="model" class="form-label">模型</label>
<select class="form-select" id="model"> <select class="form-select" id="model">
<option value="google/gemini-2.5-flash-image-preview:free">Google Gemini 2.5 Flash Image Preview (Free)</option> <option value="grok-imagine-1.0">Grok Imagine 1.0</option>
</select> </select>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-3">
<div class="mb-3">
<label for="responseFormat" class="form-label">响应格式</label>
<select class="form-select" id="responseFormat">
<option value="b64_json">Base64 (推荐)</option>
<option value="url">URL</option>
</select>
</div>
</div>
<div class="col-md-3">
<div class="mb-3"> <div class="mb-3">
<label for="timeout" class="form-label">超时时间 (秒)</label> <label for="timeout" class="form-label">超时时间 (秒)</label>
<input type="number" class="form-control" id="timeout" value="600"> <input type="number" class="form-control" id="timeout" value="600">
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-3">
<div class="mb-3"> <div class="mb-3">
<label for="proxy" class="form-label">代理 (可选)</label> <label for="proxy" class="form-label">代理 (可选)</label>
<input type="url" class="form-control" id="proxy" placeholder="http://proxy:port"> <input type="url" class="form-control" id="proxy" placeholder="http://proxy:port">
@@ -84,17 +93,17 @@
</div> </div>
</div> </div>
<!-- 图像上传区域 --> <!-- 图像上传区域(当前 API 不支持) -->
<div class="mb-4"> <div class="mb-4">
<h5><i class="fas fa-upload me-2"></i>上传参考图像</h5> <h5><i class="fas fa-upload me-2"></i>上传参考图像 <span class="badge bg-secondary">暂不支持</span></h5>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<div class="border-2 border-dashed rounded p-4 text-center h-100 d-flex flex-column justify-content-center" id="dropZone"> <div class="border-2 border-dashed rounded p-4 text-center h-100 d-flex flex-column justify-content-center bg-light" id="dropZone" style="opacity: 0.6;">
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i> <i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i>
<p class="text-muted">拖拽图像到此处或点击选择文件 (最多10张)</p> <p class="text-muted">当前 API 仅支持文本生成图像,暂不支持图像编辑</p>
<input type="file" class="d-none" id="imageInput" accept="image/*" multiple> <input type="file" class="d-none" id="imageInput" accept="image/*" multiple disabled>
<button class="btn btn-outline-primary" onclick="document.getElementById('imageInput').click()"> <button class="btn btn-outline-secondary" disabled>
选择图像 功能暂不可用
</button> </button>
</div> </div>
</div> </div>

127
script.js
View File

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