口腔健康是全身健康的重要基石,被世界卫生组织列为人体健康的十大标准之一。牙结石、龋齿、牙龈炎等常见口腔问题若未及时干预,致病菌与毒素可能进入血液循环,促进动脉粥样硬化,甚至增加心肌梗死风险。目前口腔疾病诊断虽准确率高,但多依赖专业设备和医生手法,存在成本高、流程复杂等问题,致使不少患者延误就医,往往拖到疼痛难忍才就诊,不仅错失最佳治疗时机,也加重了经济负担。
为让用户能以极低成本在家完成口腔日常筛查,我们正式推出“On-App AI口腔镜方案”。该方案可集成于口腔镜、智能牙线、唾液检测仪乃至耳窥镜等带微型摄像头的设备中,用户只需上传拍摄的口腔影像,即可通过端侧本地AI自动分析,快速筛查牙结石、龋齿、牙龈炎等六类口腔问题,并提供护理建议与就医提醒,实现“早发现、早干预”。本方案具备开箱即用、成本低廉及快速量产的优势。
下面就来教大家如何开发出一款自己的“AI口腔镜”。
改写说明:
1. 准备工作
前提条件
- 已阅读 Ray 新手村任务,了解 Ray 框架的基础知识。
- 已阅读 使用 Ray 开发万能面板,了解 Ray 面板开发的基础知识。
- AI 口腔镜模板使用
SDM(Smart Device Model)开发,了解SDM相关可以 查看 SDM 文档。
开发环境
详见 面板小程序 > 搭建环境。
2. 需求分析
产品名称:AI 口腔镜
需求原型
- 基本交互功能:
- AI 模型初始化
- 手机拍照或从相册选择照片并预览
- AI 分析功能:
- 根据照片分析口腔疾病状态
- 针对口腔疾病给出治疗建议
3. 创建项目
开发者平台创建面板小程序
面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。
详细操作步骤可以参考 创建面板小程序。
IDE 基于模板创建项目工程
打开 IDE 创建一个基于 AI 口腔镜模板 的面板小程序项目,需要在 Tuya MiniApp IDE 上操作。
详细操作步骤可以参考 初始化项目工程。
4. 工程目录
完成以上步骤后,一个面板小程序的开发模板初始化完成。以下为工程目录的介绍:
├── src
│ ├── api // 面板所有云端 API 请求聚合文件
│ ├── components // 公共组件
│ ├── constant
│ │ ├── dpCodes.ts // dpCode 常量
│ │ ├── index.ts // 存放所有的常量配置
│ ├── devices // 设备模型
│ ├── hooks // hooks
│ ├── i18n // 多语言
│ ├── pages
│ │ ├── home // 首页
│ │ ├── report // 分析报告页面
│ ├── redux // redux
│ ├── res // 图片资源 & svg 相关
│ ├── styles // 全局样式
│ ├── types // 全局类型定义
│ ├── utils // 业务常用工具方法
│ ├── app.config.ts
│ ├── app.less
│ ├── app.tsx
│ ├── composeLayout.tsx // 处理监听子设备添加、解绑、DP 变化等
│ ├── global.config.ts
│ ├── mixins.less // less mixins
│ ├── routes.config.ts // 配置路由
│ ├── variables.less // less variables
5. 关键能力依赖
- 区域:全区可用
- App 版本:涂鸦 App、智能生活 App v6.11.5 及以上版本
- Kit 依赖:
- BaseKit: v3.24.9
- MiniKit: v3.21.0
- DeviceKit: v3.9.3
- BizKit: v3.9.12
- AIKit: v1.6.0
- baseversion: v2.29.16
- 组件依赖:
- @ray-js/icons: "^1.7.36"
- @ray-js/panel-sdk: "^1.13.10"
- @ray-js/ray: "^1.7.43"
- @ray-js/ray-error-catch: "^0.0.25"
- @ray-js/smart-ui: "^2.6.3"
- @reduxjs/toolkit: "^1.9.3"
6. 基本交互功能
AI 模型初始化


功能介绍
模板中提供 AI 模型预下载方法,并同时监听 AI 模型下载进度,确保后续 AI 分析功能正常可用。
相关代码段
const handleOralModelDownProgress = (d: any) => {
dispatch(updateAiModelProgress(d?.progress || 0));
};
useEffect(() => {
// 初始化模型
ty.ai.oralDiseaseInit({
success: () => {
console.log(`oralDiseaseInit 成功`);
showToast({
title: Strings.getLang("ai_model_download_success"),
icon: "success",
});
dispatch(updateUiState({ aiModel: { init: true, progress: 100 } }));
},
fail: () => {
console.log(`oralDiseaseInit 失败`);
showToast({
title: Strings.getLang("ai_model_download_fail"),
icon: "error",
});
dispatch(updateUiState({ aiModel: { init: false, progress: 0 } }));
},
});
// 监听模型下载进度
ty.ai.onOralModelDownProgress(handleOralModelDownProgress);
return () => {
ty.ai.offOralModelDownProgress(handleOralModelDownProgress);
};
}, []);
手机拍照或从相册选择照片并预览



功能介绍
模板中提供了方法,支持用户通过选取相册内容或拍照获取图像并预览。
相关代码段
import { chooseImage, previewImage } from "@ray-js/ray";
const [imageSrc, setImageSrc] = useState<string[]>([]);
// 选择照片
const handleChooseImage = () => {
chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: res => {
console.log('chooseImage success', res);
setImageSrc(res.tempFilePaths);
},
fail: res => {
console.log('chooseImage fail', res);
},
});
};
// 预览照片
const previewChooseImage = (urls, current) => () => {
previewImage({
urls,
current,
success: res => {
console.log('previewImage success', res);
},
fail: res => {
console.log('previewImage fail', res);
},
});
};
7. AI 照片分析


功能介绍
通过对照片进行 AI 分析,检测口腔疾病、处理图像显示热区并给出治疗建议。
关键 API 代码段
import { ai, env } from "@ray-js/ray";
const handleClickAnalysis = () => {
if (imageSrc.length === 0) return;
if (!aiModelInit) {
showToast({
title: Strings.getLang('ai_model_not_init_tip'),
icon: 'error',
});
return;
}
showLoading({ title: Strings.getLang('analysis_loading') });
const path = imageSrc[0];
const outputPath = `${env.USER_DATA_PATH}/aiReport/`;
ty.ai.oralDiseasePredictionRun({
inputImagePath: path,
outImagePath: outputPath,
success: d => {
console.log('===oralDiseasePredictionRun===', d);
if (d?.nonOral) {
DialogInstance.alert({
message: Strings.getLang('analysis_nonOral'),
confirmButtonText: Strings.getLang('analysis_nonOral_confirm'),
}).then(() => {
// on close
});
} else {
dispatch(updateAiReport(d));
navigateTo({
url: '/pages/report/index',
});
}
hideLoading();
},
fail: e => {
console.log('===oralDiseasePredictionRun err===', e);
showToast({
title: e && JSON.stringify(e),
icon: 'error',
});
hideLoading();
},
});
};
8. 结束
- 恭喜你 🎉 完成了本教程的学习!
- 有任何问题可以提交工单。

被折叠的 条评论
为什么被折叠?



