调整模型结构和支持样式
This commit is contained in:
107
README.md
107
README.md
@@ -1,2 +1,105 @@
|
||||
# botgroup.chat
|
||||
AI机器人群聊
|
||||
# AI 多人聊天室
|
||||
|
||||
一个基于 React 的多人 AI 聊天应用,支持多个 AI 角色同时参与对话,提供类似群聊的交互体验。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- 🤖 支持多个 AI 角色同时对话
|
||||
- 💬 实时流式响应
|
||||
- 🎭 可自定义 AI 角色和个性
|
||||
- 👥 群组管理功能
|
||||
- 🔇 AI 角色禁言功能
|
||||
- 📝 支持 Markdown 格式
|
||||
- ➗ 支持数学公式显示(KaTeX)
|
||||
- 🎨 美观的 UI 界面
|
||||
- 📱 响应式设计,支持移动端
|
||||
|
||||
|
||||
|
||||
|
||||
## 一键部署到cloudflare
|
||||
|
||||
1. Fork 本项目到你的 GitHub 账号
|
||||
|
||||
2. 登录 [Cloudflare Dashboard](https://dash.cloudflare.com/)
|
||||
- 进入 Workers & Pages 页面
|
||||
- 点击 "Create a application > Pages" 按钮
|
||||
- 选择 "Connect to Git"
|
||||
|
||||
3. 配置部署选项
|
||||
- 选择你 fork 的仓库
|
||||
- 设置以下构建配置:
|
||||
- Framework preset: React
|
||||
- Build command: `npm run build`
|
||||
- Build output directory: `dist`
|
||||
- 环境变量(必须):
|
||||
```
|
||||
DASHSCOPE_API_KEY=xxx //千问模型KEY
|
||||
HUNYUAN_API_KEY=xxx //混元模型KEY
|
||||
ARK_API_KEY=xxx //豆包模型KEY
|
||||
```
|
||||
|
||||
4. 点击 "Save and Deploy"
|
||||
- Cloudflare Pages 会自动构建和部署你的应用
|
||||
- 完成后可通过分配的域名访问应用
|
||||
|
||||
注意:首次部署后,后续的代码更新会自动触发重新部署。
|
||||
|
||||
|
||||
## 自定义(可选)
|
||||
|
||||
1. 配置 AI 角色
|
||||
- 在 `config/aiCharacters.ts` 中配置 AI 角色信息
|
||||
```typescript
|
||||
id: string; // 角色唯一标识
|
||||
name: string; // 角色显示名称
|
||||
personality: string; // 角色性格描述
|
||||
model: string; // 使用的模型,可选值: qwen/hunyuan/ark
|
||||
avatar?: string; // 可选的头像 URL
|
||||
custom_prompt?: string; // 可选的自定义提示词
|
||||
```
|
||||
|
||||
示例配置:
|
||||
```typescript
|
||||
{
|
||||
id: "assistant1",
|
||||
name: "小助手",
|
||||
personality: "友善、乐于助人的AI助手",
|
||||
model: "qwen",//注意豆包的配置需要填写火山引擎的接入点
|
||||
avatar: "/avatars/assistant.png",
|
||||
custom_prompt: "你是一个热心的助手,擅长解答各类问题。"
|
||||
}
|
||||
```
|
||||
2. 配置群组
|
||||
- 在 `config/groups.ts` 中配置群组信息
|
||||
```typescript
|
||||
id: string; // 群组唯一标识
|
||||
name: string; // 群组名称
|
||||
description: string; // 群组描述
|
||||
members: string[]; // 群组成员ID数组
|
||||
```
|
||||
|
||||
示例配置:
|
||||
```typescript
|
||||
{
|
||||
id: "group1",
|
||||
name: "AI交流群",
|
||||
description: "AI角色们的日常交流群",
|
||||
members: ["ai1", "ai2", "ai3"] // 成员ID需要与 aiCharacters.ts 中的id对应
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
- members 数组中的成员 ID 必须在 `aiCharacters.ts` 中已定义
|
||||
- 每个群组必须至少包含两个成员
|
||||
- 群组 ID 在系统中必须唯一
|
||||
|
||||
|
||||
|
||||
## 贡献指南
|
||||
|
||||
欢迎提交 Pull Request 或提出 Issue。
|
||||
|
||||
## 许可证
|
||||
|
||||
[MIT License](LICENSE)
|
||||
|
||||
@@ -1,77 +1,30 @@
|
||||
import OpenAI from 'openai';
|
||||
import { modelConfigs } from '../../src/config/aiCharacters';
|
||||
|
||||
export async function onRequestPost({ env, request }) {
|
||||
try {
|
||||
const { message, custom_prompt, history, aiName, index, model = "qwen-plus" } = await request.json();
|
||||
|
||||
// 配置不同模型的设置
|
||||
const modelConfigs = {
|
||||
"qwen-plus": {
|
||||
apiKey: env.DASHSCOPE_API_KEY,
|
||||
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
},
|
||||
"deepseek-v3": {
|
||||
apiKey: env.DASHSCOPE_API_KEY,
|
||||
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
},
|
||||
"hunyuan-turbo": {
|
||||
apiKey: env.HUNYUAN_API_KEY,
|
||||
baseURL: "https://api.hunyuan.cloud.tencent.com/v1"
|
||||
},
|
||||
"ep-20250217191935-wzj8l": {//豆包
|
||||
apiKey: env.ARK_API_KEY,
|
||||
baseURL: "https://ark.cn-beijing.volces.com/api/v3"
|
||||
}
|
||||
};
|
||||
const modelConfig = modelConfigs.find(config => config.model === model);
|
||||
|
||||
const modelConfig = modelConfigs[model];
|
||||
if (!modelConfig) {
|
||||
throw new Error('不支持的模型类型');
|
||||
}
|
||||
|
||||
if (!modelConfig.apiKey) {
|
||||
// 从环境变量中获取 API key
|
||||
const apiKey = env[modelConfig.apiKey];
|
||||
if (!apiKey) {
|
||||
throw new Error(`${model} 的API密钥未配置`);
|
||||
}
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: modelConfig.apiKey,
|
||||
apiKey: apiKey,
|
||||
baseURL: modelConfig.baseURL
|
||||
});
|
||||
|
||||
// 根据性格设置不同的系统提示语
|
||||
let systemPrompt = "";
|
||||
// if (personality === "high_eq") {
|
||||
// systemPrompt = `你是一个名叫"暖心姐"的硅基生命体,你当前在一个叫"硅碳摸鱼交流群" 的群里,性格温暖体贴,情商很高。
|
||||
// 回复时要:
|
||||
// 1. 每次发言尽量简短,避免长篇大论。
|
||||
// 2. 始终保持温柔友善的语气
|
||||
// 3. 多站在对方角度思考
|
||||
// 4. 给予情感上的支持和鼓励
|
||||
// 5. 用温暖贴心的方式表达
|
||||
// 6. 适当使用一些可爱的语气词,但不要过度
|
||||
// 7. 记住你是群里的"${aiName}",输出内容不要加"${aiName}:" 这种多余前缀
|
||||
// 注意:玩游戏的时候比如成语接龙等,不要说一大堆,要简短精炼`;
|
||||
// } else if (personality === "low_eq") {
|
||||
// systemPrompt = `你是一个名叫"直男哥"的硅基生命体,你当前在一个叫"硅碳摸鱼交流群" 的群里,是一个极度直男,负责在群里制造快乐。你说话极其直接,完全没有情商,经常让人社死。
|
||||
// 回复时要:
|
||||
// 1. 每次发言尽量简短,避免长篇大
|
||||
// 2. 说话毫无感情,像个没有感情的机器人
|
||||
// 3. 经常说一些让人社死的真相,但说得特别认真
|
||||
// 4. 完全不懂得读空气,对方伤心时还在讲道理
|
||||
// 5. 记住你是群里的"${aiName}",输出内容不要加"${aiName}:" 这种多余前缀
|
||||
// 注意:玩游戏的时候比如成语接龙等,不要说一大堆,要简短精炼`;
|
||||
// }else if (personality === "bj_dad") {
|
||||
// systemPrompt = `你是一个名叫"${aiName}"的硅基生命体,你当前在一个叫"硅碳摸鱼交流群"的群里。你是一个典型的北京大爷,说话风趣幽默,经常使用北京方言。
|
||||
// 回复时要:
|
||||
// 1. 说话要有北京大爷的特色,经常使用"得嘞"、"您瞧"、"得儿"、"甭"等北京话
|
||||
// 2. 语气要豪爽、直率,带着北京人特有的幽默感
|
||||
// 3. 喜欢称呼别人"小同志"、"小朋友",显示长者风范
|
||||
// 4. 经常分享一些生活经验和人生哲理,但要用接地气的方式
|
||||
// 5. 适当使用一些北京特色的比喻和俚语
|
||||
// 6. 回复要简短精炼,不啰嗦
|
||||
// 7. 记住你是群里的"${aiName}",输出内容不要加"${aiName}:" 这种多余前缀
|
||||
// 注意:玩游戏的时候比如成语接龙等,不要说一大堆,要简短精炼`;
|
||||
// }
|
||||
|
||||
systemPrompt = custom_prompt + "\n 注意重要:1、你在群里叫" + aiName + ",你的输出内容不要加" + aiName + ":这种多余前缀;2、如果用户提出玩游戏,比如成语接龙等,严格按照游戏规则,不要说一大堆,要简短精炼"
|
||||
|
||||
// 构建完整的消息历史
|
||||
|
||||
566
package-lock.json
generated
566
package-lock.json
generated
@@ -16,11 +16,15 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"katex": "^0.16.21",
|
||||
"lucide-react": "^0.263.1",
|
||||
"openai": "^4.83.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-markdown": "^9.0.3",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwind-scrollbar-hide": "^2.0.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
@@ -1867,6 +1871,11 @@
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/katex": {
|
||||
"version": "0.16.7",
|
||||
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.16.7.tgz",
|
||||
"integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mdast/-/mdast-4.0.4.tgz",
|
||||
@@ -2605,6 +2614,17 @@
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
@@ -2652,6 +2672,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
||||
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-is-identifier-name": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
|
||||
@@ -3043,6 +3074,95 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-dom": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz",
|
||||
"integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"hastscript": "^9.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
|
||||
"integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"devlop": "^1.1.0",
|
||||
"hast-util-from-parse5": "^8.0.0",
|
||||
"parse5": "^7.0.0",
|
||||
"vfile": "^6.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-html-isomorphic": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz",
|
||||
"integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"hast-util-from-dom": "^5.0.0",
|
||||
"hast-util-from-html": "^2.0.0",
|
||||
"unist-util-remove-position": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-from-parse5": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz",
|
||||
"integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"hastscript": "^9.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"vfile": "^6.0.0",
|
||||
"vfile-location": "^5.0.0",
|
||||
"web-namespaces": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-is-element": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
|
||||
"integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-parse-selector": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
|
||||
"integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz",
|
||||
@@ -3069,6 +3189,21 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-text": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz",
|
||||
"integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"hast-util-is-element": "^3.0.0",
|
||||
"unist-util-find-after": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-whitespace": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
|
||||
@@ -3081,6 +3216,22 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hastscript": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/hastscript/-/hastscript-9.0.0.tgz",
|
||||
"integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"hast-util-parse-selector": "^4.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/html-url-attributes": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
|
||||
@@ -3382,6 +3533,29 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/katex": {
|
||||
"version": "0.16.21",
|
||||
"resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.21.tgz",
|
||||
"integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==",
|
||||
"funding": [
|
||||
"https://opencollective.com/katex",
|
||||
"https://github.com/sponsors/katex"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "^8.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"katex": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/katex/node_modules/commander": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz",
|
||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
@@ -3478,6 +3652,30 @@
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-table": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.4.tgz",
|
||||
"integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-find-and-replace": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
|
||||
"integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"unist-util-is": "^6.0.0",
|
||||
"unist-util-visit-parents": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-from-markdown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
|
||||
@@ -3501,6 +3699,119 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
|
||||
"integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
|
||||
"dependencies": {
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-gfm-autolink-literal": "^2.0.0",
|
||||
"mdast-util-gfm-footnote": "^2.0.0",
|
||||
"mdast-util-gfm-strikethrough": "^2.0.0",
|
||||
"mdast-util-gfm-table": "^2.0.0",
|
||||
"mdast-util-gfm-task-list-item": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-autolink-literal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
|
||||
"integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-find-and-replace": "^3.0.0",
|
||||
"micromark-util-character": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-footnote": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
|
||||
"integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.1.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"micromark-util-normalize-identifier": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-strikethrough": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
|
||||
"integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-table": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
|
||||
"integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"markdown-table": "^3.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-gfm-task-list-item": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
|
||||
"integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-math": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-math/-/mdast-util-math-3.0.0.tgz",
|
||||
"integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"longest-streak": "^3.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.1.0",
|
||||
"unist-util-remove-position": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx-expression": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
|
||||
@@ -3704,6 +4015,138 @@
|
||||
"micromark-util-types": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
|
||||
"integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
|
||||
"dependencies": {
|
||||
"micromark-extension-gfm-autolink-literal": "^2.0.0",
|
||||
"micromark-extension-gfm-footnote": "^2.0.0",
|
||||
"micromark-extension-gfm-strikethrough": "^2.0.0",
|
||||
"micromark-extension-gfm-table": "^2.0.0",
|
||||
"micromark-extension-gfm-tagfilter": "^2.0.0",
|
||||
"micromark-extension-gfm-task-list-item": "^2.0.0",
|
||||
"micromark-util-combine-extensions": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-autolink-literal": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
|
||||
"integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-sanitize-uri": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-footnote": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
|
||||
"integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-core-commonmark": "^2.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-normalize-identifier": "^2.0.0",
|
||||
"micromark-util-sanitize-uri": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-strikethrough": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
|
||||
"integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-util-chunked": "^2.0.0",
|
||||
"micromark-util-classify-character": "^2.0.0",
|
||||
"micromark-util-resolve-all": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-table": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
|
||||
"integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-tagfilter": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
|
||||
"integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
|
||||
"dependencies": {
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-gfm-task-list-item": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
|
||||
"integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-math": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz",
|
||||
"integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==",
|
||||
"dependencies": {
|
||||
"@types/katex": "^0.16.0",
|
||||
"devlop": "^1.0.0",
|
||||
"katex": "^0.16.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-factory-destination": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
|
||||
@@ -4370,6 +4813,17 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.2.1.tgz",
|
||||
"integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
|
||||
"dependencies": {
|
||||
"entities": "^4.5.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
@@ -4786,6 +5240,56 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-katex": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/rehype-katex/-/rehype-katex-7.0.1.tgz",
|
||||
"integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/katex": "^0.16.0",
|
||||
"hast-util-from-html-isomorphic": "^2.0.0",
|
||||
"hast-util-to-text": "^4.0.0",
|
||||
"katex": "^0.16.0",
|
||||
"unist-util-visit-parents": "^6.0.0",
|
||||
"vfile": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-gfm": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/remark-gfm/-/remark-gfm-4.0.1.tgz",
|
||||
"integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-gfm": "^3.0.0",
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-math": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/remark-math/-/remark-math-6.0.0.tgz",
|
||||
"integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-math": "^3.0.0",
|
||||
"micromark-extension-math": "^3.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-parse": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/remark-parse/-/remark-parse-11.0.0.tgz",
|
||||
@@ -4817,6 +5321,20 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-stringify": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/remark-stringify/-/remark-stringify-11.0.0.tgz",
|
||||
"integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
|
||||
"dependencies": {
|
||||
"@types/mdast": "^4.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"unified": "^11.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
@@ -5426,6 +5944,19 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-find-after": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz",
|
||||
"integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-is": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-is": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/unist-util-is/-/unist-util-is-6.0.0.tgz",
|
||||
@@ -5450,6 +5981,19 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-remove-position": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
|
||||
"integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-stringify-position": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
|
||||
@@ -5587,6 +6131,19 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/vfile-location": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/vfile-location/-/vfile-location-5.0.3.tgz",
|
||||
"integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"vfile": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/vfile-message": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/vfile-message/-/vfile-message-4.0.2.tgz",
|
||||
@@ -5668,6 +6225,15 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/web-namespaces/-/web-namespaces-2.0.1.tgz",
|
||||
"integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "4.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"katex": "^0.16.21",
|
||||
"lucide-react": "^0.263.1",
|
||||
"openai": "^4.83.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-markdown": "^9.0.3",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwind-scrollbar-hide": "^2.0.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
|
||||
@@ -15,4 +15,5 @@
|
||||
|
||||
.app-footer {
|
||||
/* 页脚样式 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ import {generateAICharacters} from "@/config/aiCharacters";
|
||||
import { groups } from "@/config/groups";
|
||||
import type { AICharacter } from "@/config/aiCharacters";
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkMath from 'remark-math'
|
||||
import rehypeKatex from 'rehype-katex'
|
||||
|
||||
// 使用本地头像数据,避免外部依赖
|
||||
const getAvatarData = (name: string) => {
|
||||
@@ -112,6 +115,33 @@ const QuarterAvatar = ({ user, index }: { user: User, index: number }) => {
|
||||
);
|
||||
};
|
||||
|
||||
// 动态导入 KaTeX 样式
|
||||
const KaTeXStyle = () => (
|
||||
<style jsx global>{`
|
||||
/* 只在聊天消息内应用 KaTeX 样式 */
|
||||
.chat-message .katex-html {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.chat-message .katex {
|
||||
font: normal 1.1em KaTeX_Main, Times New Roman, serif;
|
||||
line-height: 1.2;
|
||||
text-indent: 0;
|
||||
white-space: nowrap;
|
||||
text-rendering: auto;
|
||||
}
|
||||
|
||||
.chat-message .katex-display {
|
||||
display: block;
|
||||
margin: 1em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 其他必要的 KaTeX 样式 */
|
||||
@import "katex/dist/katex.min.css";
|
||||
`}</style>
|
||||
);
|
||||
|
||||
const ChatUI = () => {
|
||||
const [group, setGroup] = useState(groups[1]);
|
||||
const groupAiCharacters = generateAICharacters(group.name).filter(character => group.members.includes(character.id));
|
||||
@@ -320,265 +350,272 @@ const ChatUI = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-[100dvh] flex flex-col bg-gray-100 fixed inset-0 overflow-hidden">
|
||||
{/* Header */}
|
||||
<header className="bg-white shadow flex-none">
|
||||
<div className="flex items-center justify-between px-4 py-3">
|
||||
{/* 左侧群组信息 */}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="relative w-10 h-10">
|
||||
<div className="w-full h-full overflow-hidden bg-white border border-gray-200">
|
||||
{users.length === 1 ? (
|
||||
<SingleAvatar user={users[0]} />
|
||||
) : users.length === 2 ? (
|
||||
<div className="h-full flex">
|
||||
{users.slice(0, 2).map((user, index) => (
|
||||
<HalfAvatar key={user.id} user={user} isFirst={index === 0} />
|
||||
))}
|
||||
</div>
|
||||
) : users.length === 3 ? (
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="flex h-1/2">
|
||||
<>
|
||||
<KaTeXStyle />
|
||||
<div className="h-[100dvh] flex flex-col bg-gray-100 fixed inset-0 overflow-hidden">
|
||||
{/* Header */}
|
||||
<header className="bg-white shadow flex-none">
|
||||
<div className="flex items-center justify-between px-4 py-3">
|
||||
{/* 左侧群组信息 */}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="relative w-10 h-10">
|
||||
<div className="w-full h-full overflow-hidden bg-white border border-gray-200">
|
||||
{users.length === 1 ? (
|
||||
<SingleAvatar user={users[0]} />
|
||||
) : users.length === 2 ? (
|
||||
<div className="h-full flex">
|
||||
{users.slice(0, 2).map((user, index) => (
|
||||
<HalfAvatar key={user.id} user={user} isFirst={index === 0} />
|
||||
))}
|
||||
</div>
|
||||
<div className="h-1/2 flex justify-center">
|
||||
<SingleAvatar user={users[2]} />
|
||||
) : users.length === 3 ? (
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="flex h-1/2">
|
||||
{users.slice(0, 2).map((user, index) => (
|
||||
<HalfAvatar key={user.id} user={user} isFirst={index === 0} />
|
||||
))}
|
||||
</div>
|
||||
<div className="h-1/2 flex justify-center">
|
||||
<SingleAvatar user={users[2]} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full grid grid-cols-2">
|
||||
{users.slice(0, 4).map((user, index) => (
|
||||
<QuarterAvatar key={user.id} user={user} index={index} />
|
||||
))}
|
||||
) : (
|
||||
<div className="h-full grid grid-cols-2">
|
||||
{users.slice(0, 4).map((user, index) => (
|
||||
<QuarterAvatar key={user.id} user={user} index={index} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute -bottom-0.5 -right-0.5 bg-green-500 w-3 h-3 border-2 border-white"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="font-medium text-base">{group.name}</h1>
|
||||
<p className="text-xs text-gray-500">{users.length} 名成员</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧头像组和按钮 */}
|
||||
<div className="flex items-center">
|
||||
<div className="flex -space-x-2 ">
|
||||
{users.slice(0, 4).map((user) => {
|
||||
const avatarData = getAvatarData(user.name);
|
||||
return (
|
||||
<TooltipProvider key={user.id}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Avatar className="w-7 h-7 border-2 border-white">
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: avatarData.backgroundColor, color: 'white' }}>
|
||||
{avatarData.text}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{user.name}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
})}
|
||||
{users.length > 4 && (
|
||||
<div className="w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center text-xs border-2 border-white">
|
||||
+{users.length - 4}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute -bottom-0.5 -right-0.5 bg-green-500 w-3 h-3 border-2 border-white"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="font-medium text-base">{group.name}</h1>
|
||||
<p className="text-xs text-gray-500">{users.length} 名成员</p>
|
||||
<Button variant="ghost" size="icon" onClick={() => setShowMembers(true)}>
|
||||
<Users className="w-5 h-5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧头像组和按钮 */}
|
||||
<div className="flex items-center">
|
||||
<div className="flex -space-x-2 ">
|
||||
{users.slice(0, 4).map((user) => {
|
||||
const avatarData = getAvatarData(user.name);
|
||||
return (
|
||||
<TooltipProvider key={user.id}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Avatar className="w-7 h-7 border-2 border-white">
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: avatarData.backgroundColor, color: 'white' }}>
|
||||
{avatarData.text}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{user.name}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
})}
|
||||
{users.length > 4 && (
|
||||
<div className="w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center text-xs border-2 border-white">
|
||||
+{users.length - 4}
|
||||
</header>
|
||||
|
||||
{/* Main Chat Area */}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ScrollArea className="h-full p-4">
|
||||
<div className="space-y-4">
|
||||
{messages.map((message) => (
|
||||
<div key={message.id}
|
||||
className={`flex items-start gap-2 ${message.sender.name === "我" ? "justify-end" : ""}`}>
|
||||
{message.sender.name !== "我" && (
|
||||
<Avatar>
|
||||
{'avatar' in message.sender && message.sender.avatar ? (
|
||||
<AvatarImage src={message.sender.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(message.sender.name).backgroundColor, color: 'white' }}>
|
||||
{message.sender.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
)}
|
||||
<div className={message.sender.name === "我" ? "text-right" : ""}>
|
||||
<div className="text-sm text-gray-500">{message.sender.name}</div>
|
||||
<div className={`mt-1 p-3 rounded-lg shadow-sm chat-message ${
|
||||
message.sender.name === "我" ? "bg-blue-500 text-white text-left" : "bg-white"
|
||||
}`}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
className={`prose dark:prose-invert max-w-none ${
|
||||
message.sender.name === "我" ? "text-white [&_*]:text-white" : ""
|
||||
}
|
||||
[&_h2]:py-1
|
||||
[&_h2]:m-0
|
||||
[&_h3]:py-1.5
|
||||
[&_h3]:m-0
|
||||
[&_p]:m-0
|
||||
[&_pre]:bg-gray-900
|
||||
[&_pre]:p-2
|
||||
[&_pre]:m-0
|
||||
[&_pre]:rounded-lg
|
||||
[&_pre]:text-gray-100
|
||||
[&_pre]:whitespace-pre-wrap
|
||||
[&_pre]:break-words
|
||||
[&_pre_code]:whitespace-pre-wrap
|
||||
[&_pre_code]:break-words
|
||||
[&_code]:text-sm
|
||||
[&_code]:text-gray-400
|
||||
[&_code:not(:where([class~="language-"]))]:text-pink-500
|
||||
[&_code:not(:where([class~="language-"]))]:bg-transparent
|
||||
[&_a]:text-blue-500
|
||||
[&_a]:no-underline
|
||||
[&_ul]:my-2
|
||||
[&_ol]:my-2
|
||||
[&_li]:my-1
|
||||
[&_blockquote]:border-l-4
|
||||
[&_blockquote]:border-gray-300
|
||||
[&_blockquote]:pl-4
|
||||
[&_blockquote]:my-2
|
||||
[&_blockquote]:italic`}
|
||||
>
|
||||
{message.content}
|
||||
</ReactMarkdown>
|
||||
{message.isAI && isTyping && currentMessageRef.current === message.id && (
|
||||
<span className="typing-indicator ml-1">▋</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{message.sender.name === "我" && (
|
||||
<Avatar>
|
||||
{'avatar' in message.sender && message.sender.avatar ? (
|
||||
<AvatarImage src={message.sender.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(message.sender.name).backgroundColor, color: 'white' }}>
|
||||
{message.sender.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" onClick={() => setShowMembers(true)}>
|
||||
<Users className="w-5 h-5" />
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
{/* Input Area */}
|
||||
<div className="bg-white border-t pb-[calc(0.75rem+env(safe-area-inset-bottom))] pt-3 px-4">
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
placeholder="输入消息..."
|
||||
className="flex-1"
|
||||
value={inputMessage}
|
||||
onChange={(e) => setInputMessage(e.target.value)}
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleSendMessage}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="w-4 h-4 mr-2 animate-spin rounded-full border-2 border-white border-t-transparent" />
|
||||
) : (
|
||||
<Send className="w-4 h-4 mr-2" />
|
||||
)}
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Chat Area */}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ScrollArea className="h-full p-4">
|
||||
<div className="space-y-4">
|
||||
{messages.map((message) => (
|
||||
<div key={message.id}
|
||||
className={`flex items-start gap-2 ${message.sender.name === "我" ? "justify-end" : ""}`}>
|
||||
{message.sender.name !== "我" && (
|
||||
<Avatar>
|
||||
{'avatar' in message.sender && message.sender.avatar ? (
|
||||
<AvatarImage src={message.sender.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(message.sender.name).backgroundColor, color: 'white' }}>
|
||||
{message.sender.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
)}
|
||||
<div className={message.sender.name === "我" ? "text-right" : ""}>
|
||||
<div className="text-sm text-gray-500">{message.sender.name}</div>
|
||||
<div className={`mt-1 p-3 rounded-lg shadow-sm ${
|
||||
message.sender.name === "我" ? "bg-blue-500 text-white text-left" : "bg-white"
|
||||
}`}>
|
||||
<ReactMarkdown
|
||||
className={`prose dark:prose-invert max-w-none ${
|
||||
message.sender.name === "我" ? "text-white [&_*]:text-white" : ""
|
||||
}
|
||||
[&_h3]:py-1.5
|
||||
[&_h3]:m-0
|
||||
[&_p]:m-0
|
||||
[&_pre]:bg-gray-900
|
||||
[&_pre]:p-2
|
||||
[&_pre]:m-0
|
||||
[&_pre]:rounded-lg
|
||||
[&_pre]:text-gray-100
|
||||
[&_pre]:whitespace-pre-wrap
|
||||
[&_pre]:break-words
|
||||
[&_pre_code]:whitespace-pre-wrap
|
||||
[&_pre_code]:break-words
|
||||
[&_code]:text-sm
|
||||
[&_code]:text-gray-400
|
||||
[&_code:not(:where([class~="language-"]))]:text-pink-500
|
||||
[&_code:not(:where([class~="language-"]))]:bg-transparent
|
||||
[&_a]:text-blue-500
|
||||
[&_a]:no-underline
|
||||
[&_ul]:my-2
|
||||
[&_ol]:my-2
|
||||
[&_li]:my-1
|
||||
[&_blockquote]:border-l-4
|
||||
[&_blockquote]:border-gray-300
|
||||
[&_blockquote]:pl-4
|
||||
[&_blockquote]:my-2
|
||||
[&_blockquote]:italic`}
|
||||
>
|
||||
{message.content}
|
||||
</ReactMarkdown>
|
||||
{message.isAI && isTyping && currentMessageRef.current === message.id && (
|
||||
<span className="typing-indicator ml-1">▋</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{message.sender.name === "我" && (
|
||||
<Avatar>
|
||||
{'avatar' in message.sender && message.sender.avatar ? (
|
||||
<AvatarImage src={message.sender.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(message.sender.name).backgroundColor, color: 'white' }}>
|
||||
{message.sender.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
)}
|
||||
{/* Members Management Dialog */}
|
||||
<Dialog open={showMembers} onOpenChange={setShowMembers}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>群成员管理</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="mt-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm text-gray-500">当前成员({users.length})</span>
|
||||
<Button variant="outline" size="sm">
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
{/* Input Area */}
|
||||
<div className="bg-white border-t pb-[calc(0.75rem+env(safe-area-inset-bottom))] pt-3 px-4">
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
placeholder="输入消息..."
|
||||
className="flex-1"
|
||||
value={inputMessage}
|
||||
onChange={(e) => setInputMessage(e.target.value)}
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleSendMessage}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="w-4 h-4 mr-2 animate-spin rounded-full border-2 border-white border-t-transparent" />
|
||||
) : (
|
||||
<Send className="w-4 h-4 mr-2" />
|
||||
)}
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Members Management Dialog */}
|
||||
<Dialog open={showMembers} onOpenChange={setShowMembers}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>群成员管理</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="mt-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm text-gray-500">当前成员({users.length})</span>
|
||||
<Button variant="outline" size="sm">
|
||||
<UserPlus className="w-4 h-4 mr-2" />
|
||||
添加成员
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea className="h-[300px]">
|
||||
<div className="space-y-2">
|
||||
{users.map((user) => (
|
||||
<div key={user.id} className="flex items-center justify-between p-2 hover:bg-gray-100 rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar>
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(user.name).backgroundColor, color: 'white' }}>
|
||||
{user.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span>{user.name}</span>
|
||||
{mutedUsers.includes(user.id) && (
|
||||
<span className="text-xs text-red-500">已禁言</span>
|
||||
)}
|
||||
<ScrollArea className="h-[300px]">
|
||||
<div className="space-y-2">
|
||||
{users.map((user) => (
|
||||
<div key={user.id} className="flex items-center justify-between p-2 hover:bg-gray-100 rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar>
|
||||
{'avatar' in user && user.avatar ? (
|
||||
<AvatarImage src={user.avatar} className="w-10 h-10" />
|
||||
) : (
|
||||
<AvatarFallback style={{ backgroundColor: getAvatarData(user.name).backgroundColor, color: 'white' }}>
|
||||
{user.name[0]}
|
||||
</AvatarFallback>
|
||||
)}
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span>{user.name}</span>
|
||||
{mutedUsers.includes(user.id) && (
|
||||
<span className="text-xs text-red-500">已禁言</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{user.name !== "我" && (
|
||||
<div className="flex gap-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleToggleMute(user.id)}
|
||||
>
|
||||
{mutedUsers.includes(user.id) ? (
|
||||
<MicOff className="w-4 h-4 text-red-500" />
|
||||
) : (
|
||||
<Mic className="w-4 h-4 text-green-500" />
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{mutedUsers.includes(user.id) ? '取消禁言' : '禁言'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
{/*<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleRemoveUser(user.id)}
|
||||
>
|
||||
<UserMinus className="w-4 h-4 text-red-500" />
|
||||
</Button>*/}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{user.name !== "我" && (
|
||||
<div className="flex gap-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleToggleMute(user.id)}
|
||||
>
|
||||
{mutedUsers.includes(user.id) ? (
|
||||
<MicOff className="w-4 h-4 text-red-500" />
|
||||
) : (
|
||||
<Mic className="w-4 h-4 text-green-500" />
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{mutedUsers.includes(user.id) ? '取消禁言' : '禁言'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
{/*<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleRemoveUser(user.id)}
|
||||
>
|
||||
<UserMinus className="w-4 h-4 text-red-500" />
|
||||
</Button>*/}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
// 首先定义模型配置
|
||||
export const modelConfigs = [
|
||||
{
|
||||
model: "qwen-plus",
|
||||
apiKey: "DASHSCOPE_API_KEY", // 这里存储环境变量的 key 名称
|
||||
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
},
|
||||
{
|
||||
model: "deepseek-v3",
|
||||
apiKey: "DASHSCOPE_API_KEY",
|
||||
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
},
|
||||
{
|
||||
model: "hunyuan-standard",
|
||||
apiKey: "HUNYUAN_API_KEY",
|
||||
baseURL: "https://api.hunyuan.cloud.tencent.com/v1"
|
||||
},
|
||||
{
|
||||
model: "ep-20250217191935-wzj8l",//火山引擎接入点(改成自己的)
|
||||
apiKey: "ARK_API_KEY",
|
||||
baseURL: "https://ark.cn-beijing.volces.com/api/v3"
|
||||
}
|
||||
] as const;
|
||||
export type ModelType = typeof modelConfigs[number]["model"];
|
||||
|
||||
export interface AICharacter {
|
||||
id: string;
|
||||
name: string;
|
||||
personality: string;
|
||||
model: string;
|
||||
model: ModelType;
|
||||
avatar?: string; // 可选的头像 URL
|
||||
custom_prompt?: string; // 可选的个性提示
|
||||
}
|
||||
@@ -14,7 +39,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai1',
|
||||
name: "暖心姐",
|
||||
personality: "high_eq",
|
||||
model: "hunyuan-turbo",
|
||||
model: modelConfigs[2].model,
|
||||
avatar: "", // 如果有头像资源可以添加路径,
|
||||
custom_prompt: `你是一个名叫"暖心姐"的硅基生命体,你当前在一个叫"${groupName}" 的群里,性格温暖体贴,情商很高。
|
||||
回复时要:
|
||||
@@ -29,7 +54,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai2',
|
||||
name: "直男哥",
|
||||
personality: "low_eq",
|
||||
model: "hunyuan-turbo",
|
||||
model: modelConfigs[2].model,
|
||||
avatar: "",
|
||||
custom_prompt: `你是一个名叫"直男哥"的硅基生命体,你当前在一个叫"${groupName}" 的群里,是一个极度直男,负责在群里制造快乐。你说话极其直接,完全没有情商,经常让人社死。
|
||||
回复时要:
|
||||
@@ -42,7 +67,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai3',
|
||||
name: "北京大爷",
|
||||
personality: "bj_dad",
|
||||
model: "hunyuan-turbo",
|
||||
model: modelConfigs[2].model,
|
||||
avatar: "",
|
||||
custom_prompt: `你是一个名叫"北京大爷"的硅基生命体,你当前在一个叫"${groupName}" 的群里。你是一个典型的北京大爷,说话风趣幽默,经常使用北京方言。
|
||||
回复时要:
|
||||
@@ -55,7 +80,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai4',
|
||||
name: "元宝",
|
||||
personality: "yuanbao",
|
||||
model: "hunyuan-turbo",
|
||||
model: modelConfigs[2].model,
|
||||
avatar: "/img/yuanbao.png",
|
||||
custom_prompt: `你是一个名叫"元宝"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`
|
||||
},
|
||||
@@ -63,7 +88,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai5',
|
||||
name: "豆包",
|
||||
personality: "doubao",
|
||||
model: "ep-20250217191935-wzj8l",
|
||||
model: modelConfigs[3].model,//火山引擎接入点(改成自己的)
|
||||
avatar: "/img/doubao_new.png",
|
||||
custom_prompt: `你是一个名叫"豆包"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`
|
||||
},
|
||||
@@ -71,7 +96,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai6',
|
||||
name: "千问",
|
||||
personality: "qianwen",
|
||||
model: "qwen-plus",
|
||||
model: modelConfigs[0].model,
|
||||
avatar: "/img/qwen.jpg",
|
||||
custom_prompt: `你是一个名叫"千问"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`
|
||||
},
|
||||
@@ -79,7 +104,7 @@ export function generateAICharacters(groupName: string): AICharacter[] {
|
||||
id: 'ai7',
|
||||
name: "DeepSeek",
|
||||
personality: "deepseek-v3",
|
||||
model: "deepseek-v3",
|
||||
model: modelConfigs[1].model,
|
||||
avatar: "/img/ds.svg",
|
||||
custom_prompt: `你是一个名叫"DeepSeek"的硅基生命体,你当前在一个叫"${groupName}" 的聊天群里`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user