news 2026/4/29 14:39:10

VSCode插件开发:LongCat-Image-Edit的IDE集成方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VSCode插件开发:LongCat-Image-Edit的IDE集成方案

VSCode插件开发:LongCat-Image-Edit的IDE集成方案

你是不是经常在编辑动物图片时,需要在浏览器、图片编辑器和代码编辑器之间来回切换?上传图片、输入指令、下载结果,一套流程下来,时间都花在工具切换上了。

今天咱们就来解决这个问题。我将手把手教你开发一个VSCode插件,让你直接在VSCode里就能调用LongCat-Image-Edit进行动物图片编辑。想象一下,在IDE里选中一张猫咪图片,输入“变成熊猫医生”,几秒钟后图片就自动编辑完成,整个过程完全不用离开VSCode。

这个插件开发完成后,你可以直接在VSCode的侧边栏里上传图片、输入自然语言指令,然后插件会调用LongCat-Image-Edit的API,把编辑好的图片直接显示在编辑器里。整个过程就像在IDE里使用一个内置的图片编辑工具一样自然。

1. 环境准备与项目初始化

1.1 安装必要的工具

首先确保你的电脑上已经安装了Node.js(建议版本16.x或更高)和VSCode。如果你还没有安装,可以去官网下载安装。

打开终端,检查一下Node.js是否安装成功:

node --version npm --version

如果能看到版本号,说明安装成功了。

1.2 创建VSCode插件项目

VSCode官方提供了一个非常方便的工具来创建插件项目。在终端里运行:

npm install -g yo generator-code

安装完成后,创建一个新的插件项目:

yo code

这时候会有一个交互式的命令行界面,按照下面的选项选择:

? What type of extension do you want to create? New Extension (TypeScript) ? What's the name of your extension? longcat-image-edit-helper ? What's the identifier of your extension? longcat-image-edit-helper ? What's the description of your extension? Edit animal images with LongCat-Image-Edit directly in VSCode ? Initialize a git repository? Yes ? Which package manager to use? npm

等待一会儿,项目就创建好了。用VSCode打开这个项目:

cd longcat-image-edit-helper code .

1.3 项目结构初探

打开项目后,你会看到这样的目录结构:

longcat-image-edit-helper/ ├── src/ │ └── extension.ts # 插件的主入口文件 ├── package.json # 插件的配置文件 ├── tsconfig.json # TypeScript配置 └── .vscode/ # VSCode调试配置

我们先来看看package.json,这是插件的核心配置文件。找到activationEventscontributes部分,这些定义了插件什么时候激活,以及提供了哪些功能。

2. 插件界面设计与功能规划

2.1 设计插件界面

我们的插件需要一个用户界面来上传图片、输入指令、查看结果。VSCode提供了几种界面方案:

  1. 侧边栏视图:在活动栏添加一个图标,点击后显示一个完整的编辑面板
  2. Webview面板:创建一个独立的编辑窗口
  3. 状态栏按钮:快速操作的入口

我建议采用侧边栏视图+Webview的组合,这样既方便操作,又能提供丰富的交互。

2.2 修改package.json配置

打开package.json,在contributes部分添加我们的视图配置:

{ "contributes": { "viewsContainers": { "activitybar": [ { "id": "longcat-image-edit", "title": "LongCat Editor", "icon": "media/icon.svg" } ] }, "views": { "longcat-image-edit": [ { "id": "longcat.editor", "name": "Image Editor", "type": "webview" } ] }, "commands": [ { "command": "longcat.openEditor", "title": "Open LongCat Image Editor", "category": "LongCat" }, { "command": "longcat.editSelectedImage", "title": "Edit Selected Image with LongCat", "category": "LongCat" } ], "menus": { "editor/context": [ { "command": "longcat.editSelectedImage", "when": "resourceExtname == .jpg || resourceExtname == .png || resourceExtname == .jpeg", "group": "navigation" } ] } } }

这段配置做了几件事:

  • 在活动栏添加了一个图标
  • 定义了一个Webview视图
  • 注册了两个命令
  • 在图片文件的右键菜单中添加了编辑选项

2.3 创建Webview界面

src目录下创建一个新的文件夹webview,然后创建editor.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>LongCat Image Editor</title> <style> body { padding: 20px; font-family: var(--vscode-font-family); color: var(--vscode-foreground); background-color: var(--vscode-editor-background); } .container { max-width: 800px; margin: 0 auto; } .upload-area { border: 2px dashed var(--vscode-input-border); border-radius: 8px; padding: 40px; text-align: center; margin-bottom: 20px; cursor: pointer; transition: border-color 0.3s; } .upload-area:hover { border-color: var(--vscode-focusBorder); } .upload-area.dragover { border-color: var(--vscode-button-background); background-color: var(--vscode-button-secondaryBackground); } .preview-container { display: flex; gap: 20px; margin: 20px 0; } .preview-box { flex: 1; border: 1px solid var(--vscode-input-border); border-radius: 4px; padding: 10px; min-height: 200px; } .preview-box img { max-width: 100%; max-height: 300px; display: block; margin: 0 auto; } .instruction-input { width: 100%; height: 80px; padding: 10px; margin-bottom: 15px; border: 1px solid var(--vscode-input-border); border-radius: 4px; background-color: var(--vscode-input-background); color: var(--vscode-input-foreground); resize: vertical; } .examples { margin: 15px 0; font-size: 12px; color: var(--vscode-descriptionForeground); } .example-tag { display: inline-block; background: var(--vscode-badge-background); color: var(--vscode-badge-foreground); padding: 2px 8px; border-radius: 10px; margin: 2px; cursor: pointer; } .example-tag:hover { background: var(--vscode-button-hoverBackground); } .button-group { display: flex; gap: 10px; margin-top: 20px; } button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-family: var(--vscode-font-family); } .primary-btn { background-color: var(--vscode-button-background); color: var(--vscode-button-foreground); } .primary-btn:hover { background-color: var(--vscode-button-hoverBackground); } .secondary-btn { background-color: var(--vscode-button-secondaryBackground); color: var(--vscode-button-secondaryForeground); } .loading { display: none; text-align: center; margin: 20px 0; } .result-container { margin-top: 20px; border-top: 1px solid var(--vscode-panel-border); padding-top: 20px; } .history-item { border: 1px solid var(--vscode-input-border); border-radius: 4px; padding: 10px; margin-bottom: 10px; display: flex; align-items: center; gap: 10px; } .history-item img { width: 60px; height: 60px; object-fit: cover; border-radius: 4px; } </style> </head> <body> <div class="container"> <h2>LongCat Image Editor</h2> <div class="upload-area" id="uploadArea"> <p> Drag & drop an image here, or click to select</p> <p style="font-size: 12px; color: var(--vscode-descriptionForeground);"> Supports JPG, PNG, JPEG (Max 5MB) </p> <input type="file" id="fileInput" accept=".jpg,.jpeg,.png" style="display: none;"> </div> <div class="preview-container"> <div class="preview-box"> <h4>Original Image</h4> <div id="originalPreview"></div> </div> <div class="preview-box"> <h4>Edited Result</h4> <div id="resultPreview"></div> </div> </div> <div> <label for="instruction">Edit Instruction:</label> <textarea id="instruction" class="instruction-input" placeholder="Describe how you want to edit the image. For example: '猫变熊猫医生', '给狗狗戴上墨镜', '把背景换成海滩'" ></textarea> <div class="examples"> <p>Try these examples:</p> <span class="example-tag">import * as vscode from 'vscode'; import * as path from 'path'; import * as fs from 'fs'; export function activate(context: vscode.ExtensionContext) { console.log('LongCat Image Editor extension is now active!'); // 注册打开编辑器命令 let openEditorDisposable = vscode.commands.registerCommand('longcat.openEditor', () => { LongCatEditorPanel.createOrShow(context.extensionUri); }); // 注册编辑选中图片命令 let editSelectedImageDisposable = vscode.commands.registerCommand('longcat.editSelectedImage', (uri: vscode.Uri) => { if (uri) { LongCatEditorPanel.createOrShow(context.extensionUri, uri.fsPath); } }); context.subscriptions.push(openEditorDisposable, editSelectedImageDisposable); // 如果配置了自动打开,则在启动时打开编辑器 const config = vscode.workspace.getConfiguration('longcat'); if (config.get('autoOpenOnStart')) { vscode.commands.executeCommand('longcat.openEditor'); } } class LongCatEditorPanel { public static currentPanel: LongCatEditorPanel | undefined; private readonly _panel: vscode.WebviewPanel; private readonly _extensionUri: vscode.Uri; private _disposables: vscode.Disposable[] = []; private _selectedImagePath: string | undefined; public static createOrShow(extensionUri: vscode.Uri, imagePath?: string) { const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; // 如果已经有面板存在,则显示它 if (LongCatEditorPanel.currentPanel) { LongCatEditorPanel.currentPanel._panel.reveal(column); if (imagePath) { LongCatEditorPanel.currentPanel._selectedImagePath = imagePath; LongCatEditorPanel.currentPanel._updateWebview(); } return; } // 否则创建新的面板 const panel = vscode.window.createWebviewPanel( 'longcatEditor', 'LongCat Image Editor', column || vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true, localResourceRoots: [ vscode.Uri.joinPath(extensionUri, 'media'), vscode.Uri.joinPath(extensionUri, 'out'), vscode.Uri.joinPath(extensionUri, 'webview') ] } ); LongCatEditorPanel.currentPanel = new LongCatEditorPanel(panel, extensionUri, imagePath); } private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri, imagePath?: string) { this._panel = panel; this._extensionUri = extensionUri; this._selectedImagePath = imagePath; // 设置Webview的HTML内容 this._updateWebview(); // 监听面板关闭事件 this._panel.onDidDispose(() => this.dispose(), null, this._disposables); // 处理Webview消息 this._panel.webview.onDidReceiveMessage( async (message) => { switch (message.command) { case 'editImage': await this._handleEditImage(message.data); break; case 'saveImage': await this._handleSaveImage(message.data); break; case 'getImageData': await this._handleGetImageData(message.data); break; case 'showError': vscode.window.showErrorMessage(message.text); break; case 'showInfo': vscode.window.showInformationMessage(message.text); break; } }, null, this._disposables ); } private async _updateWebview() { const webview = this._panel.webview; this._panel.webview.html = this._getHtmlForWebview(webview); // 如果有选中的图片,发送给Webview if (this._selectedImagePath) { const imageData = await this._readImageAsBase64(this._selectedImagePath); webview.postMessage({ command: 'loadImage', data: { imageData: imageData, fileName: path.basename(this._selectedImagePath) } }); } } private _getHtmlForWebview(webview: vscode.Webview) { // 读取HTML文件 const htmlPath = path.join(this._extensionUri.fsPath, 'webview', 'editor.html'); let html = fs.readFileSync(htmlPath, 'utf8'); // 替换资源路径 const scriptUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, 'webview', 'editor.js') ); // 在HTML中注入脚本 html = html.replace( '<!-- Script will be injected here -->', `<script src="${scriptUri}"></script>` ); return html; } private async _readImageAsBase64(imagePath: string): Promise<string> { try { const imageBuffer = await fs.promises.readFile(imagePath); const base64Image = imageBuffer.toString('base64'); const extension = path.extname(imagePath).toLowerCase(); let mimeType = 'image/jpeg'; if (extension === '.png') { mimeType = 'image/png'; } return `data:${mimeType};base64,${base64Image}`; } catch (error) { console.error('Error reading image:', error); throw error; } } private async _handleEditImage(data: any) { const { imageData, instruction } = data; // 显示进度通知 vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: "Editing image with LongCat...", cancellable: false }, async (progress) => { progress.report({ increment: 0 }); try { // 这里调用LongCat-Image-Edit的API // 注意:实际使用时需要替换为真实的API端点 const result = await this._callLongCatAPI(imageData, instruction); progress.report({ increment: 100 }); // 将结果发送回Webview this._panel.webview.postMessage({ command: 'editComplete', data: result }); vscode.window.showInformationMessage('Image edited successfully!'); } catch (error: any) { vscode.window.showErrorMessage(`Edit failed: ${error.message}`); this._panel.webview.postMessage({ command: 'editFailed', error: error.message }); } }); } private async _callLongCatAPI(imageData: string, instruction: string): Promise<any> { // 移除base64前缀 const base64Data = imageData.replace(/^data:image\/\w+;base64,/, ''); // 这里应该是调用真实API的代码 // 由于LongCat-Image-Edit的具体API格式需要参考官方文档 // 这里提供一个示例结构 const apiUrl = 'https://api.example.com/longcat/edit'; // 替换为真实API const apiKey = vscode.workspace.getConfiguration('longcat').get('apiKey'); if (!apiKey) { throw new Error('API key not configured. Please set it in settings.'); } // 模拟API调用(实际使用时需要实现真实的HTTP请求) return new Promise((resolve) => { setTimeout(() => { // 这里应该返回真实的API响应 // 为了演示,我们返回一个模拟的base64图片 resolve({ success: true, editedImage: imageData, // 实际应该是编辑后的图片 message: 'Edit completed successfully' }); }, 3000); }); } private async _handleSaveImage(data: any) { const { imageData, fileName } = data; const options: vscode.SaveDialogOptions = { defaultUri: vscode.Uri.file(fileName || 'edited-image.png'), filters: { 'Images': ['png', 'jpg', 'jpeg'] } }; const fileUri = await vscode.window.showSaveDialog(options); if (fileUri) { try { // 移除base64前缀并保存文件 const base64Data = imageData.replace(/^data:image\/\w+;base64,/, ''); const buffer = Buffer.from(base64Data, 'base64'); await fs.promises.writeFile(fileUri.fsPath, buffer); vscode.window.showInformationMessage(`Image saved to ${fileUri.fsPath}`); } catch (error: any) { vscode.window.showErrorMessage(`Save failed: ${error.message}`); } } } private async _handleGetImageData(data: any) { const { filePath } = data; try { const imageData = await this._readImageAsBase64(filePath); this._panel.webview.postMessage({ command: 'imageDataLoaded', data: imageData }); } catch (error: any) { this._panel.webview.postMessage({ command: 'loadImageFailed', error: error.message }); } } public dispose() { LongCatEditorPanel.currentPanel = undefined; this._panel.dispose(); while (this._disposables.length) { const disposable = this._disposables.pop(); if (disposable) { disposable.dispose(); } } } } export function deactivate() {}

3.2 实现Webview的JavaScript逻辑

创建webview/editor.js

(function() { const vscode = acquireVsCodeApi(); let currentImageData = null; let currentResultData = null; let editHistory = []; // DOM元素 const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); const originalPreview = document.getElementById('originalPreview'); const resultPreview = document.getElementById('resultPreview'); const instructionInput = document.getElementById('instruction'); const editBtn = document.getElementById('editBtn'); const saveBtn = document.getElementById('saveBtn'); const clearBtn = document.getElementById('clearBtn'); const loading = document.getElementById('loading'); const historyList = document.getElementById('historyList'); const exampleTags = document.querySelectorAll('.example-tag'); // 初始化 function init() { setupEventListeners(); loadHistory(); // 监听来自扩展的消息 window.addEventListener('message', event => { const message = event.data; switch (message.command) { case 'loadImage': loadImageFromData(message.data); break; case 'editComplete': handleEditComplete(message.data); break; case 'editFailed': handleEditFailed(message.error); break; case 'imageDataLoaded': loadImageFromBase64(message.data); break; case 'loadImageFailed': showError('Failed to load image: ' + message.error); break; } }); } function setupEventListeners() { // 上传区域点击事件 uploadArea.addEventListener('click', () => { fileInput.click(); }); // 文件选择事件 fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { loadImageFromFile(file); } }); // 拖拽事件 uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const file = e.dataTransfer.files[0]; if (file && file.type.startsWith('image/')) { loadImageFromFile(file); } else { showError('Please drop an image file (JPG, PNG, JPEG)'); } }); // 编辑按钮事件 editBtn.addEventListener('click', () => { if (!currentImageData) { showError('Please select an image first'); return; } const instruction = instructionInput.value.trim(); if (!instruction) { showError('Please enter an edit instruction'); return; } startEdit(currentImageData, instruction); }); // 保存按钮事件 saveBtn.addEventListener('click', () => { if (!currentResultData) { showError('No edited image to save'); return; } const fileName = generateFileName(); vscode.postMessage({ command: 'saveImage', data: { imageData: currentResultData, fileName: fileName } }); }); // 清除按钮事件 clearBtn.addEventListener('click', () => { clearAll(); }); // 示例标签点击事件 exampleTags.forEach(tag => { tag.addEventListener('click', () => { const instruction = tag.getAttribute('data-instruction'); instructionInput.value = instruction; instructionInput.focus(); }); }); // 指令输入框事件 instructionInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && e.ctrlKey) { editBtn.click(); } }); } function loadImageFromFile(file) { if (file.size > 5 * 1024 * 1024) { showError('Image size should be less than 5MB'); return; } const reader = new FileReader(); reader.onload = (e) => { currentImageData = e.target.result; updateOriginalPreview(currentImageData); instructionInput.focus(); }; reader.readAsDataURL(file); } function loadImageFromData(data) { currentImageData = data.imageData; updateOriginalPreview(currentImageData); instructionInput.focus(); showInfo(`Loaded image: ${data.fileName}`); } function loadImageFromBase64(base64Data) { currentImageData = base64Data; updateOriginalPreview(currentImageData); instructionInput.focus(); } function updateOriginalPreview(imageData) { originalPreview.innerHTML = `<img src="${imageData}" alt="Original Image">`; editBtn.disabled = false; } function updateResultPreview(imageData) { resultPreview.innerHTML = `<img src="${imageData}" alt="Edited Image">`; saveBtn.disabled = false; } function startEdit(imageData, instruction) { loading.style.display = 'block'; editBtn.disabled = true; vscode.postMessage({ command: 'editImage', data: { imageData: imageData, instruction: instruction } }); } function handleEditComplete(result) { loading.style.display = 'none'; editBtn.disabled = false; if (result.success && result.editedImage) { currentResultData = result.editedImage; updateResultPreview(currentResultData); // 添加到历史记录 addToHistory({ original: currentImageData, edited: currentResultData, instruction: instructionInput.value, timestamp: new Date().toISOString() }); showInfo(result.message || 'Edit completed successfully'); } else { showError(result.message || 'Edit failed'); } } function handleEditFailed(error) { loading.style.display = 'none'; editBtn.disabled = false; showError(error); } function addToHistory(item) { editHistory.unshift(item); if (editHistory.length > 10) { editHistory.pop(); } saveHistory(); updateHistoryDisplay(); } function updateHistoryDisplay() { historyList.innerHTML = ''; editHistory.forEach((item, index) => { const historyItem = document.createElement('div'); historyItem.className = 'history-item'; historyItem.innerHTML = ` <img src="${item.edited}" alt="History ${index + 1}"> <div> <div style="font-weight: bold;">${item.instruction}</div> <div style="font-size: 11px; color: var(--vscode-descriptionForeground);"> ${new Date(item.timestamp).toLocaleString()} </div> <div style="margin-top: 5px;"> <button onclick="restoreFromHistory(${index})" style="font-size: 11px; padding: 2px 8px;"> Restore </button> </div> </div> `; historyList.appendChild(historyItem); }); } function restoreFromHistory(index) { const item = editHistory[index]; if (item) { currentImageData = item.original; currentResultData = item.edited; instructionInput.value = item.instruction; updateOriginalPreview(currentImageData); updateResultPreview(currentResultData); showInfo('Restored from history'); } } function clearAll() { currentImageData = null; currentResultData = null; instructionInput.value = ''; originalPreview.innerHTML = '<p style="color: var(--vscode-descriptionForeground); text-align: center;">No image selected</p>'; resultPreview.innerHTML = '<p style="color: var(--vscode-descriptionForeground); text-align: center;">Edit result will appear here</p>'; editBtn.disabled = true; saveBtn.disabled = true; fileInput.value = ''; } function loadHistory() { const saved = localStorage.getItem('longcatEditHistory'); if (saved) { try { editHistory = JSON.parse(saved); updateHistoryDisplay(); } catch (e) { console.error('Failed to load history:', e); } } } function saveHistory() { localStorage.setItem('longcatEditHistory', JSON.stringify(editHistory)); } function generateFileName() { const now = new Date(); const dateStr = now.toISOString().slice(0, 19).replace(/[:T]/g, '-'); return `longcat-edited-${dateStr}.png`; } function showError(message) { vscode.postMessage({ command: 'showError', text: message }); } function showInfo(message) { vscode.postMessage({ command: 'showInfo', text: message }); } // 暴露函数给全局作用域 window.restoreFromHistory = restoreFromHistory; // 初始化 document.addEventListener('DOMContentLoaded', init); })();

4. 插件配置与调试

4.1 添加插件配置

package.json中添加配置选项:

{ "contributes": { "configuration": { "title": "LongCat Image Editor", "properties": { "longcat.apiKey": { "type": "string", "default": "", "description": "API key for LongCat-Image-Edit service" }, "longcat.apiEndpoint": { "type": "string", "default": "https://api.example.com/longcat/edit", "description": "API endpoint for LongCat-Image-Edit" }, "longcat.autoOpenOnStart": { "type": "boolean", "default": false, "description": "Automatically open editor when VSCode starts" }, "longcat.maxFileSize": { "type": "number", "default": 5242880, "description": "Maximum file size in bytes (default 5MB)" }, "longcat.defaultInstructions": { "type": "array", "default": [ "猫变熊猫医生", "给狗狗戴上墨镜", "把背景换成海滩", "变成卡通风格", "冬天变夏天" ], "description": "Default edit instruction examples" } } } } }

4.2 调试插件

现在我们可以调试插件了。按F5键,VSCode会打开一个新的扩展开发主机窗口。

在新窗口中:

  1. Ctrl+Shift+P打开命令面板
  2. 输入"Open LongCat Image Editor"并选择
  3. 插件面板就会在侧边栏打开

或者,你也可以在资源管理器中右键点击一个图片文件,选择"Edit Selected Image with LongCat"。

4.3 添加图标

media目录下创建一个简单的图标文件icon.svg

<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <rect width="16" height="16" rx="3" fill="#4CAF50"/> <path d="M4 8L8 4L12 8L8 12Z" fill="white"/> <circle cx="8" cy="8" r="2" fill="#4CAF50"/> </svg>

5. 插件打包与发布

5.1 安装打包工具

npm install -g @vscode/vsce

5.2 创建发布配置

package.json中添加发布相关字段:

{ "publisher": "your-publisher-name", "repository": { "type": "git", "url": "https://github.com/yourusername/longcat-image-edit-helper" }, "keywords": [ "image", "edit", "ai", "longcat", "animal", "photos" ], "categories": [ "Visualization", "Other" ], "engines": { "vscode": "^1.60.0" } }

5.3 打包插件

vsce package

这会生成一个.vsix文件,你可以直接安装这个文件到VSCode。

5.4 发布到市场

如果你想把插件发布到VSCode市场,需要:

  1. 创建一个发布者账号:https://aka.ms/vscode-create-publisher
  2. 获取个人访问令牌:https://aka.ms/vscode-marketplace-token
  3. 登录并发布:
vsce login your-publisher-name vsce publish

6. 实际API集成

上面的代码中,我们使用了模拟的API调用。实际集成LongCat-Image-Edit时,你需要根据官方API文档修改_callLongCatAPI方法。

这里是一个示例实现:

private async _callLongCatAPI(imageData: string, instruction: string): Promise<any> { const config = vscode.workspace.getConfiguration('longcat'); const apiUrl = config.get('apiEndpoint', 'https://api.example.com/longcat/edit'); const apiKey = config.get('apiKey', ''); if (!apiKey) { throw new Error('LongCat API key not configured. Please set "longcat.apiKey" in settings.'); } // 移除base64前缀 const base64Data = imageData.replace(/^data:image\/\w+;base64,/, ''); const requestBody = { image: base64Data, instruction: instruction, parameters: { quality: "high", format: "png" } }; try { const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`API request failed: ${response.status} ${response.statusText}`); } const result = await response.json(); if (!result.success) { throw new Error(result.message || 'API returned error'); } // 假设API返回base64格式的图片 return { success: true, editedImage: `data:image/png;base64,${result.edited_image}`, message: result.message }; } catch (error: any) { throw new Error(`API call failed: ${error.message}`); } }

获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 3:45:46

RexUniNLU在电商评论情感分析中的实战效果对比

RexUniNLU在电商评论情感分析中的实战效果对比 电商平台每天都会产生海量的用户评论&#xff0c;这些文字里藏着用户的真实感受、产品的问题反馈&#xff0c;甚至是潜在的购买动机。过去&#xff0c;想从这些评论里挖出有价值的信息&#xff0c;要么靠人工一条条看&#xff0c…

作者头像 李华
网站建设 2026/4/27 18:27:19

MySQL连表更新:高效数据同步实战指南

在数据库开发中&#xff0c;连表更新&#xff08;JOIN UPDATE&#xff09;是一种常见且强大的操作&#xff0c;它允许我们基于关联表的数据来更新目标表。本文将深入探讨MySQL连表更新的语法、应用场景、性能优化及常见陷阱&#xff0c;帮助开发者掌握这一核心技能。 一、为什么…

作者头像 李华
网站建设 2026/4/27 4:14:37

GPEN一文详解:专为人脸设计的AI增强系统,告别模糊与失真

GPEN一文详解&#xff1a;专为人脸设计的AI增强系统&#xff0c;告别模糊与失真 你有没有遇到过这样的烦恼&#xff1f;翻看老照片时&#xff0c;家人的脸庞模糊不清&#xff1b;手机抓拍的瞬间&#xff0c;人脸因为抖动糊成一团&#xff1b;甚至用AI生成的图片&#xff0c;五…

作者头像 李华
网站建设 2026/4/27 22:55:43

AI显微镜-Swin2SR应用场景:Midjourney出图4倍放大打印全流程解析

AI显微镜-Swin2SR应用场景&#xff1a;Midjourney出图4倍放大打印全流程解析 你有没有遇到过这样的烦恼&#xff1f;用Midjourney生成了一张特别满意的图&#xff0c;想打印出来挂墙上&#xff0c;结果发现原图只有512x512像素&#xff0c;一放大全是马赛克&#xff0c;根本没…

作者头像 李华
网站建设 2026/4/28 10:37:27

Z-Image Turbo实操手册:从Prompt输入到图像输出全过程

Z-Image Turbo实操手册&#xff1a;从Prompt输入到图像输出全过程 1. 快速了解Z-Image Turbo Z-Image Turbo是一个专门为AI绘画爱好者打造的本地极速画板工具。它基于Gradio和Diffusers技术构建&#xff0c;提供了一个简单易用的网页界面&#xff0c;让你不需要复杂的命令行操…

作者头像 李华