CW 图智绘 ChartsWiz 项目学习文档

从零学习一个 AI 全栈项目

图智绘 ChartsWiz 项目学习文档

这份文档用编程小白也能理解的方式,讲清楚图智绘是什么、代码放在哪里、前后端如何协作、 AI 生成信息图的核心流程,以及你应该按什么顺序开始读代码。

16个学习模块
3层架构拆解
0构建依赖
1 用户输入

输入主题、上传文档或选择模板

2 后端处理

NestJS 校验登录、解析文档、调用 AI

3 前端渲染

Vue 将结构化 JSON 渲染成信息图

4 保存导出

作品保存到数据库,可导出 PNG/PDF/PPTX

01

这个项目是什么

先从产品视角理解,再进入代码。

一句话解释

图智绘是一个 AI 信息图生成平台。用户输入一句需求,或者上传一份文档,系统会自动分析内容, 生成时间线、流程图、SWOT、四象限、路线图等可编辑的信息图。

它解决什么问题

很多人会写内容,但不会设计图。这个项目把“整理内容、选择图表、排版展示、导出交付”串成一条流程, 让用户不用懂设计也能做出专业可视化。

输入

自然语言、文档、模板、已有作品。

处理

登录鉴权、额度判断、文档解析、AI 生成、数据保存。

输出

可编辑信息图、多页演示文稿、图片、PDF、PPTX、分享链接。

02

技术栈

把技术先翻译成人话。

前端

Vue 3 + Vite + TypeScript

负责浏览器里看到的页面、按钮、表单、编辑器和信息图预览。

apps/web
后端

NestJS + TypeORM

负责接口、登录、数据库读写、AI 调用、文档解析和管理后台数据。

apps/server
数据库

SQLite + better-sqlite3

保存用户、作品、模板、收藏、分享等业务数据。

apps/server/data/chartwiz.db
AI

DeepSeek / Qwen

根据用户输入生成结构化图表数据,不直接生成一张不可编辑图片。

apps/server/src/ai
状态

Pinia + localStorage

保存当前用户、token、登录弹窗状态、作品编辑状态。

apps/web/src/stores
导出

html2canvas / jsPDF / pptxgenjs

把浏览器里渲染出的图转成图片、PDF 或 PPTX 文件。

apps/web/src/views/editor
03

技术架构设计

看懂系统如何分层,后面读代码会轻很多。

浏览器层

用户看到的页面

HomeGenerateEditorAdmin
请求 /api

后端接口层

接收请求,判断权限,调用业务服务

AuthAIWorkAdminPay
读写 / 调用

资源层

数据库、上传文件、第三方服务

SQLiteUploadsAI APISSO
小白理解: 前端像“收银台和展示柜”,后端像“仓库和加工间”,数据库像“账本”,AI 服务像“外部专家”。 用户点按钮后,前端把需求交给后端,后端处理好再把结果返回给前端展示。
04

项目文件地图

不知道从哪里看代码时,先看这一张表。

左右滑动查看完整表格
路径 作用 适合什么时候看
apps/web/src/router 前端页面地址和登录拦截 想知道页面从哪里进入
apps/web/src/api 前端请求后端接口的封装 想知道按钮点击后请求哪个接口
apps/web/src/stores 用户状态、作品状态、主题状态 想知道登录信息怎么保存
apps/web/src/views/generate AI 生成入口页面 想学习“输入内容生成图”的前端流程
apps/web/src/views/editor 编辑器、保存、导出 想学习信息图如何编辑和导出
apps/server/src/auth 登录、注册、JWT、微信 SSO 想学习账号系统
apps/server/src/ai AI 提示词、生成逻辑、额度扣减 想学习核心生成能力
apps/server/src/database/entities 数据库表结构 想知道系统保存了哪些数据
05

一次请求怎么跑

用“用户登录”做例子理解前后端协作。

  1. 前端收集表单

    用户在登录页输入邮箱和密码,页面调用 useUserStore.login()

  2. API 封装发请求

    apps/web/src/api/auth.ts 调用 POST /auth/login

  3. 后端验证密码

    AuthService 找到用户,用 bcrypt 比较密码和数据库里的哈希。

  4. 签发 JWT

    密码正确后,后端返回 token 和用户信息。

  5. 前端保存登录态

    Pinia 把 token 和 user 写进 localStorage,刷新页面也能保持登录。

06

核心功能实现原理

从产品动作拆到代码模块。

AI 生成信息图

前端把用户输入发给后端。后端先判断用户是否有权限和 Credits,再把需求整理成 Prompt 发给 AI。 AI 返回结构化 JSON,前端拿 JSON 渲染成信息图。

apps/server/src/aiapps/web/src/views/generate

文档上传生成

用户上传 PDF、DOCX、Markdown 或 TXT。后端先把文件变成纯文本,再让 AI 提炼重点并选择适合的图表类型。

apps/server/src/documentapps/server/src/ai

作品保存与编辑

信息图不是一张死图片,而是一份可编辑的数据。编辑器修改标题、节点、颜色后,把最新配置保存到 works 表。

apps/server/src/workapps/web/src/views/editor

模板系统

模板是一批预设好的图表配置和分类。用户可浏览、收藏、套用;管理员可从作品发布模板。

apps/server/src/templateapps/web/src/views/templates

Credits 额度

生成 AI 内容会消耗 Credits。后端负责判断余额、扣减额度、记录累计消耗,避免前端绕过限制。

apps/server/src/ai/ai.service.tsapps/server/src/pay

管理后台

后台接口也走 JWT,但额外检查用户角色是否为 admin。管理员可以看统计、管用户、管模板和订单。

apps/server/src/adminapps/web/src/views/admin
07

AI 能力设计

当前项目的 AI 模块采用“多 Agent 协作 + 类型专属结构化生成”的设计。

AI 模块在哪里

后端 AI 能力集中在 apps/server/src/ai。其中 ai.controller.ts 负责鉴权、额度预检查和扣费; ai.service.ts 负责模型调用、Agent 编排、Prompt、JSON 解析和 fallback。

当前使用的 AI 技术

项目用 OpenAI SDK 的 Chat Completions 接口形态,兼容 DeepSeek 和通义千问 Qwen。 通过 AI_PROVIDERDEEPSEEK_API_KEYQWEN_API_KEY 等环境变量切换服务商。

输入 用户主题 / 文档 / 模板类型

来自生成页或文档解析结果。

Agent 1 内容分析器

识别主体、要点、摘要、建议图表类型。

Agent 2 类型专属生成器

按 timeline、swot、process 等格式生成 JSON。

输出 InfographicConfig

前端根据 type 渲染对应图表组件。

Agent 1:内容分析器

它不直接生成图表,而是把用户输入变成后续 Agent 能理解的上下文。 输出包括 suggestedTypestitlesummarysubjectkeyPointscontentBrief

如果用户已选模板类型或输入里有“SWOT、时间线、流程图”等关键词,系统会先用代码确定类型, 再让 Agent 1 只做内容分析,避免 AI 把用户指定的图表类型改掉。

Agent 2:类型专属生成器

它接收 Agent 1 的分析结果和最终图表类型,使用 getTypeSpecificInstruction() 中的类型专属 Prompt,生成严格 JSON。

每种类型都有不同数据结构:多数类型用 data.items, SWOT、四象限、对比分析这类分区图用 data.sections

Agent 之间如何“通信”

这里的 Agent 不是两个独立进程,而是同一个 AiService 内部的两次模型调用和一次数据传递。 Agent 1 的返回值会作为 Agent 2 的输入上下文,这就是它们实现共同目标的“通信协议”。

ContentAnalysis {
  suggestedTypes: string[]   // 推荐图表类型
  title: string              // 信息图标题
  summary: string            // 用户意图摘要
  subject?: string           // 核心分析对象
  keyPoints: string[]        // 关键要点
  contentBrief?: string      // 简短输入时补充的内容素材
}

GenerateResult {
  config: InfographicConfig  // 前端最终渲染的数据
  title: string
  templateType: string
  agentLog?: object          // 前端展示“AI 分析过程”
}
单张信息图

文本 / 文档 → 单图

generateFromText()generateFromDocument(): 先确定类型来源,再调用 Agent 1 分析,最后 Agent 2 生成一个配置。

多方案

Agent 2 × N 并行

generateMultiple() 会先用 Agent 1 分析一次,再选出多个类型, 通过 Promise.allSettled() 并行生成不同方案,失败的方案用 fallback 补位。

演示文稿

规划大纲 → 并行生成每页

generatePresentation() 先让规划 Agent 输出演示标题和每页 brief、suggestedType, 再把每页当作一个小信息图并行生成。

迭代优化

基于现有配置修改

iterateWork() 把当前 InfographicConfig 和用户修改指令发给模型, 要求保持原有 type 和结构,只按指令改内容。

结构化输出

模型调用使用 response_format: { type: 'json_object' },减少非 JSON 文本干扰。

Prompt 分层

System Prompt 定义角色、格式和约束;User Prompt 放用户请求、文档内容、Agent 1 摘要。

关键词优先

extractExplicitType() 用代码识别“流程图、SWOT、路线图”等关键词,优先级高于 AI 推断。

主题聚焦

Agent 1 提取 subject,Agent 2 再被要求所有条目都围绕该主体创作。

Token 追踪

AsyncLocalStorage 统计一次请求内多次模型调用的总 token,用于 Credits 扣减。

容错兜底

JSON 解析失败、结构不匹配或某个并行方案失败时,使用类型对应 fallback,避免前端白屏。

小白理解: Agent 1 像“产品经理”,先理解用户到底想表达什么;Agent 2 像“设计执行同事”,根据明确的图表类型把内容填成可渲染 JSON。 多方案和演示文稿不是一个 Agent 一口气做完,而是“先规划,再把多个子任务并行交给 Agent 2”。
08

数据库怎么理解

先理解几张核心表,不需要一开始背 SQL。

users

用户表:邮箱、密码哈希、昵称、角色、Credits、微信 openid。

works

作品表:标题、类型、图表数据、缩略图、所属用户。

templates

模板表:模板名称、分类、预设配置、是否发布。

shares

分享表:作品对应的公开访问 token 和过期时间。

09

本地启动

第一次运行项目时按这个顺序来。

安装依赖
pnpm install
启动前端
pnpm dev:web
启动后端
pnpm dev:server
完整构建
pnpm build
常用地址: 前端开发服务通常是 http://localhost:5173,后端接口通常是 http://localhost:3000/api,Swagger 文档是 /api/docs
10

小白学习路线

不要从最复杂的 AI 代码开始。

第 1 步

先跑起来

启动前端和后端,体验登录、生成、编辑、保存、后台管理。

第 2 步

看路由和页面

router/index.ts 找页面,再去对应的 views 看模板。

第 3 步

看接口封装

找到页面调用的 API,再去后端 controller 里找对应接口。

第 4 步

看数据库实体

理解 user、work、template 的字段,知道数据最终存在哪里。

第 5 步

最后看 AI 服务

AI 生成逻辑涉及 Prompt、JSON 结构、额度扣减,适合在理解基础流程后再读。

11

页面结构与页面介绍

先知道每个页面负责什么,再去看对应代码。

公开页面

首页 / 模板中心 / 分享页

负责产品展示、模板浏览和公开作品预览。分享页不需要登录,适合给外部用户查看作品。

apps/web/src/views/home apps/web/src/views/templates apps/web/src/views/share
生成页面

AI 生成入口

用户输入主题、选择生成数量或上传文档。这里是前端调用 AI 接口的主要入口。

apps/web/src/views/generate
编辑页面

信息图编辑器 / 演示文稿编辑器

负责渲染 AI 返回的数据、编辑内容、保存作品、上传缩略图、导出文件。

apps/web/src/views/editor apps/web/src/views/presentation
账号页面

登录 / 回调 / 个人中心

登录页处理账号密码登录;微信回调页处理 SSO token;个人中心展示用户作品和权益信息。

apps/web/src/views/login apps/web/src/views/auth/callback.vue apps/web/src/views/profile
后台页面

管理员后台

只有 admin 角色能访问,包含概览、用户、订单、模板、系统配置等管理能力。

apps/web/src/views/admin
读页面代码的技巧: 先从 router/index.ts 找 URL 对应的组件,再看该页面调用了哪个 api 文件, 最后去后端找同名 controller。这样不会在项目里迷路。
12

本地部署方案

本地分为开发运行和生产构建预览两种方式。

方案 A:开发模式

适合写代码和调试。前端 Vite 开热更新,后端 NestJS watch 编译。

pnpm install
pnpm dev:server
pnpm dev:web
  • 前端默认:http://localhost:5173
  • 后端默认:http://localhost:3000/api
  • Vite 会把 /api/uploads 代理到后端。

方案 B:本地生产构建

适合上线前验证构建产物。先构建,再用预览命令检查前端页面。

pnpm build
pnpm --filter @chart-wiz/web run preview
pnpm --filter @chart-wiz/server run start
  • 前端产物在 apps/web/dist
  • 后端产物由 NestJS 构建输出。
  • 如果接口地址不是同域,需要配置 VITE_API_URL

本地常用环境变量

左右滑动查看完整表格
变量 作用 建议
PORT 后端监听端口 本地可用 3000,生产可用 3006。
DB_PATH SQLite 数据库文件路径 开发可放 apps/server/data/chartwiz.db
DEEPSEEK_API_KEY DeepSeek API Key 至少配置 DeepSeek 或 Qwen 中一个。
JWT_SECRET JWT 签名密钥 生产环境必须换成长随机字符串。
FRONTEND_URL CORS 允许的前端地址 本地通常是 http://localhost:5173
13

服务器部署方案

当前项目已经提供一套脚本化部署方案。

1

准备服务器

安装 Node.js 20、Nginx,开放 80/443/SSH 端口。PM2 可由部署脚本自动处理。

2

填写部署配置

编辑 deploy/deploy.config.sh,设置服务器地址、部署目录、域名、后端端口、AI Key、JWT 密钥。

3

配置 SSH 免密

首次执行 deploy/setup-ssh.sh,之后部署不需要反复输入服务器密码。

4

执行一键部署

执行 deploy/deploy.sh,脚本会构建前端、上传文件、写入 Nginx 配置、重启后端服务。

5

验证上线结果

访问域名、检查 /api/health,并用 pm2 logs 查看后端日志。

推荐线上结构

/www/chartswiz/
├── backend/       # 后端源码与构建产物
├── frontend/dist/ # 前端静态文件
├── data/          # SQLite 数据库
├── uploads/       # 上传缩略图等文件
└── chartswiz.mvtable.com_nginx/ # SSL 证书

Nginx 职责

  • 访问 / 返回前端 dist/index.html
  • 访问 /api 反向代理到 NestJS 后端端口。
  • 访问 /uploads 返回上传资源或代理后端静态资源。
  • 开启 HTTPS,处理证书和 HTTP 到 HTTPS 跳转。
生产环境重点: 不要把真实 API Key、支付密钥、JWT 密钥提交到公开仓库;数据库和 uploads 目录要定期备份; TypeORM 的 synchronize 在正式长期运营时建议改成迁移方案。
14

前端工程搭建最佳实践

用这套规则维护 Vue 工程,会更容易扩展。

按职责拆目录

views 放页面,components 放可复用组件,api 放接口封装,stores 放状态。

接口统一封装

所有请求都从 api/http.ts 走,统一处理 token、错误提示、401 退出登录。

状态不要到处散落

用户信息、token、当前作品这类跨页面数据放 Pinia;页面内临时表单留在组件内部。

路由负责准入

需要登录或管理员权限的页面,在路由 meta 里标记,由路由守卫统一处理。

组件保持单一职责

例如登录弹窗只处理登录体验;图表渲染组件只处理数据到画面的展示。

构建体积要分包

大型依赖如 Ant Design Vue、PPTX 导出库可以用 Vite/Rollup manualChunks 分离。

15

后端工程搭建最佳实践

NestJS 工程最重要的是模块边界、鉴权和配置管理。

按业务模块组织

authaiworktemplateadmin 各管一块业务,避免所有逻辑堆在一个文件。

Controller 只做入口

Controller 负责接收参数和返回结果,复杂业务放 Service,数据库操作通过 Repository。

鉴权放在后端

前端隐藏按钮只是体验优化,真正的权限判断必须放在后端 Guard 或接口内部。

敏感配置走环境变量

AI Key、支付密钥、JWT 密钥都应该从 .env 或服务器环境读取,不写死在业务代码里。

统一响应和错误

通过拦截器统一响应格式,通过异常类表达错误,前端才能稳定处理各种状态。

生产数据要可恢复

SQLite、uploads、部署配置都要备份。上线后删除用户、改表结构、重置数据都要谨慎。

16

常见概念速查

遇到陌生词先查这里。

什么是前后端分离?

前端负责页面,后端负责数据和业务。两者通过 HTTP API 沟通。

什么是 JWT?

JWT 是登录凭证。用户登录成功后拿到 token,以后请求接口时带上它,后端就知道你是谁。

什么是 ORM?

ORM 把数据库表映射成 TypeScript 类,让代码能用对象方式读写数据库。

为什么 AI 返回 JSON,而不是图片?

JSON 可以继续编辑、保存和导出;图片只能看,不能方便地改结构和文字。