предисловие
- Учебник в первый день«Разработка голоса Tmall Elf — день первый»Здесь мы попытались разработатьhello world
- на второй день курса«Разработка голоса Tmall Elf — второй день»Здесь мы попытались развить голосовой навык для запроса погоды.
- Уроки третьего дня«Развитие голоса Tmall Elf — день 3»Здесь мы пытаемся разработать голосовой навык, связанный с запросом качества воздуха с несколькими намерениями.
Процесс
- Процесс настройки внешнего интерфейса
- Навыки создания географической энциклопедии
- Фоновый процесс разработки
- Измените базовый код в соответствии с реальной ситуацией
- Отправьте код и разверните его онлайн
- Процесс автоматической генерации фронтальной проверки
- Проверьте автоматически сгенерированные намерения
- Проверьте диалоговый материал и аннотации
- голосовой тест
- Проект оффлайн
Процесс настройки внешнего интерфейса
Навыки создания географической энциклопедии
Фоновый процесс разработки
На этот раз мы не будем создавать модель голосового взаимодействия, а сразу перейдем к серверной службе, чтобы создать приложение и войти в платформу разработки Alibaba Cloud (URL: workbench.aliyun.com) для разработки функций на основе кода. шаблона по умолчанию.
Измените базовый код в зависимости от реальной ситуации.
Модифицированный исходный код
package com.alibaba.ailabs;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.ailabs.common.AbstractEntry;
import com.alibaba.da.coin.ide.spi.meta.ExecuteCode;
import com.alibaba.da.coin.ide.spi.meta.ResultType;
import com.alibaba.da.coin.ide.spi.standard.ResultModel;
import com.alibaba.da.coin.ide.spi.standard.TaskQuery;
import com.alibaba.da.coin.ide.spi.standard.TaskResult;
import com.alibaba.fastjson.JSON;
import com.aliyun.fc.runtime.Context;
/**
* @Description 天猫精灵技能函数入口,FC handler:com.alibaba.ailabs.GenieEntry::handleRequest
* @Version 1.0
**/
public class GenieEntry extends AbstractEntry {
private static final Map<String, LinkedList<Integer>> USER_MAP = new ConcurrentHashMap<>();
private static final List<String> KNOWLEDGE;
private static Random random = new Random();
static {
KNOWLEDGE = Arrays.asList(
"世界热极:巴士拉(伊拉克)最高记录58.8摄氏度",
"世界冷极:东方站(南极)最低记录-89.2摄氏度",
"世界湿极:怀厄莱阿莱(太平洋上的一个岛屿)每年平均有335天下雨,年降水量达12244毫米",
"世界干极:阿塔卡马沙漠(南美洲)平均年降水量小于0.1毫米,1845年~1936年的91年间未曾下雨",
"海拔最高的山峰:珠穆朗玛峰(海拔8844.43米)",
"地球上体积最大的山及火山:冒纳罗亚火山(MaunaLoa,夏威夷岛,海拔4169米,火山体积达7万5000立方公里)",
"地球上最高的活火山:奥霍斯德尔萨拉多山(海拔6893米)",
"太阳系内已知的最高、体积最大的山及火山:奥林帕斯火山(火星,高达约27公里)",
"最大的岛屿:格陵兰岛(面积达2166086平方公里)",
"人口最多的岛屿:爪哇岛(人口达12400万)",
"唯一分属三个国家的岛屿:加里曼丹岛",
"最大的湖泊及咸水湖:里海(面积达371000平方公里)",
"最大的淡水湖:坦噶尼喀湖(非洲)",
"最深的湖泊及淡水湖:贝加尔湖(水深达1940米)",
"海拔最低的湖泊:死海(湖面海拔负392米,是已露出陆地的最低点)",
"最咸的湖泊:死海(湖水盐度达300‰,为一般海水的8.6倍)",
"最古老的湖泊:贝加尔湖(已经在地球上存在超过2500万年)",
"最长的河流:尼罗河(全长6671公里)",
"流域面积最大的河流:亚马逊河(面积达7050000平方公里)",
"含沙最多的河流:黄河(1977年录得最高含沙量达每立方米920千克沙)",
"流经最多国家的河流:多瑙河(流经西欧至东欧共18个国家)",
"最早的运河:古苏伊士运河(建于公元前19世纪,完成于前500年,8世纪被毁弃,19世纪重建。)",
"海拔最高的长河:雅鲁藏布江(河床海拔平均在3000米以上)",
"太阳系已知的最大峡谷:水手号峡谷(火星,长达4500公里,阔200公里,深11公里)",
"最大的沙漠:撒哈拉沙漠(面积约有960多万平方千米)",
"面积最大的盆地:刚果盆地",
"世界上已知体积最大的独立岩石:艾尔斯巨石(高348米,底沿周长约9400米,占地面积约1200公顷)",
"质量最大的行星:木星(约为其余八大行星质量总和的2倍)",
"太阳系中最大的卫星:木卫三",
"最深的海沟:马里亚纳海沟(深11034米)",
"最长的洋流:南极环流(长达21000公里)"
);
}
@Override
public ResultModel<TaskResult> execute(TaskQuery taskQuery, Context context) {
context.getLogger().info("taskQuery: " + JSON.toJSONString(taskQuery));
String userId = taskQuery.getRequestData().get("userOpenId");
userId = userId == null ? "testUser" : userId;
LinkedList<Integer> list = USER_MAP.get(userId);
//欢迎意图 或 用户缓存数据为空
if ("welcome".equals(taskQuery.getIntentName()) || list == null) {
list = new LinkedList<>();
int randomIndex = random.nextInt(KNOWLEDGE.size());
list.addLast(randomIndex);
USER_MAP.put(userId, list);
return intentChangeReply(KNOWLEDGE.get(randomIndex));
}
//下一个意图,随机选择一个内容回复,并将index追加到用户数据的LinkedList集合最后
if ("next".equals(taskQuery.getIntentName())) {
int randomIndex = random.nextInt(KNOWLEDGE.size());
list.addLast(randomIndex);
return intentChangeReply(KNOWLEDGE.get(randomIndex));
}
//上一个意图,将用户数据的LinkedList集合中最后一个index移除,并返回该index的内容。首先要判断集合内是否有元素,没有则不需要移除
if ("prev".equals(taskQuery.getIntentName())) {
if (list.size() > 0) {
list.removeLast();
}
if (list.size() == 0) {
return intentChangeReply("这已经是第一个了。");
}
return intentChangeReply(KNOWLEDGE.get(list.get(list.size() - 1)));
}
//退出意图,清除用户缓存
if ("exit".equals(taskQuery.getIntentName())) {
USER_MAP.remove(userId);
return reply("已为您退出,再见。");
}
return reply("请检查意图名称是否正确,或者新增的意图没有在代码里添加对应的处理分支。");
}
/**
* 结束对话的回复,回复后音箱闭麦
*/
private ResultModel<TaskResult> reply(String reply) {
return getResult(reply, ResultType.RESULT);
}
/**
* 未指定追问参数,音箱自动开麦,用户的回答可跳转到其它意图
*/
private ResultModel<TaskResult> intentChangeReply(String reply) {
return getResult(reply, ResultType.ASK_INF);
}
private ResultModel<TaskResult> getResult(String reply, ResultType askInf) {
ResultModel<TaskResult> res = new ResultModel<>();
TaskResult taskResult = new TaskResult();
taskResult.setReply(reply);
taskResult.setExecuteCode(ExecuteCode.SUCCESS);
taskResult.setResultType(askInf);
res.setReturnCode("0");
res.setReturnValue(taskResult);
return res;
}
}
Отправьте код и разверните его онлайн
- Коммит кода с Git
- Выберите предварительную среду для развертывания в Интернете. Подробности см. в учебном пособии первого дня.
Процесс автоматической генерации фронтальной проверки
Проверьте автоматически сгенерированные намерения
Изучите автоматически сгенерированный диалоговый материал
Отправьте код и разверните его онлайн
голосовой тест
Войдите в онлайн-тест, чтобы проверить
PS: В настоящее время, поскольку нет физической машины, нет реального машинного теста.
Проект оффлайн
После завершения онлайн-тестирования мне необходимо своевременно перевести развернутое приложение в автономный режим на платформе облачной разработки.Поскольку бесплатная квота ограничена, если приложение не будет переведено в автономный режим вовремя, будут понесены ненужные расходы.