1. 准备工作
前提条件
- 已阅读 Ray 新手村任务,了解 Ray 框架的基础知识。
- 已阅读 使用 Ray 开发万能面板,了解 Ray 面板开发的基础知识。
构建内容
您可以利用面板小程序开发构建出一个基于 Ray 框架的 AI 宠物设备面板。
- 宠物档案:可在面板上管理宠物信息,包括增、删、改、查,以及上传分析宠物正面照。
- 多宠识别:监测宠物进食行为,并识别具体是哪只宠物。
所需条件
- 智能生活 App
- Tuya MiniApp IDE
- NVM 及 Node 开发环境(建议使用 18.x 系列版本)
- Yarn 依赖管理工具
详见 面板小程序 > 搭建环境。
2. 创建产品
首先需要创建一个产品,定义产品有哪些功能点,然后再在面板中一一实现这些功能点。
注册登录 涂鸦开发者平台,并在平台创建产品:
- 单击页面左侧 产品 > 产品开发,在 产品开发 页面单击 创建产品。
- 在 标准类目 下选择 小家电 > 可视宠物喂食器。
- 选择 智能化方式 和 产品方案,完善产品信息,单击 创建产品。
- 在 添加标准功能 页面,根据实际需求选择对应的功能点,单击 确定。
- 在产品详情页复制产品对应的 PID,联系您的项目经理,提供该 PID 以配置开启 产品 AI 功能。
- 确认已开启产品 AI 功能后,可以在 01 功能定义 下看到 产品 AI 功能 页签。
- 在 面板端智能体 下,单击 新增智能体。
- 在 新增面板端智能体 页面,点击 选择已创建智能体,勾选 宠物 AI 智能体,单击 确定。
- 在已选择的智能体下,单击 详情。
- 复制智能体对应的 ID,保存备用。
3. 创建项目
开发者平台创建面板小程序
面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。
IDE 基于模板创建项目工程
打开 IDE 创建一个基于 AI 宠物面板模版 的面板小程序项目,需要在 Tuya MiniApp IDE 上进行操作。
4. 关键能力依赖
- App 版本
- 智能生活 v6.8.0 及以上版本
- Kit 依赖
- BaseKit: 3.0.0
- MiniKit: 3.1.0
- DeviceKit: 4.6.0
- BizKit: 4.5.1
- IPCKit: 5.18.0
- HomeKit: 3.1.4
- baseversion: 2.27.0
- 组件依赖
- @ray-js/ray^1.7.12
- @ray-js/components-ty-ipc^2.2.4
5. 配置智能体 ID
在项目内配置您在前面 创建产品 > 步骤 10 中复制的智能体 ID,修改模版文件 /src/constant/index.ts
:
// 智能体 ID,修改为产品配置的智能体 ID
const AGENT_ID = "xxx";
6. 宠物档案
添加宠物
使用面板之前要先添加宠物信息,按照引导流程选择宠物类型、品种、性别、活跃度,上传正面照,并填写宠物的昵称、生日、体重等信息。
功能展示
相关代码段
<View className={styles.content}>
{step === 0 && <PetType value={type} onChange={handlePetTypeChange} />}
{step === 1 && (
<PetBreed
petType={type}
value={breed}
onChange={handlePetBreedChange}
onBack={() => setStep((step) => step - 1)}
/>
)}
{step === 2 && (
<PetSex
value={sex}
onChange={handlePetSexChange}
onBack={() => setStep((step) => step - 1)}
/>
)}
{step === 3 && (
<PetActiveness
petType={type}
value={activeness}
onChange={handlePetActivenessChange}
onBack={() => setStep((step) => step - 1)}
/>
)}
{step === 4 && (
<PetAnalytics
goNext={handleGoNext}
onBack={() => setStep((step) => step - 1)}
/>
)}
{step === 5 && (
<PetInfo
petType={type}
breed={breed}
sex={sex}
activeness={activeness}
profile={profile}
/>
)}
</View>
const handleSave = async () => {
if (name.trim() === '') {
ToastInstance({
context: this,
message: Strings.getLang('pet_info_name_empty'),
});
return;
}
if (weight === 0) {
ToastInstance({
context: this,
message: Strings.getLang('weight_not_zero'),
});
return;
}
try {
showLoading({
title: '',
mask: true,
});
const petId = await (dispatch as AppDispatch)(
addPet({
petType,
breedCode: breed,
sex,
activeness,
name: name.trim(),
avatar: bizUrlRef.current,
weight: weight * 1000,
birth: birthday,
ownerId: getHomeId(),
timeZone: moment().format('Z'),
tuyaAppId: getTuyaAppId(),
idPhotos: profile?.idPhotos,
features: profile?.features,
})
).unwrap();
dispatch(fetchPetDetail({ petId, forceUpdate: true }));
setNavigationBarBack({ type: 'system' });
navigateBack();
if (store.getState().global.selectedPetId === -1) {
dispatch(setSelectedPetId(petId));
}
} catch (err) {
errorToast(err);
} finally {
hideLoading();
}
};
查看宠物详情,更新、删除宠物信息
点击某个宠物可以查看该宠物的详细信息,在详情页面可更新宠物信息、删除宠物记录。
相关代码段
// 更新宠物信息
const handleSave = async () => {
if (name.trim() === '') {
ToastInstance({
context: this,
message: Strings.getLang('pet_info_name_empty'),
});
return;
}
try {
showLoading({
title: '',
mask: true,
});
await (dispatch as AppDispatch)(
updatePet({
id: pet.id,
petType: pet.petType,
breedCode,
sex,
activeness,
name: name.trim(),
avatar: bizUrlRef.current,
weight: weight * 1000,
birth: birthday,
rfid: pet.rfid,
ownerId: getHomeId(),
timeZone: moment().format('Z'),
tuyaAppId: getTuyaAppId(),
idPhotos: profile?.idPhotos,
features: profile?.features,
})
).unwrap();
if (pet.id) {
await (dispatch as AppDispatch)(
fetchPetDetail({ petId: Number(pet.id), forceUpdate: true })
).unwrap();
}
navigateBack();
} catch (err) {
console.log(err);
} finally {
hideLoading();
}
};
// 删除宠物
const handleDelete = async () => {
try {
await DialogInstance.confirm({
context: this,
title: Strings.getLang('tips'),
message: Strings.getLang('pet_delete_tips'),
confirmButtonText: Strings.getLang('confirm'),
cancelButtonText: Strings.getLang('cancel'),
});
showLoading({
title: '',
mask: true,
});
await (dispatch as AppDispatch)(deletePet(pet.id)).unwrap();
navigateBack();
} catch (err) {
console.log(err);
} finally {
hideLoading();
}
};