Skip to content

timmyagentic/emomo

Repository files navigation

Emomo

AI 表情包语义搜索系统 — Go 后端 + React 前端 + Expo 移动端 monorepo

Emomo 让你用自然语言搜表情包。系统由 Go 后端(搜索 + 本地静态图片目录摄入)、React 前端(Web 用户界面)和 Expo React Native 移动端组成。当前默认检索链路以 Qwen3-VL 多模态 image embedding 为主:导入时直接为图片生成 image 向量,并为 OCR/描述/tags 写入 keyword/BM25 sparse-only 向量;搜索时 image route 权重 0.7,keyword route 权重 0.3。VLM 描述和 OCR 作为展示元数据与 keyword 辅助信号保留;dense caption embedding 仍默认关闭,待 caption 策略验证后再启用。

资源约束:表情包资源只支持静态图片;GIF 文件不再支持,也不会被摄入。

当前关系库收敛为四张核心表:memesmeme_annotationsmeme_vectors,外加只记录来源/出处、不参与检索的 meme_metadata。protobuf message schema 定义在 backend/proto/emomo/v1/,拆为 types.proto / meme.proto / api.proto。在本项目里,protobuf 的边界是 API DTO、前后端生成类型、跨边界封闭枚举,以及少量结构化 DB JSON 值(当前仅 memes.image_infomeme_annotations.labels);关系表结构、迁移、运行时配置和 UI 状态不归 protobuf 管。生成代码集中在 backend/gen/(Go)与 frontend/gen/(TS),均以 linguist-generated=true 标记。数据库结构详见 docs/DATABASE_SCHEMA.md

Supabase/PostgreSQL 部署中这四张核心表不启用 Row Level Security;前端不直接访问 Supabase 表,而是通过 Go API 访问数据,访问控制在服务端数据库连接层完成。

仓库结构

emomo/
├── backend/      # Go + Gin + Qdrant + GORM,REST API + 摄入流水线
├── frontend/     # React 19 + Vite + Framer Motion,单页应用
├── mobile/       # Expo + React Native,iOS / Android 搜索 App
├── deployments/  # 跨服务的 Docker Compose 编排(API + Grafana Alloy)
├── docs/         # 跨服务设计与使用文档
├── scripts/
│   └── start.sh  # 本机一键起后端 + 前端
├── render.yaml   # Render 部署配置(rootDir: backend)
└── railway.json  # Railway 部署配置(dockerfilePath: backend/Dockerfile)

每个子项目都有自己的 README.md / AGENTS.md / CLAUDE.md / GEMINI.md,说明该子项目的本地开发与约定:

快速上手

一键起前后端

./scripts/start.sh

脚本会先启 backend(go run ./cmd/api,端口 8080),再启 frontend(npm run dev,端口 5173)。需要先在 backend/.env 填好 API keys(Qdrant、对象存储、VLM、embedding 等)。

单独运行某一块

# 后端
cd backend
cp .env.example .env   # 首次:填好 API keys
go run ./cmd/api

# 前端
cd frontend
cp .env.example .env   # 首次:默认指向 http://localhost:8080/api/v1
npm install
npm run dev

# 移动端
cd mobile
npm install
npm run gen
EXPO_PUBLIC_API_BASE=http://localhost:8080/api/v1 npm run start

Qwen3-VL 多模态向量摄入

数据导入只支持 backend/scripts/import-data.sh 这一种入口。默认配置会使用 qwen3vl profile 写入 image 向量和 keyword/BM25 sparse-only 向量;caption dense 向量可以通过显式 -e qwen3vl_caption 做实验性回填,但不是默认导入链路:

cd backend
./scripts/import-data.sh -p ./data/memes
# 或显式指定 profile:
./scripts/import-data.sh -p ./data/memes --profile qwen3vl

详见 docs/MULTI_EMBEDDING.mdbackend/configs/config.yaml

更新 protobuf 消息 schema

修改 backend/proto/emomo/v1/ 下任意 .proto 后,需要同时重新生成后端 Go 与前端 TS:

# Go → backend/gen/
cd backend && GOTOOLCHAIN=go1.26.2 go run github.com/bufbuild/buf/cmd/buf@v1.69.0 generate

# TS → frontend/gen/
cd frontend && npm run gen

# TS → mobile/gen/
cd mobile && npm run gen

技术栈速览

子项目 关键技术
backend Go 1.26.2, Gin, GORM, Qdrant (gRPC), S3/R2, Qwen3-VL 多模态 embeddings, OpenAI-compatible VLM/OCR 辅助分析, BM25 hybrid 检索, Grafana Alloy + Loki
frontend React 19, TypeScript, Vite 7, Framer Motion, Playwright e2e
mobile Expo SDK 54, React Native 0.81, React 19, TypeScript, AsyncStorage, Expo MediaLibrary/Sharing/FileSystem

部署

  • Docker Compose(本机)docker compose --env-file backend/.env -f deployments/docker-compose.yml up -d,会起 API 容器 + Grafana Alloy 日志采集(Qdrant 与对象存储需自备)。
  • Render:根的 render.yaml 把后端服务的 rootDir 设为 backend/
  • Railway:根的 railway.json 指向 backend/Dockerfile
  • Hugging Face Space.github/workflows/sync_to_hf.yml 在每次 push 到 main 时把 backend/ 子树拆出来 force-push 到 Space 的 main 分支,所以 Space 看到的根就是 backend/

贡献约定

  • 提交信息使用 Conventional Commits(feat:fix:chore: 等);跨子项目的改动在正文里按目录分点说明。
  • AI agents 协作约定见各子项目的 AGENTS.md / frontend/AGENTS.md 与本仓库根的 AGENTS.md
  • 不提交 secrets,使用各子项目下的 .env.env.example

更多文档

License

MIT

About

基于 Go 的表情包语义搜索与采集系统,集成 Qdrant 向量检索、VLM 描述生成与文本嵌入,支持多数据源摄入和 S3/R2 对象存储的 API 服务。

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors