# 如何用 ChatGPT 5.5 把一个手绘 Demo，一路补成了能用的 SaaS

> 从「输入一句话生成手绘图」到部署上线，踩遍额度、SDK、产品形态的坑，再把假登录、假账单补成真能跑的东西——一个小项目从 Demo 到能用的 SaaS 的完整记录。

- 原文链接: https://laojin.blog/blog/20260715_handdraw_ai_demo_to_saas
- 作者: 老金
- 发布日期: 2026-07-15
- 标签: AI应用, SaaS, Next.js, Vercel, 产品化

---

![如何用 ChatGPT 5.5 把一个手绘 Demo，一路补成了能用的 SaaS](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260715/00_cover.png)

> 从「输入一句话生成手绘图」到部署上线，中间踩了额度、SDK、产品形态一堆坑，最后把假登录、假账单补成真能跑的东西。记录一个小项目从 0 到「像样」的完整过程。

最近做了一个小项目：HandDraw AI。

一开始它只是个很直接的工具：输入一句描述，选一种手绘风格，生成图片。后来部署、域名、Key、模型额度、产品形态这些问题一个个冒出来，它慢慢从一个生成器变成了 SaaS 雏形。再后来我打开代码才发现，那个 SaaS 只是个空壳——登录、账单、历史全是假的，又花了一轮把它补成真能跑的东西。

这篇把整个过程串起来讲。

## 缘起：先把核心能力跑通

最初的目标很简单：做一个手绘风图片生成器。技术栈选得很轻：

```text
Next.js App Router
TypeScript
Vercel
Gemini Image API
```

前端负责输入画面内容、选风格、传参考图；后端用 Next.js API Route 调图像模型。项目结构大致是：

```text
src/app/page.tsx               主页面
src/app/api/generate/route.ts  生图接口
src/lib/styles.ts              风格配置
src/lib/prompt.ts              Prompt 拼装
public/examples/               风格示例图
```

它内置了 13 种手绘风格——儿童涂色页、蜡笔童涂、xkcd 火柴人、水墨写意、复古像素……每种风格背后都是一段打磨过的提示词模板。

最初版本很像一个「开发者工具」：打开就是编辑器，左边填参数，右边看结果。功能能跑，但产品感很弱。

## API Key 与环境变量

AI 应用第一个绕不开的问题就是 Key 怎么放。本地用 `.env`：

```env
GEMINI_API_KEY=xxx
GEMINI_IMAGE_MODEL=gemini-3.1-flash-image
```

Key 只在服务端 API Route 读取，前端不暴露。同时 `.gitignore` 一定要忽略：

```text
.env
.env*.local
```

这点很重要——AI Key 一旦提交到 GitHub，基本就等于公开了。

## 模型名能用，不代表有额度

开发中反复测了几个模型：

```text
gemini-3-pro-image-preview
gemini-3.1-flash-image
gemini-3.1-flash-lite-image
```

一开始遇到最多的是 429：

```text
free_tier_requests limit: 0
free_tier_input_token_count limit: 0
```

这不是代码错，也不是 Key 格式错。是当前 Google 项目对这个模型没有免费额度。换了新 Key 再测就 OK 了：

```text
OK image: data:image/jpeg;base64,...
model: gemini-3.1-flash-image
```

调试这类应用，最好先把错误分清楚：

```text
500：服务端配置可能有问题
401/403：Key 或权限问题
429：额度或频率限制
200：调用成功
```

## SDK 版本变更

还遇到一个典型问题：Gemini SDK 旧版本的 Interactions API schema 不再支持。

```text
The legacy Interactions API schema is no longer supported.
Please upgrade your @google/genai JS/TS SDK to version >= 2.0.0
```

解决方式是升级 SDK，并把图片响应解析从旧的 `interaction.outputs` 改成新结构的 `interaction.steps`：

```bash
npm install @google/genai@latest
```

这也是 AI 应用开发的现实：模型和 SDK 变化很快，写完不能不管。依赖升级、接口变更、模型下线，都要预留维护空间。

## 部署到 Vercel

标准 Next.js，部署很顺：

```bash
vercel --prod
```

关键是配好环境变量（`GEMINI_API_KEY`、`GEMINI_IMAGE_MODEL`），Production 和 Development 都要配。上线后还处理了几个细节：

这些看起来不像「写代码」，但都是产品上线的一部分。

## 从「工具」到「SaaS 外壳」

最初页面的问题是：用户一进来就直面编辑器。这适合我自己调试，但普通用户根本看不懂在填什么。于是做了一次重构，把形态改成 SaaS：

```text
首页：产品介绍
登录：账号入口
价格：Free / Pro 套餐
工作台：项目、额度、生成器
```

用户路径变成：打开首页 → 了解产品 → 登录 → 选套餐 → 进入工作台 → 生成图片。

![SaaS 外壳的用户路径](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260715/01_user_path.png)

很多 AI Demo 的能力其实够用，卡住它们的是没有产品外壳——用户不知道它是什么、适合谁、怎么收费、为什么要注册。

## 把「空壳」补成真能用的产品

SaaS 外壳搭起来后，打开代码会发现——流程几乎全是演示用的空壳：

- 登录是假的，账号密码是只读占位符；
- 账单是假的，选套餐不真开通、刷新就没；
- 项目列表是硬编码的常量；
- 生成完就丢，刷新即消失，没有任何历史；
- 移动端菜单按钮是个死键。

全是摆设。于是有了这一章：整体优化页面 + 把功能真正补活。

![空壳 vs 真能跑](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260715/02_mock_vs_real.png)

原来一个文件塞下所有视图、状态、逻辑。这次拆成职责清晰的结构：

```text
src/lib/data.ts        套餐/示例数据、类型、工具函数
src/lib/history.ts     本地持久化 + 生成历史（新增）
src/components/*        Topbar / HomeView / AuthView / BillingView
                       StudioSidebar / StudioView / Footer
src/app/page.tsx       只负责状态编排
```

`page.tsx` 从「什么都干」变成「只做编排」，可维护性直接上一个台阶。

![拆掉巨型组件](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260715/03_decompose.png)

- 状态持久化：用 `localStorage` 存登录态和套餐，刷新不掉线。关键是避开 SSR 的 hydration 报错——初始用默认值，挂载后在 `useEffect` 里再读本地存储。
- 真实的生成历史：每次生成自动存一条（缩略图、风格、时间、prompt），侧边栏支持点击恢复、删除、下载；首页 dashboard 联动展示真实最近项目。
- 能用的配额系统：按套餐算额度（Starter 20 / Pro 800），进度条真实反映用量，用完自动禁用并提示。
- 修复订阅流程：未登录选套餐先引导登录、再自动激活，「当前套餐」正确高亮。
- 补齐交互：带校验的登录框、真正能展开的移动端导航、重新生成、新建、toast 提示、加载态与空状态。
- 页面优化：新增风格画廊（点任意风格直达工作台并预选）、页脚，收敛整体视觉。

### 验证与交付

功能写完不等于做完，三道关卡逐一过：

```text
npm run lint   → 0 错误 0 警告
npm run build  → 类型检查 + 静态生成通过
dev server     → 首页 200、SSR 内容正确、无 hydration 报错
```

## 工程化：一份 AGENTS.md

项目还加了 `AGENTS.md` 作为贡献者指南，记录项目结构、开发命令、代码风格、提交规范、环境变量注意事项。提交信息保持简短祈使式：

```text
Refactor app into SaaS workspace
Update Gemini SDK image response handling
Add persistence, history, and UI polish to workspace
```

这些小规范，哪怕一个人开发也有用——项目一旦持续迭代，没有基本约定很快就会乱。

## 从 Demo 到产品差的是什么

这个项目不大，但完整走了一遍 AI 产品的关键环节：核心能力验证 → Prompt 与风格配置 → Key 安全 → 额度调试 → SDK 适配 → Vercel 部署 → 域名与访问控制 → SaaS 重构 → 账号与付费路径预留 → 持久化与历史。

几个具体的感受：

模型调用真的只是第一步。真正要上线，后面还压着一长串：谁来用、怎么进入、怎么付费、怎么限额、怎么隐藏底层复杂度、怎么稳定部署、怎么处理错误。

而「看起来能用」和「真能用」之间，差的往往不是新功能，是状态管理。登录会不会掉、刷新会不会丢、额度用完怎么办——这些边界情况才是分水岭。

还有一点：交付要留痕、能验证。我在收尾时说清了哪些验证过、哪些没跑（依赖真实 Key 的 Gemini 生成没实调，避免消耗额度）。诚实的交付比漂亮的结论有用。

HandDraw AI 现在还是早期版本，但基础搭起来了。生成历史已经有了（本地版），下一步优先补两件事：真实账号系统和真实支付订阅，再把历史从 localStorage 换成后端数据库。
