Peep 命理工作台
Peep 是一站式国学命理工作台 —— 人物档案、文档管理、紫微斗数、大六壬、六爻、知识库六大模块深度整合。我们通过把 rtc-agent 作为 Web Component 嵌入 React 应用,让 AI 直接操作业务 API:
- 🧑 “创建张三的人物档案” → 调用
PersonCreate,自动跳转详情页 - 🔮 “排张三的紫微盘,看今年的流年” → 调用
ZiWei/GetScopeData,展示排盘结果 - 🎲 “起一卦,问最近适不适合跳槽” → 调用
LiuYaoCreate,展示卦象 - 📚 “写一篇关于紫微命宫的学习笔记” → 调用
WikiCreate,跳转编辑页 - 📅 “今天农历是多少?” → 调用
SolarToLunar,返回农历日期
AI 不只是聊天 —— 它能 读取数据、调用函数、操作界面。
上方视频(4x 倍速)展示了用户用自然语言与 AI 交互,完成人物创建、排盘、起卦、文档管理的完整流程。
截图展示 Peep 主界面:左侧 5 份为紫微斗数主内容区,右侧 3 份为嵌入式
<rtc-agent>AI 助手面板。
与 Mermaid 案例的区别
Section titled “与 Mermaid 案例的区别”如果说 Mermaid Live Editor 展示了最简悬浮窗接入,Peep 则展示了生产级嵌入式集成:
| 特性 | Mermaid Live Editor | Peep |
|---|---|---|
| 框架 | Svelte | React 19 |
| 窗口模式 | 悬浮窗(左下角最小化) | 嵌入式(5:3 双栏布局) |
| 鉴权方式 | 默认(rtc-agent 自带) | 自定义 AuthProvider |
| 业务复杂度 | 单一编辑器 | 6 大业务域、40+ 函数 |
| 安全机制 | 无 | 写操作确认机制 |
| 主题同步 | Svelte $effect | 轮询 + API 同步 |
| 语言同步 | 无 | zh-CN / en-US 切换 |
💡 rtc-agent 的接入方式非常灵活 —— 从最简单的悬浮窗到生产级嵌入式集成,都可以用同一套组件实现。
┌─────────────────────────────────────────────────────────────────┐│ Peep (React 19 + Vite 8) ││ ││ ┌────────────────────────────┐ ┌──────────────────────────┐ ││ │ │ │ │ ││ │ 主内容区(5 份) │ │ AI 助手(3 份) │ ││ │ │ │ ┌────────────────────┐ │ ││ │ 🧭 紫微斗数 / 大六壬 / │ │ │ <rtc-agent> │ │ ││ │ 🎲 六爻 / 📚 知识库 │ │ │ Web Component │ │ ││ │ │ │ │ 嵌入式最大化 │ │ ││ │ │ │ │ 无关闭/最小化 │ │ ││ │ │ │ └────────────────────┘ │ ││ │ │ │ │ ││ └────────────────────────────┘ └──────────────────────────┘ ││ ▲ │ ││ │ peepApi() 内部通道 │ ││ └──────────────────────────────┘ ││ (AI 调用业务 API) │└─────────────────────────────────────────────────────────────────┘关键设计决策:
| 决策 | 原因 |
|---|---|
| 嵌入式而非悬浮窗 | AI 助手是应用的核心组成部分,不是可选插件 |
| 5:3 固定比例 | 保证排盘/文档主区有足够空间,同时 AI 面板也足够宽敞 |
| 禁用拖拽/缩放/最小化 | 嵌入式模式下不需要窗口操作,AI 始终可见 |
| 自定义 AuthProvider | 完全委托给 peep 的认证系统,共享登录状态 |
| 写操作确认机制 | 防止 AI 误操作造成不可逆的数据变更 |
整个接入通过 npm 安装 @rtc-agent/component,核心改动集中在 3 个文件:
| 文件 | 改动 | 说明 |
|---|---|---|
src/core/rtcAgent.ts | 创建 rtc-agent 实例 | 配置嵌入式模式、AuthProvider、函数分组 |
src/core/rtcAgent/*.ts | 按业务域定义 40+ 函数 | Zod Schema 驱动,自动生成 OpenAPI 文档 |
src/App.tsx | 挂载到 5:3 布局右侧 | slot.replaceChildren(agent) |
第一步:5:3 双栏布局
Section titled “第一步:5:3 双栏布局”AI 面板作为应用的原生组成部分,不是浮窗:
// App.tsx — 全局布局<div className="rtc-layout"> <div className="rtc-layout-main"> {/* 主内容区:紫微斗数 / 大六壬 / 六爻 / 知识库 */} <BrowserRouter basename="/peep"> <Layout> <Routes>...</Routes> </Layout> </BrowserRouter> </div> <aside className="rtc-layout-side" aria-label="AI 助手"> <div ref={rtcSlotRef} id="rtc-slot" /> </aside></div>/* 5:3 双栏布局 */.rtc-layout { display: grid; grid-template-columns: 5fr 3fr; height: 100vh;}第二步:创建 rtc-agent 实例
Section titled “第二步:创建 rtc-agent 实例”使用 createRtcAgent 工厂函数,配置嵌入式最大化模式和自定义 AuthProvider:
import { createRtcAgent } from '@rtc-agent/component';import type { RtcAgentWithLifecycle } from '@rtc-agent/component';
export function createPeepRtcAgent(): RtcAgentWithLifecycle { return createRtcAgent({ appLabel: '窥见人生 · 命理 AI 助手', agentName: 'PeepAstro', agentDescription: '紫微斗数 · 大六壬 · 六爻 · 知识库 —— 命理分析 AI 助手', persona: PERSONA_ZH, // 或 PERSONA_EN,根据语言切换
// 嵌入式模式配置 window: { embedded: true, defaultMode: 'maximized', draggable: false, resizable: false, showMinimize: false, showMaximize: false, showClose: false, },
// 自定义 AuthProvider(模式 3) auth: { getToken: async () => { const tokens = getTokens(); if (!tokens) throw new Error('Not authenticated'); return tokens.access_token; }, refreshToken: async () => { const tokens = getTokens(); const newTokens = await refreshAccessToken(tokens.refresh_token); return { accessToken: newTokens.access_token, refreshToken: newTokens.refresh_token, expiresIn: Math.floor((newTokens.expires_at - Date.now()) / 1000), }; }, isLoggedIn: () => { const tokens = getTokens(); if (!tokens) return false; return !isTokenExpired(tokens, 5 * 60 * 1000); }, logout: async () => { clearTokens(); }, getUserId: () => { const tokens = getTokens(); if (!tokens) throw new Error('Not authenticated'); return tokens.user_id; }, deviceId: getOrCreateDeviceIdSync(), },
// 业务函数分组(6 组,40+ 函数) groups: FUNCTION_GROUPS,
scenariosURL: `${import.meta.env.BASE_URL}scenarios/`, workerURL: `${import.meta.env.BASE_URL}rtc-agent/shared-worker.js`, server: { url: 'https://rtc-agent.cherish.chat', redirectUri: `${import.meta.env.BASE_URL}auth/callback.html`, }, theme: getTheme(), lang: document.documentElement.lang as 'zh-CN' | 'en-US', databaseName: 'peep-rtc', });}第三步:定义业务函数
Section titled “第三步:定义业务函数”rtc-agent 的核心设计是 “Agent 不碰你的源码,只通过声明式 API 操作状态”。Peep 用 Zod Schema 驱动函数定义,自动生成 OpenAPI 文档供 AI 理解:
import { z, withMeta } from '@rtc-agent/component';
export const personCreateFunction = { name: 'PersonCreate', description: '创建新的命主人物档案并自动切换为该人物。' + '示例调用:PersonCreate({ name: "张三", date: "1990-05-15", timeIndex: 4, gender: "男" })', zodSchema: z.object({ name: withMeta(z.string(), { example: '张三' }).describe('姓名'), date: withMeta(z.string(), { example: '1990-05-15' }) .describe('公历出生日期,格式 YYYY-MM-DD'), timeIndex: withMeta(z.number().int().min(0).max(12), { example: 4 }) .describe('时辰索引 0-12,对应早子时(0)到晚子时(12)'), gender: withMeta(z.enum(['男', '女']), { example: '男' }).describe('性别'), calendar: withMeta(z.enum(['solar', 'lunar']), { example: 'solar' }) .optional().describe('历法类型,默认 solar(公历)'), confirmed: CONFIRM_FIELD, // 写操作确认标志 }), handler: createConfirmHandler(schema, (p) => peepApi().PersonCreate(p)), returns: { zodSchema: z.object({ id: z.number().describe('人物 ID'), name: z.string().describe('姓名'), // ... 其他字段 }), },};6 组业务函数:
| 分组 | 函数数 | 能力 |
|---|---|---|
person | 6 | 命主档案 CRUD(List / Get / Create / Update / Delete / SetDefault) |
ziwei | 3 | 紫微斗数排盘(ZiWei / GetScopeData / SetHoroscopeTime) |
daliuren | 7 | 大六壬起课(Create / List / View / Delete / BatchView / UpdateTags / UpdateNote) |
liuyao | 7 | 六爻起卦(Create / List / View / Delete / BatchView / UpdateTags / UpdateNote) |
wiki | 7 | 知识库文档(List / View / Create / Update / BatchView / ReplaceContent / InsertContent) |
lunar | 10 | 日历计算(SolarToLunar / LunarToSolar / GetEightCharacters / GetSolarTerms 等) |
第四步:写操作确认机制
Section titled “第四步:写操作确认机制”对 Create / Update / Delete 等破坏性操作,Peep 实现了两步确认机制,防止 AI 误操作:
export const CONFIRM_FIELD = withMeta(z.boolean(), { example: true }) .optional() .describe( '⚠️ 安全确认标志:首次调用时不传此字段,函数会返回操作摘要供用户确认;' + '用户确认后,AI 再次调用并传入 confirmed: true 才会真正执行。' );
export function createConfirmHandler(schema, handler) { return async (params) => { // 首次调用:未传 confirmed,返回操作摘要 if (!params.confirmed) { return { needsConfirm: true, summary: `即将创建人物「${params.name}」,出生日期 ${params.date}`, }; } // 二次调用:已确认,真正执行 return handler(params); };}工作流程:
- AI 首次调用
PersonCreate({ name: '张三', ... }) - Handler 检测到
confirmed未传,返回{ needsConfirm: true, summary: '...' } - AI 向用户展示操作摘要,等待确认
- 用户确认后,AI 再次调用
PersonCreate({ ..., confirmed: true }) - Handler 检测到
confirmed: true,真正执行创建操作
💡 这样即使 AI 幻觉或 prompt 注入,也不会直接执行不可逆操作。
主题与语言同步
Section titled “主题与语言同步”Peep 支持明暗双主题和中英双语,需要与 rtc-agent 保持同步:
// 主题同步:轮询检查(500ms 间隔)export function startThemeSync(): () => void { let lastTheme = getTheme(); const timer = setInterval(() => { const current = getTheme(); if (current !== lastTheme) { lastTheme = current; syncTheme(); // 设置 agent.theme } }, 500); return () => clearInterval(timer);}
// 语言同步:通过 API 切换export async function syncLocale(locale: Locale): Promise<void> { if (!_agent) return; await switchLocale(locale); // 触发 @lit/localize 重新渲染}// App.tsx — 启动同步useEffect(() => { const agent = createPeepRtcAgent(); slot.replaceChildren(agent); const cleanupThemeSync = startThemeSync(); return () => { cleanupThemeSync(); agent.destroy(); };}, []);
// 语言切换时同步const { locale } = useI18n();useEffect(() => { syncLocale(locale);}, [locale]);| 层 | 技术 |
|---|---|
| 框架 | React 19 · TypeScript 6 · Vite 8 |
| 样式 | Tailwind CSS 4 · 明暗双主题 |
| 组件 | Radix UI · shadcn/ui · Lucide Icons |
| 数据 | Dexie (IndexedDB) · Zustand |
| 命理引擎 | iztro · lunar-lite · lunar-typescript |
| AI 集成 | rtc-agent (npm) · Zod Schema |
| 编辑器 | ByteMD (Markdown + GFM) |
| 测试 | Playwright E2E |
| 部署 | GitHub Pages |
除了上述核心文件,还涉及:
| 文件 | 用途 |
|---|---|
src/core/rtcAgent/*.ts | 按业务域拆分的函数定义(person / ziwei / daliuren / liuyao / wiki / lunar) |
src/core/auth/AuthContext.tsx | 自定义 AuthProvider,rtc-agent 完全委托 |
public/scenarios/ | 预置场景模板 + manifest |
public/auth/callback.html | OAuth 回调页 |
整个接入 不修改 rtc-agent 任何代码,@rtc-agent/component 通过 npm 安装,打包进宿主 bundle。