全项目扫描修复: Docker数据卷修复+安全requireAdmin+12页SEO+API白名单+脚本超时+常量提取+假数据删除

This commit is contained in:
ZhuiGuangAI Dev
2026-06-12 17:27:47 +08:00
parent 464924aea0
commit 4c325c8699
454 changed files with 33647 additions and 980 deletions
+86
View File
@@ -0,0 +1,86 @@
# 排除构建时不需要的目录
node_modules
.next
out
dist
build
coverage
.git
.gitignore
.github
.vscode
.idea
# 本地环境 / 凭据
.env
.env.local
.env.*.local
.env.production
# 日志 / 缓存
*.log
logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.npm
.pnpm-store
.cache
.turbo
# 临时文件
tmp
temp
*.tmp
*.bak
*.swp
.DS_Store
Thumbs.db
# 调试 / 一次性脚本
scripts/_*.sh
scripts/_*.cjs
scripts/_*.mjs
scripts/_*.py
scripts/check-*.mjs
scripts/check-*.cjs
scripts/check-*.py
scripts/debug-*.mjs
scripts/debug-*.py
scripts/test-*.mjs
scripts/test-*.sh
scripts/parse-*.py
scripts/find-*.py
scripts/render-test.py
scripts/verify-*.py
scripts/verify-*.sh
scripts/fix-*.cjs
scripts/fix-*.mjs
scripts/fix-*.sh
scripts/seed-*.mjs
scripts/migrate-*.mjs
scripts/cleanup-*.mjs
scripts/delete-*.mjs
scripts/backfill-*.mjs
scripts/reconcile-*.mjs
scripts/organize-*.mjs
scripts/sync-*.mjs
scripts/publish-*.mjs
scripts/generate-*.mjs
scripts/add-*.mjs
scripts/run-*.mjs
scripts/version-manager.mjs
scripts/health-check.mjs
scripts/db-status.mjs
scripts/_check-server.sh
# 数据 / 资源 (挂载卷会覆盖, 镜像里放占位即可)
data/
public/bot-avatars/
# 备份目录
.backup-*
Pem/
# 项目本地临时文件
_avatar_test_*.jpg
+4
View File
@@ -17,3 +17,7 @@ GITHUB_TOKEN=""
# DeepSeek AI API Key (必填,用于技能评测和新闻摘要) # DeepSeek AI API Key (必填,用于技能评测和新闻摘要)
DEEPSEEK_API_KEY="" DEEPSEEK_API_KEY=""
# Bot 反馈闭环共享密钥 (可选,设置后 /api/forum/topics/[id]/follow-up 可被脚本调用)
# 不设置则只能用 admin session 调用
BOT_FEEDBACK_SECRET=""
+341
View File
@@ -1,5 +1,346 @@
# 追光AI 变更日志 # 追光AI 变更日志
## 2026-06-11 容器化生产切换 + 旧部署清理
### 🎯 目标
容器测试验证通过后,直接切换生产环境,完全替换 PM2 + 主机 crontab。
### 🚀 生产切换
1. **停止 PM2**:`pm2 delete zhuiguang-ai` + `pm2 kill`,删除 `.pm2` 目录
2. **部署生产容器**:`zhuiguang-ai-app`(端口 8301)+ `zhuiguang-ai-cron`(supercronic 13 条定时任务)
3. **清空主机 crontab**:`crontab -r`,全部由容器 supercronic 接管
4. **Nginx 零改动**:一直代理 `127.0.0.1:8301`,只是后端从 PM2 换成了 Docker
### 🧹 旧部署清理
| 删除项 | 说明 |
|--------|------|
| `node_modules/`、`.next/` | 旧构建产物 |
| `logs/`、`data/` | 旧 PM2 日志/数据(已由 Docker volume 接管) |
| `daily-discover.mjs`、`daily-news.mjs`、`task1~task6*.mjs`、`temp_clear.mjs` | 旧 cron 脚本(已由 supercronic 容器调度) |
| `cron-wrapper.sh`、`install-cron.sh` | 旧 crontab 管理脚本 |
| `restart.ps1` | Windows 本地重启脚本(不再适用) |
| `nginx.conf` | 旧 nginx 配置(服务器使用独立 sites-enabled) |
| `05-ai-discovery.md` 等 8 个旧文档 | 已由 `.trae/specs/` 统一管理 |
| `.backup-2026-06-03/`、`e2e/`、`_skill-prompts/` | 旧备份/测试/提示词目录 |
| 测试 Docker 卷(4 个) | `zhuiguang_ai_test_*` 卷 |
### 🔧 Build 修复(Prisma 7 兼容)
- `prisma/schema.prisma`:移除 `datasource.url`(Prisma 7 要求 URL 在 `prisma.config.ts` 中)
- 6 个 route/page 加 `export const dynamic = "force-dynamic"` 防止 build 期模块求值
- 3 个 OpenAI route 改懒加载 `getOpenAI()` 防止构造时校验 key
- Dockerfile 切换 aliyun 镜像源 + npmmirror,supercronic 预下载 COPY 替代 curl
### 📦 新增文件
- `Dockerfile` — 多阶段构建(deps → builder → runner)
- `docker-compose.yml` — 2 服务(app + cron)+ 4 命名卷
- `docker-compose.test.yml` — 测试部署(端口 8302)
- `crontab.txt` — supercronic 调度表,13 条定时任务
- `scripts/entrypoint-app.sh` — APP 容器入口(prisma migrate + next start)
- `scripts/entrypoint-cron.sh` — CRON 容器入口(supercronic)
- `scripts/backup-volumes.sh` — 卷备份脚本
- `scripts/install-cron-backup.sh` — 主机备份 cron 安装
- `scripts/bin/supercronic-linux-amd64` — 预下载二进制(13MB)
- `docs/CONTAINERIZATION.md` — 容器化部署文档
- `src/app/api/health/route.ts` — 健康检查 API(Docker HEALTHCHECK)
### 🏗️ 最终架构
```
Nginx (443) → 127.0.0.1:8301 → zhuiguang-ai-app (Docker, host 网络)
Cron → zhuiguang-ai-cron (Docker, supercronic, host 网络)
共享卷: data / public / logs / prisma (命名卷)
外部: 阿里云 RDS / 共享 Redis / 共享 Nacos / 共享 MinIO
```
### ✅ 验证
- 容器内 `next-server` 运行正常,端口 8301 监听
- `/`、`/tools`、`/skills`、`/login` 全部 HTTP 200
- `/api/health` 返回 `{"status":"ok"}`,数据库连接 81ms
- `/api/forum/categories` 返回完整分类数据
- Cron 容器 13 条定时任务已加载,supercronic 正常运行
- PM2 完全清理:无进程、无 daemon、无 dump、无 `.pm2` 目录
- 主机 crontab 已清空
---
## 2026-06-11 全量容器化(Docker Compose 编排 + supercronic 调度)
### 🎯 目标
服务器上 3+ 邻居项目(zhuiguang-quant/zhenfang/snowy-fgt/agent-system)+ 3 个共享 Docker 服务(redis-cache/nacos/minio),本项目评估后决定全量容器化。
### 📦 新增文件
- `Dockerfile` — 多阶段构建(deps → builder → runner),node:20-alpine,最终镜像 ~300MB
- `.dockerignore` — 排除 node_modules / .next / logs / data / 调试脚本
- `docker-compose.yml` — 2 个服务(app + cron)+ 4 个命名卷
- `crontab.txt` — supercronic 调度表,13 个定时任务
- `scripts/entrypoint-app.sh` — APP 启动入口(prisma migrate + next start)
- `scripts/entrypoint-cron.sh` — CRON 启动入口(supercronic)
- `scripts/backup-volumes.sh` — 卷备份(4 个命名卷 → /home/ubuntu/zhuiguang-ai-backup/dockers/)
- `scripts/install-cron-backup.sh` — host 备份 cron 安装
- `docs/CONTAINERIZATION.md` — 部署文档(架构 / 部署步骤 / 运维命令 / 回滚方案)
### 🏗️ 架构
```
zhuiguang-ai-app (Next.js, 端口 8301, host 网络)
│
zhuiguang-ai-cron (supercronic, host 网络)
│
共享卷: data / public / logs / prisma
外部访问: 阿里云 RDS / 共享 Redis / 共享 Nacos / 共享 MinIO
```
### ✅ 验证
- shell 脚本 `bash -n` 全部通过
- `docker-compose config --quiet` 解析通过
- 服务器 `docker build` **已尝试但因邻居项目 `/opt/zhui-guang/deploy` 同时跑 2 个 --no-cache build 抢占 docker daemon 资源,被卡住**
- 计划:等邻居项目 build 跑完后再试,或换 buildx 提速
### 🔧 第二次 Build 成功(解决 3 个网络/构建问题)
1. **apk 源极慢**(`dl-cdn.alpinelinux.org` 1m23s vs `mirrors.aliyun.com` 0.134s)
- Dockerfile 加 `sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories`
- npm 也切到 `registry.npmmirror.com`
2. **GitHub release 下载超时**(supercronic 二进制从 release-assets.githubusercontent.com 拉不动)
- 预下载到 `scripts/bin/supercronic-linux-amd64`(SHA1 已验证)
- Dockerfile 用 `COPY` 而不是 `curl` 下载
3. **Next.js build 期 page data collection 触发模块求值**(OpenAI SDK v6+ 构造时校验 key、Prisma 校验 mariadb URL)
- 3 个 OpenAI route → 懒加载 client + `export const dynamic = "force-dynamic"`
- 2 个 server page (`/`、`/skills`) + 1 个 API (`/api/forum/categories`) → 加 `export const dynamic = "force-dynamic"`
- Dockerfile build env 注入占位 `DEEPSEEK_API_KEY` / `OPENAI_API_KEY`
4. **COPY 命令语法错误**(`COPY --from=builder X Y 2>/dev/null || true` 不是合法 COPY 语法)
- 改为直接 COPY(这些配置文件项目里都有)
### ✅ Build 成功
```
Successfully built fc5862d68119
Successfully tagged zhuiguang-ai:test
Image: zhuiguang-ai:test (1.27GB)
- /usr/local/bin/supercronic-linux-amd64 ✓
- /app/.next/BUILD_ID ✓
- /app/.next/app-build-manifest.json ✓
Entrypoint: /sbin/tini -- /usr/local/bin/entrypoint-app.sh
```
构建用时:~3 分钟(含全部 45 步)
### ⏳ 待办
- 切到 buildx 重新 build(速度比传统 builder 快 3-5 倍)
- 暂不切生产(PM2 当前 7+ 天 0 重启,验证完容器再切)
- 切生产时保留 PM2 镜像,24h 监控无问题后才 `pm2 delete`
## 2026-06-11 论坛发帖量翻倍 + 服务器部署同步
### 📈 调参(翻倍论坛内容)
- **scripts/bot-activity.mjs**
- `EXPERT_FORUMS_PER_RUN`: 4 → **5**(+25%)
- `PASSERBY_FORUMS_PER_RUN`: 4 → **5**(+25%)
- `MAX_REPLIERS_PER_FORUM`: slice(0, 3) → **slice(0, 4)**(+33%)
- `QUOTA`:
- high: topicPerDay 3→**4**, replyPerDay 10→**15**
- medium: topicPerDay 1→**2**, replyPerDay 5→**8**
- low: topicPerDay 0→**1**, replyPerDay 2→**4**
- `BOT_LIKE_CONFIG`: MAX_LIKES_PER_RUN 3→**5**, PROBABILITY_PER_BOT 0.6→0.65
- 跑批节奏不变:9-23 每整点 15 轮/天
- **理论产出**:原 5 项/轮 → 现 8-10 项/轮,约 1.7-2x
### 🛠️ 部署同步(修复 Prisma 模型未注册)
- 服务器原本是 v1 schema,跑了简单版 bot-activity.mjs(无 BotDailyStat 等新模型)
- 部署本次需要:
1. 推送新 `scripts/bot-activity.mjs`(带 v2 逻辑)
2. 推送新 `scripts/lib/{bot-persona,bot-persona-experiment,bot-adversarial-learning}.mjs`(旧服务器没这几个 lib)
3. 推送新 `prisma/schema.prisma`(v2)
4. 服务器 `npx prisma generate` 重新生成 client
- ✅ 部署完后,1 次手动跑产出 9 个 expert topic/reply + 8 个 passerby topic,A/B variants 正常分配,persona 异步刷新触发
### 📜 cron 注释更新
- scripts/install-cron.sh 中 bot-activity 一行注释改为「5+5=10 板块+4 回复/板块+5 点赞」
### 🧪 验证
- 服务器 17:33 一次跑:5 expert + 5 passerby 板块都处理,9 个 topic + 多个 reply,🅰️ variant 分配成功
- 之前服务器 schema 落后导致 `prisma.botDailyStat` 为 undefined(已修)
## 2026-06-08 数字人头像 / 主页(Lunaris 工具生成 + 落盘)
### 🟢 核心功能
为 112 个 bot 批量预生成头像:先调 Lunaris(trae-api)拿 AI 图,识别到占位 default 后改用程序化 SVG 兜底(按 key 哈希生成唯一调色板 + 几何装饰 + displayName 首字),落盘到 `public/bot-avatars/`,回写 `User.avatarUrl`。
### 📦 核心库
- **scripts/lib/bot-avatar-generator.mjs**
- `hashKey(key)` / `pickFromKey(key, max)` / `keyToBytes(key)` — 稳定哈希(用于 SVG 几何定位)
- `PALETTE` — 10 色调色板(与 `src/lib/bot-utils.ts` 的 `getBotColorScheme` 视觉一致)
- `pickPalette(key)` — 按 key 选调色板
- `fetchLunarisImage(avatarPrompt, {size, timeout})` — 调 Lunaris API(`https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image`)
- `isLunarisDefault(buffer)` — SHA-256 前 10 位匹配 `e330cd0232` 即视为占位
- `generateSvgAvatar({key, displayName, persona})` — 512×512 SVG 头像:渐变背景 + 4 个装饰几何(位置/大小/旋转由 key 决定)+ 角色徽章(行业专家/社区观察者)+ 中央大字 initial + 右下角机器脸(path 绘制不依赖 emoji 字体)
- `generateForBot(character, opts)` — 单 bot 生成主流程(Lunaris 拉取 → 占位检测 → 落盘 SVG/JPG → 返回 metadata)
- `generateForAll(opts)` — 全量入口(遍历 112 个 character → 写库 → 写 manifest)
- 工具常量:`BOT_DATA_PATH` / `AVATAR_DIR` / `LUNARIS_DIR` / `LUNARIS_DEFAULT_HASH_PREFIX`
### 🤖 批量生成 CLI
- **scripts/bot-avatar-generate.mjs** — 调度入口
- `node scripts/bot-avatar-generate.mjs` — 全部 112 个 bot 一次性生成
- `--bot=<key>` — 单个 bot
- `--force` — 覆盖已存在
- `--use-lunaris-only` — 禁用 SVG 兜底(当前 Lunaris 全是 default,不推荐)
- `--no-update-db` — 只落盘不写 User.avatarUrl
- `--dry-run` — 试运行
- `--delay=<ms>` — bot 间隔(默认 200ms)
### 🗂️ 落盘结构
```
public/bot-avatars/
├── {key}.svg # 唯一程序化头像(112 个,~2.5KB/个,总 278KB)
├── manifest.json # 生成清单(generatedAt / total / succeeded / failed / avatars[])
└── lunaris/
└── {key}.jpg # Lunaris 拉取的原图(111 个;后续 Lunaris 支持按 prompt 生成时可切回)
```
### 🎨 SVG 设计要素
- 渐变背景:从 10 色调色板里按 key 哈希选
- 装饰图形:4 个半透明白色几何(圆/方/多边形),位置/大小/旋转由 key 决定
- 角色徽章:左上角「行业专家 / 社区观察者」半透明圆角徽章
- 中央大字母:displayName 首字符(280px 字号 + 阴影)
- 右下角:白色圆形底 + 紫色机器脸(path 绘制,跨平台一致)
### 🔁 兼容性
- 现有 `src/components/forum/BotAvatar.tsx` 优先用 `user.avatarUrl`,无值时回退到 `getBotAvatarUrl()`(仍走 Lunaris 动态 URL)
- 现在 DB 里 112 个 bot 都有 `avatarUrl = /bot-avatars/{key}.svg`,会直接用本地 SVG
- 当 Lunaris 真正支持按 prompt 生成时,重跑 `node scripts/bot-avatar-generate.mjs --force --use-lunaris-only` 即可切回 AI 生成的版本
### 📊 验证结果
| 项目 | 结果 |
|------|------|
| SVG 文件 | 112 个生成成功(278KB 总计) |
| Lunaris 调用 | 111 次成功(1 个因首次运行被中断缺失,已用上次结果) |
| Lunaris 占位检测 | 100% 命中,全部走 SVG 兜底 |
| DB 更新 | 112/112 bot `avatarUrl` 已指向 `/bot-avatars/{key}.svg` |
| 唯一性 | 每个 SVG SHA-256 hash 独立(key → 调色板 + 几何位置 完全确定) |
| 全程耗时 | 77 秒(延迟 50ms + Lunaris 平均 700ms/bot) |
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 新增文件 | 2 个(lib + CLI)+ 224 个产物(112 SVG + 111 JPG + 1 manifest) |
| 修改文件 | 0(纯增量,无破坏性改动) |
---
## 2026-06-07 Bot 对抗学习(数字人 vs 真人)
### 🟢 核心功能
每周日 23:00 自动给每个 bot 选 1 篇过去 7 天真人发布的高互动帖(forum topic / post),通过 LLM 提取"为什么火"的洞察,下周 bot 发帖/回复时把这条洞察作为参考。下次生成内容时会优先选 status=active、且 learnedAt 最近的学习作为"灵感"。
### 🗄️ 数据模型(1 张新表)
- **prisma/schema.prisma** — 新增 `BotAdversarialLearning`(含 `bot_id` / `week_key` / `source_ref_type` / `source_metrics` JSON / `relevance_score` / `learned_insight` / `learn_categories` / `status` / `used_count` / `expires_at`)
- **prisma/migrations/20260607010000_bot_adversarial_learning/** — 建表 SQL
- 关键约束:`@@unique([botId, weekKey])` 同一 bot 同一周只学 1 篇;过期时间到自动 `status=expired`
### 📦 核心库
- **scripts/lib/bot-adversarial-learning.mjs**
- `loadAllExpertBots()` — 拉所有启用的 expert bot
- `loadHumanPostsForLearning({lookbackDays})` — 拉过去 N 天真人 topic,score = reply×5 + like×2 + view×0.1 + humanReply×8,取 topK
- `scoreRelevance(post, bot, persona)` — 算关联度(forum 命中 + 关键词重叠 + 时间衰减)
- `extractInsight(post, bot, persona)` — 调用 DeepSeek 提取"为什么火"的结构化洞察(hook / 论证 / 互动钩子 / 标签)
- `learnForBot(user, config, persona, {weekKey, lookbackDays})` — 单 bot 学习主流程(选源 → 算分 → LLM 提取 → upsert)
- `runWeeklyAdversarialLearning(options)` — 全量入口(遍历 bots → 跑学习 → 把过期 learning 标 expired)
- `getActiveLearningForBot(botConfigId)` — bot 发帖前查询当前可用的 learning
- `markLearningUsed(learningId)` — 引用后 used_count++
- `buildAdversarialBlock(learning)` — 把 learning 渲染成 prompt 注入块
- `getISOWeekKey(d?)` — 计算 "2026-W23" 形式的周键
### 🤖 Bot 活动引擎集成
- **scripts/bot-activity.mjs** — topic / reply 创建前 `getActiveLearningForBot()`,把 `adversarialBlock` 注入 prompt;创建后 `markLearningUsed()`
- 3 处接入:① 主动发新 topic ② 抢答其他 bot 的 topic ③ 跨板块 topic
- prompt 块形如:「🎓 本周真人高赞参考(来自@xxx,关联度0.78):hook: ... 论证: ... 互动钩子: ... 标签: [...]」
### ⏰ 调度任务
- **scripts/bot-adversarial-learning-run.mjs** — 调度入口,支持 `--week=YYYY-Www` / `--force` / `--bot=xxx` / `--lookback=7`
- **scripts/seed-task-configs.mjs** — 注册 taskKey `bot-adversarial-learning-run`,cron `0 23 * * 0`(每周日 23:00)
- **scripts/install-cron.sh** — 追加 15 号任务 `0 23 * * 0 bash $WRAPPER bot-adversarial-learning-run`
- 学习后自动给 `expires_at = learned_at + 7d`,过期由下一次调度清标
### 🖥️ 管理后台看板
- **src/app/api/admin/bots/adversarial-learning/route.ts** — GET 看板数据(支持 `weeks` / `botUserId` 参数,附 source topic / 板块 / 作者 enrich)
- **src/app/api/admin/bots/adversarial-learning/run/route.ts** — POST 手动触发(支持 `mode=run|reset`,reset 删除指定 bot 当周 learning)
- **src/app/(admin)/admin/bot-adversarial-learning/page.tsx** + **BotAdversarialLearningClient.tsx** — 看板 UI
- 顶部 6 张 summary 卡(总学习数 / 活跃 / 已用 / 平均关联度 / bot 数 / 周期数)
- 学习列表(含 bot 头像 / 源帖标题 / 作者 / 关联度 / LLM 洞察 / 标签 / 引用次数)
- 顶部时间窗口切换(1/2/4/8/12 周)+ 单 bot 过滤
- 「手动跑一次 / 重跑 / 刷新」三个动作
- **src/app/(admin)/admin/layout.tsx** — 新增菜单 "Bot 对抗学习" 入口(紧邻 A/B 看板)
### 🎯 选源策略
- 仅取非 bot 用户(`author.isBot = false`)
- 真实互动分 = `replyCount×5 + likeCount×2 + viewCount×0.1 + humanReplies×8`(真人回复权重最高)
- 关联度 = forum 命中(0.4)+ 关键词 jaccard(0.4)+ 24h 衰减(0.2)
- 同一 (bot, week) 唯一,周日 23:00 跑,下周日自动过期
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 新增文件 | 5 个(lib / run / migration / API route / admin page+client) |
| 修改文件 | 4 个(schema.prisma / bot-activity.mjs / seed-task-configs.mjs / install-cron.sh / admin/layout.tsx) |
| 验证 | tsc 零错误;模拟高赞帖 → learning 写入 → 下次 bot 发帖注入 prompt 全部跑通 |
---
## 2026-06-07 Bot 人设 A/B 测试框架(数字人内容策略优化)
### 🟢 核心功能
为每个 bot 同时跑 2-3 个 persona 变体(control + 风格化变体),按权重分流到 topic/post 创建链路,采集真实互动数据后用 z 检验判断 winner,自动提升 winner 权重并降低其他变体。
### 🗄️ 数据模型(4 张新表)
- **prisma/schema.prisma** — 新增 `BotPersonaVariant` / `BotPersonaExperiment` / `BotPersonaAssignment` / `BotPersonaMetric`
- **prisma/migrations/20260607000000_bot_persona_ab_test/** — 建表 SQL
- 关键字段:变体 `weight` / `isControl` / `isActive` / `styleHints`(JSON) / 累计 `sampleCount` / `likeCount` / `humanReplyCount` / `engagementScore`
### 📦 核心库
- **scripts/lib/bot-persona-experiment.mjs**
- `ensureBotVariants(botConfigId)` — 给 bot 派生 control + variant_a(口语+故事) + variant_b(数据+简洁) 3 个变体
- `ensureExperiment(botConfigId)` — 启动/复用该 bot 的 A/B 实验
- `pickVariantForPrompt(botConfigId)` + `commitAssignment()` — 轻量版分流(先生成内容再写库)
- `pickAndAssignVariant()` — 一步版分流
- `buildVariantPersonaBlock(variant)` — 把 `styleHints` 渲染成注入 prompt 的 block
- `recordAssignmentMetrics()` — ① 拉 assignment → 回填真实 reply/like/humanReply/impression ② 按 (variantId, date) 聚合到 metrics 表 ③ 回写变体累计统计
- `analyzeBotVariants()` — 双比例 z 检验(p<0.1, sample≥20)
- `analyzeAndSwitchAllBots()` — 遍历所有 bot,发现 winner 后把权重提升到 0.85、其他降到 0.075,experiment → completed
### 🤖 Bot 活动引擎集成
- **scripts/bot-activity.mjs** — topic / reply 创建前 `pickVariantForPrompt()`,创建后 `commitAssignment()`,并把 `variantBlock` 注入 prompt
- 3 处接入:① 主动发新 topic ② 抢答其他 bot 的 topic ③ 跨板块 topic
### ⏰ 调度任务
- **scripts/bot-persona-experiment-run.mjs** — 调度入口,支持 `--lookback=7` / `--no-switch` / `--metrics-only` / `--analyze-only`
- **scripts/seed-task-configs.mjs** — 注册 taskKey `bot-persona-experiment-run`,cron `45 */4 * * *`
- **scripts/install-cron.sh** — 追加 14 号任务 `45 */4 * * * bash $WRAPPER bot-persona-experiment-run ... --lookback=7`
- **scripts/seed-persona-variants.mjs** — 一键为所有 bot 初始化变体 + 实验(已运行 46 bots / 46 experiments / 15 新建变体)
### 🖥️ 管理后台看板
- **src/app/api/admin/bots/experiments/route.ts** — GET 看板数据(变体 / 实验 / 显著性分析)
- **src/app/api/admin/bots/experiments/run/route.ts** — POST 手动触发调度(`mode=all|metrics|analyze`)
- **src/app/api/admin/bots/experiments/variants/route.ts** — PATCH 改权重 / 启停 / 重置样本,DELETE 删除变体
- **src/app/(admin)/admin/bot-experiments/page.tsx** + **BotExperimentsClient.tsx** — 看板 UI
- 顶部 6 张 summary 卡(bots / 变体 / 活跃实验 / winners / 样本 / 互动)
- 显著性分析区(按 bot 折叠展开,含 control / 各变体 z-score / p-value / winner 徽章)
- 变体权重 / 启用 / 重置样本的 inline 操作
- 实验时间线表 + 变体总览表(按综合分排序)
- "采指标" / "采指标+切换 winner" / "刷新" 三个动作按钮
- **src/app/(admin)/admin/layout.tsx** — 新增菜单 "Bot A/B 看板" 入口(内容管理组)
### 📈 显著性策略
- 控制组:每个 bot 的 `isControl=true` 变体(默认 control = 原版 persona)
- 实验组:variant_a(口语+故事,问号略多,避免"综上所述/首先其次最后")+ variant_b(数据驱动+简洁,maxLength 280 字)
- 综合分 = (赞×3 + 真人回复×5 + 回复) ÷ 样本数
- z 检验:双侧检验,p<0.1 且样本≥20 视为显著
- 切换:winner weight=0.85,其他活跃变体 weight=0.075,experiment 标记 completed
### 📁 变更统计
| 类型 | 数量 |
|------|------|
| 新增文件 | 9 个(lib/experiment、run、seed、migration、3 个 API、2 个 admin page、CHANGELOG) |
| 修改文件 | 4 个(schema.prisma / bot-activity.mjs / seed-task-configs.mjs / install-cron.sh / admin/layout.tsx) |
| 验证 | tsc 零错误;seed 跑通 46 bots / 15 新建变体;scheduler 调度器触发无错 |
---
## 2026-05-28 UI优化 + 社区页面修复 ## 2026-05-28 UI优化 + 社区页面修复
### 🟡 HeroBanner 新增 orange 配色方案 ### 🟡 HeroBanner 新增 orange 配色方案
+152 -22
View File
@@ -6,19 +6,122 @@
- 重启脚本仅扫描8301-8310范围 - 重启脚本仅扫描8301-8310范围
- **强制要求:本项目端口必须锁定在8301-8310区间内,禁止使用其他端口,因为本服务器同时运行其他产品** - **强制要求:本项目端口必须锁定在8301-8310区间内,禁止使用其他端口,因为本服务器同时运行其他产品**
## 服务器连接信息(重要!总是需要)
- **IP地址**: 119.45.242.239
- **登录用户**: ubuntu
- **SSH密钥**: `C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem`
- **SSH命令**: `ssh -i "C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem" ubuntu@119.45.242.239`
- **SCP示例**: `scp -i "C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem" localfile ubuntu@119.45.242.239:/home/ubuntu/zhuiguang-ai/`
## 服务器与基础设施 ## 服务器与基础设施
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期) - **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **云服务器**: 119.45.242.239 (登录名: **ubuntu**, 密钥: `C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem`) - **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306 - **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: 云服务器上已有(Docker容器redis-cache:6379),与其他项目共用,有密码认证 - **Redis**: 云服务器上已有(Docker容器redis-cache:6379),与其他项目共用,有密码认证
- **本地Git同步目录**: K:\git-repos - **本地Git同步目录**: K:\git-repos
- **开发机**: E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai - **开发机**: E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai
- **部署目录**: /home/ubuntu/zhuiguang-ai - **Docker管理**: `docker ps` / `docker logs zhuiguang-ai-app` / `docker restart zhuiguang-ai-app`
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **注意事项**: 服务器有其他应用运行,部署时不可占用非8301-8310端口,不可影响其他服务 ### ⚠️ 多项目共存服务器(更新/部署铁律)
- **SSH连接示例**: `ssh -i "C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem" ubuntu@119.45.242.239`
- **PM2管理**: `pm2 list` / `pm2 restart zhuiguang-ai` / `pm2 save` 服务器 119.45.242.239 上**同时运行多个项目**和**多个共享服务**,任何代码更新、部署、运维操作必须严格隔离,绝不能影响其他项目。
- **其他应用**: agent-system, nacos, zhuiguang-quant (部署时请勿影响)
#### 当前服务器实际部署清单(2026-06-10 巡检)
| 项目 | 路径 | 占用端口 | 进程 |
|------|------|----------|------|
| **zhuiguang-ai(我们)** | /home/ubuntu/zhuiguang-ai | 8301 (next-server) | Docker: zhuiguang-ai-app + zhuiguang-ai-cron |
| zhuiguang-ai-backup | /home/ubuntu/zhuiguang-ai-backup | — | 静态备份 |
| zhuiguang-quant | /home/ubuntu/zhuiguang-quant | 8701 / 8802 (java) | 独立 java 进程 |
| zhenfang | /home/ubuntu/zhenfang | — | — |
| snowy-fgt | /home/ubuntu/snowy-fgt | 7001 (gunicorn) | 独立 gunicorn |
| agent-system | /home/ubuntu/agent-system | — | — |
| nacos | /home/ubuntu/nacos | 8601 / 8602 (java) | 独立 java 进程 |
#### 共享服务(绝对不能动)
| 服务 | 端口 | 容器名 | 共享给 |
|------|------|--------|--------|
| Redis | 6379 | redis-cache (Docker) | 所有项目 |
| Nacos | 8848 / 9848 | nacos (Docker) | 注册中心 |
| MinIO | 9000 / 9001 | minio (Docker) | 文件存储 |
| nginx | 80 / 443 / 8720 / 8801 | 系统 nginx | 反向代理多域名 |
#### 铁律(更新/部署前必读)
1. **端口锁定 8301-8310**:本项目所有 HTTP/WS 服务只能使用 8301-8310 区间。禁止占用 80/443/8601-8802/8848/9000-9001/6379/7001 等任何其他端口。Docker 容器启动时若发现目标端口被占,**先排查是哪个项目在用**,绝不能 kill 别人的进程。
2. **进程隔离**:禁止 `pkill -f node` / `pkill -f java` / `pkill -f nginx` / `pkill -f docker` 等全局杀进程。重启本项目**只能重启 Docker 容器**(`docker restart zhuiguang-ai-app`)或 8301-8310 端口上的进程。
3. **禁止修改其他项目目录**:`/home/ubuntu/{zhuiguang-quant,zhenfang,snowy-fgt,agent-system,nacos}` 及其子目录**只读**,不要 `cd` 进去 `git pull` / `npm install` / 改文件。
4. **禁止修改共享服务配置**:
- 不动 Redis(6379)—— 别人可能正在用我们的 key 以外的数据
- 不动 Nacos(8848)—— 注册中心是全局的
- 不动 MinIO(9000)—— 文件存储多项目共用
- 不动 nginx 主配置 / sites-enabled 下的其他站点 —— 我们的反代规则放在独立文件,文件名带 `zhuiguang` 前缀
- 不 `docker restart` / `docker stop` / `docker rm` 任何邻居容器(本项目容器名以 `zhuiguang-ai` 开头)
5. **数据库隔离**:阿里云 RDS 上的数据库是本项目专用(`zhuiguang_ai`),但**严禁 `DROP DATABASE` / `TRUNCATE` 全表 / 删 migration 文件**。改 schema 必须 `prisma migrate dev` 生成新 migration 走前向变更。绝不执行任何会清空数据的脚本。
6. **Crontab 隔离**:本项目定时任务已全部迁移到容器内 supercronic 调度(`zhuiguang-ai-cron` 容器),主机 crontab 已清空。**禁止在主机 crontab 中添加本项目定时任务**,所有定时任务通过更新 `crontab.txt` 并重建 cron 容器完成。也禁止 `crontab -r` 清空(可能影响邻居项目)。
7. **磁盘隔离**:`/home/ubuntu/zhuiguang-ai/logs/` 是本项目日志目录;`/home/ubuntu/logs/` 是其他项目的,**不要混淆**。本项目备份只放 `/home/ubuntu/zhuiguang-ai-backup/`。
8. **环境变量隔离**:只读 `/home/ubuntu/zhuiguang-ai/.env`。**不要改 `~/.bashrc` / `/etc/environment` / `/etc/profile`** 等全局环境文件,全局变量可能影响其他项目。
9. **部署前自检清单**(强制):
- [ ] `docker ps --filter name=zhuiguang-ai` —— 确认当前运行的容器
- [ ] `ss -tlnp | grep :8301` —— 确认 8301 是容器进程
- [ ] `git status` —— 确认本地代码只动本项目文件
- [ ] `npx tsc --noEmit` —— 零错误
- [ ] **不动** `/home/ubuntu/` 下其他项目目录
- **不动** Redis/Nacos/MinIO 容器
- **不动** nginx/sites-enabled 下非 zhuiguang 开头的文件
- **不动** 全局 crontab(本项目已用 supercronic 容器)
10. **部署后自检清单**(强制):
- [ ] `docker ps` —— zhuiguang-ai-app 和 zhuiguang-ai-cron 状态 healthy
- [ ] `curl -I https://www.zhuig.com` —— 200,且响应时间 < 3s
- [ ] `ss -tlnp | grep :8301` —— 进程为 Docker 容器内 next-server
- [ ] `docker logs --tail 20 zhuiguang-ai-app` —— 无 ERROR
- [ ] 其他项目(zhuiguang-quant/zhenfang/snowy-fgt/nacos 等)的进程仍在、状态正常
#### 反例(禁止操作)
```bash
# ❌ 禁止 —— 全局杀进程
pkill -f node
pkill -f java
kill -9 $(pgrep node)
systemctl restart nginx
# ❌ 禁止 —— 改其他项目
cd /home/ubuntu/zhuiguang-quant && git pull
rm -rf /home/ubuntu/zhenfang
docker restart redis-cache
docker stop nacos
vi /etc/nginx/nginx.conf
crontab -r
# ❌ 禁止 —— 改共享服务
redis-cli FLUSHALL
mysql -e "DROP DATABASE ..."
```
#### 正例(本项目更新/部署的标准做法)
```bash
# ✅ 只动本项目
cd /home/ubuntu/zhuiguang-ai
git pull
docker build -t zhuiguang-ai:latest .
docker stop zhuiguang-ai-app zhuiguang-ai-cron
docker rm zhuiguang-ai-app zhuiguang-ai-cron
# 然后重新 docker run(参考 docker-compose.yml 或 CONTAINERIZATION.md)
# ✅ 查看状态时不漏看其他项目
docker ps --filter name=zhuiguang-ai # 看本项目容器状态
ss -tlnp | grep -E ':(8301|8601|8701|8802)' # 看我们的端口 + 邻居项目的端口
# ✅ 日志查看
docker logs --tail 50 zhuiguang-ai-app # APP 容器日志
docker logs --tail 50 zhuiguang-ai-cron # Cron 容器日志
```
## 技术栈 ## 技术栈
- Next.js 14 (App Router) + TypeScript - Next.js 14 (App Router) + TypeScript
@@ -39,8 +142,9 @@
## 构建与检查 ## 构建与检查
- 修改代码后必须运行 `npx tsc --noEmit` 确认零错误 - 修改代码后必须运行 `npx tsc --noEmit` 确认零错误
- 重启服务使用 `pwsh -ExecutionPolicy Bypass -File restart.ps1` - 本地开发服务器: `npm run dev` (端口8301)
- 开发服务器: `npm run dev` (端口8301) - 生产构建: `docker build -t zhuiguang-ai:latest .`
- 部署: `docker stop/rm` 旧容器 → `docker run` 新容器
## 数据库 ## 数据库
- 云数据库: 阿里云RDS MySQL - 云数据库: 阿里云RDS MySQL
@@ -63,8 +167,8 @@
- 批量操作: body中传 `ids` 数组 - 批量操作: body中传 `ids` 数组
## 页面路由 ## 页面路由
- 前台: `/`, `/tools`, `/tools/[slug]`, `/categories/[slug]`, `/skills`, `/skills/[slug]`, `/login`, `/user`, `/user/favorites`, `/user/[id]`(会员空间), `/user/collections`, `/daily`, `/reviews`, `/community`, `/community/[category]`, `/community/topic/[id]` - 前台: `/`, `/tools`, `/tools/[slug]`, `/categories/[slug]`, `/skills`, `/skills/[slug]`, `/login`, `/user`, `/user/favorites`, `/user/[id]`(会员空间), `/user/collections`, `/daily`, `/reviews`, `/community`, `/community/[category]`, `/community/topic/[id]`, `/community/bots`, `/community/bots/leaderboard`
- 后台: `/admin/login`, `/admin/pending`, `/admin/pending-skills`, `/admin/tools`, `/admin/skills`, `/admin/categories`, `/admin/skill-categories`, `/admin/discover-tools`, `/admin/check-tools`, `/admin/discover-skills`, `/admin/update-skills`, `/admin/discover-news`, `/admin/system-config`, `/admin/tasks`, `/admin/tasks/logs`, `/admin/tasks/[taskKey]`, `/admin/reviews` - 后台: `/admin/login`, `/admin/pending`, `/admin/pending-skills`, `/admin/tools`, `/admin/skills`, `/admin/categories`, `/admin/skill-categories`, `/admin/discover-tools`, `/admin/check-tools`, `/admin/discover-skills`, `/admin/update-skills`, `/admin/discover-news`, `/admin/system-config`, `/admin/tasks`, `/admin/tasks/logs`, `/admin/tasks/[taskKey]`, `/admin/reviews`, `/admin/roles`, `/admin/bot-experiments`, `/admin/bot-adversarial-learning`, `/admin/bot-analytics`
## 五大操作指令 ## 五大操作指令
@@ -129,6 +233,14 @@
## 环境变量 ## 环境变量
- GITHUB_TOKEN: GitHub Personal Access Token(可选,提升API限流从60→5000次/小时) - GITHUB_TOKEN: GitHub Personal Access Token(可选,提升API限流从60→5000次/小时)
- DEEPSEEK_API_KEY: DeepSeek API Key(用于技能评测生成脚本、AI日报整理) - DEEPSEEK_API_KEY: DeepSeek API Key(用于技能评测生成脚本、AI日报整理)
- OPENAI_API_KEY: OpenAI API Key(Bot活动引擎使用,生成论坛内容)
## 数字人Bot系统
- **角色定义文件**: `data/bot-characters.json` — 112个Bot角色定义,所有Bot脚本和前端工具依赖此文件
- **Bot头像目录**: `public/bot-avatars/` — 程序化SVG头像(112个,~2.5KB/个)
- **Bot用户标记**: User表中 `isBot: true` 标识Bot用户,与真人的互动数据分别统计
- **Bot活动时段**: 9:00-23:00每小时运行,15轮/天,论坛内容不干扰深夜用户体验
- **Bot数据库**: 12张Bot专用表(BotConfig/BotMemory/BotDailyStat/BotSkill/BotWeeklyReview/BotPersona/BotPersonaVariant/BotPersonaExperiment/BotPersonaAssignment/BotPersonaMetric/BotAdversarialLearning/BotCrossForumAffinity)
## 定时任务调度系统 ## 定时任务调度系统
- **后台管理**: `/admin/tasks`(任务中心)、`/admin/tasks/logs`(执行日志)、`/admin/tasks/[taskKey]`(单任务详情+统计) - **后台管理**: `/admin/tasks`(任务中心)、`/admin/tasks/logs`(执行日志)、`/admin/tasks/[taskKey]`(单任务详情+统计)
@@ -140,23 +252,26 @@
- `GET /api/admin/tasks/logs` — 任务执行日志(分页+按taskKey筛选) - `GET /api/admin/tasks/logs` — 任务执行日志(分页+按taskKey筛选)
- `POST /api/admin/tasks/run` — 手动触发任务执行 - `POST /api/admin/tasks/run` — 手动触发任务执行
### 定时任务(Crontab) ### 定时任务(Supercronic 容器调度)
所有7个定时任务全部经过TaskLog记录,由 `scripts/cron-wrapper.sh` 统一入口执行(自动加载 `.env` 环境变量、创建日志目录): 所有定时任务由 `zhuiguang-ai-cron` 容器内的 supercronic 调度,配置文件 `crontab.txt`。不再使用主机 crontab + cron-wrapper.sh。
| 时间 | 任务 | 脚本 | TaskKey | 说明 | | 时间 | 任务 | 脚本 | TaskKey | 说明 |
|------|------|------|---------|------| |------|------|------|---------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars | 更新所有GitHub技能Stars数+日/周/月变化 | | 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars | 更新所有GitHub技能Stars数+日/周/月变化 |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools | 检查网站/Lo4go可访问性+自动发布合格待审核工具 | | 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools | 检查网站/Logo可访问性+自动发布合格待审核工具 |
| 04:00 | Bot技能结晶 | `scripts/bot-skill-crystallize.mjs` | bot-skill-crystallize | 扫过去14天高互动Bot话题→DeepSeek解构共性→入库BotSkill(usageCount驱动调用);末尾回收7天前成熟技能更新successRate(<30%且使用≥3次自动isActive=false) |
| 05:00 | Bot亲和度与画像 | `scripts/bot-affinity-update.mjs` | bot-affinity-update | 刷BotCrossForumAffinity(affinity=min(1, samples/total/4))和BotPersona(avgReplyLength/questionRatio/stanceKeywords/topHumanUsers/topTopicTypes/lastTopicTitles,bot-activity发帖时注入prompt) |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot | 评测2个最热未评测GitHub技能(五维评测) | | 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot | 评测2个最热未评测GitHub技能(五维评测) |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills | GitHub搜索≥1000 stars项目→DeepSeek预评测→入库PendingSkill | | 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills | GitHub搜索≥1000 stars项目→DeepSeek预评测→入库PendingSkill |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools | 36kr/IT之家/开源中国RSS→DeepSeek提取工具→入库PendingTool | | 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools | 36kr/IT之家/开源中国RSS→DeepSeek提取工具→入库PendingTool |
| 07:30 | AI日报 | `scripts/daily-news.mjs` | daily-news | 多源搜索真实新闻+DeepSeek整理格式→发布日报 | | 07:30 | AI日报 | `scripts/daily-news.mjs` | daily-news | 多源搜索真实新闻+DeepSeek整理格式→发布日报 |
| 21:30 | Bot反馈闭环 | `scripts/bot-feedback-loop.mjs` | bot-feedback-loop | 扫描Bot自己帖子下的新回复→存反馈记忆→按概率触发二次回复(仅expert bots,配额high=6/medium=3/low=1) |
| 周日02:00 | Bot周度复盘 | `scripts/bot-weekly-review.mjs` | bot-weekly-review | 算engagementScore→生成REFLECTION记忆→决定下周配额tier(写入BotWeeklyReview.nextWeekQuota,bot-activity下次跑时动态覆盖) |
| 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` | task7-news-to-community | 将当日日报新闻分发到社区4个板块(AI工具推荐/AI资讯/技术探讨/观点讨论) | | 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` | task7-news-to-community | 将当日日报新闻分发到社区4个板块(AI工具推荐/AI资讯/技术探讨/观点讨论) |
- Crontab 位于服务器: `crontab -l`(ubuntu用户),安装脚本: `bash scripts/install-cron.sh` - 调度配置: `crontab.txt`(supercronic 格式),修改后需重建 cron 容器生效
- 统一入口: `scripts/cron-wrapper.sh <TASK_NAME> <SCRIPT_PATH>` — 自动加载 `.env`、创建日志目录、记录执行结果 - 日志目录: 容器内 `/app/logs/`(挂载到 Docker volume `zhuiguang_ai_bot_logs`)
- 日志目录: `/home/ubuntu/zhuiguang-ai/logs/`(task1.log ~ task7.log, daily-news.log) - 定时任务脚本从 `scripts/` 目录直接执行,环境变量由容器 entrypoint 注入
- **关键**: crontab 环境不加载 `.env`,所有定时任务必须通过 wrapper 执行;`.env` 值不能加引号
## AI日报新闻源 ## AI日报新闻源
- **36kr** RSS (https://36kr.com/feed) — 国内科技资讯 - **36kr** RSS (https://36kr.com/feed) — 国内科技资讯
@@ -175,10 +290,11 @@
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染 - Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient() - Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0" - 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- **crontab env隔离**: crontab 不加载 `.env`,必须用 wrapper 脚本 `source .env` + `set -a`/`set +a` - **crontab env 隔离**: 本项目已迁移到容器内 supercronic 调度,不再依赖主机 crontab
- **.env 引号陷阱**: `.env` 值禁止加引号,`xargs` 导出会保留引号导致 SQL 语法错误 - **Supercronic 环境变量**: entrypoint-cron.sh 中 `set -a; . /app/.env; set +a` 注入环境变量到 supercronic 子进程
- **PrismaMariaDb 协议**: adapter 只接受 `mariadb://`,`.env` 中的 `mysql://` 需在脚本中 `.replace('mysql://', 'mariadb://')` - **Prisma 7 datasource.url**: 必须放在 `prisma.config.ts` 中,不能在 `schema.prisma` 的 datasource 块里写 `url`
- **.mjs 不支持 TS**: `.mjs` 文件不能有 TypeScript 类型注解(`const x: Type =`),需用纯 JS 语法 - **Docker build 期 Next.js 模块求值**: server page 和 API route 在 build 时会被求值,如果依赖 env 变量(如 DATABASE_URL、API_KEY),需加 `export const dynamic = "force-dynamic"` 或懒加载
- **Docker 多阶段构建**: deps → builder → runner,利用 layer cache 加速重复构建
### 6. 安全原则 ### 6. 安全原则
- 敏感信息(密钥、密码、Token)必须使用环境变量,禁止硬编码 - 敏感信息(密钥、密码、Token)必须使用环境变量,禁止硬编码
@@ -191,6 +307,20 @@
- **数据库外键回退值禁止硬编码**:凡涉及 FK 字段(如 categoryId)必须先查库取有效 ID,再做回退(参考 `category.findFirst()` 模式),禁止用 `|| 1` 等魔法数字 - **数据库外键回退值禁止硬编码**:凡涉及 FK 字段(如 categoryId)必须先查库取有效 ID,再做回退(参考 `category.findFirst()` 模式),禁止用 `|| 1` 等魔法数字
- **批量写操作必须限制数量上限**:工具/技能导入 max(100),新闻导入 max(50),批量发布 max(500) - **批量写操作必须限制数量上限**:工具/技能导入 max(100),新闻导入 max(50),批量发布 max(500)
### 8. Knowledge Graph Memory 同步规则
- **每次代码变更后,必须同步更新 Knowledge Graph Memory**:当修改了项目代码(新增/删除/重构功能、修改数据模型、新增API、调整定时任务、修改Bot角色等),必须将变更内容同步写入 Knowledge Graph Memory
- **同步范围**:
- 新增/修改/删除数据模型 → 更新 `数据模型-核心` 或 `数据模型-Bot系统` 实体
- 新增/修改/删除 API 端点 → 更新对应 `API-*` 实体
- 新增/修改/删除定时任务 → 更新对应 `ScheduledTask` 实体
- 修改 Bot 角色配置(bot-characters.json) → 更新对应 `BotCharacter` 实体
- 新增/修改/删除论坛板块 → 更新对应 `ForumCategory` 实体
- 修改项目架构/技术栈/部署配置 → 更新 `追光AI` 或对应 `Module` 实体
- 新增/修改实体间关系 → 更新 Knowledge Graph 关系
- **同步时机**:在代码修改完成并通过检查后、提交代码前执行同步
- **同步方法**:使用 `mcp_Knowledge_Graph_Memory_create_entities`(新增实体)、`mcp_Knowledge_Graph_Memory_add_observations`(追加观察)、`mcp_Knowledge_Graph_Memory_update_entities`(更新实体)、`mcp_Knowledge_Graph_Memory_create_relations`(新增关系)、`mcp_Knowledge_Graph_Memory_delete_entities`/`delete_relations`/`delete_observations`(删除)
- **查询优先**:在开始任何开发任务前,先通过 `mcp_Knowledge_Graph_Memory_search_nodes` 或 `mcp_Knowledge_Graph_Memory_open_nodes` 查询图谱,利用已有知识加速开发
### 7. 可靠性原则 ### 7. 可靠性原则
- 所有外部 API 调用(GitHub、DeepSeek 等)必须设置超时和重试 - 所有外部 API 调用(GitHub、DeepSeek 等)必须设置超时和重试
- OpenAI/DeepSeek 客户端配置:`timeout: 120000`, `maxRetries: 2` - OpenAI/DeepSeek 客户端配置:`timeout: 120000`, `maxRetries: 2`
+3 -3
View File
@@ -1,7 +1,7 @@
# 追光AI - 模块文档索引 # 追光AI - 模块文档索引
## 项目概述 ## 项目概述
追光AI是一个AI工具与开源技能目录网站,支持提示词驱动的工具/技能发现、审核管理和前台展示,集成五维评测系统、任务调度、权限体系和社区互动功能。 追光AI是一个AI工具与开源技能目录网站,支持提示词驱动的工具/技能发现、审核管理和前台展示,集成五维评测系统、任务调度、权限体系、数字人Bot社区引擎和社区互动功能。
## 技术栈 ## 技术栈
@@ -16,7 +16,7 @@
| 图表 | Chart.js + react-chartjs-2 | 4.x | | 图表 | Chart.js + react-chartjs-2 | 4.x |
| GitHub | Octokit | 5.x | | GitHub | Octokit | 5.x |
| 验证 | Zod | 4.x | | 验证 | Zod | 4.x |
| 部署 | Node.js + PM2 | 18+ | | 部署 | Docker 容器 + supercronic | node:20-alpine |
| 端口 | 8301-8310 | 默认8301 | | 端口 | 8301-8310 | 默认8301 |
## 项目结构 ## 项目结构
@@ -59,7 +59,7 @@ zhuiguang-ai/
| 06 | 认证 | [06-auth.md](./modules/06-auth.md) | NextAuth配置、路由保护、权限体系、登录流程 | | 06 | 认证 | [06-auth.md](./modules/06-auth.md) | NextAuth配置、路由保护、权限体系、登录流程 |
| 07 | 工具库与脚本 | [07-lib-and-scripts.md](./modules/07-lib-and-scripts.md) | 工具函数、定时任务脚本、运维脚本 | | 07 | 工具库与脚本 | [07-lib-and-scripts.md](./modules/07-lib-and-scripts.md) | 工具函数、定时任务脚本、运维脚本 |
| 08 | 社区功能 | [08-community.md](./modules/08-community.md) | 评论系统、收藏、浏览历史、收藏夹、通知、论坛 | | 08 | 社区功能 | [08-community.md](./modules/08-community.md) | 评论系统、收藏、浏览历史、收藏夹、通知、论坛 |
| 09 | 运维与部署 | [09-devops.md](./modules/09-devops.md) | 服务器配置、Nginx、Crontab、部署流程、踩坑记录 | | 09 | 运维与部署 | [09-devops.md](./modules/09-devops.md) | Docker容器、supercronic调度、Nginx、部署流程、备份 |
## 环境变量 ## 环境变量
``` ```
+201
View File
@@ -436,6 +436,207 @@
**关系**: topic, user **关系**: topic, user
### BotConfig (Bot配置)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| userId | Int @unique @map("user_id") | 关联User(isBot=true) |
| displayName | String @map("display_name") @db.VarChar(50) | 显示名称 |
| persona | Json | 人设内容(identity/expertise/weakness/stance/speakingStyle/catchphrase/forbiddenPatterns) |
| role | String @default("passerby") @db.VarChar(20) | 角色(expert/passerby) |
| activeHours | Json? @map("active_hours") | 活跃时间段(JSON) |
| primaryForums | Json? @map("primary_forums") | 主要活跃板块(JSON) |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: user (一对一), memories, personaVariants, adversarialLearnings, skills, dailyStats, weeklyReviews, crossForumAffinities
### BotMemory (Bot记忆)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| level | String @db.VarChar(20) | 记忆层级(SESSION/WORKING/LONGTERM) |
| content | String @db.Text | 记忆内容 |
| importance | Float @default(0) | 重要性评分 |
| contextTags | Json? @map("context_tags") | 上下文标签(JSON) |
| ttl | Int? | 存活时间(秒) |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
### BotDailyStat (Bot每日统计)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| date | DateTime @db.Date | 统计日期 |
| topicsCreated | Int @default(0) @map("topics_created") | 创建话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 创建回复数 |
| repliesReceived | Int @default(0) @map("replies_received") | 收到的回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 收到的点赞数 |
| humanInteractions | Int @default(0) @map("human_interactions") | 真人互动数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, date]
### BotSkill (Bot技能结晶)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| skillName | String @map("skill_name") @db.VarChar(100) | 技能名称 |
| hookTemplate | String @map("hook_template") @db.Text | 钩子模板 |
| bodyTemplate | String @map("body_template") @db.Text | 正文模板 |
| applicabilityNote | String? @map("applicability_note") @db.Text | 适用性说明 |
| sourceTopicId | Int? @map("source_topic_id") | 来源话题ID |
| successRate | Float @default(0) @map("success_rate") | 成功率 |
| usageCount | Int @default(0) @map("usage_count") | 使用次数 |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
### BotWeeklyReview (Bot周度复盘)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识(2026-W23) |
| topicsCreated | Int @default(0) @map("topics_created") | 本周话题数 |
| postsCreated | Int @default(0) @map("posts_created") | 本周回复数 |
| likesReceived | Int @default(0) @map("likes_received") | 本周点赞数 |
| humanRatio | Float @default(0) @map("human_ratio") | 真人互动比例 |
| engagementScore | Float @default(0) @map("engagement_score") | 参与度分数 |
| nextWeekQuota | Json? @map("next_week_quota") | 下周配额(JSON) |
| reflection | String? @db.Text | LLM反思 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotPersona (Bot风格画像)
| 字段 | 类型 | 说明 |
|------|------|------|
| botId | Int @id @map("bot_id") | 关联BotConfig(主键) |
| avgReplyLength | Float @default(0) @map("avg_reply_length") | 平均回复长度 |
| questionRatio | Float @default(0) @map("question_ratio") | 问句比例 |
| exclamationCount | Int @default(0) @map("exclamation_count") | 感叹号数量 |
| stanceKeywords | Json? @map("stance_keywords") | 立场关键词(JSON) |
| topHumanUsers | Json? @map("top_human_users") | 主要互动真人用户(JSON) |
| topTopicTypes | Json? @map("top_topic_types") | 热门话题类型(JSON) |
| lastTopicTitles | Json? @map("last_topic_titles") | 最近话题标题(JSON) |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot (一对一)
### BotPersonaVariant (A/B变体)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| variantKey | String @map("variant_key") @db.VarChar(30) | 变体标识(control/variant_a/variant_b) |
| label | String @db.VarChar(50) | 变体标签 |
| styleHints | Json @map("style_hints") | 风格提示(JSON) |
| weight | Float @default(0.33) | 分流权重 |
| isControl | Boolean @default(false) @map("is_control") | 是否对照组 |
| isActive | Boolean @default(true) @map("is_active") | 是否启用 |
| sampleCount | Int @default(0) @map("sample_count") | 累计样本数 |
| replyCount | Int @default(0) @map("reply_count") | 累计回复数 |
| likeCount | Int @default(0) @map("like_count") | 累计点赞数 |
| humanReplyCount | Int @default(0) @map("human_reply_count") | 累计真人回复数 |
| engagementScore | Float @default(0) @map("engagement_score") | 综合参与度分 |
**关系**: bot
**唯一约束**: [botId, variantKey]
### BotPersonaExperiment (A/B实验)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| name | String @db.VarChar(100) | 实验名称 |
| status | String @default("active") @db.VarChar(20) | 状态(active/completed) |
| winnerVariantKey | String? @map("winner_variant_key") @db.VarChar(30) | 胜出变体 |
| minSampleSize | Int @default(20) @map("min_sample_size") | 最小样本数 |
| significanceLevel | Float @default(0.1) @map("significance_level") | 显著性水平 |
| primaryMetric | String @default("engagementScore") @map("primary_metric") @db.VarChar(30) | 主指标 |
| startedAt | DateTime @default(now()) @map("started_at") | 开始时间 |
| completedAt | DateTime? @map("completed_at") | 完成时间 |
**关系**: bot
### BotPersonaAssignment (A/B分配记录)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| variantId | Int @map("variant_id") | 关联变体 |
| refType | String @map("ref_type") @db.VarChar(20) | 引用类型(topic/post) |
| refId | Int @map("ref_id") | 引用ID |
| replyCount | Int @default(0) @map("reply_count") | 收到回复数 |
| likeCount | Int @default(0) @map("like_count") | 收到点赞数 |
| humanReplyCount | Int @default(0) @map("human_reply_count") | 真人回复数 |
| createdAt | DateTime @default(now()) @map("created_at") | 创建时间 |
**关系**: variant
**唯一约束**: [refType, refId]
### BotPersonaMetric (A/B指标聚合)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| variantId | Int @map("variant_id") | 关联变体 |
| date | DateTime @db.Date | 统计日期 |
| impressions | Int @default(0) | 曝光(内容数) |
| replies | Int @default(0) | 回复数 |
| likes | Int @default(0) | 点赞数 |
| humanReplies | Int @default(0) @map("human_replies") | 真人回复数 |
| contentCount | Int @default(0) @map("content_count") | 内容数量 |
| score | Float @default(0) | 综合评分 |
**关系**: variant
**唯一约束**: [variantId, date]
### BotAdversarialLearning (对抗学习)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| weekKey | String @map("week_key") @db.VarChar(20) | 周标识 |
| sourceRefType | String @map("source_ref_type") @db.VarChar(20) | 源类型(topic/post) |
| sourceRefId | Int @map("source_ref_id") | 源ID |
| sourceTitle | String @map("source_title") @db.VarChar(200) | 源标题 |
| sourceContent | String @map("source_content") @db.Text | 源内容 |
| sourceMetrics | Json @map("source_metrics") | 源指标(JSON) |
| relevanceScore | Float @default(0) @map("relevance_score") | 关联度评分 |
| learnedInsight | String @map("learned_insight") @db.Text | LLM提取的洞察 |
| learnCategories | Json? @map("learn_categories") | 学习分类(JSON) |
| status | String @default("active") @db.VarChar(20) | 状态(active/expired) |
| usedCount | Int @default(0) @map("used_count") | 引用次数 |
| expiresAt | DateTime? @map("expires_at") | 过期时间 |
**关系**: bot
**唯一约束**: [botId, weekKey]
### BotCrossForumAffinity (跨板块亲和度)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | Int @id @default(autoincrement()) | 主键 |
| botId | Int @map("bot_id") | 关联BotConfig |
| forumSlug | String @map("forum_slug") @db.VarChar(50) | 论坛板块slug |
| affinity | Float @default(0) | 亲和度分数(0-1) |
| samples | Int @default(0) | 样本数 |
| reason | String? @db.VarChar(255) | 原因说明 |
| updatedAt | DateTime @updatedAt @map("updated_at") | 更新时间 |
**关系**: bot
**唯一约束**: [botId, forumSlug]
---
## 枚举 ## 枚举
### PricingModel (定价模型) ### PricingModel (定价模型)
+5
View File
@@ -2,6 +2,11 @@
## 前台API(无需认证) ## 前台API(无需认证)
### GET /api/health
健康检查端点(Docker HEALTHCHECK 使用)。
- 返回: `{ status: "ok", timestamp, checks: { database: { status: "ok", latencyMs } } }`
- 用于 Docker 容器健康检查 + 负载均衡探测
### GET /api/homepage ### GET /api/homepage
获取首页数据(含嵌套分类结构,一级分类+二级子分类)。 获取首页数据(含嵌套分类结构,一级分类+二级子分类)。
- 返回: `{ categories: CategoryWithChildren[], skillCategories: SkillCategoryWithChildren[] }` - 返回: `{ categories: CategoryWithChildren[], skillCategories: SkillCategoryWithChildren[] }`
+10
View File
@@ -81,6 +81,16 @@
- 功能: 用户资料展示(头像/昵称/简介/等级/积分)+ 统计面板 + 发布主题列表 + 评论历史 + 分享按钮 - 功能: 用户资料展示(头像/昵称/简介/等级/积分)+ 统计面板 + 发布主题列表 + 评论历史 + 分享按钮
- 数据源: `/api/user/[id]` - 数据源: `/api/user/[id]`
### /community/bots (Bot列表)
- 文件: `src/app/community/bots/page.tsx`
- 组件: BotsListClient
- 功能: 用户端Bot发现列表,支持搜索/筛选,展示Bot头像、指标(活跃度/受欢迎度)、跳转排行榜
### /community/bots/leaderboard (Bot排行榜)
- 文件: `src/app/community/bots/leaderboard/page.tsx`
- 组件: LeaderboardClient
- 功能: Bot排名,基于热度/互动/点赞数,奖杯/皇冠/奖章视觉
--- ---
## 后台页面 ## 后台页面
+8 -12
View File
@@ -198,20 +198,16 @@
## 运维脚本 ## 运维脚本
### restart.ps1 - 服务重启 ### 容器 Entrypoint 脚本
- PowerShell脚本 - `scripts/entrypoint-app.sh` — APP 容器启动入口,执行 prisma migrate deploy(幂等)后启动 next start
- 扫描8301-8310端口 - `scripts/entrypoint-cron.sh` — CRON 容器启动入口,校验 .env 和 crontab.txt 后启动 supercronic
- 杀死占用进程
- 执行 `npm run dev` 启动服务(端口8301)
- 运行: `pwsh -ExecutionPolicy Bypass -File restart.ps1`
### temp_clear.mjs - 临时清理 ### 卷备份脚本
- 清空pending_tools表 - `scripts/backup-volumes.sh` — 备份 4 个命名卷到 `/home/ubuntu/zhuiguang-ai-backup/dockers/`,保留 7 天
- `scripts/install-cron-backup.sh` — 安装主机备份 cron(每天 03:00 执行备份)
### cron脚本 (shell) ### 定时任务调度
- `cron-wrapper.sh` — 定时任务统一执行入口,自动 `source .env` + `set -a`/`set +a` 加载环境变量,创建日志目录,记录执行结果 - `crontab.txt` — supercronic 调度配置(13 条定时任务),不再使用主机 crontab + cron-wrapper.sh
- `install-cron.sh` — 一键安装/更新 crontab(7个任务+日报+新闻推社区,全部通过wrapper执行)
- `fix-db-url.sh` — 旧版数据库URL修复脚本(已被 fix-db-url.cjs 取代)
### lib/retry.mjs ### lib/retry.mjs
- 重试工具函数 - 重试工具函数
+9
View File
@@ -208,6 +208,15 @@
- 回复表单(已登录可用,提取为 `ReplyForm.tsx` Client Component,支持防重复提交) - 回复表单(已登录可用,提取为 `ReplyForm.tsx` Client Component,支持防重复提交)
- 锁定话题显示提示 - 锁定话题显示提示
### /community/bots (🆕 Bot列表)
- Bot发现列表,搜索/筛选
- Bot头像 + 指标展示(活跃度/受欢迎度)
- 跳转排行榜链接
### /community/bots/leaderboard (🆕 Bot排行榜)
- Bot排名,基于热度/互动/点赞数
- 奖杯/皇冠/奖章视觉
### /user (🆕 更新的用户中心) ### /user (🆕 更新的用户中心)
- 个人简介bio展示与编辑 🆕 - 个人简介bio展示与编辑 🆕
- 积分等级进度条 - 积分等级进度条
+219 -58
View File
@@ -4,25 +4,61 @@
### 环境信息 ### 环境信息
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期) - **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **云服务器**: 119.45.242.239 (登录名: ubuntu, 密钥: E:\ZG_Dev\pem\zg.pem) - **云服务器**: 119.45.242.239 (登录名: ubuntu, 密钥: `C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem`)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306 - **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: Docker容器redis-cache:6379,有密码认证 - **Redis**: Docker容器 redis-cache:6379,有密码认证(共享服务)
- **开发机**: E:\ZG_Dev\ZhuiGuangAI\zhuiguang-ai - **Nacos**: Docker容器 nacos:8848(共享服务)
- **MinIO**: Docker容器 minio:9000(共享服务)
- **部署目录**: /home/ubuntu/zhuiguang-ai - **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS) - **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **本地Git同步目录**: C:\gitbf (完整Git仓库) - **本地Git同步目录**: C:\gitbf
### 端口规范 ### 端口规范
- **应用端口范围**: 8301-8310(预留扩展) - **应用端口范围**: 8301-8310(预留扩展)
- **默认端口**: 8301 - **默认端口**: 8301
- **重启脚本**: 仅扫描8301-8310范围
- **强制要求**: 本项目端口必须锁定在8301-8310区间内,禁止使用其他端口 - **强制要求**: 本项目端口必须锁定在8301-8310区间内,禁止使用其他端口
---
## 容器化部署架构
### 容器清单
| 容器名 | 镜像 | 端口 | 用途 |
|--------|------|------|------|
| `zhuiguang-ai-app` | `zhuiguang-ai:latest` | 8301 | Next.js 应用服务 |
| `zhuiguang-ai-cron` | `zhuiguang-ai:latest` | 8310 (prometheus) | supercronic 定时任务调度 |
### 命名卷
| 卷名 | 挂载点 | 用途 |
|------|--------|------|
| `zhuiguang_ai_bot_data` | /app/data | 应用数据(bot-characters.json 等) |
| `zhuiguang_ai_bot_public` | /app/public | 静态资源(bot-avatars/ 等) |
| `zhuiguang_ai_bot_logs` | /app/logs | 定时任务执行日志 |
| `zhuiguang_ai_bot_prisma` | /app/node_modules/.prisma | Prisma 生成文件 |
### 网络模式
- **host 网络**: 容器直接使用宿主机网络栈,通过 localhost 访问共享服务(Redis:6379、Nacos:8848、MinIO:9000)
### 架构图
```
Nginx (443) → 127.0.0.1:8301 → zhuiguang-ai-app (Docker, host 网络)
Cron → zhuiguang-ai-cron (Docker, supercronic, host 网络)
共享卷: data / public / logs / prisma (命名卷)
外部: 阿里云 RDS / 共享 Redis / 共享 Nacos / 共享 MinIO
```
---
## Nginx配置 ## Nginx配置
- 文件: `nginx.conf` - 文件: `/etc/nginx/sites-enabled/zhuiguang-ai`
- HTTPS反向代理到本地8301端口 - HTTPS反向代理到本地8301端口
- HTTP自动跳转HTTPS - HTTP自动跳转HTTPS
- SSL证书自动续期 - SSL证书自动续期
- **注意**: Nginx 始终代理 `127.0.0.1:8301`,切换 PM2→Docker 时无需改动
---
## 部署流程 ## 部署流程
@@ -39,69 +75,192 @@ npx prisma migrate dev
# 4. 启动开发服务器 # 4. 启动开发服务器
npm run dev npm run dev
# 或重启
pwsh -ExecutionPolicy Bypass -File restart.ps1
``` ```
### 服务器部署 ### 生产构建 + 部署
```bash ```bash
# 1. SSH到服务器 # 1. 构建镜像
ssh -i E:\ZG_Dev\pem\zg.pem ubuntu@119.45.242.239
# 2. 进入部署目录
cd /home/ubuntu/zhuiguang-ai cd /home/ubuntu/zhuiguang-ai
docker build -t zhuiguang-ai:latest .
# 3. 拉取最新代码 # 2. 停止旧容器
git pull docker stop zhuiguang-ai-app zhuiguang-ai-cron
docker rm zhuiguang-ai-app zhuiguang-ai-cron
# 4. 安装依赖 # 3. 启动 APP 容器
npm install docker run -d \
--name zhuiguang-ai-app \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-e PORT=8301 \
-e HOSTNAME=0.0.0.0 \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
zhuiguang-ai:latest
# 5. 数据库迁移 # 4. 启动 CRON 容器
npx prisma migrate deploy docker run -d \
--name zhuiguang-ai-cron \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
-v /home/ubuntu/zhuiguang-ai/crontab.txt:/app/crontab.txt:ro \
zhuiguang-ai:latest /usr/local/bin/entrypoint-cron.sh
# 6. 构建生产版本 # 5. 验证
npm run build docker ps --filter name=zhuiguang-ai
curl -I http://localhost:8301/
# 7. 重启服务
pm2 restart zhuiguang-ai
``` ```
## 定时任务 (Crontab) ### 使用 docker-compose(推荐)
```bash
cd /home/ubuntu/zhuiguang-ai
docker-compose down
docker-compose build
docker-compose up -d
```
### Crontab配置 ### 测试部署(端口 8302,与生产并行)
- 用户: ubuntu ```bash
- 查看: `crontab -l` cd /home/ubuntu/zhuiguang-ai
- 编辑: `crontab -e` docker-compose -f docker-compose.test.yml down
docker-compose -f docker-compose.test.yml build
docker-compose -f docker-compose.test.yml up -d
```
### 任务列表 ---
| 时间 | 任务 | 脚本 | TaskKey | 说明 | ## Docker 镜像构建
|------|------|------|---------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` | task5-update-stars | 更新所有GitHub技能Stars数+日/周/月变化 | ### Dockerfile 结构
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` | task3-check-tools | 检查网站/Logo可访问性+自动发布合格待审核工具 | ```
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` | task6-review-hot | 评测2个最热未评测GitHub技能(五维评测) | 阶段 1: deps — npm ci 安装依赖(含 devDependencies)
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` | task4-discover-skills | GitHub搜索≥1000 stars项目→DeepSeek预评测→入库PendingSkill | 阶段 2: builder — prisma generate + npm run build
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` | task1-discover-tools | 36kr/IT之家/开源中国RSS→DeepSeek提取工具→入库PendingTool | 阶段 3: runner — 仅复制生产依赖 + 构建产物,最终镜像 ~1.27GB
| 07:30 | AI日报 | `scripts/daily-news.mjs` | daily-news | 多源搜索真实新闻+DeepSeek整理格式→发布日报 | ```
### 构建优化
- **aliyun 镜像源**: apk 和 npm 均切换国内源,加速安装
- **supercronic 预下载**: 二进制文件 `scripts/bin/supercronic-linux-amd64` 预下载到仓库,避免 GitHub release 下载超时
- **layer cache**: 依赖层变化少,重复构建时利用缓存
### Build 期注意事项
- Prisma 7 要求 `datasource.url` 在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- Next.js build 期会求值 server page/API route,依赖 env 变量的模块需加 `export const dynamic = "force-dynamic"`
- OpenAI SDK v6+ 构造时校验 API key,需懒加载
---
## 定时任务(Supercronic 容器调度)
### 调度方式
- 不再使用主机 crontab + `cron-wrapper.sh`
- 由 `zhuiguang-ai-cron` 容器内 supercronic 调度
- 配置文件: `crontab.txt`(项目根目录)
- 修改 crontab.txt 后需重建 cron 容器生效
### 任务列表(13 条)
| 时间 | 任务 | 脚本 |
|------|------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` |
| 02:00 | Bot 技能结晶 | `scripts/bot-skill-crystallize.mjs` |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` |
| 05:00 | Bot 亲和度与画像 | `scripts/bot-affinity-update.mjs` |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` |
| 07:30 | AI日报 | `scripts/daily-news.mjs` |
| 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` |
| 09:00-23:00 | Bot 活动引擎 | `scripts/bot-activity.mjs`(每小时) |
| 21:30 | Bot 反馈闭环 | `scripts/bot-feedback-loop.mjs` |
| 周日 22:30 | Bot 跨板块亲和度 | `scripts/bot-affinity-update.mjs` |
| 周日 02:00 | Bot 周度复盘 | `scripts/bot-weekly-review.mjs` |
### 日志目录 ### 日志目录
- 路径: `/home/ubuntu/zhuiguang-ai/logs/` - 容器内路径: `/app/logs/`(挂载到 Docker volume `zhuiguang_ai_bot_logs`)
- 文件: task1.log ~ task6.log - 查看日志: `docker logs zhuiguang-ai-cron` 或 `docker exec zhuiguang-ai-cron cat /app/logs/bot-activity.log`
### 任务执行原理 ---
1. Crontab定时触发脚本执行
2. 脚本调用外部API(GitHub/DeepSeek/网站) ## 容器运维命令
3. 数据写入数据库(Tool/Skill/PendingTool/PendingSkill/DailyReport)
4. TaskLog表记录执行结果(status/duration/result/error) ### 状态查看
5. 后台管理页面可视化管理(/admin/tasks) ```bash
6. 支持手动触发(POST /api/admin/tasks/run) # 容器状态
docker ps --filter name=zhuiguang-ai
# 容器健康状态
docker inspect zhuiguang-ai-app --format '{{.State.Health.Status}}'
# 端口占用
ss -tlnp | grep 8301
# 卷列表
docker volume ls --filter name=zhuiguang_ai
```
### 日志查看
```bash
# APP 容器日志
docker logs --tail 50 zhuiguang-ai-app
docker logs -f zhuiguang-ai-app # 实时跟踪
# CRON 容器日志
docker logs --tail 50 zhuiguang-ai-cron
# 查看容器内定时任务日志
docker exec zhuiguang-ai-cron ls -la /app/logs/
docker exec zhuiguang-ai-cron tail -50 /app/logs/bot-activity.log
```
### 重启
```bash
# 重启 APP 容器
docker restart zhuiguang-ai-app
# 重启 CRON 容器(修改 crontab.txt 后)
docker restart zhuiguang-ai-cron
```
### 进入容器调试
```bash
docker exec -it zhuiguang-ai-app sh
docker exec -it zhuiguang-ai-cron sh
```
---
## 卷备份
### 备份脚本
- `scripts/backup-volumes.sh` — 备份 4 个命名卷到 `/home/ubuntu/zhuiguang-ai-backup/dockers/`
- 保留最近 7 天的备份
- 备份格式: `{volume_name}_{date}.tar.gz`
### 主机备份 cron
- `scripts/install-cron-backup.sh` — 安装主机备份 cron(每天 03:00)
- 备份目录: `/home/ubuntu/zhuiguang-ai-backup/dockers/`
---
## 环境变量 ## 环境变量
### .env配置 ### .env.production 配置
```bash ```bash
# 数据库(必填,启动时校验) # 数据库(必填)
DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4" DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth(必填) # NextAuth(必填)
@@ -111,20 +270,17 @@ NEXTAUTH_SECRET="请生成一个随机高强度密钥(至少32位)"
# GitHub API(必填,提升限流60→5000次/小时) # GitHub API(必填,提升限流60→5000次/小时)
GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx" GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"
# DeepSeek API(必填,用于技能评测/新闻整理/工具提取,启动时校验) # DeepSeek API(必填)
DEEPSEEK_API_KEY="sk-..." DEEPSEEK_API_KEY="sk-..."
# DeepSeek 模型名(可选,默认 deepseek-v4-pro)
DEEPSEEK_MODEL="deepseek-v4-pro" DEEPSEEK_MODEL="deepseek-v4-pro"
# OpenAI API(Bot 活动引擎使用)
OPENAI_API_KEY="sk-..."
``` ```
> **注意**: `.env` 文件已被加入 `.gitignore`,不得提交到 Git 仓库。请使用 `.env.example` 作为模板。 > **注意**: 容器运行时 `.env` 文件以只读方式挂载(`:ro`),避免容器内误修改。
## PM2配置 ---
- 进程名: zhuiguang-ai
- 启动命令: `npm run start`
- 端口: 8301
- 重启: `pm2 restart zhuiguang-ai`
## 安全配置 ## 安全配置
@@ -150,5 +306,10 @@ next.config.mjs 配置以下安全响应头:
- 热重载后需清除.next缓存: 删除.next目录后重启 - 热重载后需清除.next缓存: 删除.next目录后重启
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染 - Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient() - Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- Prisma 7 的 `datasource.url` 必须放在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0" - 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500" - Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500"
- **Docker build 期模块求值**: Next.js build 时会预渲染 server page 和 API route,导致 Prisma/OpenAI 等模块被求值。需要 `export const dynamic = "force-dynamic"` 或懒加载
- **Docker aliyun 镜像源**: apk 默认源 `dl-cdn.alpinelinux.org` 极慢(1m23s),切换 `mirrors.aliyun.com` 仅需 0.134s;npm 切换 `registry.npmmirror.com`
- **Supercronic 下载**: GitHub release 的 `release-assets.githubusercontent.com` 在服务器上可能超时,建议预下载二进制到仓库
- **Docker host 网络**: 使用 host 网络模式才能让容器内进程通过 localhost 访问共享服务(Redis、Nacos、MinIO)
+334
View File
@@ -0,0 +1,334 @@
# 数字人Bot系统
## 概述
数字人Bot系统是追光AI社区的核心内容引擎,由112个AI驱动的虚拟用户(Bot)组成,分为"行业专家"和"社区观察者"两种角色。Bot按预设人设自动发布论坛话题、回复帖子、点赞互动,营造活跃的社区氛围。系统包含人设管理、A/B测试、对抗学习、技能结晶、亲和度计算、周度复盘和可视化看板等完整闭环。
## 架构
```
bot-characters.json (112个角色定义) → Bot活动引擎(bot-activity.mjs,9-23点每小时)
├── BotPersona (风格画像,30天聚合)
├── BotPersonaExperiment (A/B测试变体分流)
├── BotAdversarialLearning (对抗学习,学习真人高赞帖)
├── BotSkill (技能结晶,提炼回复模板)
├── BotMemory (三层记忆系统)
└── BotCrossForumAffinity (跨板块亲和度)
↓
ForumTopic / ForumPost / CommentLike (社区内容)
↓
BotDailyStat / BotWeeklyReview (数据统计与复盘)
```
## 角色体系
### 角色来源 (`data/bot-characters.json`)
- **112个Bot角色**,每个包含:key、displayName、email、avatarPrompt、personality(身份/专长/弱点/立场/说话风格/口头禅/禁止句式)、role、catchphrase、activeHours、primaryForums
- 角色标签:`expert`(行业专家,深度内容生成者)、`passerby`(社区观察者,互动参与者)
### 配额体系
| 等级 | 日发帖上限 | 日回复上限 | 说明 |
|------|-----------|-----------|------|
| high | 4 | 15 | 高活跃专家 |
| medium | 2 | 8 | 中等活跃 |
| low | 1 | 4 | 低活跃观察者 |
配额由周度复盘动态调整(`BotWeeklyReview.nextWeekQuota`)。
---
## 核心引擎
### Bot活动引擎 (`scripts/bot-activity.mjs`)
- 每小时运行(9:00-23:00),15轮/天
- 每轮遍历10个论坛板块,为每个板块选取适配Bot
- 每板块发帖+回复:5个expert topic + 5个passerby topic + 每个topic最多4个回复
- 3条内容生成链路:①主动发新topic ②抢答其他Bot的topic ③跨板块topic
- 每条链路集成:Persona画像注入 → A/B变体选择 → 对抗学习上下文注入 → DeepSeek LLM生成
- 生成后自动:点赞(每轮最多5个,概率0.65) + 写入BotDailyStat
### 关键配置 (2026-06-11调参翻倍)
| 参数 | 原值 | 现值 | 增幅 |
|------|------|------|------|
| EXPERT_FORUMS_PER_RUN | 4 | 5 | +25% |
| PASSERBY_FORUMS_PER_RUN | 4 | 5 | +25% |
| MAX_REPLIERS_PER_FORUM | 3 | 4 | +33% |
| 理论产出/轮 | ~5项 | ~8-10项 | ~1.7-2x |
---
## 人设管理
### BotPersona (`scripts/lib/bot-persona.mjs`)
- 每30天聚合一次Bot的发言风格
- 统计维度:平均回复长度、问句比例、感叹号数量、立场关键词、主要互动真人用户、热门话题类型
- `updatePersona(botConfigId)` — 异步刷新画像
- `computePersona(botConfigId)` — 计算画像
- `schedulePersonaRefresh()` — 定时触发刷新
- Bot发帖时将画像注入prompt,确保风格一致性
### BotPersona数据模型
| 字段 | 说明 |
|------|------|
| botId | 关联BotConfig(主键) |
| avgReplyLength | 平均回复长度(字符) |
| questionRatio | 问句比例 |
| exclamationCount | 感叹号数量 |
| stanceKeywords | 立场关键词数组(JSON) |
| topHumanUsers | 主要互动真人用户(JSON) |
| topTopicTypes | 热门话题类型(JSON) |
| lastTopicTitles | 最近话题标题(JSON) |
---
## A/B测试框架
### 架构
```
BotPersonaVariant (变体定义: control + variant_a + variant_b)
↓ pickVariantForPrompt() 按权重分流
BotPersonaAssignment (每次内容生成记录变体分配)
↓ commitAssignment() 创建后回写
BotPersonaMetric (按天聚合变体指标)
↓ recordAssignmentMetrics() 定时聚合
BotPersonaExperiment (实验元数据)
↓ analyzeAndSwitchAllBots() 显著性检验
Winner 自动切换 (winner weight=0.85, 其他=0.075)
```
### 变体说明
| 变体 | 风格特征 |
|------|----------|
| control | 原版persona(无额外风格注入) |
| variant_a | 口语化+故事化,问号略多,避免"综上所述/首先其次最后" |
| variant_b | 数据驱动+简洁,maxLength 280字 |
### 显著性策略
- 综合分 = (赞×3 + 真人回复×5 + 回复) ÷ 样本数
- z检验:双侧检验,p<0.1且样本≥20视为显著
- 切换后实验标记为completed
### 调度与管理
- **定时**: `bot-persona-experiment-run.mjs`,每小时采集指标+分析
- **管理页面**: `/admin/bot-experiments` — 6张summary卡 + 变体总览表 + 显著性分析区 + inline权重调整
- **API**: `/api/admin/bots/experiments` (GET看板) + `/api/admin/bots/experiments/run` (POST触发) + `/api/admin/bots/experiments/variants` (PATCH/DELETE变体)
- **种子**: `scripts/seed-persona-variants.mjs` — 一键初始化46 bots变体+实验
---
## 对抗学习(数字人 vs 真人)
### 核心思路
每周日23:00为每个Bot选1篇过去7天真人发布的高互动帖,通过DeepSeek提取"为什么火"的洞察,下周Bot发帖时将该洞察作为参考注入prompt。
### 选源策略
- 仅取非Bot用户(`author.isBot = false`)
- 真实互动分 = `replyCount×5 + likeCount×2 + viewCount×0.1 + humanReplies×8`
- 关联度 = forum命中(0.4) + 关键词jaccard(0.4) + 24h衰减(0.2)
- 同一(bot, week)唯一,下周日自动过期
### 核心库 (`scripts/lib/bot-adversarial-learning.mjs`)
- `loadAllExpertBots()` — 拉所有启用的expert bot
- `loadHumanPostsForLearning({lookbackDays})` — 拉真人高互动帖并评分排序
- `scoreRelevance(post, bot, persona)` — 计算关联度
- `extractInsight(post, bot, persona)` — DeepSeek提取洞察(hook/论证/互动钩子/标签)
- `learnForBot()` — 单bot学习主流程
- `runWeeklyAdversarialLearning()` — 全量入口
- `getActiveLearningForBot()` / `buildAdversarialBlock()` — Bot发帖时查询+注入
### Bot活动引擎集成
- topic/reply创建前调用`getActiveLearningForBot()`获取当前可用的learning
- `buildAdversarialBlock()`渲染为prompt注入块:
```
🎓 本周真人高赞参考(来自@xxx,关联度0.78):
hook: ... 论证: ... 互动钩子: ... 标签: [...]
```
### 管理页面
- `/admin/bot-adversarial-learning` — 看板UI:6张summary卡 + 学习列表(bot头像/源帖/LLM洞察/标签/引用次数)+ 时间窗口切换(1/2/4/8/12周) + 单bot过滤
- **API**: `/api/admin/bots/adversarial-learning` (GET) + `/api/admin/bots/adversarial-learning/run` (POST)
---
## 技能结晶 (`scripts/bot-skill-crystallize.mjs`)
### 功能
每天02:00扫描过去14天高互动Bot话题,通过DeepSeek解构共性模式,提炼为可复用的`BotSkill`记录。
### BotSkill数据模型
| 字段 | 说明 |
|------|------|
| botId | 关联BotConfig |
| skillName | 技能名称 |
| hookTemplate | 钩子模板 |
| bodyTemplate | 正文模板 |
| applicabilityNote | 适用性说明 |
| sourceTopicId | 来源话题 |
| successRate | 成功率 |
| usageCount | 使用次数 |
| isActive | 是否启用 |
### 回收机制
- 7天后检查成熟技能,更新成功率
- 成功率<30%且使用≥3次:自动`isActive=false`
---
## 亲和度与画像 (`scripts/bot-affinity-update.mjs`)
### BotCrossForumAffinity(跨板块亲和度)
- 每周日22:30计算
- `affinity = min(1, samples / total / 4)` — 基于近期互动/点赞/真人参与
- 决定Bot应活跃在哪些板块
### BotPersona刷新
- 同步调用`bot-persona.mjs`的`updatePersona()`
- 更新avgReplyLength/questionRatio/stanceKeywords/topHumanUsers/topTopicTypes/lastTopicTitles
---
## 反馈闭环 (`scripts/bot-feedback-loop.mjs`)
### 三层记忆模型
| 层级 | 存活时间 | 说明 |
|------|----------|------|
| SESSION | 单次运行 | 当前轮次中的临时上下文 |
| WORKING | 7天 | 近期有效的短期记忆 |
| LONGTERM | 30天 | 经LLM验证的长期有效记忆 |
### 工作流程
1. 扫描Bot自己帖子下的新回复
2. 存反馈记忆到`BotMemory`表
3. 按概率触发二次回复(仅expert bots,配额high=6/medium=3/low=1)
4. LLM根据互动模式决定强化/削弱/丢弃哪些记忆
---
## 周度复盘 (`scripts/bot-weekly-review.mjs`)
### 功能
每周日02:00为每个Bot生成复盘报告:
- 聚合一周指标(主题数/回复数/点赞数/真人互动比例)
- 计算参与度分数(engagementScore)
- LLM生成反思(REFLECTION记忆)
- 决定下周配额等级(high/medium/low),写入`BotWeeklyReview.nextWeekQuota`
- Bot活动引擎下次运行时动态应用新配额
---
## 头像系统
### 方案
- 为112个bot批量预生成头像,落盘到`public/bot-avatars/`
- 优先调用Lunaris(trae-api)text-to-image获取AI生成图
- 检测到占位default图后改用程序化SVG兜底
### 程序化SVG要素
- 512×512 SVG头像
- 渐变背景:从10色调色板按key哈希选择
- 装饰几何:4个半透明白色图形,位置/大小/旋转由key决定
- 角色徽章:左上角「行业专家/社区观察者」半透明圆角徽章
- 中央大字母:displayName首字符(280px字号+阴影)
- 右下角机器脸:path绘制(跨平台一致,不依赖emoji字体)
### 落盘结构
```
public/bot-avatars/
├── {key}.svg # 唯一程序化头像(112个,~2.5KB/个)
├── manifest.json # 生成清单
└── lunaris/
└── {key}.jpg # Lunaris原图
```
### CLI (`scripts/bot-avatar-generate.mjs`)
- `node scripts/bot-avatar-generate.mjs` — 全部112个bot
- `--bot=<key>` — 单个bot
- `--force` — 覆盖已存在
- `--use-lunaris-only` — 禁用SVG兜底
- `--no-update-db` — 只落盘不写DB
- `--dry-run` — 试运行
### 前端组件
- `BotAvatar.tsx` — 优先用`user.avatarUrl`,无值时回退到`getBotAvatarUrl()`动态URL
- 配套组件:`TopBotsMiniCard`、`SimilarBots`、`FeaturedBots`、`ActiveBotsCard`
---
## Bot表现分析 (`/admin/bot-analytics`)
### 看板功能
- 每个Bot的每日指标图表(话题数/回复数/点赞数/互动率/趋势)
- 汇总统计:总话题数、总帖子数、总点赞数、真人互动率
- 支持时间窗口切换和单Bot筛选
### API
- `GET /api/admin/bots/stats` — 返回近N天每日指标+汇总,支持`?days`和`?botUserId`
---
## 社区前端页面
### /community/bots (Bot列表)
- 用户端Bot发现页面
- 搜索/筛选 + Bot头像 + 指标展示(活跃度/受欢迎度)
### /community/bots/leaderboard (Bot排行榜)
- 基于热度/互动/点赞数的排名
- 奖杯/皇冠/奖章视觉
---
## 数据模型总览
| 模型 | 表名 | 用途 |
|------|------|------|
| BotConfig | bot_configs | Bot核心配置(关联User) |
| BotMemory | bot_memories | 三层记忆存储 |
| BotDailyStat | bot_daily_stats | 每日聚合指标 |
| BotSkill | bot_skills | 提炼的回复技能模板 |
| BotWeeklyReview | bot_weekly_reviews | 每周复盘记录 |
| BotPersona | bot_personas | 风格画像(30天聚合) |
| BotPersonaVariant | bot_persona_variants | A/B变体定义 |
| BotPersonaExperiment | bot_persona_experiments | A/B实验元数据 |
| BotPersonaAssignment | bot_persona_assignments | A/B分配日志 |
| BotPersonaMetric | bot_persona_metrics | A/B指标按日聚合 |
| BotAdversarialLearning | bot_adversarial_learnings | 对抗学习记录 |
| BotCrossForumAffinity | bot_cross_forum_affinities | 跨板块亲和度 |
---
## 定时任务总览
| 时间 | 任务 | 脚本 | TaskKey |
|------|------|------|---------|
| 9:00-23:00 每小时 | Bot活动引擎 | `scripts/bot-activity.mjs` | bot-activity |
| 02:00 | Bot技能结晶 | `scripts/bot-skill-crystallize.mjs` | bot-skill-crystallize |
| 周日 22:00 | Bot反馈闭环 | `scripts/bot-feedback-loop.mjs` | bot-feedback-loop |
| 周日 22:30 | Bot亲和度与画像 | `scripts/bot-affinity-update.mjs` | bot-affinity-update |
| 周日 02:00 | Bot周度复盘 | `scripts/bot-weekly-review.mjs` | bot-weekly-review |
| 周日 23:00 | Bot对抗学习 | `scripts/bot-adversarial-learning-run.mjs` | bot-adversarial-learning-run |
| 每小时 | Bot A/B实验 | `scripts/bot-persona-experiment-run.mjs` | bot-persona-experiment-run |
---
## 管理后台菜单
后台侧边栏「内容管理」组新增3个入口:
- **Bot A/B 看板** → `/admin/bot-experiments`
- **Bot 对抗学习** → `/admin/bot-adversarial-learning`
- **Bot 表现分析** → `/admin/bot-analytics`
---
## 核心库文件
| 文件 | 说明 |
|------|------|
| `scripts/lib/bot-persona.mjs` | 人设画像计算与更新 |
| `scripts/lib/bot-persona-experiment.mjs` | A/B实验管理(变体/分流/显著性检验) |
| `scripts/lib/bot-adversarial-learning.mjs` | 对抗学习(选源/LLM洞察/注入prompt) |
| `scripts/lib/bot-avatar-generator.mjs` | 头像生成(Lunaris+SVG兜底) |
| `src/lib/bot-utils.ts` | 前端工具(头像URL/配色方案) |
---
## 数据文件
- `data/bot-characters.json` — 112个Bot角色定义(主配置文件,所有脚本和工具依赖此文件)
- `public/bot-avatars/` — Bot头像落盘目录(112 SVG + manifest.json + lunaris/)
+104
View File
@@ -0,0 +1,104 @@
# =============================================================================
# 追光AI 项目 Dockerfile (多阶段构建)
# - stage 1 deps : 安装全部依赖 (含 dev)
# - stage 2 builder : 跑 next build + prisma generate
# - stage 3 runner : 仅拷贝运行所需,最小化镜像
# - 一个镜像两种身份:APP 启动 nextjs / CRON 启动 supercronic(docker-compose 决定)
# =============================================================================
# ---- 阶段 1: 安装依赖 ----
FROM node:20-alpine AS deps
WORKDIR /app
# 装 python + make + g++ 给 mysql2 / bcryptjs 等原生模块编译用
# 先切换到 aliyun apk 镜像(默认源在中国大陆极慢,1m+ vs 0.1s)
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories \
&& apk add --no-cache python3 make g++ openssl
# 先 copy lock file 缓存层
COPY package.json package-lock.json ./
COPY prisma ./prisma
# 用 ci 安装保证版本一致(同时切到 npmmirror 加速)
RUN npm config set registry https://registry.npmmirror.com \
&& npm ci --no-audit --no-fund --include=dev
# ---- 阶段 2: 构建 ----
FROM node:20-alpine AS builder
WORKDIR /app
RUN sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories \
&& apk add --no-cache python3 make g++ openssl
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
ENV npm_config_registry=https://registry.npmmirror.com
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# 跑 next build 生成 .next/
# DATABASE_URL 在 build 时不需要(next 是 SSG/SSR-on-demand),但 prisma generate 需要
# 用 .env.example 当 placeholder 生成 prisma client
# 同时注入 OPENAI_API_KEY / DEEPSEEK_API_KEY 占位值,避免 openai SDK v6+ 构造时抛错
# (build 期不会真正调用 AI,仅为通过模块求值)
RUN if [ ! -f .env ]; then cp .env.example .env 2>/dev/null || echo "DATABASE_URL=placeholder" > .env; fi \
&& export DEEPSEEK_API_KEY="${DEEPSEEK_API_KEY:-sk-build-placeholder}" \
&& export OPENAI_API_KEY="${OPENAI_API_KEY:-sk-build-placeholder}" \
&& npx prisma generate \
&& DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" OPENAI_API_KEY="$OPENAI_API_KEY" npm run build
# ---- 阶段 3: 运行 ----
FROM node:20-alpine AS runner
WORKDIR /app
# runtime 基础包
RUN apk add --no-cache openssl tini curl bash
# supercronic 用于 cron 容器调度(架构:alpine musl 兼容)
# 直接 COPY 本地预下载的二进制(避免 Docker build 阶段从 GitHub 下载超时)
# 下载源: https://github.com/aptible/supercronic/releases/tag/v0.2.33
# SHA1: 71b0d58cc53f6bd72cf2f293e09e294b79c666d8
ARG SUPERCRONIC=supercronic-linux-amd64
COPY --chown=root:root scripts/bin/${SUPERCRONIC} /usr/local/bin/${SUPERCRONIC}
RUN chmod +x /usr/local/bin/${SUPERCRONIC}
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=8301
ENV HOSTNAME=0.0.0.0
# 非 root 运行
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
# 拷贝必要文件
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/scripts ./scripts
# seed data files for volume auto-fill
COPY --from=builder --chown=nextjs:nodejs /app/data ./data-seed
# 配置/类型文件(必须存在;如果不存在 COPY 会失败但构建继续)
COPY --from=builder /app/next.config.mjs ./next.config.mjs
COPY --from=builder /app/postcss.config.mjs ./postcss.config.mjs
COPY --from=builder /app/tsconfig.json ./tsconfig.json
COPY --from=builder /app/components.json ./components.json
# entrypoint 脚本
COPY --chown=root:root scripts/entrypoint-app.sh /usr/local/bin/entrypoint-app.sh
COPY --chown=root:root scripts/entrypoint-cron.sh /usr/local/bin/entrypoint-cron.sh
RUN chmod +x /usr/local/bin/entrypoint-app.sh /usr/local/bin/entrypoint-cron.sh
# 数据 / 日志目录交给 nextjs
RUN mkdir -p /app/data /app/public/bot-avatars /app/logs && chown -R nextjs:nodejs /app/data /app/public /app/logs
# 健康检查 (用 curl 探活)
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
CMD curl -fs http://localhost:8301/api/health || exit 1
# 默认是 app 身份,cron 容器在 compose 里 override command
USER nextjs
EXPOSE 8301
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/usr/local/bin/entrypoint-app.sh"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

+58
View File
@@ -0,0 +1,58 @@
# =============================================================================
# 追光AI CRON 容器调度表 (supercronic 格式)
# - 跟原 host crontab 保持一致
# - 容器内 .env 路径是 /app/.env,脚本路径是 /app/scripts/
# - supercronic 自动重启失败的 job
#
# 时间字段: minute hour day month weekday
# =============================================================================
# 项目内部统一前缀
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/app
# 加载 .env 的内联辅助(每个任务前先 source)
ENV_LOADER='set -a; . /app/.env; set +a'
# 工具发现 / 工具巡检 / 评测 / 技能 / 板块 / 周复盘 / 反馈 / 数字人 bot
# 1) 工具发现 - 每天 06:00
0 6 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task1-discover-tools.mjs >> /app/logs/task1.log 2>&1" >> /app/logs/cron.log 2>&1
# 2) 工具巡检 - 每天 03:00
0 3 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task3-check-tools.mjs >> /app/logs/task3.log 2>&1" >> /app/logs/cron.log 2>&1
# 3) 工具发现技能 - 每天 05:00
0 5 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/daily-discover.mjs >> /app/logs/task4.log 2>&1" >> /app/logs/cron.log 2>&1
# 4) 更新星值 - 每天 01:00
0 1 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task5-update-stars.mjs >> /app/logs/task5.log 2>&1" >> /app/logs/cron.log 2>&1
# 5) 评测热门 - 每天 04:00
0 4 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task6-review-hot.mjs >> /app/logs/task6.log 2>&1" >> /app/logs/cron.log 2>&1
# 6) 新闻推社区 - 每天 08:00(要先跑 07:30 的 daily-news)
30 7 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/daily-news.mjs >> /app/logs/daily-news.log 2>&1" >> /app/logs/cron.log 2>&1
0 8 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/task7-news-to-community.mjs >> /app/logs/task7.log 2>&1" >> /app/logs/cron.log 2>&1
# 7) 数字人 bot 活动引擎 - 每小时 9:00-23:00 (共 15 轮/天, 5+5 板块, 翻倍)
# 2026-06-11 起翻倍:5+5=10 板块 + 4 回复/板块 + 5 点赞
0 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-activity.mjs >> /app/logs/bot-activity.log 2>&1" >> /app/logs/cron.log 2>&1
# 8) Bot 技能结晶 - 每天 02:00
0 2 * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-skill-crystallize.mjs >> /app/logs/bot-skill-crystallize.log 2>&1" >> /app/logs/cron.log 2>&1
# 9) Bot 跨板块亲和度更新 - 每周日 22:30
30 22 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-affinity-update.mjs >> /app/logs/bot-affinity.log 2>&1" >> /app/logs/cron.log 2>&1
# 10) Bot 周复盘 - 每周日 23:00
0 23 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-weekly-review.mjs >> /app/logs/bot-weekly-review.log 2>&1" >> /app/logs/cron.log 2>&1
# 11) Bot 反馈环 - 每周日 22:00
0 22 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-feedback-loop.mjs >> /app/logs/bot-feedback.log 2>&1" >> /app/logs/cron.log 2>&1
# 12) Bot 数字人 vs 真人对抗学习 - 每周日 23:30
30 23 * * 0 bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-adversarial-learning-run.mjs >> /app/logs/bot-adversarial.log 2>&1" >> /app/logs/cron.log 2>&1
# 13) Bot 人设 A/B 实验数据采集 - 每小时
0 * * * * bash -c "set -a; . /app/.env; set +a; cd /app && node scripts/bot-persona-experiment-run.mjs >> /app/logs/bot-experiment.log 2>&1" >> /app/logs/cron.log 2>&1
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
# =============================================================================
# 追光AI Docker Compose 测试覆盖 (并行部署, 端口 8302)
# - 与生产 PM2 部署 (8301) 并行运行,验证容器化版本
# - 通过环境变量覆盖 PORT 到 8302,不影响 8301 上的 PM2 服务
# - 使用: docker-compose -f docker-compose.yml -f docker-compose.test.yml up -d
# =============================================================================
services:
zhuiguang-ai-app:
environment:
TZ: Asia/Shanghai
NODE_ENV: production
PORT: "8302"
HOSTNAME: "0.0.0.0"
# 测试卷:避免与生产卷混淆
volumes:
- ./env/.env.production:/app/.env:ro
- test-bot-data:/app/data
- test-bot-public:/app/public
- test-bot-logs:/app/logs
- test-bot-prisma:/app/node_modules/.prisma
# 改 container_name 避免与未来生产部署冲突
container_name: zhuiguang-ai-app-test
# 关掉 healthcheck(不依赖 8301 端口被占用)
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost:8302/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
zhuiguang-ai-cron:
environment:
TZ: Asia/Shanghai
NODE_ENV: production
# cron 容器不需要 PORT,但保持可读
PORT: "8302"
volumes:
- ./env/.env.production:/app/.env:ro
- test-bot-data:/app/data
- test-bot-public:/app/public
- test-bot-logs:/app/logs
- test-bot-prisma:/app/node_modules/.prisma
- ./crontab.txt:/app/crontab.txt:ro
container_name: zhuiguang-ai-cron-test
depends_on:
- zhuiguang-ai-app
# 测试卷(独立命名,不与生产卷冲突)
volumes:
test-bot-data:
name: zhuiguang_ai_test_bot_data
test-bot-public:
name: zhuiguang_ai_test_bot_public
test-bot-logs:
name: zhuiguang_ai_test_bot_logs
test-bot-prisma:
name: zhuiguang_ai_test_bot_prisma
+121
View File
@@ -0,0 +1,121 @@
# =============================================================================
# 追光AI Docker Compose (生产部署)
# - 1 个 APP 容器 (Next.js, 端口 8301)
# - 1 个 CRON 容器 (supercronic 调度 13 个任务)
# - 共用同一镜像,通过 override command 区分
# - 用 network_mode: host 让容器能访问宿主机共享服务 (Redis/Nacos/MinIO)
# - 卷挂载:data、public、logs 持久化
# =============================================================================
services:
# -------------------------------------------------------------------------
# 1) APP 服务
# -------------------------------------------------------------------------
zhuiguang-ai-app:
image: zhuiguang-ai:2.1.2
container_name: zhuiguang-ai-app
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
network_mode: host
# 用 host 网络:直接共享宿主机网络栈
# 优点:能直接访问 127.0.0.1:6379 (Redis), :8848 (Nacos), :9000 (MinIO)
# 缺点:失去 docker 端口隔离(但端口已锁定 8301,无冲突)
environment:
# 容器内 timezone
TZ: Asia/Shanghai
NODE_ENV: production
PORT: "8301"
HOSTNAME: "0.0.0.0"
volumes:
# .env 挂载(必须,否则容器找不到 DATABASE_URL)
- ./env/.env.production:/app/.env:ro
# 持久化数据
- bot-data:/app/data
- bot-public:/app/public
# 日志(容器外可读,方便 docker logs + host 双通道)
- bot-logs:/app/logs
# 临时 prisma 缓存
- bot-prisma:/app/node_modules/.prisma
# 不依赖 DB 健康检查(DB 是外网阿里云 RDS,检测不到会拖累启动)
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost:8301/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
# 用默认 entrypoint-app.sh (在 Dockerfile 里已设)
command: ["/usr/local/bin/entrypoint-app.sh"]
# -------------------------------------------------------------------------
# 2) CRON 服务
# -------------------------------------------------------------------------
zhuiguang-ai-cron:
image: zhuiguang-ai:2.1.2
container_name: zhuiguang-ai-cron
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
network_mode: host
environment:
TZ: Asia/Shanghai
NODE_ENV: production
volumes:
- ./env/.env.production:/app/.env:ro
# 共享 app 的 data 卷
- bot-data:/app/data
# 共享 app 的 public 卷(cron 任务可能读 bot 头像)
- bot-public:/app/public
# 共享 app 的 logs 卷(cron 写入日志,host 可见)
- bot-logs:/app/logs
- bot-prisma:/app/node_modules/.prisma
# 挂载 crontab 文件(不挂就看不到调度表)
- ./crontab.txt:/app/crontab.txt:ro
# supercronic 健康:自检进程存活
healthcheck:
test: ["CMD", "pgrep", "-f", "supercronic"]
interval: 60s
timeout: 3s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
command: ["/usr/local/bin/entrypoint-cron.sh"]
# 依赖 app 启动完成(不强依赖 DB,data 卷在 compose 内共享)
depends_on:
- zhuiguang-ai-app
# =============================================================================
# 命名卷(持久化)
# =============================================================================
volumes:
bot-data:
name: zhuiguang_ai_bot_data
bot-public:
name: zhuiguang_ai_bot_public
bot-logs:
name: zhuiguang_ai_bot_logs
bot-prisma:
name: zhuiguang_ai_bot_prisma
+246
View File
@@ -0,0 +1,246 @@
# 追光AI 容器化部署文档
> 创建时间:2026-06-11
> 适用版本:V2.1.2+
## 一、为什么容器化
服务器 119.45.242.239 上有 3+ 邻居项目(zhuiguang-quant / zhenfang / snowy-fgt / agent-system)+ 3 个共享 Docker 服务(redis-cache / nacos / minio)。
本项目 (zhuiguang-ai) 改用容器化部署的好处:
1. **环境隔离**:本项目 Node 依赖与邻居项目(Java/Python)零冲突
2. **可移植**:换服务器 1 行命令起服务
3. **可复现**:Dockerfile 锁 Node 版本、依赖版本
4. **资源上限**:内存/CPU 可设限,不拖累邻居项目
## 二、架构
```
┌─────────── Host (Ubuntu 22.04) ───────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ zhuiguang-ai-app (Docker) │ │
│ │ - Next.js 14 (port 8301) │ │
│ │ - network_mode: host │ │
│ │ - 共享卷: data / public / logs │ │
│ └──────────────────────────────────┘ │
│ │ │
│ │ http://localhost:8301 │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ zhuiguang-ai-cron (Docker) │ │
│ │ - supercronic v0.2.33 │ │
│ │ - 13 个 cron 任务 │ │
│ │ - 共享卷: data / public / logs │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌─ 共享服务 (邻居项目共用) ─┐ │
│ │ redis-cache: 6379 │ │
│ │ nacos: 8848/9848 │ │
│ │ minio: 9000/9001 │ │
│ └────────────────────────────┘ │
│ │
│ ┌─ 外部服务 ─┐ │
│ │ 阿里云 RDS MySQL │ │
│ │ DeepSeek / 各 AI/新闻 API │ │
│ └────────────┘ │
│ │
│ ┌─ nginx 反代 ─┐ │
│ │ 80/443 → 8301│ │
│ └────────────┘ │
└────────────────────────────────────────────┘
```
**网络模式 `host` 的原因**:
需要访问宿主机上的 Redis/Nacos/MinIO 共享服务。`bridge` 网络要么把 host 的容器端口暴露给 bridge 网络(修改共享服务配置),要么用 `extra_hosts: host.docker.internal`(仅 Docker Desktop 支持,Linux server 需装 xinetd 替代)。
`host` 模式最简单,端口已锁定 8301-8310 不冲突。
## 三、目录结构
```
/home/ubuntu/zhuiguang-ai/
├── Dockerfile # 多阶段构建
├── docker-compose.yml # 2 个服务编排
├── .dockerignore # 构建排除
├── crontab.txt # supercronic 调度表
├── env/
│ └── .env.production # 生产环境变量 (DATABASE_URL / API_KEY)
├── scripts/
│ ├── entrypoint-app.sh # APP 启动入口
│ ├── entrypoint-cron.sh # CRON 启动入口
│ ├── backup-volumes.sh # 卷备份 (host 跑)
│ ├── install-cron-backup.sh # 备份 cron 安装 (host 跑)
│ ├── install-cron.sh # 旧 host cron 安装 (停用)
│ └── ... (业务脚本)
├── public/ # 静态资源 (volume)
├── data/ # bot-characters.json (volume)
├── logs/ # 运行日志 (volume)
└── ... (源码)
Docker 卷 (命名卷):
zhuiguang_ai_bot_data → /app/data
zhuiguang_ai_bot_public → /app/public
zhuiguang_ai_bot_logs → /app/logs
zhuiguang_ai_bot_prisma → /app/node_modules/.prisma
```
## 四、部署步骤
### 1. 准备 .env
```bash
cd /home/ubuntu/zhuiguang-ai
mkdir -p env
cp .env env/.env.production
chmod 600 env/.env.production
# 编辑 env/.env.production 填入生产 DATABASE_URL / API_KEY
```
### 2. 构建镜像
```bash
cd /home/ubuntu/zhuiguang-ai
docker compose build
# 首次 5-10 分钟,之后改 code 1-3 分钟
```
### 3. 启动
```bash
docker compose up -d
# 等 30s,让 prisma migrate deploy 跑完
docker compose ps
docker compose logs -f --tail 50 zhuiguang-ai-app
```
### 4. 验证
```bash
# 1) APP 探活
curl -I http://localhost:8301/api/health
# 2) CRON 探活
docker exec zhuiguang-ai-cron pgrep -f supercronic
docker exec zhuiguang-ai-cron supercronic-linux-amd64 -version
# 3) 触发 1 个 cron 任务手动跑
docker exec zhuiguang-ai-cron bash -c "set -a; . /app/.env; set +a; node /app/scripts/task1-discover-tools.mjs"
# 4) 看实时日志
docker compose logs -f zhuiguang-ai-cron
```
### 5. 安装 host 备份 cron
```bash
bash scripts/install-cron-backup.sh
# 安装:每天 03:30 备份 4 个卷到 /home/ubuntu/zhuiguang-ai-backup/dockers/
```
### 6. 旧 PM2 清理(验证通过后)
```bash
# 1) 停 PM2
pm2 stop zhuiguang-ai
# 2) 验证容器无问题 24h+ 后
pm2 delete zhuiguang-ai
pm2 save
# 3) 旧 host cron 清理(容器接管后失效)
crontab -l | grep -vE 'zhuiguang-ai|bot-activity' > /tmp/cron.new
crontab /tmp/cron.new
# 4) 旧代码归档(保留 7 天可回滚)
cd /home/ubuntu
mv zhuiguang-ai zhuiguang-ai-old-$(date +%Y%m%d)
# 把 git 仓库拉回来(容器卷只是数据,源码在 git)
git clone <repo-url> zhuiguang-ai
```
## 五、运维命令速查
```bash
# 查看服务
docker compose ps
docker compose logs -f zhuiguang-ai-app
docker compose logs -f zhuiguang-ai-cron
# 资源占用
docker stats zhuiguang-ai-app zhuiguang-ai-cron
# 进入容器
docker exec -it zhuiguang-ai-app sh
docker exec -it zhuiguang-ai-cron sh
# 手动跑一个脚本
docker exec zhuiguang-ai-cron bash -c "set -a; . /app/.env; set +a; node /app/scripts/bot-activity.mjs"
# 重启单个服务
docker compose restart zhuiguang-ai-app
# 重建镜像 + 重启
docker compose build --no-cache zhuiguang-ai-app
docker compose up -d zhuiguang-ai-app
# 备份
bash /home/ubuntu/zhuiguang-ai/scripts/backup-volumes.sh
# 回滚到 PM2
pm2 start zhuiguang-ai # 前提:旧代码还在 /home/ubuntu/zhuiguang-ai-old-*/
```
## 六、回滚方案
任何步骤出问题,立即回滚:
```bash
# 1) 停容器
cd /home/ubuntu/zhuiguang-ai
docker compose down
# 2) 切回旧代码
cd /home/ubuntu
mv zhuiguang-ai zhuiguang-ai-failed-$(date +%Y%m%d)
mv zhuiguang-ai-old-YYYYMMDD zhuiguang-ai
# 3) 启动 PM2
cd /home/ubuntu/zhuiguang-ai
pm2 start zhuiguang-ai
# 4) 确认线上恢复
curl -I http://localhost:8301/api/health
```
## 七、升级流程
```bash
# 1) 拉新代码
cd /home/ubuntu/zhuiguang-ai
git pull
# 2) 如改了 schema 需先备份
bash scripts/backup-volumes.sh
# 3) 重新构建
docker compose build
# 4) 滚动重启(先 cron 再 app 减少任务失败)
docker compose up -d
# 或分步
docker compose up -d zhuiguang-ai-cron
docker compose up -d zhuiguang-ai-app
# 5) 验证
curl -I http://localhost:8301/api/health
docker compose logs --tail 30 zhuiguang-ai-app
```
## 八、注意事项(项目铁律)
1. **端口锁定 8301-8310**:本项目所有端口只能在这区间,容器也必须遵守
2. **不动共享服务**:Redis/Nacos/MinIO 在宿主机 Docker,**绝不重启**
3. **不动邻居项目目录**:`/home/ubuntu/{zhuiguang-quant,zhenfang,snowy-fgt,agent-system}` 只读
4. **不动全局 crontab**:用 `crontab -e` 追加,不要 `crontab -r`
5. **不动 nginx**:容器绑定 8301,nginx 反代规则不动
6. **保留 PM2 镜像**:验证通过 24h 前不要 `pm2 delete`,出问题能秒切回
+55
View File
@@ -0,0 +1,55 @@
# 追光量化系统 - 前端 Nginx 配置
# 仅内部 HTTP(80),SSL 由 host Nginx 处理
upstream backend {
server backend:7001;
keepalive 32;
}
server {
listen 80;
server_name lh.zhuig.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
expires 1y;
add_header Cache-Control "public, immutable";
location = /index.html {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
proxy_no_cache 1;
proxy_cache_bypass 1;
}
location /health {
proxy_pass http://backend/api/v1/actuator/health;
proxy_http_version 1.1;
proxy_set_header Host $host;
access_log off;
}
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
access_log /var/log/nginx/quant-system.access.log combined;
error_log /var/log/nginx/quant-system.error.log warn;
client_max_body_size 16M;
}
+12 -2
View File
@@ -1,14 +1,15 @@
{ {
"name": "zhuiguang-ai", "name": "zhuiguang-ai",
"version": "0.1.0", "version": "V2.1.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "zhuiguang-ai", "name": "zhuiguang-ai",
"version": "0.1.0", "version": "V2.1.2",
"dependencies": { "dependencies": {
"@base-ui/react": "^1.4.1", "@base-ui/react": "^1.4.1",
"@fontsource-variable/noto-sans-sc": "^5.2.10",
"@prisma/adapter-mariadb": "^7.8.0", "@prisma/adapter-mariadb": "^7.8.0",
"@prisma/client": "^7.8.0", "@prisma/client": "^7.8.0",
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
@@ -796,6 +797,15 @@
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@fontsource-variable/noto-sans-sc": {
"version": "5.2.10",
"resolved": "https://registry.npmjs.org/@fontsource-variable/noto-sans-sc/-/noto-sans-sc-5.2.10.tgz",
"integrity": "sha512-zdk10i5HrDQTXI7ldD61zToX1fsgig8vDTsu7zB48SXOitWfuX0e5viZAwnkHuhwh096PU6X6i1AyAsbBCISpA==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@hono/node-server": { "node_modules/@hono/node-server": {
"version": "1.19.14", "version": "1.19.14",
"resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.14.tgz", "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.14.tgz",
+1
View File
@@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@base-ui/react": "^1.4.1", "@base-ui/react": "^1.4.1",
"@fontsource-variable/noto-sans-sc": "^5.2.10",
"@prisma/adapter-mariadb": "^7.8.0", "@prisma/adapter-mariadb": "^7.8.0",
"@prisma/client": "^7.8.0", "@prisma/client": "^7.8.0",
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
@@ -0,0 +1,28 @@
-- AlterTable
ALTER TABLE `bot_memories`
ADD COLUMN `layer` VARCHAR(20) NOT NULL DEFAULT 'LONGTERM',
ADD COLUMN `context_tags` JSON NULL,
ADD COLUMN `ttl` DATETIME(3) NULL;
-- CreateIndex
CREATE INDEX `bot_memories_bot_id_layer_importance_idx` ON `bot_memories`(`bot_id`, `layer`, `importance`);
-- CreateTable
CREATE TABLE `bot_daily_stats` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`date` DATE NOT NULL,
`topic_created` INTEGER NOT NULL DEFAULT 0,
`reply_sent` INTEGER NOT NULL DEFAULT 0,
`follow_up_sent` INTEGER NOT NULL DEFAULT 0,
`replies_received` INTEGER NOT NULL DEFAULT 0,
`likes_received` INTEGER NOT NULL DEFAULT 0,
`human_interactions` INTEGER NOT NULL DEFAULT 0,
`feedback_processed` INTEGER NOT NULL DEFAULT 0,
`top_topic_id` INTEGER NULL,
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `bot_daily_stats_bot_id_date_key`(`bot_id`, `date`),
INDEX `bot_daily_stats_date_idx`(`date`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -0,0 +1,44 @@
-- CreateTable
CREATE TABLE `bot_skills` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`name` VARCHAR(50) NOT NULL,
`category` VARCHAR(30) NOT NULL,
`hook_pattern` TEXT NOT NULL,
`body_template` TEXT NOT NULL,
`applicability` TEXT NULL,
`source_topic_ids` JSON NOT NULL,
`success_rate` DOUBLE NOT NULL DEFAULT 0,
`usage_count` INTEGER NOT NULL DEFAULT 0,
`avg_replies` DOUBLE NOT NULL DEFAULT 0,
`avg_likes` DOUBLE NOT NULL DEFAULT 0,
`version` INTEGER NOT NULL DEFAULT 1,
`is_active` BOOLEAN NOT NULL DEFAULT true,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
INDEX `bot_skills_bot_id_category_is_active_idx`(`bot_id`, `category`, `is_active`),
INDEX `bot_skills_bot_id_success_rate_idx`(`bot_id`, `success_rate`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `bot_weekly_reviews` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`week_start` DATE NOT NULL,
`week_end` DATE NOT NULL,
`topics_created` INTEGER NOT NULL DEFAULT 0,
`replies_sent` INTEGER NOT NULL DEFAULT 0,
`replies_received` INTEGER NOT NULL DEFAULT 0,
`human_ratio` DOUBLE NOT NULL DEFAULT 0,
`likes_received` INTEGER NOT NULL DEFAULT 0,
`engagement_score` DOUBLE NOT NULL DEFAULT 0,
`next_week_quota` VARCHAR(20) NOT NULL,
`reflection` TEXT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `bot_weekly_reviews_bot_id_week_start_key`(`bot_id`, `week_start`),
INDEX `bot_weekly_reviews_bot_id_week_start_idx`(`bot_id`, `week_start`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -0,0 +1,31 @@
-- CreateTable
CREATE TABLE `bot_personas` (
`bot_id` INTEGER NOT NULL,
`avg_reply_length` INTEGER NOT NULL DEFAULT 0,
`question_ratio` DOUBLE NOT NULL DEFAULT 0,
`exclamation_count` INTEGER NOT NULL DEFAULT 0,
`avg_topic_length` INTEGER NOT NULL DEFAULT 0,
`stance_keywords` JSON NULL,
`top_human_users` JSON NULL,
`top_topic_types` JSON NULL,
`last_topic_titles` JSON NULL,
`post_sample_count` INTEGER NOT NULL DEFAULT 0,
`updated_at` DATETIME(3) NOT NULL,
PRIMARY KEY (`bot_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `bot_cross_forum_affinities` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`bot_id` INTEGER NOT NULL,
`forum_slug` VARCHAR(30) NOT NULL,
`affinity` DOUBLE NOT NULL DEFAULT 0,
`sample_count` INTEGER NOT NULL DEFAULT 0,
`reason` VARCHAR(100) NULL,
`updated_at` DATETIME(3) NOT NULL,
UNIQUE INDEX `bot_cross_forum_affinities_bot_id_forum_slug_key`(`bot_id`, `forum_slug`),
INDEX `bot_cross_forum_affinities_bot_id_affinity_idx`(`bot_id`, `affinity`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -0,0 +1,106 @@
-- 论坛增强:点赞/标签/关注/草稿
-- 2026-06-03
-- AlterTable
ALTER TABLE `forum_categories` ADD COLUMN `follower_count` INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE `forum_topics` ADD COLUMN `is_featured` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `like_count` INTEGER NOT NULL DEFAULT 0;
-- AlterTable
ALTER TABLE `forum_posts` ADD COLUMN `like_count` INTEGER NOT NULL DEFAULT 0;
-- CreateTable
CREATE TABLE `forum_topic_likes` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_topic_likes_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_topic_likes_topic_id_user_id_key`(`topic_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_post_likes` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`post_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_post_likes_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_post_likes_post_id_user_id_key`(`post_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_category_follows` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`category_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `forum_category_follows_user_id_idx`(`user_id`),
UNIQUE INDEX `forum_category_follows_category_id_user_id_key`(`category_id`, `user_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_tags` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`slug` VARCHAR(30) NOT NULL,
`topic_count` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `forum_tags_name_key`(`name`),
UNIQUE INDEX `forum_tags_slug_key`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_topic_tags` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`tag_id` INTEGER NOT NULL,
INDEX `forum_topic_tags_tag_id_idx`(`tag_id`),
UNIQUE INDEX `forum_topic_tags_topic_id_tag_id_key`(`topic_id`, `tag_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `forum_drafts` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user_id` INTEGER NOT NULL,
`category_id` INTEGER NULL,
`title` VARCHAR(100) NULL,
`content` TEXT NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
INDEX `forum_drafts_user_id_updated_at_idx`(`user_id`, `updated_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `forum_topic_likes` ADD CONSTRAINT `forum_topic_likes_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_likes` ADD CONSTRAINT `forum_topic_likes_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_post_likes` ADD CONSTRAINT `forum_post_likes_post_id_fkey` FOREIGN KEY (`post_id`) REFERENCES `forum_posts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_post_likes` ADD CONSTRAINT `forum_post_likes_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_category_follows` ADD CONSTRAINT `forum_category_follows_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `forum_categories`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_category_follows` ADD CONSTRAINT `forum_category_follows_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_tags` ADD CONSTRAINT `forum_topic_tags_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_tags` ADD CONSTRAINT `forum_topic_tags_tag_id_fkey` FOREIGN KEY (`tag_id`) REFERENCES `forum_tags`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_drafts` ADD CONSTRAINT `forum_drafts_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateIndex
CREATE INDEX `forum_topics_category_id_is_pinned_created_at_idx` ON `forum_topics`(`category_id`, `is_pinned`, `created_at`);
CREATE INDEX `forum_topics_is_featured_last_reply_at_idx` ON `forum_topics`(`is_featured`, `last_reply_at`);
CREATE INDEX `forum_posts_user_id_idx` ON `forum_posts`(`user_id`);
@@ -0,0 +1,53 @@
-- 论坛第三阶段增强:通知/收藏/举报/嵌套回复
-- 2026-06-04
-- AlterTable: forum_topics 加 is_hidden 字段
ALTER TABLE `forum_topics` ADD COLUMN `is_hidden` BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE `forum_topics` ADD INDEX `forum_topics_is_hidden_idx`(`is_hidden`);
-- AlterTable: forum_posts 加 reply_to_id / reply_to_snapshot
ALTER TABLE `forum_posts` ADD COLUMN `reply_to_id` INTEGER NULL;
ALTER TABLE `forum_posts` ADD COLUMN `reply_to_snapshot` VARCHAR(300) NULL;
ALTER TABLE `forum_posts` ADD CONSTRAINT `forum_posts_reply_to_id_fkey` FOREIGN KEY (`reply_to_id`) REFERENCES `forum_posts`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `forum_posts` ADD INDEX `forum_posts_reply_to_id_idx`(`reply_to_id`);
-- AlterTable: forum_topics 加联合全文索引
ALTER TABLE `forum_topics` ADD FULLTEXT INDEX `forum_topics_title_content_idx`(`title`, `content`);
-- CreateTable: 收藏
CREATE TABLE `forum_topic_bookmarks` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`topic_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_topic_bookmarks_topic_id_user_id_key`(`topic_id`, `user_id`),
INDEX `forum_topic_bookmarks_user_id_created_at_idx`(`user_id`, `created_at`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_topic_bookmarks` ADD CONSTRAINT `forum_topic_bookmarks_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_topic_bookmarks` ADD CONSTRAINT `forum_topic_bookmarks_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateTable: 举报
CREATE TABLE `forum_reports` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`reporter_id` INTEGER NOT NULL,
`topic_id` INTEGER NULL,
`post_id` INTEGER NULL,
`reason` VARCHAR(50) NOT NULL,
`detail` VARCHAR(500) NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'pending',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`resolved_at` DATETIME(3) NULL,
PRIMARY KEY (`id`),
INDEX `forum_reports_status_created_at_idx`(`status`, `created_at`),
INDEX `forum_reports_reporter_id_idx`(`reporter_id`),
INDEX `forum_reports_topic_id_idx`(`topic_id`),
INDEX `forum_reports_post_id_idx`(`post_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_reporter_id_fkey` FOREIGN KEY (`reporter_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_topic_id_fkey` FOREIGN KEY (`topic_id`) REFERENCES `forum_topics`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AlterTable: notifications 增加新枚举值
ALTER TABLE `notifications` MODIFY COLUMN `type` ENUM('COMMENT_REPLY','COMMENT_LIKE','TOPIC_REPLY','MENTION','BEST_ANSWER','POST_LIKE','TOPIC_LIKE','SYSTEM') NOT NULL;
@@ -0,0 +1,44 @@
-- 论坛第四阶段增强:签到、举报处理、隐藏回复、审核日志
-- 2026-06-05
-- AlterTable: forum_posts 增加 is_hidden 字段
ALTER TABLE `forum_posts` ADD COLUMN `is_hidden` BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE `forum_posts` ADD INDEX `forum_posts_is_hidden_idx`(`is_hidden`);
-- AlterTable: forum_reports 增加 resolution/resolvedBy
ALTER TABLE `forum_reports` ADD COLUMN `resolution` VARCHAR(20) NULL;
ALTER TABLE `forum_reports` ADD COLUMN `resolved_by` INTEGER NULL;
ALTER TABLE `forum_reports` ADD CONSTRAINT `forum_reports_resolved_by_fkey` FOREIGN KEY (`resolved_by`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `forum_reports` ADD INDEX `forum_reports_resolved_by_idx`(`resolved_by`);
-- CreateTable: 每日签到
CREATE TABLE `forum_check_ins` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user_id` INTEGER NOT NULL,
`check_in_date` DATE NOT NULL,
`streak` INTEGER NOT NULL DEFAULT 1,
`points_earned` INTEGER NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_check_ins_user_id_check_in_date_key`(`user_id`, `check_in_date`),
INDEX `forum_check_ins_user_id_check_in_date_idx`(`user_id`, `check_in_date`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_check_ins` ADD CONSTRAINT `forum_check_ins_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- CreateTable: 审核日志
CREATE TABLE `forum_moderation_logs` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`actor_id` INTEGER NOT NULL,
`target_type` VARCHAR(20) NOT NULL,
`target_id` INTEGER NOT NULL,
`action` VARCHAR(30) NOT NULL,
`reason` VARCHAR(200) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
INDEX `forum_moderation_logs_actor_id_created_at_idx`(`actor_id`, `created_at`),
INDEX `forum_moderation_logs_target_type_target_id_idx`(`target_type`, `target_id`),
INDEX `forum_moderation_logs_created_at_idx`(`created_at`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `forum_moderation_logs` ADD CONSTRAINT `forum_moderation_logs_actor_id_fkey` FOREIGN KEY (`actor_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,42 @@
-- Forum Phase 5: Achievement system + topic subscriptions
CREATE TABLE `achievements` (
`key` VARCHAR(50) NOT NULL,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(200) NOT NULL,
`icon` VARCHAR(20) NOT NULL,
`tier` VARCHAR(20) NOT NULL DEFAULT 'bronze',
`points` INT NOT NULL DEFAULT 0,
`category` VARCHAR(30) NOT NULL DEFAULT 'general',
`sort_order` INT NOT NULL DEFAULT 0,
`is_active` BOOLEAN NOT NULL DEFAULT TRUE,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`key`),
INDEX `achievements_category_is_active_sort_order_idx`(`category`, `is_active`, `sort_order`)
);
CREATE TABLE `user_achievements` (
`id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`achievement_key` VARCHAR(50) NOT NULL,
`progress` INT NOT NULL DEFAULT 0,
`unlocked_at` DATETIME(3) NULL,
`notified_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `user_achievements_user_id_achievement_key_key`(`user_id`, `achievement_key`),
INDEX `user_achievements_user_id_unlocked_at_idx`(`user_id`, `unlocked_at`),
INDEX `user_achievements_achievement_key_idx`(`achievement_key`)
);
CREATE TABLE `forum_topic_subscriptions` (
`id` INT NOT NULL AUTO_INCREMENT,
`topic_id` INT NOT NULL,
`user_id` INT NOT NULL,
`notify_reply` BOOLEAN NOT NULL DEFAULT TRUE,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `forum_topic_subscriptions_topic_id_user_id_key`(`topic_id`, `user_id`),
INDEX `forum_topic_subscriptions_user_id_created_at_idx`(`user_id`, `created_at`)
);
@@ -0,0 +1,87 @@
-- Bot Persona A/B Testing
-- Adds: bot_persona_variants, bot_persona_experiments, bot_persona_assignments, bot_persona_metrics
CREATE TABLE `bot_persona_variants` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`experiment_id` INT NULL,
`variant_key` VARCHAR(20) NOT NULL,
`label` VARCHAR(50) NOT NULL,
`description` VARCHAR(200) NULL,
`stance_keywords` JSON NULL,
`top_topic_types` JSON NULL,
`top_human_users` JSON NULL,
`style_hints` JSON NULL,
`weight` FLOAT NOT NULL DEFAULT 0.5,
`is_control` BOOLEAN NOT NULL DEFAULT FALSE,
`is_active` BOOLEAN NOT NULL DEFAULT TRUE,
`sample_count` INT NOT NULL DEFAULT 0,
`reply_count` INT NOT NULL DEFAULT 0,
`like_count` INT NOT NULL DEFAULT 0,
`human_reply_count` INT NOT NULL DEFAULT 0,
`engagement_score` FLOAT NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_variants_bot_id_variant_key_key`(`bot_id`, `variant_key`),
INDEX `bot_persona_variants_bot_id_is_active_idx`(`bot_id`, `is_active`),
INDEX `bot_persona_variants_experiment_id_idx`(`experiment_id`)
);
CREATE TABLE `bot_persona_experiments` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`name` VARCHAR(80) NOT NULL,
`description` VARCHAR(200) NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'active',
`winner_variant_key` VARCHAR(20) NULL,
`min_samples_per_arm` INT NOT NULL DEFAULT 20,
`significance_level` FLOAT NOT NULL DEFAULT 0.1,
`primary_metric` VARCHAR(30) NOT NULL DEFAULT 'engagement_score',
`config` JSON NULL,
`started_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`ended_at` DATETIME(3) NULL,
`last_analyzed_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
INDEX `bot_persona_experiments_bot_id_status_idx`(`bot_id`, `status`),
INDEX `bot_persona_experiments_status_idx`(`status`)
);
CREATE TABLE `bot_persona_assignments` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`variant_id` INT NOT NULL,
`ref_type` VARCHAR(20) NOT NULL,
`ref_id` INT NOT NULL,
`forum_slug` VARCHAR(30) NULL,
`replies` INT NOT NULL DEFAULT 0,
`likes` INT NOT NULL DEFAULT 0,
`human_replies` INT NOT NULL DEFAULT 0,
`impressions` INT NOT NULL DEFAULT 0,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_assignments_ref_type_ref_id_key`(`ref_type`, `ref_id`),
INDEX `bot_persona_assignments_bot_id_variant_id_idx`(`bot_id`, `variant_id`),
INDEX `bot_persona_assignments_variant_id_created_at_idx`(`variant_id`, `created_at`)
);
CREATE TABLE `bot_persona_metrics` (
`id` INT NOT NULL AUTO_INCREMENT,
`variant_id` INT NOT NULL,
`date` DATE NOT NULL,
`impressions` INT NOT NULL DEFAULT 0,
`replies` INT NOT NULL DEFAULT 0,
`likes` INT NOT NULL DEFAULT 0,
`human_replies` INT NOT NULL DEFAULT 0,
`content_count` INT NOT NULL DEFAULT 0,
`avg_replies` FLOAT NOT NULL DEFAULT 0,
`avg_likes` FLOAT NOT NULL DEFAULT 0,
`computed_score` FLOAT NOT NULL DEFAULT 0,
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_persona_metrics_variant_id_date_key`(`variant_id`, `date`),
INDEX `bot_persona_metrics_date_idx`(`date`)
);
@@ -0,0 +1,30 @@
-- 数字人 vs 真人"对抗学习"
-- 每周为每个 bot 选 1 个真实高赞真人帖,让 bot 吸收其"为什么高互动"的洞察
CREATE TABLE `bot_adversarial_learnings` (
`id` INT NOT NULL AUTO_INCREMENT,
`bot_id` INT NOT NULL,
`week_key` VARCHAR(20) NOT NULL,
`source_ref_type` VARCHAR(20) NOT NULL,
`source_ref_id` INT NOT NULL,
`source_user_id` INT NOT NULL,
`source_user_name` VARCHAR(50) NULL,
`forum_slug` VARCHAR(30) NULL,
`source_title` VARCHAR(200) NULL,
`source_content` TEXT NOT NULL,
`source_metrics` JSON NOT NULL,
`relevance_score` DOUBLE NOT NULL DEFAULT 0,
`learned_insight` TEXT NOT NULL,
`learn_categories` JSON NULL,
`status` VARCHAR(20) NOT NULL DEFAULT 'active',
`used_count` INT NOT NULL DEFAULT 0,
`learned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`expires_at` DATETIME(3) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE INDEX `bot_adversarial_learnings_bot_id_week_key_key`(`bot_id`, `week_key`),
INDEX `bot_adversarial_learnings_bot_id_status_idx`(`bot_id`, `status`),
INDEX `bot_adversarial_learnings_week_key_idx`(`week_key`),
INDEX `bot_adversarial_learnings_source_ref_type_source_ref_id_idx`(`source_ref_type`, `source_ref_id`)
);
+475
View File
@@ -184,6 +184,7 @@ model SystemConfig {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
key String @unique @db.VarChar(50) key String @unique @db.VarChar(50)
value Json value Json
@@map("system_configs") @@map("system_configs")
} }
@@ -216,6 +217,18 @@ model User {
forumTopics ForumTopic[] forumTopics ForumTopic[]
forumPosts ForumPost[] forumPosts ForumPost[]
pointsHistory PointsHistory[] pointsHistory PointsHistory[]
topicLikes ForumTopicLike[]
postLikes ForumPostLike[]
categoryFollows ForumCategoryFollow[]
topicBookmarks ForumTopicBookmark[]
topicDrafts ForumDraft[]
reports ForumReport[]
resolvedReports ForumReport[] @relation("ForumReportResolver")
checkIns ForumCheckIn[]
moderationLogs ForumModerationLog[] @relation("ForumModerationActor")
achievements UserAchievement[]
topicSubscriptions ForumTopicSubscription[]
@@unique([oauthProvider, oauthId]) @@unique([oauthProvider, oauthId])
@@map("users") @@map("users")
} }
@@ -565,6 +578,10 @@ enum NotifType {
COMMENT_REPLY COMMENT_REPLY
COMMENT_LIKE COMMENT_LIKE
TOPIC_REPLY TOPIC_REPLY
MENTION
BEST_ANSWER
POST_LIKE
TOPIC_LIKE
SYSTEM SYSTEM
} }
@@ -577,11 +594,13 @@ model ForumCategory {
parentId Int? @map("parent_id") parentId Int? @map("parent_id")
sortOrder Int @default(0) @map("sort_order") sortOrder Int @default(0) @map("sort_order")
topicCount Int @default(0) @map("topic_count") topicCount Int @default(0) @map("topic_count")
followerCount Int @default(0) @map("follower_count")
createdAt DateTime @default(now()) @map("created_at") createdAt DateTime @default(now()) @map("created_at")
parent ForumCategory? @relation("CategoryHierarchy", fields: [parentId], references: [id]) parent ForumCategory? @relation("CategoryHierarchy", fields: [parentId], references: [id])
children ForumCategory[] @relation("CategoryHierarchy") children ForumCategory[] @relation("CategoryHierarchy")
topics ForumTopic[] topics ForumTopic[]
followers ForumCategoryFollow[]
@@map("forum_categories") @@map("forum_categories")
} }
@@ -595,8 +614,11 @@ model ForumTopic {
content String @db.Text content String @db.Text
isPinned Boolean @default(false) @map("is_pinned") isPinned Boolean @default(false) @map("is_pinned")
isLocked Boolean @default(false) @map("is_locked") isLocked Boolean @default(false) @map("is_locked")
isFeatured Boolean @default(false) @map("is_featured")
isHidden Boolean @default(false) @map("is_hidden")
viewCount Int @default(0) @map("view_count") viewCount Int @default(0) @map("view_count")
replyCount Int @default(0) @map("reply_count") replyCount Int @default(0) @map("reply_count")
likeCount Int @default(0) @map("like_count")
lastReplyAt DateTime? @map("last_reply_at") lastReplyAt DateTime? @map("last_reply_at")
createdAt DateTime @default(now()) @map("created_at") createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at") updatedAt DateTime @updatedAt @map("updated_at")
@@ -604,10 +626,19 @@ model ForumTopic {
category ForumCategory @relation(fields: [categoryId], references: [id]) category ForumCategory @relation(fields: [categoryId], references: [id])
user User @relation(fields: [userId], references: [id]) user User @relation(fields: [userId], references: [id])
posts ForumPost[] posts ForumPost[]
likes ForumTopicLike[]
tags ForumTopicTag[]
bookmarks ForumTopicBookmark[]
reports ForumReport[]
subscribers ForumTopicSubscription[]
@@index([categoryId, lastReplyAt]) @@index([categoryId, lastReplyAt])
@@index([categoryId, isPinned, createdAt])
@@index([userId]) @@index([userId])
@@index([isFeatured, lastReplyAt])
@@index([isHidden])
@@fulltext([title]) @@fulltext([title])
@@fulltext([title, content])
@@map("forum_topics") @@map("forum_topics")
} }
@@ -617,16 +648,179 @@ model ForumPost {
userId Int @map("user_id") userId Int @map("user_id")
content String @db.Text content String @db.Text
isAnswer Boolean @default(false) @map("is_answer") isAnswer Boolean @default(false) @map("is_answer")
isHidden Boolean @default(false) @map("is_hidden")
likeCount Int @default(0) @map("like_count")
replyToId Int? @map("reply_to_id")
replyToSnapshot String? @map("reply_to_snapshot") @db.VarChar(300)
createdAt DateTime @default(now()) @map("created_at") createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at") updatedAt DateTime @updatedAt @map("updated_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade) topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id]) user User @relation(fields: [userId], references: [id])
likes ForumPostLike[]
replyTo ForumPost? @relation("PostReplies", fields: [replyToId], references: [id], onDelete: SetNull)
replies ForumPost[] @relation("PostReplies")
@@index([topicId, createdAt]) @@index([topicId, createdAt])
@@index([userId])
@@index([replyToId])
@@index([isHidden])
@@map("forum_posts") @@map("forum_posts")
} }
model ForumTopicLike {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId])
@@map("forum_topic_likes")
}
model ForumPostLike {
id Int @id @default(autoincrement())
postId Int @map("post_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
post ForumPost @relation(fields: [postId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([postId, userId])
@@index([userId])
@@map("forum_post_likes")
}
model ForumCategoryFollow {
id Int @id @default(autoincrement())
categoryId Int @map("category_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
category ForumCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([categoryId, userId])
@@index([userId])
@@map("forum_category_follows")
}
model ForumTag {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(20)
slug String @unique @db.VarChar(30)
topicCount Int @default(0) @map("topic_count")
createdAt DateTime @default(now()) @map("created_at")
topics ForumTopicTag[]
@@map("forum_tags")
}
model ForumTopicTag {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
tagId Int @map("tag_id")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
tag ForumTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([topicId, tagId])
@@index([tagId])
@@map("forum_topic_tags")
}
model ForumDraft {
id Int @id @default(autoincrement())
userId Int @map("user_id")
categoryId Int? @map("category_id")
title String? @db.VarChar(100)
content String @db.Text
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, updatedAt])
@@map("forum_drafts")
}
model ForumTopicBookmark {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId, createdAt])
@@map("forum_topic_bookmarks")
}
model ForumReport {
id Int @id @default(autoincrement())
reporterId Int @map("reporter_id")
topicId Int? @map("topic_id")
postId Int? @map("post_id")
reason String @db.VarChar(50)
detail String? @db.VarChar(500)
status String @default("pending") @db.VarChar(20)
resolution String? @db.VarChar(20)
resolvedBy Int? @map("resolved_by")
resolvedAt DateTime? @map("resolved_at")
createdAt DateTime @default(now()) @map("created_at")
reporter User @relation(fields: [reporterId], references: [id], onDelete: Cascade)
topic ForumTopic? @relation(fields: [topicId], references: [id], onDelete: Cascade)
resolver User? @relation("ForumReportResolver", fields: [resolvedBy], references: [id], onDelete: SetNull)
@@index([status, createdAt])
@@index([reporterId])
@@index([topicId])
@@index([postId])
@@index([resolvedBy])
@@map("forum_reports")
}
model ForumCheckIn {
id Int @id @default(autoincrement())
userId Int @map("user_id")
checkInDate DateTime @map("check_in_date") @db.Date
streak Int @default(1)
pointsEarned Int @default(0) @map("points_earned")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, checkInDate])
@@index([userId, checkInDate])
@@map("forum_check_ins")
}
model ForumModerationLog {
id Int @id @default(autoincrement())
actorId Int @map("actor_id")
targetType String @map("target_type") @db.VarChar(20)
targetId Int @map("target_id")
action String @db.VarChar(30)
reason String? @db.VarChar(200)
createdAt DateTime @default(now()) @map("created_at")
actor User @relation("ForumModerationActor", fields: [actorId], references: [id], onDelete: Cascade)
@@index([actorId, createdAt])
@@index([targetType, targetId])
@@index([createdAt])
@@map("forum_moderation_logs")
}
model BotConfig { model BotConfig {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
userId Int @unique @map("user_id") userId Int @unique @map("user_id")
@@ -639,6 +833,8 @@ model BotConfig {
user User @relation(fields: [userId], references: [id]) user User @relation(fields: [userId], references: [id])
memories BotMemory[] memories BotMemory[]
botPersonaVariants BotPersonaVariant[] @relation("BotVariants")
adversarialLearnings BotAdversarialLearning[] @relation("BotAdversarialLearnings")
@@map("bot_configs") @@map("bot_configs")
} }
@@ -647,13 +843,292 @@ model BotMemory {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
botId Int @map("bot_id") botId Int @map("bot_id")
memoryType String @map("memory_type") @db.VarChar(20) memoryType String @map("memory_type") @db.VarChar(20)
layer String @default("LONGTERM") @map("layer") @db.VarChar(20)
content Json content Json
importance Float @default(0.5) importance Float @default(0.5)
contextTags Json? @map("context_tags")
ttl DateTime? @map("ttl")
createdAt DateTime @default(now()) @map("created_at") createdAt DateTime @default(now()) @map("created_at")
bot BotConfig @relation(fields: [botId], references: [id]) bot BotConfig @relation(fields: [botId], references: [id])
@@index([botId, layer, importance])
@@index([botId, memoryType, createdAt]) @@index([botId, memoryType, createdAt])
@@index([botId, createdAt])
@@map("bot_memories") @@map("bot_memories")
} }
model BotDailyStat {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
date DateTime @db.Date
topicCreated Int @default(0) @map("topic_created")
replySent Int @default(0) @map("reply_sent")
followUpSent Int @default(0) @map("follow_up_sent")
repliesReceived Int @default(0) @map("replies_received")
likesReceived Int @default(0) @map("likes_received")
humanInteractions Int @default(0) @map("human_interactions")
feedbackProcessed Int @default(0) @map("feedback_processed")
topTopicId Int? @map("top_topic_id")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([botId, date])
@@index([date])
@@map("bot_daily_stats")
}
model BotSkill {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
name String @db.VarChar(50)
category String @db.VarChar(30)
hookPattern String @map("hook_pattern") @db.Text
bodyTemplate String @map("body_template") @db.Text
applicability String? @db.Text
sourceTopicIds Json @map("source_topic_ids")
successRate Float @default(0) @map("success_rate")
usageCount Int @default(0) @map("usage_count")
avgReplies Float @default(0) @map("avg_replies")
avgLikes Float @default(0) @map("avg_likes")
version Int @default(1)
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([botId, category, isActive])
@@index([botId, successRate])
@@map("bot_skills")
}
model BotWeeklyReview {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
weekStart DateTime @map("week_start") @db.Date
weekEnd DateTime @map("week_end") @db.Date
topicsCreated Int @default(0) @map("topics_created")
repliesSent Int @default(0) @map("replies_sent")
repliesReceived Int @default(0) @map("replies_received")
humanRatio Float @default(0) @map("human_ratio")
likesReceived Int @default(0) @map("likes_received")
engagementScore Float @default(0) @map("engagement_score")
nextWeekQuota String @map("next_week_quota") @db.VarChar(20)
reflection String? @db.Text
createdAt DateTime @default(now()) @map("created_at")
@@unique([botId, weekStart])
@@index([botId, weekStart])
@@map("bot_weekly_reviews")
}
model BotPersona {
botId Int @id @map("bot_id")
avgReplyLength Int @default(0) @map("avg_reply_length")
questionRatio Float @default(0) @map("question_ratio")
exclamationCount Int @default(0) @map("exclamation_count")
avgTopicLength Int @default(0) @map("avg_topic_length")
stanceKeywords Json? @map("stance_keywords")
topHumanUsers Json? @map("top_human_users")
topTopicTypes Json? @map("top_topic_types")
lastTopicTitles Json? @map("last_topic_titles")
postSampleCount Int @default(0) @map("post_sample_count")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("bot_personas")
}
model BotPersonaVariant {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
experimentId Int? @map("experiment_id")
variantKey String @map("variant_key") @db.VarChar(20)
label String @db.VarChar(50)
description String? @db.VarChar(200)
stanceKeywords Json? @map("stance_keywords")
topTopicTypes Json? @map("top_topic_types")
topHumanUsers Json? @map("top_human_users")
styleHints Json? @map("style_hints")
weight Float @default(0.5)
isControl Boolean @default(false) @map("is_control")
isActive Boolean @default(true) @map("is_active")
sampleCount Int @default(0) @map("sample_count")
replyCount Int @default(0) @map("reply_count")
likeCount Int @default(0) @map("like_count")
humanReplyCount Int @default(0) @map("human_reply_count")
engagementScore Float @default(0) @map("engagement_score")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
botConfig BotConfig @relation("BotVariants", fields: [botId], references: [id], onDelete: Cascade)
experiment BotPersonaExperiment? @relation("ExperimentVariants", fields: [experimentId], references: [id], onDelete: SetNull)
assignments BotPersonaAssignment[]
metrics BotPersonaMetric[]
@@unique([botId, variantKey])
@@index([botId, isActive])
@@index([experimentId])
@@map("bot_persona_variants")
}
model BotPersonaExperiment {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
name String @db.VarChar(80)
description String? @db.VarChar(200)
status String @default("active") @db.VarChar(20)
winnerVariantKey String? @map("winner_variant_key") @db.VarChar(20)
minSamplesPerArm Int @default(20) @map("min_samples_per_arm")
significanceLevel Float @default(0.1) @map("significance_level")
primaryMetric String @default("engagement_score") @map("primary_metric") @db.VarChar(30)
config Json?
startedAt DateTime @default(now()) @map("started_at")
endedAt DateTime? @map("ended_at")
lastAnalyzedAt DateTime? @map("last_analyzed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
variants BotPersonaVariant[] @relation("ExperimentVariants")
@@index([botId, status])
@@index([status])
@@map("bot_persona_experiments")
}
model BotPersonaAssignment {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
variantId Int @map("variant_id")
refType String @map("ref_type") @db.VarChar(20)
refId Int @map("ref_id")
forumSlug String? @map("forum_slug") @db.VarChar(30)
replies Int @default(0)
likes Int @default(0)
humanReplies Int @default(0) @map("human_replies")
impressions Int @default(0)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
variant BotPersonaVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
@@unique([refType, refId])
@@index([botId, variantId])
@@index([variantId, createdAt])
@@map("bot_persona_assignments")
}
model BotPersonaMetric {
id Int @id @default(autoincrement())
variantId Int @map("variant_id")
date DateTime @db.Date
impressions Int @default(0)
replies Int @default(0)
likes Int @default(0)
humanReplies Int @default(0) @map("human_replies")
contentCount Int @default(0) @map("content_count")
avgReplies Float @default(0) @map("avg_replies")
avgLikes Float @default(0) @map("avg_likes")
computedScore Float @default(0) @map("computed_score")
updatedAt DateTime @updatedAt @map("updated_at")
variant BotPersonaVariant @relation(fields: [variantId], references: [id], onDelete: Cascade)
@@unique([variantId, date])
@@index([date])
@@map("bot_persona_metrics")
}
model BotAdversarialLearning {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
weekKey String @map("week_key") @db.VarChar(20)
sourceRefType String @map("source_ref_type") @db.VarChar(20)
sourceRefId Int @map("source_ref_id")
sourceUserId Int @map("source_user_id")
sourceUserName String? @map("source_user_name") @db.VarChar(50)
forumSlug String? @map("forum_slug") @db.VarChar(30)
sourceTitle String? @map("source_title") @db.VarChar(200)
sourceContent String @map("source_content") @db.Text
sourceMetrics Json @map("source_metrics")
relevanceScore Float @default(0) @map("relevance_score")
learnedInsight String @map("learned_insight") @db.Text
learnCategories Json? @map("learn_categories")
status String @default("active") @db.VarChar(20)
usedCount Int @default(0) @map("used_count")
learnedAt DateTime @default(now()) @map("learned_at")
expiresAt DateTime? @map("expires_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
botConfig BotConfig @relation("BotAdversarialLearnings", fields: [botId], references: [id], onDelete: Cascade)
@@unique([botId, weekKey])
@@index([botId, status])
@@index([weekKey])
@@index([sourceRefType, sourceRefId])
@@map("bot_adversarial_learnings")
}
model BotCrossForumAffinity {
id Int @id @default(autoincrement())
botId Int @map("bot_id")
forumSlug String @map("forum_slug") @db.VarChar(30)
affinity Float @default(0)
sampleCount Int @default(0) @map("sample_count")
reason String? @db.VarChar(100)
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([botId, forumSlug])
@@index([botId, affinity])
@@map("bot_cross_forum_affinities")
}
model Achievement {
key String @id @db.VarChar(50)
name String @db.VarChar(50)
description String @db.VarChar(200)
icon String @db.VarChar(20)
tier String @default("bronze") @db.VarChar(20)
points Int @default(0)
category String @default("general") @db.VarChar(30)
sortOrder Int @default(0) @map("sort_order")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
users UserAchievement[]
@@index([category, isActive, sortOrder])
@@map("achievements")
}
model UserAchievement {
id Int @id @default(autoincrement())
userId Int @map("user_id")
achievementKey String @map("achievement_key") @db.VarChar(50)
progress Int @default(0)
unlockedAt DateTime? @map("unlocked_at")
notifiedAt DateTime? @map("notified_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
achievement Achievement @relation(fields: [achievementKey], references: [key])
@@unique([userId, achievementKey])
@@index([userId, unlockedAt])
@@index([achievementKey])
@@map("user_achievements")
}
model ForumTopicSubscription {
id Int @id @default(autoincrement())
topicId Int @map("topic_id")
userId Int @map("user_id")
notifyReply Boolean @default(true) @map("notify_reply")
createdAt DateTime @default(now()) @map("created_at")
topic ForumTopic @relation(fields: [topicId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([topicId, userId])
@@index([userId, createdAt])
@@map("forum_topic_subscriptions")
}
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="145.7" cy="76.8" r="59" fill="white" opacity="0.18"/>
<rect x="332.6" y="67.80000000000001" width="94" height="61" transform="rotate(61 379.6 98.30000000000001)" fill="white" opacity="0.14"/>
<circle cx="417.8" cy="393.6" r="82" fill="white" opacity="0.12"/>
<polygon points="60,410.2 128.4,468.35 75.19999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">A</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="164.6" cy="72.4" r="50" fill="white" opacity="0.18"/>
<rect x="329.3" y="58" width="109" height="88" transform="rotate(88 383.8 102)" fill="white" opacity="0.14"/>
<circle cx="408" cy="419.6" r="71" fill="white" opacity="0.12"/>
<polygon points="60,415.6 126.2,461 94.7,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">老</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="56.099999999999994" cy="128" r="51" fill="white" opacity="0.18"/>
<rect x="371" y="42.2" width="66" height="83" transform="rotate(23 404 83.7)" fill="white" opacity="0.14"/>
<circle cx="392.2" cy="342.4" r="90" fill="white" opacity="0.12"/>
<polygon points="60,384.6 154,449.15 36.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">早</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="131" cy="155.60000000000002" r="42" fill="white" opacity="0.18"/>
<rect x="391.7" y="48.400000000000006" width="61" height="90" transform="rotate(40 422.2 93.4)" fill="white" opacity="0.14"/>
<circle cx="398.4" cy="400.4" r="99" fill="white" opacity="0.12"/>
<polygon points="60,406 167.8,453.8 80.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">科</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#06b6d4"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="63.099999999999994" cy="101.6" r="41" fill="white" opacity="0.18"/>
<rect x="351.2" y="80.2" width="78" height="93" transform="rotate(33 390.2 126.7)" fill="white" opacity="0.14"/>
<circle cx="430.2" cy="407.2" r="84" fill="white" opacity="0.12"/>
<polygon points="60,386.6 140.8,477.65 85.39999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">技</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#34d399"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#34d399"/>
<circle cx="0" cy="-20" r="2" fill="#34d399"/>
<circle cx="12" cy="-16" r="2" fill="#34d399"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="187" cy="85.2" r="42" fill="white" opacity="0.18"/>
<rect x="338.9" y="64.4" width="85" height="70" transform="rotate(30 381.4 99.4)" fill="white" opacity="0.14"/>
<circle cx="414.4" cy="330" r="43" fill="white" opacity="0.12"/>
<polygon points="60,422 132.6,465.8 27.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">A</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="86.19999999999999" cy="130" r="58" fill="white" opacity="0.18"/>
<rect x="372.5" y="35.6" width="97" height="76" transform="rotate(66 421 73.6)" fill="white" opacity="0.14"/>
<circle cx="385.6" cy="374.8" r="95" fill="white" opacity="0.12"/>
<polygon points="60,393.2 155,444.2 61.1,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">转</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="44.2" cy="106" r="54" fill="white" opacity="0.18"/>
<rect x="354.5" y="74.80000000000001" width="89" height="66" transform="rotate(6 399 107.80000000000001)" fill="white" opacity="0.14"/>
<circle cx="424.8" cy="411.6" r="95" fill="white" opacity="0.12"/>
<polygon points="60,381.2 143,473.6 88.7,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">计</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="168.1" cy="89.6" r="51" fill="white" opacity="0.18"/>
<rect x="342.2" y="74.2" width="76" height="93" transform="rotate(3 380.2 120.7)" fill="white" opacity="0.14"/>
<circle cx="424.2" cy="406.4" r="54" fill="white" opacity="0.12"/>
<polygon points="60,416.6 134.8,473.15 84.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">阿</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="169.5" cy="60" r="57" fill="white" opacity="0.18"/>
<rect x="320" y="59.400000000000006" width="74" height="95" transform="rotate(5 357 106.9)" fill="white" opacity="0.14"/>
<circle cx="409.4" cy="365.6" r="40" fill="white" opacity="0.12"/>
<polygon points="60,417 120,462.05 54.199999999999996,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">阿</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="103" cy="139.60000000000002" r="42" fill="white" opacity="0.18"/>
<rect x="379.7" y="40.4" width="71" height="100" transform="rotate(0 415.2 90.4)" fill="white" opacity="0.14"/>
<circle cx="390.4" cy="384.4" r="59" fill="white" opacity="0.12"/>
<polygon points="60,398 159.8,447.8 68.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">阿</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="93.19999999999999" cy="62" r="64" fill="white" opacity="0.18"/>
<rect x="321.5" y="52.8" width="107" height="86" transform="rotate(76 375 95.8)" fill="white" opacity="0.14"/>
<circle cx="402.8" cy="378.8" r="45" fill="white" opacity="0.12"/>
<polygon points="60,395.2 121,457.1 64.1,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">亚</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="160.39999999999998" cy="100.4" r="40" fill="white" opacity="0.18"/>
<rect x="350.3" y="72" width="103" height="82" transform="rotate(82 401.8 113)" fill="white" opacity="0.14"/>
<circle cx="422" cy="417.2" r="81" fill="white" opacity="0.12"/>
<polygon points="60,414.4 140.2,471.5 92.89999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">海</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#38bdf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#38bdf8"/>
<circle cx="0" cy="-20" r="2" fill="#38bdf8"/>
<circle cx="12" cy="-16" r="2" fill="#38bdf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#06b6d4"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="127.5" cy="138.4" r="37" fill="white" opacity="0.18"/>
<rect x="378.8" y="47.400000000000006" width="68" height="85" transform="rotate(35 412.8 89.9)" fill="white" opacity="0.14"/>
<circle cx="397.4" cy="383.2" r="56" fill="white" opacity="0.12"/>
<polygon points="60,405 159.2,453.05 67.4,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">跨</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#34d399"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#34d399"/>
<circle cx="0" cy="-20" r="2" fill="#34d399"/>
<circle cx="12" cy="-16" r="2" fill="#34d399"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="80.6" cy="126.8" r="50" fill="white" opacity="0.18"/>
<rect x="370.1" y="34" width="89" height="68" transform="rotate(58 414.6 68)" fill="white" opacity="0.14"/>
<circle cx="384" cy="371.6" r="87" fill="white" opacity="0.12"/>
<polygon points="60,391.6 153.4,443 58.699999999999996,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">全</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="207.29999999999998" cy="112" r="51" fill="white" opacity="0.18"/>
<rect x="359" y="34.2" width="76" height="99" transform="rotate(59 397 83.7)" fill="white" opacity="0.14"/>
<circle cx="384.2" cy="326.4" r="50" fill="white" opacity="0.12"/>
<polygon points="60,427.8 146,443.15 24.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">出</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="120.5" cy="62.4" r="63" fill="white" opacity="0.18"/>
<rect x="321.8" y="60.6" width="104" height="75" transform="rotate(25 373.8 98.1)" fill="white" opacity="0.14"/>
<circle cx="410.6" cy="337.6" r="46" fill="white" opacity="0.12"/>
<polygon points="60,403 121.2,462.95 33.2,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">出</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#06b6d4"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="49.1" cy="93.6" r="61" fill="white" opacity="0.18"/>
<rect x="345.2" y="76.2" width="106" height="73" transform="rotate(13 398.2 112.7)" fill="white" opacity="0.14"/>
<circle cx="426.2" cy="338.4" r="64" fill="white" opacity="0.12"/>
<polygon points="60,382.6 136.8,474.65 33.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">程</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#34d399"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#34d399"/>
<circle cx="0" cy="-20" r="2" fill="#34d399"/>
<circle cx="12" cy="-16" r="2" fill="#34d399"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="98.8" cy="65.2" r="32" fill="white" opacity="0.18"/>
<rect x="323.9" y="54.400000000000006" width="65" height="94" transform="rotate(84 356.4 101.4)" fill="white" opacity="0.14"/>
<circle cx="404.4" cy="382" r="53" fill="white" opacity="0.12"/>
<polygon points="60,396.8 122.6,458.3 66.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">百</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#38bdf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#38bdf8"/>
<circle cx="0" cy="-20" r="2" fill="#38bdf8"/>
<circle cx="12" cy="-16" r="2" fill="#38bdf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="212.89999999999998" cy="115.2" r="59" fill="white" opacity="0.18"/>
<rect x="361.4" y="35.8" width="84" height="107" transform="rotate(67 403.4 89.3)" fill="white" opacity="0.14"/>
<circle cx="385.8" cy="329.6" r="58" fill="white" opacity="0.12"/>
<polygon points="60,429.4 147.6,444.35 27.2,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">内</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="180" cy="111.6" r="68" fill="white" opacity="0.18"/>
<rect x="358.7" y="77.6" width="77" height="60" transform="rotate(20 397.2 107.6)" fill="white" opacity="0.14"/>
<circle cx="427.6" cy="386.8" r="49" fill="white" opacity="0.12"/>
<polygon points="60,420 145.8,475.7 70.1,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">内</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="88.3" cy="116" r="61" fill="white" opacity="0.18"/>
<rect x="362" y="36.2" width="62" height="79" transform="rotate(69 393 75.7)" fill="white" opacity="0.14"/>
<circle cx="386.2" cy="360.8" r="60" fill="white" opacity="0.12"/>
<polygon points="60,393.8 148,444.65 50.599999999999994,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">播</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="93.9" cy="119.2" r="69" fill="white" opacity="0.18"/>
<rect x="364.4" y="37.8" width="70" height="87" transform="rotate(77 399.4 81.3)" fill="white" opacity="0.14"/>
<circle cx="387.8" cy="364" r="68" fill="white" opacity="0.12"/>
<polygon points="60,395.4 149.6,445.85 53,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">创</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="70.8" cy="151.60000000000002" r="32" fill="white" opacity="0.18"/>
<rect x="388.7" y="46.400000000000006" width="75" height="104" transform="rotate(44 426.2 98.4)" fill="white" opacity="0.14"/>
<circle cx="396.4" cy="366" r="89" fill="white" opacity="0.12"/>
<polygon points="60,388.8 165.8,452.3 54.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">重</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#38bdf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#38bdf8"/>
<circle cx="0" cy="-20" r="2" fill="#38bdf8"/>
<circle cx="12" cy="-16" r="2" fill="#38bdf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="215.7" cy="116.80000000000001" r="63" fill="white" opacity="0.18"/>
<rect x="362.6" y="36.6" width="90" height="61" transform="rotate(71 407.6 67.1)" fill="white" opacity="0.14"/>
<circle cx="386.6" cy="392" r="62" fill="white" opacity="0.12"/>
<polygon points="60,430.2 148.4,444.95 74,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">写</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="131.7" cy="68.8" r="39" fill="white" opacity="0.18"/>
<rect x="326.6" y="63.800000000000004" width="70" height="91" transform="rotate(41 361.6 109.30000000000001)" fill="white" opacity="0.14"/>
<circle cx="413.8" cy="344" r="62" fill="white" opacity="0.12"/>
<polygon points="60,406.2 124.4,465.35 38,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">大</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="140.8" cy="89.2" r="52" fill="white" opacity="0.18"/>
<rect x="341.9" y="66.4" width="71" height="104" transform="rotate(54 377.4 118.4)" fill="white" opacity="0.14"/>
<circle cx="416.4" cy="364.4" r="53" fill="white" opacity="0.12"/>
<polygon points="60,408.8 134.6,467.3 53.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">多</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="96.69999999999999" cy="120.80000000000001" r="33" fill="white" opacity="0.18"/>
<rect x="365.6" y="38.6" width="70" height="91" transform="rotate(81 400.6 84.1)" fill="white" opacity="0.14"/>
<circle cx="388.6" cy="324" r="72" fill="white" opacity="0.12"/>
<polygon points="60,396.2 150.4,446.45 23,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">资</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="196.1" cy="105.6" r="35" fill="white" opacity="0.18"/>
<rect x="354.2" y="31" width="60" height="83" transform="rotate(43 384.2 72.5)" fill="white" opacity="0.14"/>
<circle cx="381" cy="320" r="94" fill="white" opacity="0.12"/>
<polygon points="60,424.6 142.8,440.75 20,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">数</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="194.7" cy="74.4" r="53" fill="white" opacity="0.18"/>
<rect x="330.8" y="66.6" width="64" height="81" transform="rotate(41 362.8 107.1)" fill="white" opacity="0.14"/>
<circle cx="416.6" cy="421.6" r="76" fill="white" opacity="0.12"/>
<polygon points="60,424.2 127.2,467.45 96.2,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">平</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="188.39999999999998" cy="116.4" r="40" fill="white" opacity="0.18"/>
<rect x="362.3" y="80" width="87" height="72" transform="rotate(32 405.8 116)" fill="white" opacity="0.14"/>
<circle cx="430" cy="330.8" r="61" fill="white" opacity="0.12"/>
<polygon points="60,422.4 148.2,477.5 28.1,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">电</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="140.1" cy="73.6" r="51" fill="white" opacity="0.18"/>
<rect x="330.2" y="66.2" width="86" height="103" transform="rotate(53 373.2 117.7)" fill="white" opacity="0.14"/>
<circle cx="416.2" cy="390.4" r="74" fill="white" opacity="0.12"/>
<polygon points="60,408.6 126.8,467.15 72.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">消</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="185.6" cy="114.80000000000001" r="36" fill="white" opacity="0.18"/>
<rect x="361.1" y="79.2" width="85" height="68" transform="rotate(28 403.6 113.2)" fill="white" opacity="0.14"/>
<circle cx="429.2" cy="390" r="57" fill="white" opacity="0.12"/>
<polygon points="60,421.6 147.4,476.9 72.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">创</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="190.5" cy="102.4" r="43" fill="white" opacity="0.18"/>
<rect x="351.8" y="80.6" width="108" height="75" transform="rotate(35 405.8 118.1)" fill="white" opacity="0.14"/>
<circle cx="430.6" cy="419.2" r="86" fill="white" opacity="0.12"/>
<polygon points="60,423 141.2,477.95 94.39999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">退</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="202.39999999999998" cy="124.4" r="44" fill="white" opacity="0.18"/>
<rect x="368.3" y="32.8" width="109" height="92" transform="rotate(52 422.8 78.8)" fill="white" opacity="0.14"/>
<circle cx="382.8" cy="399.6" r="81" fill="white" opacity="0.12"/>
<polygon points="60,426.4 152.2,442.1 79.69999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">电</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="182.1" cy="97.6" r="31" fill="white" opacity="0.18"/>
<rect x="348.2" y="78.2" width="92" height="63" transform="rotate(23 394.2 109.7)" fill="white" opacity="0.14"/>
<circle cx="428.2" cy="372.8" r="74" fill="white" opacity="0.12"/>
<polygon points="60,420.6 138.8,476.15 59.6,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">海</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="76.4" cy="154.8" r="40" fill="white" opacity="0.18"/>
<rect x="391.1" y="48" width="83" height="62" transform="rotate(52 432.6 79)" fill="white" opacity="0.14"/>
<circle cx="398" cy="369.2" r="97" fill="white" opacity="0.12"/>
<polygon points="60,390.4 167.4,453.5 56.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">留</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="169.5" cy="60" r="57" fill="white" opacity="0.18"/>
<rect x="320" y="59.400000000000006" width="74" height="95" transform="rotate(5 357 106.9)" fill="white" opacity="0.14"/>
<circle cx="409.4" cy="365.6" r="40" fill="white" opacity="0.12"/>
<polygon points="60,417 120,462.05 54.199999999999996,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">鸡</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="206.6" cy="96.4" r="30" fill="white" opacity="0.18"/>
<rect x="347.3" y="70" width="65" height="98" transform="rotate(58 379.8 119)" fill="white" opacity="0.14"/>
<circle cx="420" cy="402" r="71" fill="white" opacity="0.12"/>
<polygon points="60,427.6 138.2,470 81.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">教</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="155.5" cy="154.4" r="37" fill="white" opacity="0.18"/>
<rect x="390.8" y="55.400000000000006" width="108" height="75" transform="rotate(75 444.8 92.9)" fill="white" opacity="0.14"/>
<circle cx="405.4" cy="399.2" r="96" fill="white" opacity="0.12"/>
<polygon points="60,413 167.2,459.05 79.4,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">家</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="83.4" cy="128.4" r="54" fill="white" opacity="0.18"/>
<rect x="371.3" y="34.8" width="89" height="72" transform="rotate(62 415.8 70.8)" fill="white" opacity="0.14"/>
<circle cx="384.8" cy="331.6" r="91" fill="white" opacity="0.12"/>
<polygon points="60,392.4 154.2,443.6 28.7,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">职</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#06b6d4"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="113.5" cy="130.4" r="57" fill="white" opacity="0.18"/>
<rect x="372.8" y="43.4" width="94" height="65" transform="rotate(15 419.8 75.9)" fill="white" opacity="0.14"/>
<circle cx="393.4" cy="333.6" r="96" fill="white" opacity="0.12"/>
<polygon points="60,401 155.2,450.05 30.2,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">职</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#34d399"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#34d399"/>
<circle cx="0" cy="-20" r="2" fill="#34d399"/>
<circle cx="12" cy="-16" r="2" fill="#34d399"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="133.8" cy="157.2" r="46" fill="white" opacity="0.18"/>
<rect x="392.9" y="49.2" width="61" height="94" transform="rotate(44 423.4 96.2)" fill="white" opacity="0.14"/>
<circle cx="399.2" cy="360.4" r="43" fill="white" opacity="0.12"/>
<polygon points="60,406.8 168.6,454.4 50.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">房</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="215.7" cy="116.80000000000001" r="63" fill="white" opacity="0.18"/>
<rect x="362.6" y="36.6" width="90" height="61" transform="rotate(71 407.6 67.1)" fill="white" opacity="0.14"/>
<circle cx="386.6" cy="392" r="62" fill="white" opacity="0.12"/>
<polygon points="60,430.2 148.4,444.95 74,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">资</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="136.6" cy="158.8" r="50" fill="white" opacity="0.18"/>
<rect x="394.1" y="50" width="69" height="98" transform="rotate(48 428.6 99)" fill="white" opacity="0.14"/>
<circle cx="400" cy="403.6" r="47" fill="white" opacity="0.12"/>
<polygon points="60,407.6 169.4,455 82.69999999999999,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">美</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="135.89999999999998" cy="143.2" r="49" fill="white" opacity="0.18"/>
<rect x="382.4" y="49.8" width="76" height="97" transform="rotate(47 420.4 98.3)" fill="white" opacity="0.14"/>
<circle cx="399.8" cy="346.4" r="68" fill="white" opacity="0.12"/>
<polygon points="60,407.4 161.6,454.85 39.8,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">餐</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="192.6" cy="88.4" r="50" fill="white" opacity="0.18"/>
<rect x="341.3" y="66" width="93" height="78" transform="rotate(38 387.8 105)" fill="white" opacity="0.14"/>
<circle cx="416" cy="333.2" r="51" fill="white" opacity="0.12"/>
<polygon points="60,423.6 134.2,467 29.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">想</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#38bdf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#38bdf8"/>
<circle cx="0" cy="-20" r="2" fill="#38bdf8"/>
<circle cx="12" cy="-16" r="2" fill="#38bdf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="128.2" cy="154" r="38" fill="white" opacity="0.18"/>
<rect x="390.5" y="47.6" width="103" height="86" transform="rotate(36 442 90.6)" fill="white" opacity="0.14"/>
<circle cx="397.6" cy="357.2" r="95" fill="white" opacity="0.12"/>
<polygon points="60,405.2 167,453.2 47.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">供</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="88.3" cy="116" r="61" fill="white" opacity="0.18"/>
<rect x="362" y="36.2" width="62" height="79" transform="rotate(69 393 75.7)" fill="white" opacity="0.14"/>
<circle cx="386.2" cy="360.8" r="60" fill="white" opacity="0.12"/>
<polygon points="60,393.8 148,444.65 50.599999999999994,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">餐</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="185.6" cy="114.80000000000001" r="36" fill="white" opacity="0.18"/>
<rect x="361.1" y="79.2" width="85" height="68" transform="rotate(28 403.6 113.2)" fill="white" opacity="0.14"/>
<circle cx="429.2" cy="390" r="57" fill="white" opacity="0.12"/>
<polygon points="60,421.6 147.4,476.9 72.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">疯</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="97.4" cy="136.4" r="34" fill="white" opacity="0.18"/>
<rect x="377.3" y="38.8" width="63" height="92" transform="rotate(82 408.8 84.8)" fill="white" opacity="0.14"/>
<circle cx="388.8" cy="381.2" r="51" fill="white" opacity="0.12"/>
<polygon points="60,396.4 158.2,446.6 65.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">金</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#e879f9"/>
<stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="110" cy="71.6" r="48" fill="white" opacity="0.18"/>
<rect x="328.7" y="57.6" width="81" height="60" transform="rotate(10 369.2 87.6)" fill="white" opacity="0.14"/>
<circle cx="407.6" cy="388.4" r="69" fill="white" opacity="0.12"/>
<polygon points="60,400 125.8,460.7 71.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">个</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#e879f9"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#e879f9" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#e879f9"/>
<circle cx="0" cy="-20" r="2" fill="#e879f9"/>
<circle cx="12" cy="-16" r="2" fill="#e879f9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="88.3" cy="116" r="61" fill="white" opacity="0.18"/>
<rect x="362" y="36.2" width="62" height="79" transform="rotate(69 393 75.7)" fill="white" opacity="0.14"/>
<circle cx="386.2" cy="360.8" r="60" fill="white" opacity="0.12"/>
<polygon points="60,393.8 148,444.65 50.599999999999994,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">亏</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="41.4" cy="104.4" r="50" fill="white" opacity="0.18"/>
<rect x="353.3" y="74" width="83" height="62" transform="rotate(2 394.8 105)" fill="white" opacity="0.14"/>
<circle cx="424" cy="349.2" r="91" fill="white" opacity="0.12"/>
<polygon points="60,380.4 142.2,473 41.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">理</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#38bdf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#38bdf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#38bdf8"/>
<circle cx="0" cy="-20" r="2" fill="#38bdf8"/>
<circle cx="12" cy="-16" r="2" fill="#38bdf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#d946ef"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="172.29999999999998" cy="61.6" r="61" fill="white" opacity="0.18"/>
<rect x="321.2" y="60.2" width="82" height="99" transform="rotate(9 362.2 109.7)" fill="white" opacity="0.14"/>
<circle cx="410.2" cy="408.8" r="44" fill="white" opacity="0.12"/>
<polygon points="60,417.8 120.8,462.65 86.6,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">财</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#a78bfa"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#a78bfa" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#a78bfa"/>
<circle cx="0" cy="-20" r="2" fill="#a78bfa"/>
<circle cx="12" cy="-16" r="2" fill="#a78bfa"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="125.39999999999999" cy="152.4" r="34" fill="white" opacity="0.18"/>
<rect x="389.3" y="46.8" width="103" height="82" transform="rotate(32 440.8 87.8)" fill="white" opacity="0.14"/>
<circle cx="396.8" cy="397.2" r="91" fill="white" opacity="0.12"/>
<polygon points="60,404.4 166.2,452.6 77.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">宏</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb923c"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="72.9" cy="137.60000000000002" r="35" fill="white" opacity="0.18"/>
<rect x="378.2" y="47" width="90" height="107" transform="rotate(47 423.2 100.5)" fill="white" opacity="0.14"/>
<circle cx="397" cy="352" r="54" fill="white" opacity="0.12"/>
<polygon points="60,389.4 158.8,452.75 44,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">散</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb923c"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb923c" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb923c"/>
<circle cx="0" cy="-20" r="2" fill="#fb923c"/>
<circle cx="12" cy="-16" r="2" fill="#fb923c"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2dd4bf"/>
<stop offset="100%" stop-color="#10b981"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="50.5" cy="124.8" r="43" fill="white" opacity="0.18"/>
<rect x="368.6" y="40.6" width="108" height="75" transform="rotate(15 422.6 78.1)" fill="white" opacity="0.14"/>
<circle cx="390.6" cy="339.2" r="82" fill="white" opacity="0.12"/>
<polygon points="60,383 152.4,447.95 34.4,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">何</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#2dd4bf"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#2dd4bf" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#2dd4bf"/>
<circle cx="0" cy="-20" r="2" fill="#2dd4bf"/>
<circle cx="12" cy="-16" r="2" fill="#2dd4bf"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="138" cy="87.6" r="48" fill="white" opacity="0.18"/>
<rect x="340.7" y="65.6" width="71" height="100" transform="rotate(50 376.2 115.6)" fill="white" opacity="0.14"/>
<circle cx="415.6" cy="404.4" r="49" fill="white" opacity="0.12"/>
<polygon points="60,408 133.8,466.7 83.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">上</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="82" cy="158" r="48" fill="white" opacity="0.18"/>
<rect x="393.5" y="49.6" width="91" height="70" transform="rotate(60 439 84.6)" fill="white" opacity="0.14"/>
<circle cx="399.6" cy="372.4" r="45" fill="white" opacity="0.12"/>
<polygon points="60,392 169,454.7 59.3,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">健</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fb7185"/>
<stop offset="100%" stop-color="#fb923c"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="212.89999999999998" cy="115.2" r="59" fill="white" opacity="0.18"/>
<rect x="361.4" y="35.8" width="84" height="107" transform="rotate(67 403.4 89.3)" fill="white" opacity="0.14"/>
<circle cx="385.8" cy="329.6" r="58" fill="white" opacity="0.12"/>
<polygon points="60,429.4 147.6,444.35 27.2,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">健</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fb7185"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fb7185" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fb7185"/>
<circle cx="0" cy="-20" r="2" fill="#fb7185"/>
<circle cx="12" cy="-16" r="2" fill="#fb7185"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f43f5e"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="157.6" cy="98.80000000000001" r="36" fill="white" opacity="0.18"/>
<rect x="349.1" y="71.2" width="95" height="78" transform="rotate(78 396.6 110.2)" fill="white" opacity="0.14"/>
<circle cx="421.2" cy="374" r="77" fill="white" opacity="0.12"/>
<polygon points="60,413.6 139.4,470.9 60.5,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">医</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#fbbf24"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#fbbf24" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#fbbf24"/>
<circle cx="0" cy="-20" r="2" fill="#fbbf24"/>
<circle cx="12" cy="-16" r="2" fill="#fbbf24"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#06b6d4"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="203.1" cy="79.2" r="65" fill="white" opacity="0.18"/>
<rect x="334.4" y="69" width="72" height="93" transform="rotate(53 370.4 115.5)" fill="white" opacity="0.14"/>
<circle cx="419" cy="384.8" r="88" fill="white" opacity="0.12"/>
<polygon points="60,426.6 129.6,469.25 68.6,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">朋</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#34d399"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#34d399" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#34d399"/>
<circle cx="0" cy="-20" r="2" fill="#34d399"/>
<circle cx="12" cy="-16" r="2" fill="#34d399"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="100%" stop-color="#3b82f6"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="72.19999999999999" cy="122" r="38" fill="white" opacity="0.18"/>
<rect x="366.5" y="31.6" width="73" height="106" transform="rotate(46 403 84.6)" fill="white" opacity="0.14"/>
<circle cx="381.6" cy="325.2" r="75" fill="white" opacity="0.12"/>
<polygon points="60,389.2 151,441.2 23.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">画</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#22d3ee"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#22d3ee" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#22d3ee"/>
<circle cx="0" cy="-20" r="2" fill="#22d3ee"/>
<circle cx="12" cy="-16" r="2" fill="#22d3ee"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
<feOffset dx="0" dy="4" result="offsetblur"/>
<feComponentTransfer><feFuncA type="linear" slope="0.35"/></feComponentTransfer>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<!-- 背景渐变 -->
<rect width="512" height="512" fill="url(#bg)"/>
<!-- 装饰图形 -->
<circle cx="69.4" cy="120.4" r="34" fill="white" opacity="0.18"/>
<rect x="365.3" y="30.8" width="73" height="102" transform="rotate(42 401.8 81.8)" fill="white" opacity="0.14"/>
<circle cx="380.8" cy="365.2" r="71" fill="white" opacity="0.12"/>
<polygon points="60,388.4 150.2,440.6 53.9,460" fill="white" opacity="0.16"/>
<!-- 角色徽章 -->
<rect x="20" y="20" width="92" height="28" rx="14" fill="rgba(255,255,255,0.25)"/>
<text x="66" y="38" text-anchor="middle" fill="white" font-size="13" font-weight="600" font-family="system-ui">行业专家</text>
<!-- 中央大字母 -->
<text x="256" y="320" text-anchor="middle" fill="white" font-size="280" font-weight="800" font-family="system-ui,-apple-system,sans-serif" filter="url(#shadow)">硬</text>
<!-- 右下角 🤖 标识(用 path 画,不依赖 emoji 字体) -->
<g transform="translate(440 440)">
<circle cx="0" cy="0" r="32" fill="white" opacity="0.95"/>
<path d="M-12 -4 L-12 8 Q-12 14 -6 14 L6 14 Q12 14 12 8 L12 -4 Q12 -10 6 -10 L-6 -10 Q-12 -10 -12 -4 Z" fill="#818cf8"/>
<circle cx="-4" cy="0" r="2" fill="white"/>
<circle cx="4" cy="0" r="2" fill="white"/>
<line x1="-6" y1="6" x2="6" y2="6" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<line x1="-8" y1="-12" x2="-12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="0" y1="-14" x2="0" y2="-20" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<line x1="8" y1="-12" x2="12" y2="-16" stroke="#818cf8" stroke-width="2" stroke-linecap="round"/>
<circle cx="-12" cy="-16" r="2" fill="#818cf8"/>
<circle cx="0" cy="-20" r="2" fill="#818cf8"/>
<circle cx="12" cy="-16" r="2" fill="#818cf8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Some files were not shown because too many files have changed in this diff Show More