如何将自定义间隔计数Python脚本集成到Alexa技能代码库
Alexa间隔计数技能Python集成方案
核心前提说明
你原本写的
time.sleep()阻塞循环写法完全无法直接在Alexa Lambda环境运行:Alexa单次Lambda请求最长超时仅8秒,不可能挂起进程等几十秒逐个数数;且Alexa不会读取控制台print()内容作为语音输出,所有语音反馈都需要通过符合规范的响应结构返回。
第一步:先配置技能交互模型
- 新建自定义Alexa技能,调用名设置为「间隔计数器」即可
- 新建自定义意图
CountIntent,绑定两个必填槽位:- 槽位
endNumber:类型选AMAZON.NUMBER,对应用户要数到的目标值,比如示例指令里的30 - 槽位
intervalSeconds:类型选AMAZON.NUMBER,对应用户要求的计数间隔秒数,比如示例指令里的2
- 槽位
- 为
CountIntent配置样本语句,填入你的示例指令:count to {endNumber} in intervals of {intervalSeconds} seconds - 为两个必填槽位配置追问话术,比如没拿到目标值时问「请问你要数到多少?」,没拿到间隔时问「请问每隔几秒数一个数?」,配置后Alexa会自动补全缺失参数,不需要额外写代码
- 技能权限页开启SSML长内容播报权限,测试阶段不需要额外开其他付费服务
第二步:集成代码到lambda_function.py
Lambda运行环境先配置官方Python SDK依赖ask-sdk-core,直接把下面的核心代码替换默认的lambda_function.py内容即可,已经把计数逻辑和Alexa基础框架做了整合:
import ask_sdk_core.utils as ask_utils from ask_sdk_core.skill_builder import SkillBuilder from ask_sdk_core.dispatch_components import AbstractRequestHandler from ask_sdk_model import Response # 测试阶段用全局变量存用户计数状态,正式上线建议替换成DynamoDB存储,避免Lambda热启动导致状态串号 user_count_state = {} class LaunchRequestHandler(AbstractRequestHandler): """处理技能启动请求""" def can_handle(self, handler_input): return ask_utils.is_request_type("LaunchRequest")(handler_input) def handle(self, handler_input): welcome_text = "欢迎使用间隔计数器,你可以说类似指令:数到30,间隔2秒" return ( handler_input.response_builder .speak(welcome_text) .ask(welcome_text) .response ) class CountIntentHandler(AbstractRequestHandler): """处理计数启动请求""" def can_handle(self, handler_input): return ask_utils.is_intent_name("CountIntent")(handler_input) def handle(self, handler_input): slots = handler_input.request_envelope.request.intent.slots # 读取用户传入的两个参数 target_num = int(slots["endNumber"].value) interval_sec = int(slots["intervalSeconds"].value) # 基础参数校验,避免用户输入超出合理范围的数值 if target_num < 1 or target_num > 100: return handler_input.response_builder.speak("目标数值请设置在1到100之间").response if interval_sec < 1 or interval_sec > 10: return handler_input.response_builder.speak("间隔秒数请设置在1到10秒之间").response # 初始化当前用户的计数状态 user_id = handler_input.request_envelope.context.system.user.user_id user_count_state[user_id] = { "current": 1, "target": target_num, "interval": interval_sec } # 用SSML的break标签实现间隔停顿,不需要sleep阻塞进程 def build_count_ssml(): state = user_count_state[user_id] if state["current"] > state["target"]: return "计数完成。" cur_num = state["current"] state["current"] += 1 # 每播报一个数字,停顿对应间隔秒数,再接下一个数字的播报 return f"{cur_num}<break time='{state['interval']}s'/>{build_count_ssml()}" return ( handler_input.response_builder .speak(f"<speak>{build_count_ssml()}</speak>") .response ) class CancelOrStopIntentHandler(AbstractRequestHandler): """处理停止、取消指令""" def can_handle(self, handler_input): return (ask_utils.is_intent_name("AMAZON.CancelIntent")(handler_input) or ask_utils.is_intent_name("AMAZON.StopIntent")(handler_input)) def handle(self, handler_input): # 清空当前用户的计数状态 user_id = handler_input.request_envelope.context.system.user.user_id if user_id in user_count_state: del user_count_state[user_id] return handler_input.response_builder.speak("已停止计数。").response # 注册所有处理器,生成Lambda入口函数 sb = SkillBuilder() sb.add_request_handler(LaunchRequestHandler()) sb.add_request_handler(CountIntentHandler()) sb.add_request_handler(CancelOrStopIntentHandler()) lambda_handler = sb.lambda_handler()
关键注意事项
- 不要用
time.sleep()实现间隔:SSML的<break>标签是Alexa原生支持的停顿能力,停顿计时在Alexa端完成,完全不占用Lambda运行时长,不会触发8秒超时 - 不要用
print()输出语音内容:所有要播报的内容都要通过response_builder的speak方法传入,支持纯文本和SSML格式 - 单次SSML播报总时长不能超过240秒,如果要实现更长时间的计数,可以把长内容拆成多段,用AudioPlayer接口逐段推入播放队列即可,普通测试场景上面的递归生成SSML的方案完全够用
- 正式上线前把全局变量存储的用户状态替换成DynamoDB存储,避免Lambda热启动时多个用户的计数状态串号
内容的提问来源于stack exchange,提问作者thentangler
相关产品推荐
相关产品推荐

