k230/k230/agent_client_http.py

247 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import socket
import json
import time
import os
import network
import struct
import gc
from audio_module import AudioPlayer
# Try importing wave, handle different environments
try:
import media.wave as wave
except ImportError:
try:
import wave
except ImportError:
wave = None
class AgentClientHTTP:
"""
K230 Agent Client (HTTP)
"""
def __init__(self, server_host, server_port=8000):
self._server_host = server_host
self._server_port = server_port
self._sta = None
self._is_connected = False
def connect_wifi(self, ssid, password=None, timeout=15):
"""
Connect to WiFi
"""
self._sta = network.WLAN(network.STA_IF)
self._sta.active(True)
if password:
self._sta.connect(ssid, password)
else:
self._sta.connect(ssid)
print("正在连接WiFi: " + ssid + "...")
start_time = time.time()
while not self._sta.isconnected():
if time.time() - start_time > timeout:
raise RuntimeError("WiFi连接超时: " + ssid)
time.sleep(1)
try:
os.exitpoint()
except BaseException:
pass
ip = self._sta.ifconfig()[0]
print("WiFi连接成功! IP: " + ip)
self._is_connected = True
return ip
def disconnect(self):
"""断开网络连接"""
if self._sta:
if self._sta.isconnected():
self._sta.disconnect()
self._sta.active(False)
print("WiFi已断开网卡已关闭。")
self._is_connected = False
def trigger_abnormal_state(self, reason, context_data=None):
"""
Trigger abnormal state and save response as WAV.
"""
url_path = "/abnormal_trigger"
payload = {
"type": "abnormal_trigger",
"trigger_reason": reason,
"enable_streaming": True,
"context_data": context_data or {}
}
body_json = json.dumps(payload)
print(f"[AgentHTTP] 请求服务器: {self._server_host}:{self._server_port}...")
try:
# Send Request
response_data = self._send_http_request(url_path, body_json)
# Parse Header/Body
header_end = response_data.find(b"\r\n\r\n")
if header_end == -1:
print("[AgentHTTP] 响应格式错误")
return None
body_bytes = response_data[header_end + 4:]
if len(body_bytes) == 0:
print("[AgentHTTP] 响应正文为空")
return None
print(f"[AgentHTTP] 成功接收音频数据: {len(body_bytes)} 字节")
# Save as WAV file
# TTS server returns 24000Hz, 1 channel, 16bit (2 bytes) PCM
wav_file = "/sdcard/agent_response.wav"
self._save_wav(wav_file, body_bytes, rate=24000, channels=1, sampwidth=2)
return wav_file
except Exception as e:
print(f"[AgentHTTP] 请求失败: {e}")
return None
def _save_wav(self, filename, pcm_data, rate=24000, channels=1, sampwidth=2):
"""
Save PCM data with WAV header
"""
print(f"[AgentHTTP] 保存 WAV 文件: {filename} (Rate: {rate}, Ch: {channels})")
try:
if wave:
# Use wave module if available
wf = wave.open(filename, 'wb')
wf.set_channels(channels)
wf.set_sampwidth(sampwidth)
wf.set_framerate(rate)
wf.write_frames(pcm_data)
wf.close()
else:
# Manual WAV header creation
total_len = len(pcm_data) + 36
header = struct.pack(
'<4sI4s4sIHHIIHH4sI',
b'RIFF',
total_len,
b'WAVE',
b'fmt ',
16,
1,
channels,
rate,
rate * channels * sampwidth,
channels * sampwidth,
sampwidth * 8,
b'data',
len(pcm_data))
with open(filename, 'wb') as f:
f.write(header)
f.write(pcm_data)
except Exception as e:
print(f"[AgentHTTP] 保存 WAV 失败: {e}")
def play_audio_file(self, file_path):
"""
Play audio file using AudioPlayer.play_file (handles WAV)
"""
if not file_path:
return
print(f"[AgentHTTP] 正在播放: {file_path}...")
player = None
try:
player = AudioPlayer()
# play_file will init and start stream, write frames, and then deinit in
# finally block
player.play_file(file_path)
print("[AgentHTTP] 播放完成。")
except Exception as e:
print(f"[AgentHTTP] 播放出错: {e}")
finally:
# Double check deinit to prevent noise/resource leak
if player:
try:
if player.is_running: # Check if flag exists
player.deinit()
except BaseException:
pass
def _send_http_request(self, path, body_json):
"""
Send HTTP POST
"""
addr_info = socket.getaddrinfo(self._server_host, self._server_port)
addr = addr_info[0][-1]
s = socket.socket()
s.settimeout(10)
try:
s.connect(addr)
body_bytes = body_json.encode('utf-8')
req = f"POST {path} HTTP/1.1\r\n"
req += f"Host: {self._server_host}:{self._server_port}\r\n"
req += "Content-Type: application/json\r\n"
req += f"Content-Length: {len(body_bytes)}\r\n"
req += "Connection: close\r\n\r\n"
s.send(req.encode('utf-8'))
s.send(body_bytes)
response = bytearray()
while True:
chunk = s.recv(4096)
if not chunk:
break
response.extend(chunk)
return response
finally:
s.close()
if __name__ == "__main__":
# ========== CONFIG ==========
WIFI_SSID = "dongshengwu"
WIFI_PASSWORD = "wds666666"
SERVER_HOST = "172.20.10.2"
SERVER_PORT = 8000
# ============================
client = AgentClientHTTP(server_host=SERVER_HOST, server_port=SERVER_PORT)
try:
# 1. Connect
client.connect_wifi(WIFI_SSID, WIFI_PASSWORD)
# 2. Trigger & Save
print("\n[测试] 触发皮肤状态异常提示...")
wav_file = client.trigger_abnormal_state("poor_skin")
# 3. Play
if wav_file:
client.play_audio_file(wav_file)
except Exception as e:
print("程序异常: " + str(e))
finally:
# 4. Clean up resources
print("\n[资源清理] 断开 WiFi 并回收资源...")
gc.collect()
print("测试结束,已安全退出。")