# Paion **Repository Path**: chging/paion ## Basic Information - **Project Name**: Paion - **Description**: 一个可以将展会、会议等现场记录的数据生成各种形式报告、ppt及演示视频的agent平台。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-01 - **Last Updated**: 2026-05-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 拍案 Paion — 现场信息决策资产引擎

让现场信息不再流失,让每一次活动都成为企业的知识资产

「现场一拍,决策有案」

--- ![image-20260522160512631](./README.assets/image-20260522160512631.png) image-20260522160638210image-20260522160805746image-20260522160832582image-20260522160903679image-20260522160928916image-20260522161005143 ## 📖 目录 - [产品愿景](#产品愿景) - [核心特性](#核心特性) - [技术架构](#技术架构) - [快速开始](#快速开始) - [部署指南](#部署指南) - [功能模块](#功能模块) - [数据模型](#数据模型) - [开发指南](#开发指南) --- ## 产品愿景 ### 品牌释义 **拍案(Paion)** 源于中文成语「拍案叫绝」,在产品语境中被赋予双重寓意: - **「拍」即采集**:用户在展会、会议等现场「拍」摄照片、录音、视频,这些多媒体素材是系统的输入源头 - **「案」即决策**:「案」在古汉语中指案牍、案卷,引申为决策依据和知识资产 英文名称 **Paion** 是 **Present-scene AI-powered Information Operations Network** 的缩写,直译为「现场 AI 驱动的信息运营网络」。 ### 产品定位 拍案定位为**现场信息决策资产引擎**,其核心价值主张是: > 将展会、会议、客户拜访等现场活动中产生的照片、录音、视频等多媒体素材,通过 AI 自动转化为结构化报告、实体知识图谱和可复用的决策资产,让信息不再流失,让决策有据可依。 拍案不是一个简单的 AI 工具,而是一套完整的**现场信息管理工作流**,覆盖从素材采集、AI 分析、报告生成到知识沉淀的全链路。 ### 解决的核心问题 | 问题 | 传统方案的不足 | 拍案的解决方案 | |------|--------------|-------------| | **信息采集碎片化** | 素材分散在个人设备,团队无法共享 | 基于事件的素材管理中心,支持团队协作上传 | | **信息提炼人工化** | 从大量素材中提炼关键信息需要 3-5 个工作日 | AI 自动完成 OCR/转录/提炼,分钟级处理 | | **报告输出标准化不足** | 不同人整理的报告格式各异,质量参差不齐 | 提供老板版(精简)和详细版(完整)两种标准模板 | | **知识沉淀缺失** | 每次活动的信息孤立,无法积累长期资产 | 自动提取实体、建立跨事件关联,形成企业知识库 | --- ## 核心特性 ### 🎯 一拍即得的工作流 1. **现场采集**:在工作台主页拖拽或点击上传,支持图片、音频、视频、PDF 多种格式 2. **自动分析**:系统自动触发 OCR 文字识别、语音转录、语义提炼、实体抽取 3. **结构化输出**:生成老板版(精简摘要)和详细版(完整分析)两种报告 4. **知识沉淀**:自动提取实体、建立跨事件关联,形成企业知识图谱 ### 🤖 AI 驱动的分析引擎 - **OCR 文字识别**:从图片、PDF 中提取文字内容 - **语音转录**:将音频、视频中的语音转为文字 - **语义提炼**:通过 LLM 理解内容、提取关键信息、生成摘要 - **实体抽取**:自动识别公司、人物、产品、技术等实体 - **关系建立**:跨事件关联实体,形成知识图谱 ### 📊 灵活的报告系统 - **两种报告模板**:老板版(1-2 页精简)和详细版(完整分析) - **在线批注**:支持对报告进行高亮、评论、标记 - **链接分享**:生成分享链接,未登录用户也能查看 - **视频摘要**:一键生成报告对应的视频总结(可选) ### 🔍 全局知识库 - **实体图谱**:可视化展示公司、人物、产品等实体的关系网络 - **跨事件检索**:在所有活动的报告、知识块中全文搜索 - **智能推荐**:基于历史实体自动推荐相关信息 ### 👥 团队协作 - **协作者邀请**:事件创建者可邀请团队成员共同上传素材 - **权限管理**:支持查看、编辑等不同权限级别 - **实时通知**:协作者上传时自动通知事件创建者 --- ## 技术架构 ### 整体设计 ``` ┌─────────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌──────────────────┐ ┌──────────────────────────┐ │ │ │ Web 端(浏览器) │ │ Android App(WebView) │ │ │ │ React 19 + Vite │ │ Kotlin + WebView │ │ │ └────────┬─────────┘ └────────────┬─────────────┘ │ └───────────┼──────────────────────────┼─────────────────┘ │ tRPC over HTTP │ HTTPS ┌───────────▼──────────────────────────▼─────────────────┐ │ 服务端层 │ │ Express 4 + tRPC 11 + Node.js 22 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ │ │ 认证模块 │ │ 业务路由 │ │ AI 引擎 │ │ SSE 推送 │ │ │ │ OAuth │ │ tRPC │ │ LLM/OCR │ │ 通知中心 │ │ │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │ └──────────────────────────┬──────────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────────┐ │ 基础设施层 │ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │ │ │ MySQL/TiDB │ │ S3 对象存储 │ │ Manus OAuth │ │ │ │ Drizzle ORM │ │ 文件存储 │ │ 身份认证 │ │ │ └──────────────┘ └──────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 技术栈 | 层次 | 技术 | 说明 | |------|------|------| | **前端框架** | React 19 + TypeScript | 生态成熟,类型安全,组件复用性强 | | **样式系统** | Tailwind CSS 4 | 原子化 CSS,快速构建响应式 UI | | **UI 组件库** | shadcn/ui | 基于 Radix UI,无障碍访问,高度可定制 | | **API 层** | tRPC 11 | 端到端类型安全,无需手写 API 文档 | | **后端框架** | Express 4 + Node.js 22 | 轻量灵活,与 tRPC 集成简单 | | **ORM** | Drizzle ORM | 类型安全,迁移简单,性能优秀 | | **数据库** | MySQL / TiDB | 关系型数据库,支持复杂查询和事务 | | **文件存储** | S3 兼容对象存储 | 弹性扩展,CDN 加速,成本可控 | | **实时推送** | Server-Sent Events (SSE) | 轻量单向推送,适合通知场景 | | **AI 引擎** | Manus 内置 LLM API | 无需额外 API Key,开箱即用 | | **身份认证** | Manus OAuth 2.0 | 统一身份管理,安全可靠 | ### 数据流设计 拍案的核心数据流围绕**事件(Event)**展开,分为三个阶段: **阶段一:素材采集** ``` 用户上传素材 → S3 预签名 URL → 文件直传 S3 → confirmUpload 写入 DB → 触发通知(协作者上传时通知事件创建者) ``` **阶段二:AI 分析** ``` analyzeEvent 触发 → 后台异步处理: Step 1: OCR/转录(提取文字内容) Step 2: 语义提炼(生成 knowledgeBlocks) Step 3: 实体抽取(写入 entities + relationships) Step 4: 报告生成(生成 markdownContent) → 分析完成通知推送(SSE 实时推送给事件创建者) ``` **阶段三:知识沉淀** ``` 报告生成 → 搜索索引写入(searchIndex) → 实体图谱更新(跨事件关联) → 视频摘要生成(可选) ``` --- ## 快速开始 ### 前置要求 - Node.js 22+ - pnpm 9+ - MySQL 8.0+ 或 TiDB 6.0+ ### 本地开发 ```bash # 1. 克隆仓库 git clone https://gitee.com/chging/paion.git cd paion # 2. 安装依赖 pnpm install # 3. 配置环境变量 # 复制 .env.example 到 .env,填写必要的配置项 cp .env.example .env # 4. 初始化数据库 pnpm db:push # 5. 启动开发服务器 pnpm dev ``` 开发服务器将在 `http://localhost:3000` 启动,支持热模块替换(HMR)。 ### 构建生产版本 ```bash # 构建前端和后端 pnpm build # 启动生产服务器 pnpm start ``` --- ## 部署指南 ### 环境变量配置 系统需要以下环境变量: | 环境变量 | 说明 | 示例 | |---------|------|------| | `DATABASE_URL` | MySQL 连接字符串 | `mysql://user:pass@host:3306/paion` | | `JWT_SECRET` | Session 签名密钥 | 任意 32+ 字符的随机字符串 | | `VITE_APP_ID` | Manus OAuth 应用 ID | 从 Manus 平台获取 | | `OAUTH_SERVER_URL` | Manus OAuth 服务器地址 | `https://api.manus.im` | | `VITE_OAUTH_PORTAL_URL` | Manus 登录门户地址 | `https://oauth.manus.im` | | `OWNER_OPEN_ID` | 系统所有者的 OpenID | 从 Manus 平台获取 | | `OWNER_NAME` | 系统所有者的名称 | 任意字符串 | | `BUILT_IN_FORGE_API_URL` | Manus Forge API 地址 | `https://api.manus.im/forge` | | `BUILT_IN_FORGE_API_KEY` | Manus Forge API 密钥 | 从 Manus 平台获取 | | `VITE_FRONTEND_FORGE_API_KEY` | 前端 Forge API 密钥 | 从 Manus 平台获取 | | `VITE_FRONTEND_FORGE_API_URL` | 前端 Forge API 地址 | `https://api.manus.im/forge` | | `PORT` | 服务器端口(可选) | 默认 3000 | | `NODE_ENV` | 运行环境 | `production` 或 `development` | ### 数据库初始化 ```bash # 生成迁移文件并执行迁移 pnpm db:push ``` 该命令会: 1. 根据 `drizzle/schema.ts` 生成迁移文件 2. 执行迁移,创建所有必要的表和索引 ### Docker 部署 ```dockerfile # Dockerfile FROM node:22-alpine WORKDIR /app # 安装依赖 COPY package.json pnpm-lock.yaml ./ RUN npm install -g pnpm && pnpm install --frozen-lockfile # 复制源代码 COPY . . # 构建应用 RUN pnpm build # 暴露端口 EXPOSE 3000 # 启动应用 CMD ["pnpm", "start"] ``` 构建和运行: ```bash docker build -t paion:latest . docker run -p 3000:3000 \ -e DATABASE_URL="mysql://..." \ -e JWT_SECRET="..." \ paion:latest ``` ### 云平台部署 #### Cloud Run(Google Cloud) ```bash # 1. 创建 .gcloudignore echo "node_modules/" > .gcloudignore # 2. 部署到 Cloud Run gcloud run deploy paion \ --source . \ --platform managed \ --region us-central1 \ --set-env-vars DATABASE_URL="mysql://..." \ --set-env-vars JWT_SECRET="..." ``` #### Vercel ```bash # 1. 安装 Vercel CLI npm install -g vercel # 2. 部署 vercel ``` 注意:Vercel 的无服务器函数有 10 秒超时限制,不适合长时间的 AI 分析任务。建议使用 Cloud Run 或自托管服务器。 ### 性能优化 - **文件上传**:使用 S3 预签名 URL 实现客户端直传,避免文件流量经过应用服务器 - **数据库查询**:所有查询都带有 `userId` 条件,确保数据隔离和查询效率 - **缓存策略**:前端使用 tRPC 的自动缓存机制,减少不必要的网络请求 - **SSE 心跳**:每 25 秒发送一次心跳,保持连接活跃,防止代理断开 --- ## 功能模块 ### M01 — 用户认证与账户管理 - **OAuth 登录**:基于 Manus OAuth 2.0 协议,无需用户名密码 - **角色权限**:支持 `user`(普通用户)和 `admin`(管理员)两种角色 - **会话管理**:使用 JWT Cookie 实现会话持久化,支持登出 ### M02 — 事件管理 - **事件创建**:支持主页直接上传自动创建、手动创建两种方式 - **事件编辑**:修改事件名称、描述、类型、时间等信息 - **事件列表**:卡片网格展示,支持按类型筛选、按时间排序 - **事件删除**:支持删除事件及其所有关联数据 ### M03 — 素材管理 - **多格式支持**:图片(JPG/PNG/WEBP/HEIC)、音频(MP3/WAV/M4A)、视频(MP4/MOV)、PDF - **客户端直传**:使用 S3 预签名 URL,避免文件经过应用服务器 - **进度展示**:实时显示上传进度条,支持暂停和续传 - **素材预览**:图片网格、音频播放器、视频播放器、PDF 查看 ### M04 — AI 智能分析 - **OCR 文字识别**:从图片、PDF 中提取文字内容 - **语音转录**:将音频、视频中的语音转为文字 - **语义提炼**:通过 LLM 理解内容、提取关键信息、生成摘要 - **实体抽取**:自动识别公司、人物、产品、技术等实体 ### M05 — 报告生成与管理 - **两种模板**:老板版(精简)和详细版(完整) - **在线编辑**:支持对报告进行批注、高亮、评论 - **链接分享**:生成分享链接,未登录用户也能查看 - **视频摘要**:一键生成报告对应的视频总结 ### M06 — 协作者管理 - **邀请机制**:事件创建者可邀请团队成员 - **权限控制**:支持查看、编辑等不同权限级别 - **实时通知**:协作者上传时自动通知事件创建者 ### M07 — 实体知识图谱 - **可视化展示**:力导向图展示实体关系网络 - **跨事件关联**:自动关联历史事件中的相同实体 - **智能搜索**:支持按实体类型、名称搜索 ### M08 — 全局搜索 - **跨事件检索**:在所有活动的报告、知识块中全文搜索 - **搜索建议**:基于历史搜索和热门实体提供建议 - **结果分类**:按事件、实体、报告、知识块分类展示 ### M09 — 通知中心 - **SSE 实时推送**:素材上传、分析完成等事件实时通知 - **通知列表**:展示所有通知历史,支持标记为已读、删除 - **通知点击跳转**:点击通知直接跳转到相关页面 --- ## 数据模型 ### 核心表结构 #### users 表 — 用户信息 ```sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, openId VARCHAR(64) UNIQUE NOT NULL, name TEXT, email VARCHAR(320), avatar TEXT, loginMethod VARCHAR(64), role ENUM('user', 'admin') DEFAULT 'user', plan ENUM('free', 'pro') DEFAULT 'free', planExpiresAt TIMESTAMP, storageQuotaMB INT DEFAULT 500, analysisQuota INT DEFAULT 10, analysisUsed INT DEFAULT 0, credits INT DEFAULT 0, planNote TEXT, isDisabled BOOLEAN DEFAULT FALSE, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, lastSignedIn TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` #### events 表 — 活动事件 ```sql CREATE TABLE events ( id INT AUTO_INCREMENT PRIMARY KEY, userId INT NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, location VARCHAR(255), eventType ENUM('conference', 'exhibition', 'meeting', 'other'), startTime BIGINT, endTime BIGINT, status ENUM('pending', 'processing', 'done', 'failed') DEFAULT 'pending', analysisStep ENUM('ocr', 'extract', 'report', 'done') DEFAULT 'ocr', coverImage TEXT, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (userId) REFERENCES users(id) ); ``` #### assets 表 — 上传的素材 ```sql CREATE TABLE assets ( id INT AUTO_INCREMENT PRIMARY KEY, eventId INT NOT NULL, uploadedBy INT NOT NULL, fileName VARCHAR(255) NOT NULL, fileType ENUM('image', 'audio', 'video', 'pdf'), fileSize INT, s3Key VARCHAR(512) NOT NULL, s3Url TEXT NOT NULL, processStatus ENUM('pending', 'processing', 'done', 'failed') DEFAULT 'pending', extractedText LONGTEXT, processError TEXT, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (eventId) REFERENCES events(id), FOREIGN KEY (uploadedBy) REFERENCES users(id) ); ``` #### reports 表 — 生成的报告 ```sql CREATE TABLE reports ( id INT AUTO_INCREMENT PRIMARY KEY, eventId INT NOT NULL, reportType ENUM('summary', 'detailed') DEFAULT 'summary', markdownContent LONGTEXT NOT NULL, htmlContent LONGTEXT, viewCount INT DEFAULT 0, shareToken VARCHAR(64) UNIQUE, isShared BOOLEAN DEFAULT FALSE, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (eventId) REFERENCES events(id) ); ``` #### entities 表 — 提取的实体 ```sql CREATE TABLE entities ( id INT AUTO_INCREMENT PRIMARY KEY, eventId INT NOT NULL, type ENUM('company', 'person', 'product', 'technology', 'other'), name VARCHAR(255) NOT NULL, description TEXT, metadata JSON, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (eventId) REFERENCES events(id) ); ``` #### relationships 表 — 实体关系 ```sql CREATE TABLE relationships ( id INT AUTO_INCREMENT PRIMARY KEY, sourceEntityId INT NOT NULL, targetEntityId INT NOT NULL, relationType VARCHAR(64), description TEXT, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (sourceEntityId) REFERENCES entities(id), FOREIGN KEY (targetEntityId) REFERENCES entities(id) ); ``` --- ## 开发指南 ### 项目结构 ``` paion/ ├── client/ # 前端代码 │ ├── src/ │ │ ├── pages/ # 页面组件 │ │ ├── components/ # 可复用组件 │ │ ├── contexts/ # React Context │ │ ├── hooks/ # 自定义 Hook │ │ ├── lib/ # 工具函数 │ │ ├── App.tsx # 主应用组件 │ │ └── main.tsx # 入口文件 │ ├── public/ # 静态资源 │ └── index.html # HTML 模板 ├── server/ # 后端代码 │ ├── routers.ts # tRPC 路由定义 │ ├── db.ts # 数据库查询函数 │ ├── storage.ts # S3 存储操作 │ ├── sseManager.ts # SSE 连接管理 │ └── _core/ # 核心模块 │ ├── index.ts # Express 应用启动 │ ├── context.ts # tRPC 上下文 │ ├── oauth.ts # OAuth 处理 │ ├── env.ts # 环境变量 │ ├── llm.ts # LLM 调用 │ └── vite.ts # Vite 集成 ├── drizzle/ # 数据库迁移 │ ├── schema.ts # 数据库 Schema │ └── migrations/ # 迁移文件 ├── doc/ # 文档 │ ├── 01-软件整体设计方案.md │ └── 02-软件详细设计.md ├── package.json ├── tsconfig.json ├── vite.config.ts └── drizzle.config.ts ``` ### 添加新功能的流程 1. **更新数据库 Schema**:在 `drizzle/schema.ts` 中定义新表或修改现有表 2. **生成迁移**:运行 `pnpm db:push` 生成迁移文件 3. **添加数据库查询**:在 `server/db.ts` 中实现查询函数 4. **定义 tRPC 路由**:在 `server/routers.ts` 中添加新的 procedure 5. **编写前端 UI**:在 `client/src/pages/` 或 `client/src/components/` 中实现页面或组件 6. **调用 tRPC 接口**:在前端使用 `trpc.*.useQuery()` 或 `trpc.*.useMutation()` 调用后端接口 7. **编写单元测试**:在 `server/*.test.ts` 中添加测试用例 8. **运行测试**:执行 `pnpm test` 确保所有测试通过 ### 测试 ```bash # 运行所有测试 pnpm test # 运行特定测试文件 pnpm test server/paion.test.ts # 监听模式 pnpm test --watch ``` ### 代码规范 - **TypeScript**:所有代码必须通过 `pnpm check` 的 TypeScript 检查 - **代码格式**:使用 Prettier 进行代码格式化,运行 `pnpm format` - **命名规范**: - 文件名:使用 kebab-case(如 `user-profile.tsx`) - 类名/组件名:使用 PascalCase(如 `UserProfile`) - 变量/函数名:使用 camelCase(如 `getUserProfile`) - 常量:使用 UPPER_SNAKE_CASE(如 `MAX_FILE_SIZE`) ### 常见任务 #### 添加新的 tRPC 路由 ```typescript // server/routers.ts export const appRouter = router({ users: router({ getProfile: protectedProcedure .query(async ({ ctx }) => { return await db.getUserProfile(ctx.user.id); }), updateProfile: protectedProcedure .input(z.object({ name: z.string() })) .mutation(async ({ ctx, input }) => { return await db.updateUserProfile(ctx.user.id, input); }), }), }); ``` #### 在前端调用 tRPC 接口 ```typescript // client/src/pages/Profile.tsx import { trpc } from "@/lib/trpc"; export default function Profile() { const { data: profile, isLoading } = trpc.users.getProfile.useQuery(); const updateMutation = trpc.users.updateProfile.useMutation(); return (
{isLoading ?
加载中...
:
{profile?.name}
}
); } ``` #### 上传文件到 S3 ```typescript // server/routers.ts import { storagePut } from "../storage"; export const appRouter = router({ assets: router({ upload: protectedProcedure .input(z.object({ fileName: z.string(), fileBuffer: z.instanceof(Buffer) })) .mutation(async ({ input }) => { const { url, key } = await storagePut( `uploads/${Date.now()}-${input.fileName}`, input.fileBuffer, "application/octet-stream" ); return { url, key }; }), }), }); ``` --- ## 许可证 MIT --- ## 联系方式 - **官网**:https://paionai.com - **文档**:https://docs.paionai.com - **反馈**:feedback@paionai.com --- **拍案 Paion — 现场一拍,决策有案** ✨