ARmahjongAssist 是一个结合 RayNeo AR 眼镜 与 本地化 AI 的麻将辅助系统。通过 AR 眼镜实时采集手牌图像,在本地服务器进行 YOLO 识别与牌效分析,并将最佳切牌建议实时投射在眼镜屏幕上。
- 完全本地化: 图像识别采用 ONNX Runtime 本地运行,无需上传图片至第三方云服务,保护隐私且低延迟。
- 语音交互: 集成FasterWhisper语音转文本和 LLM 接口(如 Qwen) 进行自然语言意图理解,支持通过语音识别场况计算“绝张”。
- Docker 部署: 提供标准化的 Docker 环境,一键启动后端服务。
本项目分为两个核心部分:
- 平台: Android (Min SDK 31, Target SDK 36)
- 设备: RayNeo AR 眼镜
- 功能: 负责拍摄麻将手牌照片,上传至服务器,并接收服务器返回的切牌/鸣牌建议进行显示。
- 语言: Python 3.9+
- 框架: FastAPI
- 核心技术:
- YOLOv8 (ONNX): 本地运行麻将牌识别模型 (位于
server/models/yolo)。 - Local LLM Integration: 通过 OpenAI 兼容API连接本地、云端大模型。
- Mahjong Library: 进行麻将的牌理分析(向听数、进张数计算)。
- YOLOv8 (ONNX): 本地运行麻将牌识别模型 (位于
- 功能: 接收图像,识别手牌与副露,计算当前最优打法,维护对局状态。
- 安装 Docker Desktop (包含 Docker 和 Docker Compose)。
- 准备一个兼容 OpenAI 接口的本地大模型服务 (推荐使用 LM Studio 或 Ollama 运行 Qwen-4B 或类似模型)。
-
克隆项目
git clone https://github.com/fAres4s/ARmahjongAssist.git cd ARmahjongAssist -
配置环境变量 进入
server目录,复制.env.example,命名副本为.env:cd server cp .env.example .env编辑
.env文件,配置本地 LLM 地址 (例如 LM Studio 默认是http://host.docker.internal:1234/v1):LLM_BASE_URL=http://host.docker.internal:1234/v1 LLM_API_KEY=lm-studio LLM_MODEL=qwen/qwen3-4b-2507 (复制于 LM Studio server配置页面右侧的API Usage -> This model's API identifier)
-
启动服务 返回项目根目录并构建启动:
cd .. docker-compose up -d --build服务将运行在
http://localhost:8000。
-
环境准备
- Android Studio Ladybug 或更高版本。
- JDK 17 或更高版本。
- RayNeo X3 AR 眼镜或其他兼容 Android 设备 (需开启开发者模式/USB调试)。
-
配置服务端地址
- 确保眼镜与电脑处于同一局域网。
- 获取电脑的局域网 IP (例如
192.168.1.100)。 - 在 Android Studio 中打开
app/src/main/java/com/example/ai_assist/MainActivity.kt。 - 找到
setupDependencies方法,修改baseUrl:// 替换为你的电脑局域网 IP 地址 .baseUrl("http://192.168.1.100:8000/")
-
编译与安装
- 使用 Android Studio 打开项目根目录。
- 等待 Gradle Sync 完成。
- 通过 USB 连接设备。
- 点击顶部工具栏的 Run 'app' (绿色播放按钮)。
- 应用将安装在设备上并启动,眼镜需要先连接到WiFi后才能使用。
客户端的全局配置位于 app/src/main/java/com/example/ai_assist/AppConfig.kt,您可以根据需要修改以下常量:
- SERVER_BASE_URL: 后端服务器地址(例如
http://192.168.1.100:8000/)。 - USE_COLOR_FONT: 是否启用彩色麻将字体(
true为彩色,false为默认单色)。 - FONT_SCALE_COLOR: 彩色字体的缩放比例(默认
1.8f)。 - FONT_SCALE_DEFAULT: 单色字体的缩放比例(默认
2.5f)。
- 开始/结束对局:三击右侧触控区域开始/结束对局。
- 麻将识别:在每一句对局开始之后,可以单击触控区域开启拍照。
- 使用语音场况感知:向后滑动镜腿,可以开始/停止语音录制。
- 查看切牌建议:根据当前手牌状态,眼镜屏幕上会显示最优切牌建议。
为了优化不同光照和环境下的麻将牌识别效果,本项目提供了一个可视化的参数调试工具。
-
访问工具 确保服务端已启动,在浏览器中访问:
http://localhost:8000/static/yolo_debug.html -
功能说明
- 上传图片: 上传一张实际拍摄的麻将手牌图片,本项目默认的输入尺寸是1200x400(实际拍摄手牌的照片是1200x800,上下等分为暗牌和鸣牌组合,分别识别)。
- 调整参数: 实时调整 Confidence Threshold (置信度) 和 IoU Threshold (重叠阈值)。
- 可视化分析: 点击“分析”后,右侧会显示识别结果的标注图。
-
配置生效
- 在调试工具中的调整仅对当前调试请求生效,不会影响正在进行的对局。
- 调试出满意的参数后,请修改服务端根目录下的
.env文件以永久生效:YOLO_CONF_THRESHOLD=0.54 # 示例值 YOLO_IOU_THRESHOLD=0.85 # 示例值
- 修改配置文件后需要重启服务端:
docker-compose restart backend
如果您需要修改服务端代码或进行调试,可以直接在本地运行 Python 环境。
-
环境准备
cd server python -m venv venv source venv/bin/activate # 示例为MacOS,Windows 请执行: venv\Scripts\activate pip install -r requirements.txt
-
运行服务 确保
.env配置正确,然后运行:python main.py
-
运行测试
pytest tests
ARmahjongAssist/
├── app/ # Android 客户端 (RayNeo AR 眼镜端)
├── server/ # Python 服务端 (AI 推理与业务逻辑)
├── docker-compose.yml # Docker 一键部署配置
└── README.md # 项目文档
app/
├── libs/ # 外部依赖库 (RayNeo SDK)
├── src/main/java/com/example/ai_assist/
│ ├── model/ # 数据模型 (API 响应实体、会话状态)
│ ├── repository/ # 数据仓库层 (处理 API 调用与数据流)
│ ├── service/ # 核心服务模块
│ │ ├── GameApiService.kt # Retrofit 接口定义 (与 Server 通信)
│ │ └── RayNeoDeviceManager.kt # RayNeo 硬件控制 (按键、传感器)
│ ├── utils/ # 工具类
│ │ ├── RayNeoAudioRecorder.kt # 音频录制工具
│ │ └── MahjongMapper.kt # 麻将编码映射工具
│ ├── viewmodel/ # MVVM ViewModel (UI 状态管理)
│ └── MainActivity.kt # 主界面入口
│ └── src/main/res/ # UI 资源文件 (布局、图标、样式)
server/
├── models/ # 本地模型文件仓库
│ └── yolo/ # YOLOv8 ONNX 模型及类别文件
├── static/ # 静态资源目录
│ └── uploads/ # 存放客户端上传的临时图片
├── tests/ # 单元测试与集成测试用例
├── main.py # FastAPI 应用入口,服务初始化与路由定义
├── config.py # 配置管理 (环境变量加载、路径定义)
├── vision_service.py # 视觉识别服务:封装 YOLO 模型调用与坐标转换
├── yolo_inference.py # YOLO 推理核心:基于 ONNX Runtime 的图像预处理与后处理
├── llm_service.py # LLM 服务:与本地大模型 (OpenAI 接口) 交互,处理自然语言意图
├── stt_service.py # 语音转文字服务:基于 faster-whisper 实现离线语音识别
├── efficiency_engine.py # 牌效引擎:封装 mahjong 库,计算向听数与最佳切牌
├── mahjong_state_tracker.py # 状态追踪器:维护对局状态 (手牌、副露、场况)
├── database.py # 数据库模块:SQLite 封装,记录对局历史与交互日志
├── schemas.py # Pydantic 数据模型:定义 API 请求与响应结构
├── Dockerfile # 服务端镜像构建文件
└── requirements.txt # Python 依赖列表
- 图像上传: 客户端发送图片 ->
main.py接收 -> 保存至static/uploads。 - 视觉识别:
VisionService调用yolo_inference.py解析图片,提取麻将牌坐标与类别。 - 状态更新: 识别结果传入
MahjongStateTracker,更新当前手牌状态。 - 牌效计算:
EfficiencyEngine基于当前手牌计算向听数 (Shanten) 和进张 (Ukeire)。 - LLM 意图分析 (可选): 若包含语音,
STTService转录文本 ->LLMService分析用户意图 (如"刚才打了什么") -> 改变MahjongStateTracker的可见牌列表。 - 结果返回: 综合视觉与牌效结果,通过
schemas.py定义的格式返回给客户端。
感谢 Jon Chan 提供的 Mahjong Dataset。该数据集发布于 Roboflow Universe (2026-01-26)。特别感谢其提供的开源数据支持了我们的 CV 模型训练。
感谢 FluffyStuff/riichi-mahjong-tiles 提供的麻将 PNG 素材。
感谢 SYSTRAN/faster-whisper 提供的快速语音转文本支持。
感谢 googlefonts/nanoemoji 工具支持彩色麻将字体的制作。