湘里人 发表于 2025-1-13 21:37:52

K10AI机器人【基于官方micropython_unihiker_k10固件和百度千...

本帖最后由 湘里人 于 2025-1-14 16:26 编辑

一、刷micropython_unihiker_k10官方库
具体方法见官方介绍:烧录固件


二、百度千帆大模型:
https://qianfan.cloud.baidu.com/ ... fa8684dc35f119d4f3f
登陆界面

登陆成功后,点击页面上方的“大模型服务与开发平台ModelBuilder”

在右侧找到“应用接入”

创建应用:输入应用名称和应用描述,选择全部服务,点击“确定”创建应用。

应用创建完后,复制 API Key和 Secret Key用于“获取AccessToken”。



二、语音识别和语音合成应用
网址:https://console.bce.baidu.com/ai/#/ai/speech/app/create
1、创建应用。

2、应用创建完后,复制 API Key和 Secret Key用于“获取AccessToken”。



3、领取语音应用的免费额度
进入https://console.bce.baidu.com/ai-engine/speech/overview/index,领取免费资源



三、api调用
进入示例代码中心:https://console.bce.baidu.com/support/?u=dhead#/api
在“全部产品”中选择“千帆ModelBuilder”或“语音技术”

1.获取AccessToken



2、示例代码的获取,以语音识别为例。


四、界面美化   unihiker_k10官方库集成了LVGL(轻量级和多功能图形库),为创建美观的视觉效果提供了可能,但官方固件对中文支持不是很好。
1、建立中文字库,实现中文显示
具体操作见我以前的帖子:K10官方micropython_unihiker_k10固件支持中文显示的方法
2、机器人的动态表情,命名为change_eyes.py
from unihiker_k10 import screen, acce
import time, gc
import lvgl as lv
import fs_driver, math

# 初始化LVGL和屏幕
screen.init(dir=2)
scrn = lv.screen_active()
scrn.set_style_bg_color(lv.color_hex(0x000000), 0)

# 初始化文件系统驱动
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')


# 创建开口向上的弧线
arc3 = lv.arc(scrn)
arc3.set_size(200, 100)# 设置弧线的大小
arc3.set_bg_angles(90, 100)# 设置背景角度为0到180度,表示开口向上
arc3.set_angles(0, 180)# 设置显示角度为0到180度
arc3.align(lv.ALIGN.BOTTOM_MID, 50, -60)# 将弧线放置在屏幕底部中间位置,稍微向上移动

# 创建第一个蓝色实心球(眼球)
eye1 = lv.led(scrn)
eye1.set_size(60, 30)# 设置大小为32x20像素
eye1.set_color(lv.color_hex(0x0000FF))# 设置颜色为蓝色
eye1.align(lv.ALIGN.TOP_LEFT, 50, 90)# 将眼球放置在第一个圆球的中间

# 创建第二个蓝色实心球(眼球)
eye2 = lv.led(scrn)
eye2.set_size(60, 30)# 设置大小为32x20像素
eye2.set_color(lv.color_hex(0x0000FF))# 设置颜色为蓝色
eye2.align(lv.ALIGN.TOP_RIGHT, -50, 90)# 将眼球放置在第二个圆球的中间


def animate_mouth():
    for angle in range(360, 300, -10):
      arc3.set_angles(angle, angle + 180)# 设置显示角度为0到180度
#         time.sleep(2)# 持续2秒
      time.sleep(0.1)
    for angle in range(300, 360, 10):
      arc3.set_angles(angle, angle + 180)# 设置显示角度为0到180度
#         time.sleep(2)# 持续2秒
      time.sleep(0.1)


# 动态改变眼球的水平位置以模拟表情变化
def change_eyes():
#   # 向左看
    eye1.align(lv.ALIGN.TOP_LEFT, 40, 90)
    eye2.align(lv.ALIGN.TOP_RIGHT, -60, 90)
    time.sleep(0.2)# 持续1秒
   
    # 向右看
    eye1.align(lv.ALIGN.TOP_LEFT, 60, 90)
    eye2.align(lv.ALIGN.TOP_RIGHT, -40, 90)
    time.sleep(0.2)# 持续1秒
   
    # 回到中间
    eye1.align(lv.ALIGN.TOP_LEFT, 50, 90)
    eye2.align(lv.ALIGN.TOP_RIGHT, -50, 90)
    time.sleep(0.2)# 持续1秒
    animate_mouth()
# 启动眼球变化
change_eyes()

# 启动表情变化
# change_expression()


3、上传字库和机器人表情文件



五、主脚本
from unihiker_k10 import screen, mic, button, wifi,speaker
import ubinascii
import json
import time
import urequests as requests
import lvgl as lv
import fs_driver, math
from change_eyes import change_eyes
from machine import Timer
# 全局变量
scrn = None
font_cn = None
token= None
AItoken=None
text = ""
label_title = None



# 连接WiFi
def connect_wifi(ssid, password):
    wifi.connect(ssid=ssid, psd=password, timeout=50000)
    while not wifi.status():
      time.sleep(0.1)
    print("WiFi connected:", wifi.info())
   
   

# 初始化屏幕和字体
def init_screen():
    global scrn, font_cn, label_title
    screen.init(dir=2)
    scrn = lv.screen_active()
    scrn.set_style_bg_color(lv.color_hex(0x000000), 0)
    fs_drv = lv.fs_drv_t()
    fs_driver.fs_register(fs_drv, 'S')
    font_cn = lv.binfont_create("S:my_font_16.bin")
    if font_cn is None:
      print("字体加载失败")
    else:
      print("字体加载成功")
   
    # 创建一个新的标签
    label_title = lv.label(scrn)
    label_title.set_text("字体加载成功")
    label_title.set_width(200)
    label_title.align(lv.ALIGN.TOP_LEFT, 20, 20)
    if font_cn:
      label_title.set_style_text_font(font_cn, 0)# 设置中文字体
    scrn.set_style_bg_color(lv.color_hex(0x000000), 0)





# 更新标签的回调函数
def update_label():
    global text
    print("text:",text, time.localtime())
    label_title.set_text(text)




# 百度语音识别
def baidu_speech_recognize(audio_file, token):
    print("token:",token)
    url = "https://vop.baidu.com/server_api"
    with open(audio_file, "rb") as f:
      audio_data = f.read()
    base64_data = ubinascii.b2a_base64(audio_data)[:-1].decode('utf-8')
    payload = json.dumps({
      "format": "wav",
      "rate": 16000,
      "channel": 1,
      "cuid": "UNIHIKER_K10",
      "speech": base64_data,
      "len": len(audio_data),
      "token": token
    })
    headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    }
    response = requests.post(url, headers=headers, data=payload)
    print(response.text)
    data = json.loads(response.text)
    return ''.join(data['result'])

def Baidu_TTS(filename,text, token):
    # 设置请求参数
    params = {
      'tok': token,
      'tex': text,# 直接使用text,不需要quote_plus
      'per': 5,#基础音库:度小宇=1,度小美=0,度逍遥(基础)=3,度丫丫=4,精品音库:度逍遥(精品)=5003,度小鹿=5118,度博文=106,度小童=110,度小萌=111,度米朵=103,度小娇=5
      'spd': 5,#中语速
      'pit': 5,#中语调
      'vol': 9,#中音量
      'aue': 6,#wav,3为mp3格式(默认); 4为pcm-16k;5为pcm-8k;6为wav(内容同pcm-16k);
      'cuid': "ZZloekkfqvZFKhpVtFXGlAopgnHnHCgQ",#用户唯一标识
      'lan': 'zh',
      'ctp': 1#客户端类型选择,web端填写固定值1
    }
    headers = {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Accept': '*/*'
    }
    # 将参数编码,然后放入body,生成Request对象
    data = urlencode(params).encode('utf-8')
    # 发送POST请求
    response = requests.post("http://tsn.baidu.com/text2audio", headers=headers,data=data)
    # 检查响应状态码
    if response.status_code == 200:
      # 将返回的音频数据写入文件
      print("开始生成合成音频")
      
      gc.collect()# 写入前收集垃圾
      with open(filename, "wb") as f:
            f.write(response.content)
      gc.collect()# 写入后收集垃圾
      print("完成生成合成音频")
    else:
      print("无法获取音频文件")
   

def Baidu_Big_Model(text,AItoken):#大模型对话函数
    url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie_speed?access_token="+AItoken
   
    payload = json.dumps({
      "messages": [
            {
                "role": "user",
                "content": text
            }
      ],
      "temperature": 0.95,
      "top_p": 0.8,
      "penalty_score": 1,
      "enable_system_memory": False,
      "disable_search": False,
      "enable_citation": False,
      "system": "请将回答控制在30字,最后加个‘完’字结束对话",
      "response_format": "text"
    })
    headers = {
      'Content-Type': 'application/json'
    }

    response = requests.post(url, headers=headers, data=payload.encode('utf-8'))

    if response.status_code == 200:
      print(response.text)
      data = json.loads(response.text)
      decoded_str= data['result']   
      return(decoded_str)

def urlencode(params):#编码成 URL 编码格式的字符串
    encoded_pairs = []
    for key, value in params.items():
      # 确保键和值都是字符串
      key_str = str(key)
      value_str = str(value)
      # 手动实现简单的URL编码
      encoded_key = key_str.replace(" ", "%20")
      encoded_value = value_str.replace(" ", "%20")
      encoded_pairs.append(f"{encoded_key}={encoded_value}")
    return "&".join(encoded_pairs)

#获取token
def get_access_token(API_KEY,SECRET_KEY):
   
    url = "https://aip.baidubce.com/oauth/2.0/token"
    params = {
      'grant_type': 'client_credentials',
      'client_id': API_KEY,
      'client_secret': SECRET_KEY
    }
    data = urlencode(params).encode('utf-8')

    response = requests.post(url, data=data)
    access_token=json.loads(response.text)['access_token']
    print(access_token)
    return access_token





# 开始录音
def start_recording():
    global scrn, font_cn,label_title,token,AItoken,text
   
    print("开始录音")
    text ="开始对话"
    mic.recode_sys(name="sound.wav", time=5)
#   label_title.set_text("开始录音……")
# 上传录音并识别
    print("音频上传,进行百度识别")
    text ="音频上传,进行百度识别"
    time.sleep(0.1)
    label_title.set_text(text)
    time.sleep(0.1)
    text = baidu_speech_recognize("sound.wav", token)
    print("百度语音识别结果:", text)
    text = Baidu_Big_Model(text,AItoken)
    time.sleep(0.1)
    label_title.set_text(text)
    time.sleep(0.1)
    audio_file = "audio2.wav"
    Baidu_TTS(audio_file,text, token)#语音合成
    time.sleep(0.1)
    #播放音频
    print("播放音频")
    speaker.play_sys_music(audio_file)


def up_recording():
    global scrn, font_cn,label_title,token,AItoken
    label_title.set_text("功能暂未开发")
# 初始化板载按键传感器 A 和 B
def init_buttons():
    bt_a = button(button.a)
    bt_b = button(button.b)
    bt_a.event_pressed = start_recording
    bt_b.event_pressed = up_recording

# 主函数
def main():
    global scrn, font_cn,label_title,token,AItoken,text
    connect_wifi("r……", "wi……")
    init_screen()
    init_buttons()
    API_KEY = "sexS8Y……"
    SECRET_KEY = "nS2qMT……yjhTKrsWQ"
    token = get_access_token(API_KEY,SECRET_KEY)#语音识别和语音合成的token
      
    print(token)
    API_KEY = "ShZO7VeT……lmnF"
    SECRET_KEY = "b5bxt……xV"   
#   AItoken ="24.1bd84e812aa……………………"   
    AItoken = get_access_token(API_KEY,SECRET_KEY)#大模型的token
   
    text ="按A键开始与大模型对话"
    label_title.set_text(text)

#   tim1 = Timer(1)
#   tim1.init(period=100, mode=Timer.PERIODIC, callback=lambda t:update_label())
    while True:
#         #   # 启动眼球变化
      change_eyes()
      time.sleep(0.1)

if __name__ == "__main__":
    main()
   
   


需修改部分


文件打包【字库,change_eyes.py,main.py】

效果图
https://www.bilibili.com/video/BV15fctecEe2/?t=34.6
六、待完善之处
1、语音识别和合成调用所需时间太长
2、机器人的表情和文字显示会因其它程序的运行而中断
多次尝试,没有解决。







dreamful 发表于 2025-3-18 13:54:32

百度语音识别结果: 你好你好你好你好。
{"error_code":6,"error_msg":"No permission to access data"}
Traceback (most recent call last):
File "k10_base/_k10_base.py", line 153, in func
File "main.py", line 205, in start_recording
File "main.py", line 154, in Baidu_Big_Model
KeyError: result 卡在了大模型对话的这里了,不知道什么原因。

飒龘 发表于 6 天前

dreamful 发表于 2025-3-18 13:54
百度语音识别结果: 你好你好你好你好。
{"error_code":6,"error_msg":"No permission to access data"}
Tr ...

我知道,这是因为他写错了一个地方。语音合成的api和大模型的api是不一样。你需要去语音那块把语音合成的api给填一下。
页: [1]
查看完整版本: K10AI机器人【基于官方micropython_unihiker_k10固件和百度千...