写技术文章时,配图工作往往占用不少时间——封面需要概括主题,正文插图需对应具体段落,生成后还可能要调整标题、比例或局部元素。过去我的做法是逐段整理提示词,分别生成和修改图片,流程分散且重复。这次我尝试把这些步骤整合到一个工具中,记录下实现过程中涉及模型接入、任务编排和本地开发环境问题的处理方式。
工具概览
这个工具暂命名为「博文视觉生成器」。上传 Markdown 文档后,可以运行“AI 智能规划配图”,也可以单独选择全文或某个段落,生成封面或正文插图。
- 文本模型:通过蓝耘MaaS接入 GLM5.3(控制台模型ID为
glm-5.3)。 - 视觉模型:图像生成和编辑使用 Sense U1.5 Lite。
项目使用 Vue 3 + Vite 开发,是一个纯前端应用,不含业务后端。界面分左右两栏:左侧是博文文档区(支持上传、编辑、预览和段落选择),右侧是视觉创作区(可选择封面/插图、风格与比例)。
整体调用链路如下:
一、模型服务选型与接入配置
1.1 选型考虑
项目需要在Codex中开发,同时前端要调用文本模型分析长文章,因此接入方式、模型参数清晰度和排错便利性是主要考量。蓝耘MaaS提供OpenAI兼容接口,可以复用现有请求层,只需替换base_url、api_key和模型ID。
接入前检查了以下配置项:
- 接口协议:文档提供OpenAI兼容调用示例。
- 模型字段:确认上下文长度是否能覆盖长文任务,并记录实际调用ID
glm-5.3。 - 模型切换方式:同类兼容接口便于后续对照测试。
- 密钥与用量查询:API Key按项目创建,资源包页面可查看剩余量。

图1 蓝耘接口文档

图2 蓝耘用量监控

图3 蓝耘模型列表
1.2 Codex 与 CC Switch 配置
日常使用Codex时,有时额度用尽,需通过CC Switch切换其他模型服务。CC Switch可以保存多个供应商配置,在界面中切换Provider,更新Codex的模型、端点和认证信息,无需手工编辑配置文件。
Codex使用 ~/.codex/config.toml 保存Provider、模型与端点设置。对于只提供OpenAI Chat Completions接口的第三方服务,需要启用本地路由,将Codex的Responses请求转换为上游支持的格式。
1.3 创建项目专用API Key
在MaaS控制台创建仅限本项目的API Key,确认模型ID为 glm-5.3,并核对OpenAI兼容的基础地址。独立密钥便于隔离问题,测试结束后可停用。

图4 创建API Key
1.4 在CC Switch中配置Provider
CC Switch中新增自定义Provider,关键字段如下:
| CC Switch 字段 | 应填写的内容 | 说明 |
|---|---|---|
| Provider 名称 | 蓝耘-GLM5.3 | 仅用于识别 |
| Base URL | 控制台提供的OpenAI兼容基础地址 | 不是控制台网页地址 |
| API Key | 项目专用Key | 不提交到仓库 |
| 模型 | glm-5.3 | 实际调用ID |
| 接口格式 | 按接口文档选择 | 若只有Chat Completions,需打开本地路由 |
注意:是否开启本地路由取决于上游接口格式,而非模型名称。配置后保存并启用,检查 ~/.codex/config.toml 确认 model_provider、model 和 base_url 已更新。

图5 CC Switch配置
配置后进行连通性测试,确保接口可用。

图6 接口连通测试
1.5 验证Codex模型切换
切换Provider后,重新打开Codex,给出一个具体但不消耗过多额度的任务,例如阅读Vue项目目录结构并给出状态管理建议。验证Codex能否响应、模型名是否来自当前Provider,以及项目上下文是否可读取。

图7 Codex模型验证

图8 Codex理解项目
二、项目创建与初始化
2.1 创建项目
通过初始Prompt生成Vue 3 + Vite项目框架,后续多轮对话补充页面布局、并行任务、图片编辑和错误重试等功能。markdown-it 负责将Markdown转为HTML,dompurify 清理渲染结果。图片生成和编辑请求统一放在 src/services,页面组件只处理状态和交互。

图9 输入初始Prompt

图10 追加开发Prompt

图11 项目目录结构
2.2 页面模型配置
右上角“模型配置”弹窗中填写文本模型和图像模型的服务地址、接口路径、模型ID和API Key。保存后配置写入localStorage,页面顶部显示配置状态。
三、核心实现
3.1 文本模型做视觉策划,而非直接生图
直接让图像模型读全文,容易只抓住表面关键词。因此将“理解文章”和“生成图片”拆开。上传Markdown后,提取标题和内容块,用户可选择全文或段落。createImagePrompt 将选中内容、图片用途、比例和风格发送给GLM5.3,请求中的 model 为 glm-5.3。
核心调用(简化,省略错误处理):
const payload = {
model,
messages: [
{ role: 'system', content: visualDirectorPrompt },
{
role: 'user',
content: `请根据以下${scopeName}生成一条${targetName}指令。
文章标题:${documentTitle}
画面比例:${ratio}
视觉风格:${style}
--- 内容开始 ---
${source}
--- 内容结束 ---`,
},
],
temperature: 0.45,
stream: false,
}
visualDirectorPrompt 约束了输出内容:封面概括全文,插图解释段落;图片中的文字(标题、数字、技术名词)由图像模型生成;只保留一个主标题和不超过三项核心信息;描述构图、层级、配色和留白;不添加原文没有的事实;最终只返回图像指令,不含解释或JSON。
3.2 统一生图和改图工作流
右侧创作区没有将“智能生成”和“图片编辑”硬切为两个页面。用户生成图片后可点击“编辑图片”进入近全屏编辑器;也可先点击“编辑已有图片”上传本地图片。
编辑器保留图片版本列表,编辑指令只描述“要改什么”,例如“把背景改成浅色网格,保留中间标题和流程结构”。编辑时把当前图片、修改要求和输出比例一起发送。
文生图请求:
const payload = {
model,
prompt,
n: 1,
size: editSizeByRatio[ratio] || 'auto',
output_format: 'png',
response_format: 'b64_json',
watermark: true,
prompt_extend: true,
}
图片编辑请求(/images/edits):
const payload = {
model,
images: [{ image_url: imageUrl }],
prompt: instruction,
n: 1,
size: editSizeByRatio[ratio] || 'auto',
response_format: 'b64_json',
watermark: true,
prompt_extend: true,
}
前端不负责二次排字,视觉指令、原图和比例交给模型,标题与技术名词与画面一同生成。
四、实际遇到的问题与处理
4.1 本地开发CORS限制
页面从 http://localhost:5173 直接请求图像接口时触发跨域错误。使用Vite代理解决:
const sensenovaProxy = {
target: 'https://token.sensenova.cn',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/sensenova/, ''),
}
export default defineConfig({
server: {
proxy: {
'/api/sensenova': sensenovaProxy,
},
},
})
请求层将目标地址改写为同源代理路径:
if (target.origin === 'https://token.sensenova.cn') {
return `/api/sensenova${target.pathname}${target.search}`
}
修改后生图和改图接口正常。注意此代理仅开发预览有效,公开部署需服务端配置反向代理或后端代调。
4.2 并行任务提升效率
最初一次只能处理一张图,全篇配图耗时较长。改为独立任务并行执行——先为每条建议创建任务,再立即调用 executeTask,每个任务独立维护 prompting、generating、completed、failed 状态。
taskList.forEach((item) => {
const newTask = {
id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
title: item.title,
status: 'pending',
// ... 其他字段
}
tasks.value.unshift(newTask)
executeTask(newTask)
})
单任务失败不阻塞其他任务。当前仅少量配图,直接并行足够;若需大规模生成,后续可加并发上限和等待队列。
4.3 失败任务保留与重试
生图接口偶发网络中断或服务端错误。失败后不删除任务,而是改为 failed 状态,显示错误信息,并提供“重试”和“重新下发”按钮。
async function executeTask(task) {
task.status = 'prompting'
task.error = ''
try {
task.prompt = await createImagePrompt(/* ... */)
task.status = 'generating'
task.imageUrl = (await generateImage(task.prompt)).imageUrl
task.status = 'completed'
} catch (error) {
task.status = 'failed'
task.error = toErrorMessage(error)
}
}
function retryTask(taskId) {
const task = tasks.value.find(item => item.id === taskId)
if (task) executeTask(task)
}
重试沿用原文章、类型、风格和比例,无需重新填写。目前整条链路重跑,后续可缓存已成功的视觉指令,仅重试生图阶段。
五、效果实测
5.1 上传Markdown
上传包含多个章节、操作步骤和技术名词的Markdown文章,程序正确读取一级标题、字符数、文件大小和内容块数量。

图12 上传Markdown
界面分区清晰:顶部项目名和配置入口;中间左文档右视觉控制台;底部生图任务列表。文档区可在编辑和预览间切换。
5.2 AI智能策划全篇配图
点击“AI 智能策划全篇配图”后,GLM5.3通读文章,优先处理封面、核心流程、参数对比和操作重点,给出标题、理由及对应段落。

图13 全文配图方案
确认方案后,并行创建所有任务,每项任务独立生成视觉指令并调用图像接口。

图14 配图并行生成
任务卡片显示当前阶段和等待时间,图片完成后直接展示,并可展开查看视觉指令。

图15 配图生成完成
此次生成的封面和正文插图均能对应文章主题与具体段落,未变成泛化的背景图。并行任务中个别失败不影响其他任务。
5.3 图片编辑
点击任务卡片中的“微调”或另行上传图片,用自然语言说明修改要求,无需重写整条生图提示词。

图16 图片编辑窗口
例如要求将画面右侧的平板改成两台(安卓平板和iPad),同时保留标题、电脑主体、配色和整体构图。

图17 图片编辑结果
每次编辑生成新版本,原图保留,版本列表可来回切换比较。
5.4 配图回填与导出
图片完成后可逐张插入对应段落,或点击“一键插入到文章”统一处理。封面放在标题附近,正文插图根据任务中保存的段落定位;匹配不到则追加到文末。

图18 插入并导出文章
导出文件在原名称后加“配图版”,不覆盖原始Markdown。图片集中放入 images 子目录。

图19 导出文章预览
重新打开导出的文章,封面和正文插图位置正确,原标题、段落和代码块未被改动。
六、总结与后续方向
本项目通过蓝耘MaaS接入GLM5.3作为文本模型,用于开发阶段(Codex协作)和运行阶段(将全文/段落转换为结构化图像指令),图像生成与编辑由Sense U1.5 Lite负责。两组接口独立,便于分别排查问题。
当前版本是可运行的MVP,后续计划:
- 使用后端代理保护长期密钥;
- 持久化生成记录、提示词对比和调用日志;
- 利用调用记录比较不同文本模型在“长文理解→视觉指令”任务中的表现差异。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/baronbool/article/details/164212403




