Qwen3-VL-8B项目实战构建一个简单的AI绘画描述词优化工具你有没有遇到过这样的情况看到一张特别喜欢的画无论是网上的插画还是自己拍的照片都想用AI绘画工具生成一张风格类似的但就是不知道该怎么描述。自己写的提示词要么太笼统要么缺了关键的细节出来的图总感觉差了点意思。今天我们就来动手解决这个问题。我将带你一起用Qwen3-VL-8B这个强大的多模态大模型搭建一个简单实用的Web工具。它的核心功能很直接你上传一张图片它帮你“看懂”图片里的内容然后生成一组详细、风格化的描述词。这些描述词可以直接复制粘贴到Stable Diffusion、Midjourney等工具里帮你快速生成风格一致的图像。整个过程不复杂我们会从前端界面、后端逻辑到模型API调用一步步走通。即使你之前没有太多全栈开发经验跟着做下来也能收获一个能跑起来的实用小项目。1. 项目目标与核心思路在开始写代码之前我们先明确一下这个工具要做什么以及我们打算怎么做。核心目标制作一个网页用户能上传图片网页能返回一组高质量的、可用于文生图模型的描述词。为什么选择Qwen3-VL-8BQwen3-VL-8B是一个能同时理解图像和文本的模型。它不仅能识别图片里的物体、场景、人物还能理解风格、构图、光影这些更抽象的元素。让它来“看图说话”生成适合AI绘画的提示词再合适不过了。我们的实现思路前端做一个简洁的网页有上传图片的按钮和展示结果的区域。后端用Python的Flask框架搭建一个简单的服务器接收前端传来的图片。模型调用后端接收到图片后调用Qwen3-VL-8B的API这里我们使用兼容OpenAI API格式的接口方便调用让模型分析图片并生成描述词。结果返回后端把模型生成的描述词整理好再传回前端展示给用户。整个数据流就是用户上传图片 - 前端发给后端 - 后端调用模型API - 模型返回分析结果 - 后端处理后返回前端 - 前端展示结果。听起来是不是挺清晰的接下来我们就分步实现。2. 环境准备与项目搭建我们先来把项目的基础架子搭好安装必要的工具包。2.1 创建项目目录与虚拟环境打开你的终端或命令行工具执行以下命令# 创建一个新的项目文件夹 mkdir qwen-vl-prompt-helper cd qwen-vl-prompt-helper # 创建一个Python虚拟环境推荐使用Python 3.8以上版本 python -m venv venv # 激活虚拟环境 # 在Windows上 venv\Scripts\activate # 在MacOS/Linux上 source venv/bin/activate激活虚拟环境后你的命令行提示符前面通常会显示(venv)这表示你已经在这个独立的环境里了。2.2 安装必要的Python包我们需要安装几个关键的包Flask: 用来构建我们的Web后端。openai: 虽然我们调用的是Qwen的API但其兼容OpenAI的格式用这个库很方便。Pillow或opencv-python: 用于基础的图像处理如格式验证。这里我们用轻量的Pillow。python-dotenv: 用来管理API密钥等配置信息避免硬编码在代码里。在激活的虚拟环境中运行pip install flask openai pillow python-dotenv安装完成后我们可以开始编写代码了。3. 后端开发Flask服务器与模型集成后端是整个工具的大脑负责处理请求、调用模型和返回结果。我们分两部分来写主应用文件和配置文件。3.1 创建配置文件首先创建一个名为.env的文件注意前面有个点用来存放我们的敏感配置比如API的访问地址和密钥。# .env 文件内容 OPENAI_API_BASEhttps://your-qwen-vl-api-endpoint.com/v1 # 替换为实际的Qwen VL API地址 OPENAI_API_KEYyour-api-key-here # 替换为你的API密钥 MODEL_NAMEQwen/Qwen2.5-VL-8B-Instruct # 指定使用的模型名称重要提示你需要将OPENAI_API_BASE和OPENAI_API_KEY替换成你自己可用的Qwen3-VL-8B API服务信息。许多云服务商或开源部署方案都提供了兼容OpenAI API的接口。3.2 编写Flask主应用接下来创建主程序文件app.py。# app.py import os from flask import Flask, request, jsonify, render_template from openai import OpenAI from PIL import Image import io import base64 from dotenv import load_dotenv # 加载.env文件中的环境变量 load_dotenv() app Flask(__name__) # 初始化OpenAI客户端指向我们的Qwen VL API client OpenAI( base_urlos.getenv(OPENAI_API_BASE), api_keyos.getenv(OPENAI_API_KEY), ) def analyze_image_and_generate_prompt(image_data): 核心函数调用Qwen3-VL-8B分析图片并生成绘画描述词。 # 准备消息引导模型生成适合AI绘画的提示词 messages [ { role: user, content: [ { type: text, text: 请详细分析这张图片的内容、风格、构图、色彩和氛围。然后生成一段详细、风格化的英文描述词Prompt这段描述词将直接用于Stable Diffusion这类文生图模型以生成风格和内容相似的图像。描述词需要包含主体、细节、艺术风格、画质、光照等关键元素。请只输出最终的描述词文本不要有其他解释。 }, { type: image_url, image_url: { url: fdata:image/jpeg;base64,{image_data} } } ] } ] try: response client.chat.completions.create( modelos.getenv(MODEL_NAME), messagesmessages, max_tokens500, # 描述词可能较长适当增加token限制 temperature0.7, # 保持一定的创造性 ) # 提取模型返回的文本内容 prompt_text response.choices[0].message.content.strip() return prompt_text except Exception as e: print(f调用模型API时出错: {e}) return None app.route(/) def index(): 提供前端HTML页面 return render_template(index.html) app.route(/analyze, methods[POST]) def analyze(): 处理图片上传和分析请求 if image not in request.files: return jsonify({error: 没有上传图片文件}), 400 file request.files[image] # 简单的文件类型校验 if file.filename : return jsonify({error: 未选择文件}), 400 if not file.content_type.startswith(image/): return jsonify({error: 请上传图片文件}), 400 try: # 读取图片文件并转换为base64编码这是API要求的格式之一 img_bytes file.read() img_base64 base64.b64encode(img_bytes).decode(utf-8) # 调用分析函数 generated_prompt analyze_image_and_generate_prompt(img_base64) if generated_prompt: return jsonify({ success: True, prompt: generated_prompt }) else: return jsonify({error: 模型分析失败请重试}), 500 except Exception as e: print(f服务器处理错误: {e}) return jsonify({error: 服务器处理图片时出错}), 500 if __name__ __main__: # 创建templates文件夹如果不存在 os.makedirs(templates, exist_okTrue) # 运行Flask开发服务器 app.run(debugTrue, host0.0.0.0, port5000)这段代码做了几件事设置了Flask应用和OpenAI客户端指向我们的Qwen API。定义了一个核心函数analyze_image_and_generate_prompt它构建请求消息调用模型并返回生成的描述词。我们通过精心设计的提示词Prompt来引导模型输出我们想要的格式。提供了两个路由/返回前端页面/analyze处理图片上传和分析的POST请求。在/analyze路由中我们接收图片转换成base64格式调用上面的分析函数最后将结果以JSON格式返回。4. 前端开发用户交互界面后端准备好了我们需要一个界面让用户能上传图片和看到结果。在templates文件夹下创建index.html。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleAI绘画描述词优化工具 - 基于Qwen3-VL-8B/title style * { box-sizing: border-box; margin: 0; padding: 0; font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; } .container { background-color: white; border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); width: 100%; max-width: 900px; overflow: hidden; padding: 40px; } header { text-align: center; margin-bottom: 40px; } h1 { color: #2d3436; margin-bottom: 10px; font-size: 2.5em; } .subtitle { color: #636e72; font-size: 1.1em; line-height: 1.6; } .upload-area { border: 3px dashed #74b9ff; border-radius: 15px; padding: 60px 20px; text-align: center; margin-bottom: 30px; cursor: pointer; transition: all 0.3s ease; background-color: #f8f9fa; } .upload-area:hover, .upload-area.dragover { background-color: #e3f2fd; border-color: #0984e3; } .upload-icon { font-size: 48px; color: #74b9ff; margin-bottom: 20px; } .upload-text { font-size: 18px; color: #2d3436; margin-bottom: 10px; } .upload-hint { color: #636e72; font-size: 14px; } #fileInput { display: none; } .preview-section { display: flex; flex-wrap: wrap; gap: 30px; margin-bottom: 40px; } .image-preview, .result-panel { flex: 1; min-width: 300px; } .panel-title { font-size: 1.3em; color: #2d3436; padding-bottom: 10px; margin-bottom: 15px; border-bottom: 2px solid #dfe6e9; } #previewImage { width: 100%; max-height: 400px; object-fit: contain; border-radius: 10px; border: 1px solid #ddd; display: none; /* 初始隐藏 */ } #promptOutput { width: 100%; height: 350px; padding: 20px; border: 1px solid #b2bec3; border-radius: 10px; background-color: #f8f9fa; font-family: Courier New, monospace; font-size: 15px; line-height: 1.5; resize: vertical; white-space: pre-wrap; word-wrap: break-word; overflow-y: auto; } .button-group { text-align: center; margin-top: 20px; } button { background-color: #0984e3; color: white; border: none; padding: 15px 40px; font-size: 18px; border-radius: 50px; cursor: pointer; transition: background-color 0.3s; margin: 0 10px; } button:hover { background-color: #0770c4; } button:disabled { background-color: #b2bec3; cursor: not-allowed; } #copyBtn { background-color: #00b894; } #copyBtn:hover:not(:disabled) { background-color: #00a085; } .status { text-align: center; margin-top: 20px; min-height: 24px; font-weight: bold; } .success { color: #00b894; } .error { color: #d63031; } .loading { color: #fdcb6e; } footer { text-align: center; margin-top: 40px; color: #636e72; font-size: 0.9em; border-top: 1px solid #dfe6e9; padding-top: 20px; } /style /head body div classcontainer header h1 AI绘画描述词优化工具/h1 p classsubtitle 上传你的绘画、照片或任何图像基于Qwen3-VL-8B模型智能分析一键生成可用于Stable Diffusion、Midjourney等工具的详细风格化提示词Prompt。 /p /header main !-- 图片上传区域 -- div classupload-area iduploadArea div classupload-icon/div p classupload-text点击选择或拖拽图片到此处/p p classupload-hint支持 JPG, PNG, WEBP 等格式建议尺寸小于5MB/p input typefile idfileInput acceptimage/* /div !-- 预览与结果区域 -- div classpreview-section div classimage-preview h3 classpanel-title图片预览/h3 img idpreviewImage alt预览图片 /div div classresult-panel h3 classpanel-title生成的描述词 (Prompt)/h3 textarea idpromptOutput readonly placeholder生成的描述词将显示在这里.../textarea /div /div !-- 按钮组 -- div classbutton-group button idanalyzeBtn disabled开始分析图片/button button idcopyBtn disabled复制描述词/button /div !-- 状态提示 -- div classstatus idstatusMessage/div /main footer p本项目基于 Qwen3-VL-8B 多模态大模型构建 | 提示词生成结果可用于主流文生图工具/p /footer /div script // DOM元素 const fileInput document.getElementById(fileInput); const uploadArea document.getElementById(uploadArea); const previewImage document.getElementById(previewImage); const promptOutput document.getElementById(promptOutput); const analyzeBtn document.getElementById(analyzeBtn); const copyBtn document.getElementById(copyBtn); const statusMessage document.getElementById(statusMessage); let currentImageFile null; // 点击上传区域触发文件选择 uploadArea.addEventListener(click, () fileInput.click()); // 文件选择变化事件 fileInput.addEventListener(change, function(e) { if (this.files this.files[0]) { handleImageFile(this.files[0]); } }); // 拖拽上传事件 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); if (e.dataTransfer.files e.dataTransfer.files[0]) { handleImageFile(e.dataTransfer.files[0]); fileInput.files e.dataTransfer.files; // 同步到file input } }); // 处理选中的图片文件 function handleImageFile(file) { // 简单校验 if (!file.type.startsWith(image/)) { showStatus(请选择图片文件, error); return; } if (file.size 5 * 1024 * 1024) { showStatus(图片大小请控制在5MB以内。, error); return; } currentImageFile file; // 预览图片 const reader new FileReader(); reader.onload function(e) { previewImage.src e.target.result; previewImage.style.display block; }; reader.readAsDataURL(file); // 启用分析按钮清空旧结果 analyzeBtn.disabled false; promptOutput.value ; copyBtn.disabled true; showStatus(图片已就绪点击“开始分析图片”生成描述词。, success); } // 分析按钮点击事件 analyzeBtn.addEventListener(click, async () { if (!currentImageFile) return; analyzeBtn.disabled true; showStatus(正在调用模型分析图片请稍候..., loading); const formData new FormData(); formData.append(image, currentImageFile); try { const response await fetch(/analyze, { method: POST, body: formData }); const result await response.json(); if (result.success) { promptOutput.value result.prompt; copyBtn.disabled false; showStatus(描述词生成成功你可以复制并使用它了。, success); } else { showStatus(生成失败: ${result.error}, error); } } catch (error) { console.error(请求失败:, error); showStatus(网络请求失败请检查后端服务是否运行。, error); } finally { analyzeBtn.disabled false; } }); // 复制按钮点击事件 copyBtn.addEventListener(click, async () { if (!promptOutput.value) return; try { await navigator.clipboard.writeText(promptOutput.value); showStatus(描述词已复制到剪贴板, success); // 可选提供一点视觉反馈 const originalText copyBtn.textContent; copyBtn.textContent 已复制; setTimeout(() { copyBtn.textContent originalText; }, 1500); } catch (err) { console.error(复制失败:, err); showStatus(复制失败请手动选择文本复制。, error); } }); // 显示状态信息 function showStatus(message, type ) { statusMessage.textContent message; statusMessage.className status ${type}; } /script /body /html这个前端页面看起来挺清爽的功能也齐全支持点击和拖拽两种方式上传图片。实时预览上传的图片。点击“开始分析图片”按钮将图片发送到后端。在一个文本框中展示模型生成的描述词。提供“复制描述词”按钮方便一键复制。5. 运行与测试代码都写好了让我们来启动项目看看效果。确保你在项目根目录qwen-vl-prompt-helper并且虚拟环境是激活状态。运行Flask应用python app.py你应该会看到类似这样的输出* Serving Flask app app * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://你的本地IP:5000打开浏览器访问http://127.0.0.1:5000。上传一张图片测试。你可以找一张风格鲜明的插画、风景照或者人像。点击或拖拽上传后再点击“开始分析图片”。等待并查看结果。几秒到十几秒后取决于模型API的速度右侧文本框里就会出现生成的描述词了。效果示例 我上传了一张赛博朋克风格的城市夜景图。工具生成的描述词大概是这样的A breathtaking cyberpunk cityscape at night, neon-lit rain-slicked streets, towering skyscrapers with holographic advertisements, flying cars leaving light trails, dense fog and atmospheric glow, vibrant colors of pink, blue, and purple, highly detailed, cinematic lighting, wide-angle view, digital painting, trending on ArtStation, by artists like Simon Stålenhag and Ash Thorp, 8K resolution, ultra-realistic, unreal engine 5.这段描述词非常详细包含了场景、细节、色彩、风格、画质甚至参考艺术家直接用到Stable Diffusion里很容易就能生成风格类似的图片。6. 项目总结与扩展思路跟着走完这一趟我们已经成功搭建了一个能实际使用的AI绘画辅助工具。它虽然简单但完整地串联了前端交互、后端逻辑和AI模型调用解决了一个很具体的需求。回顾一下我们做了什么 我们用Flask快速搭建了Web后端用HTML/CSS/JavaScript做了一个直观的前端界面然后通过调用Qwen3-VL-8B的API赋予了工具“看懂”图片并“专业描述”图片的能力。整个流程是通的代码也是可运行的。如果你还想让这个工具变得更强大可以试试这些方向描述词风格定制在界面上加几个选项让用户选择想要生成的描述词风格比如“简洁实用型”、“极致细节型”、“特定艺术家风格模仿型”。后端根据选择动态修改发给模型的提示词Prompt。多图对比与融合允许用户上传2-3张图片让模型分析它们的共同点生成一个融合了多图特点的描述词。历史记录与收藏引入简单的数据库比如SQLite让用户可以保存自己生成过的描述词和原图。一键试画集成一个开源的Stable Diffusion WebUI的API在生成描述词后加一个“用此描述词试画”的按钮直接在本工具里看到生成的画作形成闭环。部署上线使用Docker将项目容器化然后部署到云服务器或容器平台让更多人能访问使用。这个项目就像一颗种子展示了如何将前沿的大模型能力通过不算复杂的工程手段封装成一个解决实际问题的应用。希望它不仅能帮你快速生成提示词更能给你带来一些关于AI应用落地的启发。动手去改它、扩展它才是学习的最佳方式。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
Qwen3-VL-8B项目实战:构建一个简单的AI绘画描述词优化工具
Qwen3-VL-8B项目实战构建一个简单的AI绘画描述词优化工具你有没有遇到过这样的情况看到一张特别喜欢的画无论是网上的插画还是自己拍的照片都想用AI绘画工具生成一张风格类似的但就是不知道该怎么描述。自己写的提示词要么太笼统要么缺了关键的细节出来的图总感觉差了点意思。今天我们就来动手解决这个问题。我将带你一起用Qwen3-VL-8B这个强大的多模态大模型搭建一个简单实用的Web工具。它的核心功能很直接你上传一张图片它帮你“看懂”图片里的内容然后生成一组详细、风格化的描述词。这些描述词可以直接复制粘贴到Stable Diffusion、Midjourney等工具里帮你快速生成风格一致的图像。整个过程不复杂我们会从前端界面、后端逻辑到模型API调用一步步走通。即使你之前没有太多全栈开发经验跟着做下来也能收获一个能跑起来的实用小项目。1. 项目目标与核心思路在开始写代码之前我们先明确一下这个工具要做什么以及我们打算怎么做。核心目标制作一个网页用户能上传图片网页能返回一组高质量的、可用于文生图模型的描述词。为什么选择Qwen3-VL-8BQwen3-VL-8B是一个能同时理解图像和文本的模型。它不仅能识别图片里的物体、场景、人物还能理解风格、构图、光影这些更抽象的元素。让它来“看图说话”生成适合AI绘画的提示词再合适不过了。我们的实现思路前端做一个简洁的网页有上传图片的按钮和展示结果的区域。后端用Python的Flask框架搭建一个简单的服务器接收前端传来的图片。模型调用后端接收到图片后调用Qwen3-VL-8B的API这里我们使用兼容OpenAI API格式的接口方便调用让模型分析图片并生成描述词。结果返回后端把模型生成的描述词整理好再传回前端展示给用户。整个数据流就是用户上传图片 - 前端发给后端 - 后端调用模型API - 模型返回分析结果 - 后端处理后返回前端 - 前端展示结果。听起来是不是挺清晰的接下来我们就分步实现。2. 环境准备与项目搭建我们先来把项目的基础架子搭好安装必要的工具包。2.1 创建项目目录与虚拟环境打开你的终端或命令行工具执行以下命令# 创建一个新的项目文件夹 mkdir qwen-vl-prompt-helper cd qwen-vl-prompt-helper # 创建一个Python虚拟环境推荐使用Python 3.8以上版本 python -m venv venv # 激活虚拟环境 # 在Windows上 venv\Scripts\activate # 在MacOS/Linux上 source venv/bin/activate激活虚拟环境后你的命令行提示符前面通常会显示(venv)这表示你已经在这个独立的环境里了。2.2 安装必要的Python包我们需要安装几个关键的包Flask: 用来构建我们的Web后端。openai: 虽然我们调用的是Qwen的API但其兼容OpenAI的格式用这个库很方便。Pillow或opencv-python: 用于基础的图像处理如格式验证。这里我们用轻量的Pillow。python-dotenv: 用来管理API密钥等配置信息避免硬编码在代码里。在激活的虚拟环境中运行pip install flask openai pillow python-dotenv安装完成后我们可以开始编写代码了。3. 后端开发Flask服务器与模型集成后端是整个工具的大脑负责处理请求、调用模型和返回结果。我们分两部分来写主应用文件和配置文件。3.1 创建配置文件首先创建一个名为.env的文件注意前面有个点用来存放我们的敏感配置比如API的访问地址和密钥。# .env 文件内容 OPENAI_API_BASEhttps://your-qwen-vl-api-endpoint.com/v1 # 替换为实际的Qwen VL API地址 OPENAI_API_KEYyour-api-key-here # 替换为你的API密钥 MODEL_NAMEQwen/Qwen2.5-VL-8B-Instruct # 指定使用的模型名称重要提示你需要将OPENAI_API_BASE和OPENAI_API_KEY替换成你自己可用的Qwen3-VL-8B API服务信息。许多云服务商或开源部署方案都提供了兼容OpenAI API的接口。3.2 编写Flask主应用接下来创建主程序文件app.py。# app.py import os from flask import Flask, request, jsonify, render_template from openai import OpenAI from PIL import Image import io import base64 from dotenv import load_dotenv # 加载.env文件中的环境变量 load_dotenv() app Flask(__name__) # 初始化OpenAI客户端指向我们的Qwen VL API client OpenAI( base_urlos.getenv(OPENAI_API_BASE), api_keyos.getenv(OPENAI_API_KEY), ) def analyze_image_and_generate_prompt(image_data): 核心函数调用Qwen3-VL-8B分析图片并生成绘画描述词。 # 准备消息引导模型生成适合AI绘画的提示词 messages [ { role: user, content: [ { type: text, text: 请详细分析这张图片的内容、风格、构图、色彩和氛围。然后生成一段详细、风格化的英文描述词Prompt这段描述词将直接用于Stable Diffusion这类文生图模型以生成风格和内容相似的图像。描述词需要包含主体、细节、艺术风格、画质、光照等关键元素。请只输出最终的描述词文本不要有其他解释。 }, { type: image_url, image_url: { url: fdata:image/jpeg;base64,{image_data} } } ] } ] try: response client.chat.completions.create( modelos.getenv(MODEL_NAME), messagesmessages, max_tokens500, # 描述词可能较长适当增加token限制 temperature0.7, # 保持一定的创造性 ) # 提取模型返回的文本内容 prompt_text response.choices[0].message.content.strip() return prompt_text except Exception as e: print(f调用模型API时出错: {e}) return None app.route(/) def index(): 提供前端HTML页面 return render_template(index.html) app.route(/analyze, methods[POST]) def analyze(): 处理图片上传和分析请求 if image not in request.files: return jsonify({error: 没有上传图片文件}), 400 file request.files[image] # 简单的文件类型校验 if file.filename : return jsonify({error: 未选择文件}), 400 if not file.content_type.startswith(image/): return jsonify({error: 请上传图片文件}), 400 try: # 读取图片文件并转换为base64编码这是API要求的格式之一 img_bytes file.read() img_base64 base64.b64encode(img_bytes).decode(utf-8) # 调用分析函数 generated_prompt analyze_image_and_generate_prompt(img_base64) if generated_prompt: return jsonify({ success: True, prompt: generated_prompt }) else: return jsonify({error: 模型分析失败请重试}), 500 except Exception as e: print(f服务器处理错误: {e}) return jsonify({error: 服务器处理图片时出错}), 500 if __name__ __main__: # 创建templates文件夹如果不存在 os.makedirs(templates, exist_okTrue) # 运行Flask开发服务器 app.run(debugTrue, host0.0.0.0, port5000)这段代码做了几件事设置了Flask应用和OpenAI客户端指向我们的Qwen API。定义了一个核心函数analyze_image_and_generate_prompt它构建请求消息调用模型并返回生成的描述词。我们通过精心设计的提示词Prompt来引导模型输出我们想要的格式。提供了两个路由/返回前端页面/analyze处理图片上传和分析的POST请求。在/analyze路由中我们接收图片转换成base64格式调用上面的分析函数最后将结果以JSON格式返回。4. 前端开发用户交互界面后端准备好了我们需要一个界面让用户能上传图片和看到结果。在templates文件夹下创建index.html。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleAI绘画描述词优化工具 - 基于Qwen3-VL-8B/title style * { box-sizing: border-box; margin: 0; padding: 0; font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; } .container { background-color: white; border-radius: 20px; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); width: 100%; max-width: 900px; overflow: hidden; padding: 40px; } header { text-align: center; margin-bottom: 40px; } h1 { color: #2d3436; margin-bottom: 10px; font-size: 2.5em; } .subtitle { color: #636e72; font-size: 1.1em; line-height: 1.6; } .upload-area { border: 3px dashed #74b9ff; border-radius: 15px; padding: 60px 20px; text-align: center; margin-bottom: 30px; cursor: pointer; transition: all 0.3s ease; background-color: #f8f9fa; } .upload-area:hover, .upload-area.dragover { background-color: #e3f2fd; border-color: #0984e3; } .upload-icon { font-size: 48px; color: #74b9ff; margin-bottom: 20px; } .upload-text { font-size: 18px; color: #2d3436; margin-bottom: 10px; } .upload-hint { color: #636e72; font-size: 14px; } #fileInput { display: none; } .preview-section { display: flex; flex-wrap: wrap; gap: 30px; margin-bottom: 40px; } .image-preview, .result-panel { flex: 1; min-width: 300px; } .panel-title { font-size: 1.3em; color: #2d3436; padding-bottom: 10px; margin-bottom: 15px; border-bottom: 2px solid #dfe6e9; } #previewImage { width: 100%; max-height: 400px; object-fit: contain; border-radius: 10px; border: 1px solid #ddd; display: none; /* 初始隐藏 */ } #promptOutput { width: 100%; height: 350px; padding: 20px; border: 1px solid #b2bec3; border-radius: 10px; background-color: #f8f9fa; font-family: Courier New, monospace; font-size: 15px; line-height: 1.5; resize: vertical; white-space: pre-wrap; word-wrap: break-word; overflow-y: auto; } .button-group { text-align: center; margin-top: 20px; } button { background-color: #0984e3; color: white; border: none; padding: 15px 40px; font-size: 18px; border-radius: 50px; cursor: pointer; transition: background-color 0.3s; margin: 0 10px; } button:hover { background-color: #0770c4; } button:disabled { background-color: #b2bec3; cursor: not-allowed; } #copyBtn { background-color: #00b894; } #copyBtn:hover:not(:disabled) { background-color: #00a085; } .status { text-align: center; margin-top: 20px; min-height: 24px; font-weight: bold; } .success { color: #00b894; } .error { color: #d63031; } .loading { color: #fdcb6e; } footer { text-align: center; margin-top: 40px; color: #636e72; font-size: 0.9em; border-top: 1px solid #dfe6e9; padding-top: 20px; } /style /head body div classcontainer header h1 AI绘画描述词优化工具/h1 p classsubtitle 上传你的绘画、照片或任何图像基于Qwen3-VL-8B模型智能分析一键生成可用于Stable Diffusion、Midjourney等工具的详细风格化提示词Prompt。 /p /header main !-- 图片上传区域 -- div classupload-area iduploadArea div classupload-icon/div p classupload-text点击选择或拖拽图片到此处/p p classupload-hint支持 JPG, PNG, WEBP 等格式建议尺寸小于5MB/p input typefile idfileInput acceptimage/* /div !-- 预览与结果区域 -- div classpreview-section div classimage-preview h3 classpanel-title图片预览/h3 img idpreviewImage alt预览图片 /div div classresult-panel h3 classpanel-title生成的描述词 (Prompt)/h3 textarea idpromptOutput readonly placeholder生成的描述词将显示在这里.../textarea /div /div !-- 按钮组 -- div classbutton-group button idanalyzeBtn disabled开始分析图片/button button idcopyBtn disabled复制描述词/button /div !-- 状态提示 -- div classstatus idstatusMessage/div /main footer p本项目基于 Qwen3-VL-8B 多模态大模型构建 | 提示词生成结果可用于主流文生图工具/p /footer /div script // DOM元素 const fileInput document.getElementById(fileInput); const uploadArea document.getElementById(uploadArea); const previewImage document.getElementById(previewImage); const promptOutput document.getElementById(promptOutput); const analyzeBtn document.getElementById(analyzeBtn); const copyBtn document.getElementById(copyBtn); const statusMessage document.getElementById(statusMessage); let currentImageFile null; // 点击上传区域触发文件选择 uploadArea.addEventListener(click, () fileInput.click()); // 文件选择变化事件 fileInput.addEventListener(change, function(e) { if (this.files this.files[0]) { handleImageFile(this.files[0]); } }); // 拖拽上传事件 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); if (e.dataTransfer.files e.dataTransfer.files[0]) { handleImageFile(e.dataTransfer.files[0]); fileInput.files e.dataTransfer.files; // 同步到file input } }); // 处理选中的图片文件 function handleImageFile(file) { // 简单校验 if (!file.type.startsWith(image/)) { showStatus(请选择图片文件, error); return; } if (file.size 5 * 1024 * 1024) { showStatus(图片大小请控制在5MB以内。, error); return; } currentImageFile file; // 预览图片 const reader new FileReader(); reader.onload function(e) { previewImage.src e.target.result; previewImage.style.display block; }; reader.readAsDataURL(file); // 启用分析按钮清空旧结果 analyzeBtn.disabled false; promptOutput.value ; copyBtn.disabled true; showStatus(图片已就绪点击“开始分析图片”生成描述词。, success); } // 分析按钮点击事件 analyzeBtn.addEventListener(click, async () { if (!currentImageFile) return; analyzeBtn.disabled true; showStatus(正在调用模型分析图片请稍候..., loading); const formData new FormData(); formData.append(image, currentImageFile); try { const response await fetch(/analyze, { method: POST, body: formData }); const result await response.json(); if (result.success) { promptOutput.value result.prompt; copyBtn.disabled false; showStatus(描述词生成成功你可以复制并使用它了。, success); } else { showStatus(生成失败: ${result.error}, error); } } catch (error) { console.error(请求失败:, error); showStatus(网络请求失败请检查后端服务是否运行。, error); } finally { analyzeBtn.disabled false; } }); // 复制按钮点击事件 copyBtn.addEventListener(click, async () { if (!promptOutput.value) return; try { await navigator.clipboard.writeText(promptOutput.value); showStatus(描述词已复制到剪贴板, success); // 可选提供一点视觉反馈 const originalText copyBtn.textContent; copyBtn.textContent 已复制; setTimeout(() { copyBtn.textContent originalText; }, 1500); } catch (err) { console.error(复制失败:, err); showStatus(复制失败请手动选择文本复制。, error); } }); // 显示状态信息 function showStatus(message, type ) { statusMessage.textContent message; statusMessage.className status ${type}; } /script /body /html这个前端页面看起来挺清爽的功能也齐全支持点击和拖拽两种方式上传图片。实时预览上传的图片。点击“开始分析图片”按钮将图片发送到后端。在一个文本框中展示模型生成的描述词。提供“复制描述词”按钮方便一键复制。5. 运行与测试代码都写好了让我们来启动项目看看效果。确保你在项目根目录qwen-vl-prompt-helper并且虚拟环境是激活状态。运行Flask应用python app.py你应该会看到类似这样的输出* Serving Flask app app * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://你的本地IP:5000打开浏览器访问http://127.0.0.1:5000。上传一张图片测试。你可以找一张风格鲜明的插画、风景照或者人像。点击或拖拽上传后再点击“开始分析图片”。等待并查看结果。几秒到十几秒后取决于模型API的速度右侧文本框里就会出现生成的描述词了。效果示例 我上传了一张赛博朋克风格的城市夜景图。工具生成的描述词大概是这样的A breathtaking cyberpunk cityscape at night, neon-lit rain-slicked streets, towering skyscrapers with holographic advertisements, flying cars leaving light trails, dense fog and atmospheric glow, vibrant colors of pink, blue, and purple, highly detailed, cinematic lighting, wide-angle view, digital painting, trending on ArtStation, by artists like Simon Stålenhag and Ash Thorp, 8K resolution, ultra-realistic, unreal engine 5.这段描述词非常详细包含了场景、细节、色彩、风格、画质甚至参考艺术家直接用到Stable Diffusion里很容易就能生成风格类似的图片。6. 项目总结与扩展思路跟着走完这一趟我们已经成功搭建了一个能实际使用的AI绘画辅助工具。它虽然简单但完整地串联了前端交互、后端逻辑和AI模型调用解决了一个很具体的需求。回顾一下我们做了什么 我们用Flask快速搭建了Web后端用HTML/CSS/JavaScript做了一个直观的前端界面然后通过调用Qwen3-VL-8B的API赋予了工具“看懂”图片并“专业描述”图片的能力。整个流程是通的代码也是可运行的。如果你还想让这个工具变得更强大可以试试这些方向描述词风格定制在界面上加几个选项让用户选择想要生成的描述词风格比如“简洁实用型”、“极致细节型”、“特定艺术家风格模仿型”。后端根据选择动态修改发给模型的提示词Prompt。多图对比与融合允许用户上传2-3张图片让模型分析它们的共同点生成一个融合了多图特点的描述词。历史记录与收藏引入简单的数据库比如SQLite让用户可以保存自己生成过的描述词和原图。一键试画集成一个开源的Stable Diffusion WebUI的API在生成描述词后加一个“用此描述词试画”的按钮直接在本工具里看到生成的画作形成闭环。部署上线使用Docker将项目容器化然后部署到云服务器或容器平台让更多人能访问使用。这个项目就像一颗种子展示了如何将前沿的大模型能力通过不算复杂的工程手段封装成一个解决实际问题的应用。希望它不仅能帮你快速生成提示词更能给你带来一些关于AI应用落地的启发。动手去改它、扩展它才是学习的最佳方式。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。