前提条件

开发环境

详见 面板小程序 > 搭建环境

产品名称:AI 智能体

需求原型

创建智能体

准备好 智能生活 OEM App 和智能产品(可选)后,需要在 智能体平台 上创建智能体。

  1. 单击 创建 Agent 按钮,填入项目相关必选信息后,单击 确定 创建一个智能体。

  1. 依照您的需求,在 01 模型能力配置 下定制智能体的模型、记忆、工具、知识库及工作流等功能,再在 02 提示词开发 下配置提示词(Prompt),完成当前数据中心的智能体创建。

调试智能体

  1. 配置完成 Prompt 后,单击 获取调试二维码 按钮获取二维码。

  1. 调试完成后,按照您的需要分别配置不同数据中心的智能体,然后单击 发布,并配置版本号,将智能体发布至线上环境。

  1. 发布完成后,单击 上架 将智能体上架到平台账号下,用于后续产品的绑定。

  1. 完成上述步骤后返回智能体列表页面,可以看到您刚刚创建的专属智能体。

由于产品定义了面板和设备所拥有的功能点与智能体,所以在开发一个智能设备面板之前,首先需要创建一个 AI 毛绒玩具产品,定义产品有哪些功能点、携带哪些智能体,然后再在面板中一一实现这些功能点。

首先,注册登录 涂鸦开发者平台,并在平台创建产品:

  1. 在涂鸦开发者平台产品类目下,单击 创建产品

  1. 在标准类目下选择 影音穿戴 > AI 毛绒玩具

  1. 选择 智能化方式产品方案,完善产品信息,单击 创建产品

  1. 添加标准功能 页面,选择适合硬件方案维度的功能点,单击 确定

  1. 完成以上步骤后,您已经完成了产品的创建。接下来,在 01 功能定义 > 产品 AI 功能 下继续添加产品 AI 功能。

  1. 添加产品 AI 能力:单击 添加产品 AI 能力 来选择您的产品需要使用的 AI 能力,选择完成后单击 确定

  1. 选择产品 AI Agent:选择为产品配置智能体(本模板以设备端智能体为例),单击 选择智能体 进入添加智能体页面,进行设备默认智能体配置。

  1. 在智能体列表中选择要与设备绑定的默认智能体。

  1. 完成智能体绑定配置后,单击 下一步 设备交互 进入交互设置。

  1. 设备交互 页面中,选择面板模板,后续操作可参考 产品开发指南

开发者平台创建面板小程序

面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。

详细操作步骤可以参考 创建面板小程序

IDE 基于模板创建项目工程

打开 IDE 创建一个基于 AI 智能体小程序模板 的面板小程序项目,需要在 Tuya MiniApp IDE 上操作。

详细操作步骤可以参考 初始化项目工程

完成以上步骤后,一个面板小程序的开发模板初始化完成。以下为工程目录的介绍:

├── src
│  	├── api // 面板所有云端 API 请求聚合文件
│  	├── components
│  	│   ├── AICard // 智能体卡片组件
│  	│   ├── DialogConfirm // 确认弹窗组件
│  	│   ├── DialogInput // 文本输入弹窗组件
│  	│   ├── DialogPicker // DP 选择弹窗组件
│  	│   ├── GridBattery // 电池电量组件
│  	│   ├── icon-font // svg 图标容器组件
│  	│   ├── Modal // 弹窗通用组件
│  	│   ├── NoData // 无数据兜底组件
│  	│   ├── PickerItem // 选择按钮通用组件
│  	│   ├── SearchBar // 搜索组件
│  	│   ├── Tag // 分类标签子组件
│  	│   ├── TagBar // 分类标签组件
│  	│   ├── Text // 通用文本组件
│  	│   ├── TopBar // 通用 TopBar 组件
│  	│   ├── TouchableOpacity // 通用按钮组件
│  	├── constant
│  	│   ├── dpCodes.ts // dpCode 常量
│  	│   ├── index.ts // 存放所有的常量配置
│  	├── devices // 设备模型
│  	├── hooks // hooks
│  	├── i18n // 多语言
│  	├── pages
│   │   ├── AIDialogue // 智能体列表页面
│   │   ├── AvatarSelect // 头像选择
│   │   ├── CloneSetting // 音色克隆方式选择页面
│   │   ├── CloneVoice // 音色克隆操作页面
│   │   ├── CustomAgentEdit // 智能体角色新增和编辑
│   │   ├── DialogHistory // 单个智能体会话历史记录页面
│   │   ├── home // 首页
│   │   ├── VoiceSetting // 单个音色编辑页面
│   │   ├── VoiceSquare // 音色广场页面
│  	├── 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

获取角色列表

功能说明

使用 getAIAgentRoles API 方法获取智能体角色列表,目前角色数量上限为 10 个。

相关代码段

// 角色列表请求函数
export const getAIAgentRoles = async () => {
  try {
    // getAgentRoles
    const response = await getAI2AgentRoles({
      devId: getDevInfo().devId,
      pageNo: 1,
      pageSize: 10,
      panelCode: 'ai_platform',
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const getBoundAgentsFunc = async () => {
  getAIAgentRoles()
    .then((res: any) => {
      const { list: boundAgentList } = res;
      console.log('==55boundAgentList', boundAgentList);
      dispatch(updateRoleList([...boundAgentList]));
      setRefresherTriggeredState(false);
    })
    .catch(err => {
      setInitLoading(false);
      console.log('getBoundAgentsFunc::err::', err);
      setRefresherTriggeredState(false);

    });
};

将智能体与设备进行绑定

功能说明

点击智能体会话卡片右上角的 绑定到设备 按钮后,智能体角色将和设备进行绑定,面板顶部的默认智能体信息展示区域将会自动切换为该智能体角色的对应内容,同时该智能体会话卡片将自动排序为第一个。完成上述绑定操作后,C 端用户在与设备交互时,将感知到最新的智能体角色相关内容。

相关代码段

export const bindAIAgentRoles = async (roleId: string) => {
  try {
    // bindAgentRoles
    const response = await bindAI2AgentRoles({
      devId: getDevInfo().devId,
      roleId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const bindAIRole = (roleId: string, inBind: boolean) => {
  if (inBind) return;
  showLoading({
    title: '',
  });
  bindAIAgentRoles(roleId)
    .then(() => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_binding_success'),
        icon: 'success',
      });
      emitter.emit('refreshDialogData', '');
    })
    .catch(() => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_binding_fail'),
        icon: 'error',
      });
    });
};

相关代码段

export const deleteAIAgentRoles = async (roleId: string) => {
  try {
    // deleteAgentRoles 
    const response = await deleteAI2AgentRoles({
      devId: getDevInfo().devId,
      roleId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const deleteAIRole = (roleId: string) => {
  showLoading({
    title: '',
  });
  deleteAIAgentRoles(roleId)
    .then(() => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_delete_success'),
        icon: 'success',
      });
      emitter.emit('refreshDialogData', '');
    })
    .catch((err) => {
      hideLoading();
      console.log('deleteAIAgentRoles::err::', err);
      showToast({
        title: Strings.getLang('dsc_delete_fail'),
        icon: 'error',
      });
    });
  setUnbindId('-1');
  setIsShowUnbindConfirm(false);
};

页面介绍

角色会话记录展示页主要用于展示 C 端用户与智能体角色的对话记录,当 C 端用户暂未与智能体产生对话内容时,模版将会展示空内容提示图文。用户点击智能体会话记录的顶部的卡片后,便可跳转至角色编辑页面。

相关代码段

// 获取角色会话记录
export const getDialogHistoryList = async (params: GetHistoryParams) => {
  try {
    // getAIAgentHistory 
    const response = await getAI2AgentEndpointHistory({
      devId: getDevInfo().devId,
      roleId: params.roleId,
      pageNo: params.pageNo,
      pageSize: params.pageSize,
      startTime: dayjs().subtract(3, 'months').format('YYYY-MM-DD HH:mm:ss'),
      endTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const [historyList, setHistoryList] = useState([]);

const getDialogHistoryListFunc = useCallback((params: GetListParams) => {
    return new Promise((resolve, reject) => {
      getDialogHistoryList({
        pageNo: params.current,
        pageSize: params.pageSize,
        roleId,
        startTime: params.startTime,
        endTime: params.endTime,
      })
        .then((res: DialogHistoryRes) => {
          const { totalPage, list } = res;
          resolve({
            total: totalPage,
            list,
          });
        })
        .catch(error => {
          reject(error);
        });
    });
  }, []);

  const { pagination, data, run } = usePagination(
    ({ current, pageSize, startTime, endTime }) =>
      getDialogHistoryListFunc({
        current,
        pageSize,
        startTime,
        endTime,
      }) as Promise<GetDialogHistory>,
    {
      manual: true,
    }
  );

清除上下文

功能说明

该功能主要用于删除一组或多组角色的聊天信息。

相关代码段

// 清除上下文接口 clearAgentHistoryMessage
export const clearAgentHistoryMessage = async (params: any) => {
  try {
    // deleteAIAgentHistoryMessage 
    const response = await deleteAI2AgentEndpointHistory({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const handleDeleteMessage = async () => {
  try {
    showLoading({ title: '' });
    await clearAgentHistoryMessage({
      roleId,
      requestIds: selectedItems?.join(','), // requestId 就是 docId
    });

    const newList = historyList.filter(item => !selectedItems.includes(item.requestId));
    setHistoryList(newList);

    hideLoading();
    showToast({
      title: Strings.getLang('dsc_delete_chat_history_tip_new'),
      icon: 'success',
    });
  } catch (err) {
    hideLoading();
    showToast({
      title: Strings.getLang('dsc_delete_chat_history_failed'),
      icon: 'error',
    });
  }
};

清除历史聊天记录

功能说明

该功能主要用于清除 C 端用户与智能体角色之间的聊天记录,并初始化该智能体角色的聊天内容记录。

相关代码段

// 清除历史聊天记录接口
export const clearingHistoryRecord = async (roleId: string) => {
  try {
    // deleteAIAgentHistory 
    const response = await clearAI2AgentEndpointHistory({
      devId: getDevInfo().devId,
      roleId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const handleClearingHistoryRecord = () => {
  showModal({
    title: '',
    content: Strings.getLang('dsc_delete_chat_history'),
    confirmText: Strings.getLang('delete'),
    cancelText: Strings.getLang('dsc_cancel'),
    success: ({ confirm }) => {
      if (confirm) {
        showLoading({
          title: '',
        });
        clearingHistoryRecord(roleId)
          .then(() => {
            hideLoading();
            showToast({
              title: Strings.getLang('dsc_delete_chat_history_tip'),
              icon: 'success',
            });
            navigateBack({});
            setTimeout(() => {
              emitter.emit('refreshHistoryData', '');
            }, 2000);
          })
          .catch(() => {
            hideLoading();
            showToast({
              title: Strings.getLang('dsc_delete_chat_history_failed'),
              icon: 'error',
            });
          });
      }
    },
  });
};

页面介绍

角色新增/编辑页面主要用于修改角色信息(头像、名称,角色介绍、记忆体),以及选择音色、语种、和大模型。

获取角色模板列表/模板详情

功能说明

B 端可以预设一些模板,提供给用户选择,简化用户操作流程。

相关代码段

//获取角色模板列表
export const getAIAgentRolesTemplateList = async () => {
  try {
    // getAgentRolesTemplates 
    const response = await getAI2AgentRolesTemplates({ devId: getDevInfo().devId, panelCode: 'ai_platform' });

    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const getTemplateList = async () => {
  getAIAgentRolesTemplateList()
    .then((res: any) => {
      console.log('==getTemplateList', res);
      setTemplateList(res);
      if (res?.length > 0) {
        setTemplateRoleId(res[0].roleId);
      }
    })
    .catch(err => {
      console.log('getTemplateList::err::', err);
    });
};
//获取角色模板详情
export const getAIAgentRolesTemplatesDetail = async (roleId: string) => {
  try {
    // getAgentRolesTemplatesDetail 
    const response = await getAI2AgentRolesTemplatesDetail({ devId: getDevInfo().devId, roleId });

    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const getTemplateListDetail = async (roleId: string) => {
  getAIAgentRolesTemplatesDetail(roleId)
    .then((res: any) => {
      console.log('==getTemplateListDetail', res);
      initRoleData(res);
      initRoleInfoData();
    })
    .catch(err => {
      console.log('getTemplateListDetail::err::', err, roleId);
    });
};

获取角色详情

功能说明

编辑角色时,获取当前角色详情。

相关代码段

export const getAIAgentRoleDetail = async (roleId: string) => {
  try {
    // getAgentRolesDetail 
    const response = await getAI2AgentRolesDetail({
      devId: getDevInfo().devId,
      roleId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const getAgentRoleDetail = async (roleId: string) => {
  getAIAgentRoleDetail(roleId)
    .then((res: any) => {
      console.log('==getAIAgentRoleDetail', res);
      initRoleData(res);
      initRoleInfoData();
    })
    .catch(err => {
      console.log('getAIAgentRoleDetail::err::', err);
    });
};

创建/编辑角色

功能说明

创建/编辑角色。

相关代码段

// 创建角色
export const createRole = async (params: any) => {
  try {
    // postCreateAgentRole 
    const response = await addAI2AgentRoles({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};
// 编辑角色
export const updateRole = async (params: any) => {
  try {
    // postUpdateAgentRole 
    const response = await updateAI2AgentRoles({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const handleSave = async () => {
  if (!name || nameErrorMessage) {
    showToast({
      title: `${Strings.getLang('please_complete')}${Strings.getLang('role_name')}`,
      icon: 'error',
    });
    return;
  }
  if (!introduction) {
    showToast({
      title: `${Strings.getLang('please_complete')}${Strings.getLang('introduction')}`,
      icon: 'error',
    });
    return;
  }
  if (!roleInfo?.voiceId && !selectedVoiceId) {
    showToast({
      title: `${Strings.getLang('please_complete')}${Strings.getLang('role_voice')}`,
      icon: 'error',
    });
    return;
  }
  if (!selectedModel) {
    showToast({
      title: `${Strings.getLang('please_complete')}${Strings.getLang('model')}`,
      icon: 'error',
    });
    return;
  }

  const params = {
    roleName: name,
    roleIntroduce: introduction,
    roleImgUrl: roleInfo?.roleImgUrl || roleImgUrl,
    useLangCode: roleInfo?.useLangId || selectedLanguageCode,
    useTimbreId: roleInfo?.voiceId || selectedVoiceId,
    useLlmId: selectedModel,
    memoryInfo: memoryInfo,
  }

  try {
    if (roleId) {
      params.roleId = roleId
      await updateRole(params);
    } else {
      await createRole(params);
    }
    hideLoading();
    showToast({
      title: Strings.getLang('save_success'),
      icon: 'success',
    });

    emitter.emit('refreshDialogData', '');
    navigateBack({ delta: 9999 });
  } catch (error) {
    console.log('createRole/updateRole:::', error);
    hideLoading();
    showToast({
      title: Strings.getLang('save_failed'),
      icon: 'error',
    });
  }
};

获取角色头像

功能说明

B 端可以预设一些头像,提供给用户选择。

相关代码段

// 头像
export const getAIAvatars = async () => {
  try {
    // getAgentAvatars
    const response = await getAI2AgentAvatars({
      devId: getDevInfo().devId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const getBoundAgentsFunc = async () => {
  getAIAvatars()
    .then(res => {
      console.log('getAIAvatars::', res);
      setAvatarList(res);
    })
    .catch(err => {
      console.log('getAIAvatars::err::', err);
    });
};

获取语言语种

功能说明

获取支持的语言语种。

相关代码段

// 获取支持的语言语种
export const getAgentLanguages = async () => {
  try {
    // getAgentLanguageConfig 
    const response = await getAI2AgentConfigLangList({
      devId: getDevInfo().devId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const useAgentLanguages = (id: number) => {
  const [langRangeList, setSupportLangs] = useState<Array<{ key: string; dataString: string }>>([]);

  useEffect(() => {
    const fetchSupportedLangs = async () => {
      try {
        const response = await getAgentLanguages();
        if (response) {
          setSupportLangs(
            response?.map(item => ({
              dataString: item?.langName,
              key: item?.langCode,
            }))
          );
        }
      } catch (error) {
        console.error('Failed to fetch supported languages:', error);
      }
    };

    fetchSupportedLangs();
  }, []);

  return { langRangeList };
};

import useAgentLanguages from '@/hooks/useAgentLanguages';
const { langRangeList } = useAgentLanguages(id);

获取大模型列表

功能说明

获取大模型列表。

相关代码段

// 获取大模型列表
export const getAgentModels = async () => {
  try {
    // getAgentModelConfig
    const response = await getAI2AgentConfigLlmList({
      devId: getDevInfo().devId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const fetchSupportedModels = async () => {
  try {
    const response = await getAgentModels();
    console.log('getAgentModels:::', response);
    if (response) {
      const models = response?.map(model => ({
        key: model.llmId,
        dataString: model.llmName,
      }));
      setModelList(models);
    }
  } catch (error) {
    console.error('Failed to fetch supported models:', error);
  }
};

页面介绍

音色管理页面主要用于切换智能体角色所携带的音色信息,主要包含用户克隆音色管理、系统默认音色管理。

音色克隆

功能说明

C 端用户可以在 我的 音色分类中查看自己的克隆音色。若暂无克隆音色,可通过点击 克隆音色 按钮跳转至克隆音色页面,开始克隆自己的专属音色。

相关代码段

// 获取录音能力集
const RecorderManager = getRecorderManager({
  complete: () => {
    console.log('==complete');
  },
  success: (params: null) => {
    console.log('===success==getRecorderManager', params);
  },
  fail: (params: null) => {
    console.log('===fail==getRecorderManager', params);
  },
});

// 开始录音
const startRecording = async () => {
  if (!RecorderManagerRef.current) {
    RecorderManager?.start?.({
      sampleRate: 16000,
      encodeBitRate: 96000,
      frameSize: 10,
      format: 'wav' as any,
      complete: () => {
        console.log('===startRecording==complete');
      },
      success: params => {
        console.log('===startRecording==success', params);
        RecorderManagerRef.current = true;
      },
      fail: params => {
        console.log('===startRecording==fail', params);
        resetAll();
      },
    });
  }
  try {
    ty.createAIAssistant({
      complete: () => {
        console.log('createAIAssistant==complete');
      },
      success: (params: null) => {
        console.log('createAIAssistant===success==getRecorderManager', params);
      },
      fail: (params: null) => {
        console.log('createAIAssistant===fail==getRecorderManager', params);
      },
    });
    const authorize = await Asr.authorize();
    if (!authorize) {
      resetAll();
      showToast({
        title: Strings.getLang('no_asr_permission'),
        icon: 'error',
      });
      return;
    }
    // if (!asrRef.current) {
    // Create ASR detector
    const asr = createAsrDetector();
    // Start ASR
    asrRef.current = asr;
    // }
    await asrRef.current?.start();
    // 初始化成功,可以开始录音
    changeAsrInted(true);
    timer.current = setInterval(() => {
      timerCheck();
    }, 1000);
  } catch (error) {
    console.error('Error starting ASR:', error);
    stopTouch();
    showToast({
      title: Strings.getLang('dsc_clone_fail'),
      icon: 'error',
    });
    clearAsr();
  }
};

// 完成录音
const stopRecording = async () => {
  RecorderManager?.stop?.({
    complete: () => {
      console.log('===stopRecording==complete');
      // setCloneState('start');
      RecorderManagerRef.current = false;
      clearAsr();
    },
    success: params => {
      console.log('params?.tempFilePath', params?.tempFilePath);
      try {
        uploadImage({
          filePath: params?.tempFilePath,
          bizType: 'voice_clone',
          contentType: 'audio/mpeg',
          success: params => {
            const { publicUrl } = JSON.parse(params?.result);
            console.log('publicUrl', publicUrl);
            submitVoice(publicUrl);
          },
          fail: params => {
            console.log('===uploadImage==fail', params);
            clearAsr();
            resetAll();
          },
        });
        console.log('uploadImage:::success:::params', params);
      } catch (err) {
        console.log('catch uploadImage err:', err);
      }
    },
    fail: params => {
      console.log('===stopRecording==fail', params);
      clearAsr();
      resetAll();
    },
  });
};

人声朗诵克隆

功能展示

功能说明

克隆流程如下:

  1. C 端用户点击面板进入声音克隆页面,选择 朗读文本 克隆方式。
  2. 点击录音按钮,按照文本朗读对应内容,再次点击录音按钮后,开始生成克隆音色。
  3. 完成克隆后,便可在音色列表中查看、切换、编辑克隆音色。
  4. 切换克隆音色后,按住设备语音按键,唤醒设备开始语音对话,此时设备便可使用克隆音色与 C 端用户沟通。

录制音频克隆

功能展示

功能说明

  1. C 端用户点击面板进入声音克隆页面,选择 录制现有声音 克隆方式。
  2. 点击录音按钮,播放现有声音(至多录制 15 秒),再次点击录音按钮后,开始生成克隆音色。
  3. 完成克隆后,便可在音色列表中查看、切换、编辑克隆音色。
  4. 切换克隆音色后,按住设备语音按键,唤醒设备开始语音对话,此时设备便可使用克隆音色与 C 端用户沟通。

音色广场列表展示

功能说明

音色广场列表主要用于展示系统默认音色列表,C 端用户可在广场内挑选适合自己的音色内容赋能给智能体角色。在筛选音色方面,模版支持分类筛选、搜索筛选功能。

相关代码段

// 获取克隆音色列表
export const getCloneVoiceList = async (params: any) => {
  try {
    // getCloneList
    const response = await getAI2TimbreCloneList({ devId: getDevInfo().devId, ...params });

    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

// 获取标准音色列表
export const getStandardVoiceList = async (params: any) => {
  try {
    // getMarketList 
    const response = await getAI2TimbreMarketList({
      devId: getDevInfo().devId,
      pageNo: params.pageNo,
      pageSize: params.pageSize,
      tag: '',
      keyWord: params.keyWord,
      lang: params.lang,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

// 音色列表请求函数(包含克隆音色列表)
const getVoiceListFunc = (params: GetListParams) => {
  return new Promise((resolve, reject) => {
    getStandardVoiceList({
      pageNo: params.current,
      pageSize: params.pageSize,
      tag,
      agentId,
      keyWord: params.searchText,
      lang: selectedLang,
    })
      .then((res: VoiceRes) => {
        const { totalPage, list = [] } = res;
        hideLoading();
        setLoading(false);
        resolve({
          total: totalPage,
          list,
        });
      })
      .catch(error => {
        hideLoading();
        setLoading(false);
        reject(error);
      });
  });
};
const initClone = () => {
  getCloneVoiceList({ lang: selectedLang })
    .then(res => {
      hideLoading();
      setResList(res);
      setLoading(false);
    })
    .catch(error => {
      hideLoading();
      setLoading(false);
    });
};

 // 音色列表请求管理
const { pagination, data, run } = usePagination(
  ({ current, pageSize, searchText }) =>
    getVoiceListFunc({ current, pageSize, searchText }) as Promise<GetStandardVoice>,
  {
    manual: true,
  }
);

// 响应懒加载
useEffect(() => {
  if (data?.list) {
    pagination.current > 1
      ? dispatch(updateVoiceList([...data?.list]))
      : dispatch(initVoiceList([...data?.list]));
  }
}, [data]);

音色搜索

相关代码段

// 搜索与查询智能体列表接口请求流程相同,区别在于【searchText】字段的不同,拉取整体列表使【searchText】字段为空字符串
const { pagination, data, run } = usePagination(
  ({ current, pageSize, searchText }) =>
    getVoiceListFunc({ current, pageSize, searchText }) as Promise<GetStandardVoice>,
  {
    manual: true,
  }
);

音色切换

相关代码段

// 切换音色(编辑智能体详情)
export const updateRole = async (params: any) => {
  try {
    // postUpdateAgentRole 
    const response = await updateAI2AgentRoles({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const handleItemChecked = async (idKey: string, item: any) => {
  try {
    if (tag === 'mine') {
      showLoading({ title: Strings.getLang('clone_voice_generating') });
      const cloneMp3 = await localGetCloneRadioSource({
        objectKey: item?.demoUrl || undefined,
        voiceId: idKey,
        lang: selectedLang,
        // lang: finalLanguage,
      }).catch(err => {
        hideLoading();
      });
      setTimeout(() => {
        hideLoading();
      }, 500);
      if (cloneMp3) {
        playVoiceAudio(cloneMp3);
      }
    } else {
      playVoiceAudio(item?.demoUrl);
    }
    if (squareEntry === 'role') {
      dispatch(
        updateRoleInfo({
          voiceId: idKey,
          voiceName: item?.voiceName,
          supportLangs: item?.supportLangs,
        })
      );

      return;
    }
    if (tag !== 'mine') {
      showLoading({
        title: '',
      });
    }
    const params = { ...roleInfo, useTimbreId: idKey, roleId };
    if (squareEntry === 'role') {
      delete params.roleId;
    }
    updateRole(params)
      .then(async res => {
        if (res) {
          dispatch(updateRoleInfo({ voiceId: idKey, voiceName: item?.voiceName }));

          setTimeout(async () => {
            const agentCloudInfo = (await getAgentInfo(roleId)) as AgentInfo;
            dispatch(updateAgentInfo({ ...agentCloudInfo, roleId }));
            hideLoading();
          }, 500);
        }
        hideLoading();
      })
      .catch(error => {
        if (platform === 'android' && error?.innerError?.errorCode === '13890100') {
          showToast({
            title: error?.innerError?.errorMsg,
            icon: 'error',
          });
        } else if (platform === 'ios') {
          showToast({
            title: iOSExtractErrorMessage(error?.innerError?.errorMsg),
            icon: 'error',
          });
        } else {
          showToast({
            title: Strings.getLang('dsc_choose_fail'),
            icon: 'error',
          });
        }
        hideLoading();
      });
  } catch (err) {
    console.log('handleItemChecked:::err', err);
    hideLoading();
  }
};

编辑音色

页面说明

该页面用于编辑音色具体内容,音色广场中的音色在此页面支持修改音色的语速,克隆音色在该页面支持修改音色的语速、以及重置、删除克隆音色等功能。

编辑语调、语速

相关代码段

// 编辑智能体详情(语调、语速为智能体详情信息)
export const updateRole = async (params: any) => {
  try {
    // postUpdateAgentRole 
    const response = await updateAI2AgentRoles({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const onChangeToneOrSpeed = (sv: number, tv: number) => {
  showLoading({
    title: '',
  });
  updateRole({ roleId, [speedKey]: `${sv}`, [toneKey]: `${tv}` })
    .then(async res => {
      sv >= 0 && setSpeedValue(sv);
      tv >= 0 && setToneValue(tv);
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_edit_success'),
        icon: 'success',
      });
    })
    .catch(() => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_edit_fail'),
        icon: 'error',
      });
    });
};

恢复默认设置(语调、语速)

相关代码段

// 恢复默认设置(语调、语速)
export const localResetToDefaultVoice = async (params: any) => {
  try {
    // resetToDefaultVoice
    const response = await restoreAI2AgentRolesSpeed({
      devId: getDevInfo().devId,
      ...params,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const onChangeToneOrSpeedReset = () => {
  showLoading({
    title: '',
  });
  localResetToDefaultVoice({ roleId })
    .then(async res => {
      const sv = res?.speed;
      const tv = res?.tone;
      sv >= 0 && setSpeedValue(sv);
      tv >= 0 && setToneValue(tv);
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_edit_success'),
        icon: 'success',
      });
    })
    .catch(() => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_edit_fail'),
        icon: 'error',
      });
    });
};

编辑克隆音色名称

相关代码段

// 编辑克隆音色名称
export const renameCloneVoice = async (voiceId: string, nameText: string) => {
  try {
    // renameAITimbreClone 
    const response = await renameAI2TimbreClone({
      voiceId,
      name: nameText,
      devId: getDevInfo().devId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const editCloneName = (text: string) => {
  showLoading({
    title: '',
  });
  renameCloneVoice(voiceId, text)
    .then(async res => {
      setTimeout(async () => {
        const agentCloudInfo = (await getAgentInfo(Number(roleId))) as AgentInfo;
        updateAgentInfo({ ...agentCloudInfo, roleId });
      }, 300);

      hideLoading();
      setNameText(text);
      showToast({
        title: Strings.getLang('dsc_edit_success'),
        icon: 'success',
      });
      emitter.emit('refreshVoiceData', '');
    })
    .catch(err => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_edit_fail'),
        icon: 'error',
      });
    });
};

删除克隆音色

相关代码段

// 删除克隆音色
export const deleteCloneVoice = async (voiceId: string) => {
  try {
    // deleteAITimbreClone
    const response = await delAI2TimbreClone({
      voiceId,
      devId: getDevInfo().devId,
    });
    return response;
  } catch (err) {
    return Promise.reject(err);
  }
};

const handleDeleteClone = () => {
  showLoading({
    title: '',
  });
  deleteCloneVoice(voiceId)
    .then(async () => {
      hideLoading();
      showToast({
        title: Strings.getLang('dsc_delete_success'),
        icon: 'success',
      });
      const agentCloudInfo = (await getAgentInfo(Number(roleId))) as AgentInfo;
      updateAgentInfo({ ...agentCloudInfo, roleId });
      emitter.emit('refreshVoiceData', '');
      setTimeout(() => {
        router.back();
      }, 300);
    })
    .catch(error => {
      hideLoading();
      if (platform === 'android' && error?.innerError?.errorCode === '138903140') {
        showToast({
          title: error?.innerError?.errorMsg,
          icon: 'error',
        });
      } else if (platform === 'ios') {
        showToast({
          title: iOSExtractErrorMessage(error?.innerError?.errorMsg),
          icon: 'error',
        });
      } else {
        showToast({
          title: Strings.getLang('dsc_delete_fail'),
          icon: 'error',
        });
      }
    });
};