smartpi 0.1.40__py3-none-any.whl → 0.1.42__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. smartpi/__init__.py +1 -1
  2. smartpi/ai_asr.py +1037 -0
  3. smartpi/ai_llm.py +934 -0
  4. smartpi/ai_tts.py +938 -0
  5. smartpi/ai_vad.py +83 -0
  6. smartpi/base_driver.py +265 -11
  7. smartpi/local_model.py +432 -0
  8. smartpi/mcp_client.py +100 -0
  9. smartpi/mcp_fastmcp.py +322 -0
  10. smartpi/mcp_intent_recognizer.py +408 -0
  11. smartpi/models/__init__.py +0 -0
  12. smartpi/models/snakers4_silero-vad/__init__.py +0 -0
  13. smartpi/models/snakers4_silero-vad/hubconf.py +56 -0
  14. smartpi/models/snakers4_silero-vad/src/silero_vad/data/silero_vad.jit +0 -0
  15. smartpi/models/snakers4_silero-vad/src/silero_vad/data/silero_vad.onnx +0 -0
  16. smartpi/models/snakers4_silero-vad/src/silero_vad/data/silero_vad_16k_op15.onnx +0 -0
  17. smartpi/models/snakers4_silero-vad/src/silero_vad/data/silero_vad_half.onnx +0 -0
  18. smartpi/onnx_pose_workflow.py +1 -1
  19. smartpi/rknn_pose_workflow.py +1 -1
  20. smartpi/tencentcloud-speech-sdk-python/__init__.py +1 -0
  21. smartpi/tencentcloud-speech-sdk-python/asr/__init__.py +0 -0
  22. smartpi/tencentcloud-speech-sdk-python/asr/flash_recognizer.py +178 -0
  23. smartpi/tencentcloud-speech-sdk-python/asr/speech_recognizer.py +311 -0
  24. smartpi/tencentcloud-speech-sdk-python/common/__init__.py +1 -0
  25. smartpi/tencentcloud-speech-sdk-python/common/credential.py +6 -0
  26. smartpi/tencentcloud-speech-sdk-python/common/log.py +16 -0
  27. smartpi/tencentcloud-speech-sdk-python/common/utils.py +7 -0
  28. smartpi/tencentcloud-speech-sdk-python/examples/tts/tts_text.txt +60 -0
  29. smartpi/tencentcloud-speech-sdk-python/soe/__init__.py +0 -0
  30. smartpi/tencentcloud-speech-sdk-python/soe/speaking_assessment.py +276 -0
  31. smartpi/tencentcloud-speech-sdk-python/tts/__init__.py +0 -0
  32. smartpi/tencentcloud-speech-sdk-python/tts/flowing_speech_synthesizer.py +294 -0
  33. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer.py +144 -0
  34. smartpi/tencentcloud-speech-sdk-python/tts/speech_synthesizer_ws.py +234 -0
  35. smartpi/tencentcloud-speech-sdk-python/vc/__init__.py +0 -0
  36. smartpi/tencentcloud-speech-sdk-python/vc/speech_convertor_ws.py +237 -0
  37. {smartpi-0.1.40.dist-info → smartpi-0.1.42.dist-info}/METADATA +1 -1
  38. smartpi-0.1.42.dist-info/RECORD +76 -0
  39. smartpi-0.1.40.dist-info/RECORD +0 -44
  40. {smartpi-0.1.40.dist-info → smartpi-0.1.42.dist-info}/WHEEL +0 -0
  41. {smartpi-0.1.40.dist-info → smartpi-0.1.42.dist-info}/top_level.txt +0 -0
smartpi/ai_vad.py ADDED
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+ import sys
3
+ import os
4
+ import time
5
+ import numpy as np
6
+
7
+ class VADProviderBase:
8
+ """VAD provider base class"""
9
+ @staticmethod
10
+ def create_vad_instance(
11
+ vad_mini_volume=1000,
12
+ vad_mini_length=500,
13
+ vad_pause_timeout=3000,
14
+ vad_silence_timeout=10000,
15
+ threshold=0.02
16
+ ):
17
+ """Factory method to create VAD instance - always returns EnergyVADProvider"""
18
+ # 忽略vad_mini_volume, vad_mini_length, vad_silence_timeout参数
19
+ # 将vad_pause_timeout作为min_silence_duration_ms传递
20
+ return EnergyVADProvider(
21
+ threshold=threshold,
22
+ min_silence_duration_ms=vad_pause_timeout
23
+ )
24
+
25
+ class EnergyVADProvider(VADProviderBase):
26
+ """Audio energy-based VAD provider"""
27
+ def __init__(self, threshold=0.02, min_silence_duration_ms=300):
28
+ print(f"Initializing EnergyVAD: threshold={threshold}, min_silence_duration_ms={min_silence_duration_ms}")
29
+ # 初始化VAD配置,使用默认值作为备选
30
+ self.vad_threshold = float(threshold) if threshold else 0.02
31
+ self.silence_threshold_ms = int(min_silence_duration_ms) if min_silence_duration_ms else 300
32
+ print("EnergyVAD initialized successfully")
33
+
34
+ def is_vad(self, conn, audio_data):
35
+ """使用音频能量检测语音活动"""
36
+ try:
37
+ # 确保conn对象有必要的属性
38
+ if not hasattr(conn, 'client_audio_buffer'):
39
+ conn.client_audio_buffer = []
40
+ if not hasattr(conn, 'client_have_voice'):
41
+ conn.client_have_voice = False
42
+ if not hasattr(conn, 'client_have_voice_last_time'):
43
+ conn.client_have_voice_last_time = 0
44
+ if not hasattr(conn, 'client_voice_stop'):
45
+ conn.client_voice_stop = False
46
+
47
+ # 将新数据加入缓冲区
48
+ conn.client_audio_buffer.extend(audio_data)
49
+
50
+ # 处理缓冲区中的数据
51
+ client_have_voice = False
52
+ # 对于能量检测,我们可以使用较小的块大小,例如256采样点
53
+ while len(conn.client_audio_buffer) >= 256 * 2:
54
+ # 提取前256个采样点(512字节)
55
+ chunk = bytes(conn.client_audio_buffer[:256 * 2])
56
+ conn.client_audio_buffer = conn.client_audio_buffer[256 * 2:]
57
+
58
+ # 计算能量
59
+ audio_int16 = np.frombuffer(chunk, dtype=np.int16)
60
+ energy = np.abs(audio_int16).mean()
61
+
62
+ client_have_voice = energy > self.vad_threshold
63
+
64
+ # 更新VAD状态
65
+ if client_have_voice:
66
+ conn.client_have_voice = True
67
+ conn.client_have_voice_last_time = time.time() * 1000
68
+ conn.client_voice_stop = False
69
+ elif conn.client_have_voice:
70
+ # 检查静默时间
71
+ stop_duration = time.time() * 1000 - conn.client_have_voice_last_time
72
+ if stop_duration >= self.silence_threshold_ms:
73
+ conn.client_have_voice = False
74
+ conn.client_voice_stop = True
75
+
76
+ return client_have_voice
77
+ except Exception as e:
78
+ print(f"能量检测出错: {e}")
79
+ return False
80
+
81
+ def reset_states(self):
82
+ """重置VAD状态"""
83
+ pass # 状态现在存储在conn对象中,不需要在这里重置
smartpi/base_driver.py CHANGED
@@ -130,14 +130,15 @@ def write_data(command_h: int, command_l: int, send_data: bytes= None, lock: byt
130
130
  send_packet = [0x86, 0xAB, 0x00, 0x09, command_h, command_l, 0x01, pro_check, 0xCF]
131
131
  send_bytes = bytes(send_packet)
132
132
 
133
- # for x in send_bytes:
134
- # print(f"{x:02X}", end=' ')
135
- # print("\n")
133
+ print("send:")
134
+ for x in send_bytes:
135
+ print(f"{x:02X}", end=' ')
136
+ print("\n")
136
137
  buf_clear()
137
138
  serial_lock.acquire() #获取线程锁
138
139
  fcntl.flock(ser.fileno(), fcntl.LOCK_EX) #进程锁,阻塞其他进程
139
140
  ser.write(send_bytes)
140
- serial_lock.release() #释放线程锁
141
+ serial_lock.release() #释放线程锁
141
142
  fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
142
143
  elif lock == False:
143
144
  buffer = bytearray()
@@ -152,9 +153,10 @@ def write_data(command_h: int, command_l: int, send_data: bytes= None, lock: byt
152
153
  send_packet = [0x86, 0xAB, 0x00, 0x09, command_h, command_l, 0x01, pro_check, 0xCF]
153
154
  send_bytes = bytes(send_packet)
154
155
 
155
- # for x in send_bytes:
156
- # print(f"{x:02X}", end=' ')
157
- # print("\n")
156
+ print("send:")
157
+ for x in send_bytes:
158
+ print(f"{x:02X}", end=' ')
159
+ print("\n")
158
160
  buf_clear()
159
161
  ser.write(send_bytes)
160
162
 
@@ -502,11 +504,7 @@ def mode_change(send_data: str) -> Optional[bytes]:
502
504
  return None
503
505
 
504
506
  def shut_down():
505
- serial_lock.acquire() #获取线程锁
506
- fcntl.flock(ser.fileno(), fcntl.LOCK_EX) # 进程锁,阻塞其他进程
507
507
  write_data(0XFF, 0XFE)
508
- serial_lock.release() #释放线程锁
509
- fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
510
508
  time.sleep(0.5)
511
509
 
512
510
  def power_button_detec() -> bytes:
@@ -551,6 +549,262 @@ def buf_clear():
551
549
  fcntl.ioctl(ser.fileno(), termios.TCIOFLUSH)
552
550
  except:
553
551
  pass
552
+
553
+
554
+ def enter_bootloader_mode():
555
+ """进入Bootloader模式"""
556
+ serial_lock.acquire() #获取线程锁
557
+ fcntl.flock(ser.fileno(), fcntl.LOCK_EX) #进程锁,阻塞其他进程
558
+ write_data(BOOT_UPDATE_H, BOOT_UPDATE_L, None, False)
559
+ start_time = time.time()
560
+ while True:
561
+ response =process_received_data()
562
+ if response:
563
+ serial_lock.release() #释放线程锁
564
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
565
+ buf_clear()
566
+ print("get:")
567
+ for x in response:
568
+ print(f"{x:02X}", end=' ')
569
+ print("\n")
570
+ return True
571
+ else:
572
+ if time.time() - start_time > 2:
573
+ print("读取超时")
574
+ buf_clear()
575
+ serial_lock.release() #释放线程锁
576
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
577
+ return None
578
+
579
+ def send_update_request():
580
+ """发送更新请求"""
581
+ serial_lock.acquire() #获取线程锁
582
+ fcntl.flock(ser.fileno(), fcntl.LOCK_EX) #进程锁,阻塞其他进程
583
+ write_data(UPDATE_REQUEST_H, UPDATE_REQUEST_L, None, False)
584
+ start_time = time.time()
585
+ while True:
586
+ response = process_received_data()
587
+ if response:
588
+ serial_lock.release() #释放线程锁
589
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
590
+ buf_clear()
591
+ print("get:")
592
+ for x in response:
593
+ print(f"{x:02X}", end=' ')
594
+ print("\n")
595
+ return True
596
+ else:
597
+ if time.time() - start_time > 2:
598
+ print("更新请求超时")
599
+ buf_clear()
600
+ serial_lock.release() #释放线程锁
601
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
602
+ return None
603
+
604
+ def send_file_size(file_size):
605
+ """发送文件大小"""
606
+ serial_lock.acquire() #获取线程锁
607
+ fcntl.flock(ser.fileno(), fcntl.LOCK_EX) #进程锁,阻塞其他进程
608
+
609
+ try:
610
+ # 将文件大小转换为4字节小端序
611
+ size_data = struct.pack('<I', file_size)
612
+ write_data(MAX_COM_LEN_H, MAX_COM_LEN_L, size_data, False)
613
+
614
+ start_time = time.time()
615
+ while True:
616
+ response = process_received_data()
617
+ if response:
618
+ serial_lock.release() #释放线程锁
619
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
620
+ buf_clear()
621
+ for x in response:
622
+ print(f"{x:02X}", end=' ')
623
+ print("\n")
624
+ return True
625
+ else:
626
+ if time.time() - start_time > 2:
627
+ print("发送文件大小超时")
628
+ buf_clear()
629
+ serial_lock.release() #释放线程锁
630
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
631
+ return None
632
+ except Exception as e:
633
+ print(f"发送文件大小出错: {e}")
634
+ serial_lock.release() #释放线程锁
635
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
636
+ return None
637
+
638
+ def send_file_data_chunk(chunk_data, chunk_num, total_chunks):
639
+ """发送文件数据块"""
640
+ serial_lock.acquire() #获取线程锁
641
+ fcntl.flock(ser.fileno(), fcntl.LOCK_EX) #进程锁,阻塞其他进程
642
+
643
+ try:
644
+ write_data(PAGE_SEND_H, PAGE_SEND_L, chunk_data, False)
645
+
646
+ start_time = time.time()
647
+ while True:
648
+ response = process_received_data()
649
+ if response:
650
+ serial_lock.release() #释放线程锁
651
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
652
+ buf_clear()
653
+ # 显示进度
654
+ progress = (chunk_num + 1) * 100 // total_chunks
655
+ if progress % 10 == 0 or chunk_num == total_chunks - 1:
656
+ print(f"传输进度: {progress}% ({chunk_num+1}/{total_chunks})")
657
+ return True
658
+ else:
659
+ if time.time() - start_time > 2:
660
+ print(f"第{chunk_num+1}块数据发送超时")
661
+ buf_clear()
662
+ serial_lock.release() #释放线程锁
663
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
664
+ return None
665
+ except Exception as e:
666
+ print(f"发送数据块出错: {e}")
667
+ serial_lock.release() #释放线程锁
668
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN) # 释放进程锁
669
+ return None
670
+
671
+ def send_restart_command():
672
+ """发送重启命令"""
673
+ print("发送重启指令...")
674
+ serial_lock.acquire()
675
+ fcntl.flock(ser.fileno(), fcntl.LOCK_EX)
676
+
677
+ try:
678
+ # 发送重启命令 (0xFF 0xFF)
679
+ write_data(0xFF, 0xFF, None, False)
680
+
681
+ # 重启不需要等待响应,因为设备会立即重启
682
+ time.sleep(0.5)
683
+ print("重启指令已发送")
684
+ return True
685
+ except Exception as e:
686
+ print(f"发送重启指令出错: {e}")
687
+ return False
688
+ finally:
689
+ serial_lock.release()
690
+ fcntl.flock(ser.fileno(), fcntl.LOCK_UN)
691
+
692
+ def transmit_file_to_usb(file_path, chunk_size=512):
693
+ """
694
+ 传输文件到虚拟U盘的主函数
695
+
696
+ Args:
697
+ file_path: 要传输的文件路径
698
+ chunk_size: 每个数据块的大小(默认512字节)
699
+
700
+ Returns:
701
+ bool: 传输是否成功
702
+ """
703
+ print("=" * 50)
704
+ print("开始文件传输到虚拟U盘")
705
+ print("=" * 50)
706
+
707
+ # 检查文件是否存在
708
+ if not os.path.exists(file_path):
709
+ print(f"错误: 文件不存在 - {file_path}")
710
+ return False
711
+
712
+ # 获取文件大小
713
+ try:
714
+ file_size = os.path.getsize(file_path)
715
+ print(f"文件: {os.path.basename(file_path)}")
716
+ print(f"大小: {file_size} 字节")
717
+ except Exception as e:
718
+ print(f"获取文件大小出错: {e}")
719
+ return False
720
+
721
+ # 确保串口已初始化
722
+ if not ser.is_open:
723
+ print("初始化串口...")
724
+ uart3_init()
725
+ if not ser.is_open:
726
+ print("串口初始化失败")
727
+ return False
728
+
729
+ # 1. 进入Bootloader模式
730
+ enter_bootloader_mode()
731
+
732
+ time.sleep(5)
733
+
734
+ # 2. 发送更新请求
735
+ if not send_update_request():
736
+ print("更新请求失败,传输中止")
737
+ return False
738
+
739
+ # # 3. 发送文件大小
740
+ # if not send_file_size(file_size):
741
+ # print("文件大小发送失败,传输中止")
742
+ # return False
743
+ #
744
+ # # 4. 读取并发送文件数据
745
+ # print("开始传输文件数据...")
746
+ # try:
747
+ # with open(file_path, 'rb') as f:
748
+ # total_chunks = (file_size + chunk_size - 1) // chunk_size
749
+ #
750
+ # for chunk_num in range(total_chunks):
751
+ # # 读取数据块
752
+ # chunk_data = f.read(chunk_size)
753
+ # if not chunk_data:
754
+ # print(f"错误: 第{chunk_num+1}块数据读取失败")
755
+ # return False
756
+ #
757
+ # # 如果数据块不足chunk_size,填充0(可选)
758
+ # if len(chunk_data) < chunk_size:
759
+ # chunk_data += b'\x00' * (chunk_size - len(chunk_data))
760
+ #
761
+ # # 发送数据块
762
+ # if not send_file_data_chunk(chunk_data, chunk_num, total_chunks):
763
+ # print(f"第{chunk_num+1}块数据发送失败,传输中止")
764
+ # return False
765
+ #
766
+ # print("文件数据传输完成!")
767
+ #
768
+ # except Exception as e:
769
+ # print(f"读取或发送文件数据出错: {e}")
770
+ # return False
771
+ #
772
+ # # 5. 发送重启命令
773
+ # if not send_restart_command():
774
+ # print("重启指令发送失败")
775
+ # return False
776
+ #
777
+ # print("=" * 50)
778
+ # print("文件传输成功完成!")
779
+ # print("文件已保存到虚拟U盘")
780
+ # print("设备将自动重启...")
781
+ # print("=" * 50)
782
+
783
+ # 等待设备重启
784
+ time.sleep(3)
785
+ return True
786
+
787
+ def example_file_transfer():
788
+ """文件传输使用示例"""
789
+ print("文件传输示例")
790
+ print("-" * 30)
791
+
792
+ # 初始化串口
793
+ uart3_init()
794
+
795
+ # 指定要传输的文件路径
796
+ # 请根据实际情况修改
797
+ file_path = "/home/zmrobo/UPDATE.DAT"
798
+
799
+ # 执行文件传输
800
+ success = transmit_file_to_usb(file_path)
801
+
802
+ if success:
803
+ print("文件传输成功!")
804
+ return 0
805
+ else:
806
+ print("文件传输失败!")
807
+ return 1
554
808
 
555
809
  """H2-RCU初始化"""
556
810
  def smartpi_init():