シリアルダメそうなので、もうtelnetしかないのかね? というわけで、ざっくり書き直し。

telnetlib3入れる。まぁ、rootだと注意されるけど気にしない。
root@m5stack-LLM:~# pip install telnetlib3
Collecting telnetlib3
Downloading telnetlib3-2.0.4-py2.py3-none-any.whl (93 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 93.3/93.3 KB 877.0 kB/s eta 0:00:00
Installing collected packages: telnetlib3
Successfully installed telnetlib3-2.0.4
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
こんな感じ。
#!/usr/bin/env python3
import asyncio
import telnetlib3
import json
DEFAULT_TIMEOUT = 120 # 各コマンドの応答待ちタイムアウト(秒)
async def send_command_and_wait(reader, writer, command, timeout=DEFAULT_TIMEOUT):
"""
JSON コマンドを送信し、タイムアウト付きで1行分の応答を待つ
"""
command_str = json.dumps(command)
full_command = command_str + "\n"
writer.write(full_command)
await writer.drain()
print("送信:", command_str)
try:
response_line = await asyncio.wait_for(reader.readline(), timeout=timeout)
except asyncio.TimeoutError:
raise TimeoutError(f"タイムアウト({timeout}秒): 応答がありません。")
response_line = response_line.strip()
try:
response_json = json.loads(response_line)
except Exception as e:
raise ValueError(f"応答のパースに失敗しました: {e}")
print("受信:", response_json)
return response_json
async def receiver_loop(reader):
"""
Telnet接続から継続的に JSON メッセージを受信し、表示するループ
"""
print("受信ループ開始:常時メッセージ待機中...")
while True:
try:
line = await reader.readline()
if not line:
print("リモート側が接続を閉じました。")
break
line = line.strip()
if not line:
continue
try:
msg = json.loads(line)
print("非同期受信:", msg)
except Exception as e:
print("JSONパースエラー:", e, "受信データ:", line)
except Exception as e:
print("受信ループで例外発生:", e)
break
async def main():
host = '127.0.0.1'
port = 10001
try:
reader, writer = await telnetlib3.open_connection(host, port)
print(f"Telnet接続確立: {host}:{port}")
except Exception as e:
print("Telnet接続に失敗:", e)
return
初期化・セットアップ用コマンドのリスト
commands = [
{
"request_id": "1",
"work_id": "audio",
"action": "setup",
"object": "audio.setup",
"data": {
"capcard": 0,
"capdevice": 0,
"capVolume": 0.5,
"playcard": 0,
"playdevice": 1,
"playVolume": 0.5
}
},
{
"request_id": "2",
"work_id": "kws",
"action": "setup",
"object": "kws.setup",
"data": {
"model": "sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01",
"response_format": "kws.bool",
"input": "sys.pcm",
"enoutput": True,
"kws": "ECHO"
}
},
{
"request_id": "asr_setup",
"work_id": "asr",
"action": "setup",
"object": "asr.setup",
"data": {
"model": "sherpa-ncnn-streaming-zipformer-20M-2023-02-17",
"response_format": "asr.utf-8.stream",
"enoutput": True,
"enkws": True,
"rule1": 2.4,
"rule2": 1.2,
"rule3": 30,
"input": ["sys.pcm", "kws.1001"]
}
},
{
"request_id": "llm_setup",
"work_id": "llm",
"action": "setup",
"object": "llm.setup",
"data": {
"model": "qwen2.5-0.5B-prefill-20e",
"response_format": "llm.utf-8.stream",
"enoutput": True,
"enkws": True,
"max_token_len": 127,
"prompt": "",
"input": ["asr.1002", "kws.1001"]
}
},
{
"request_id": "tts_setup",
"work_id": "melotts",
"action": "setup",
"object": "melotts.setup",
"data": {
"model": "melotts_zh-cn",
"response_format": "sys.pcm",
"input": ["llm.1003", "kws.1001"],
"enoutput": False,
"enaudio": True
}
}
]
各コマンドを順次送信して応答を待つ
for cmd in commands:
try:
response = await send_command_and_wait(reader, writer, cmd, timeout=DEFAULT_TIMEOUT)
error_code = response.get("error", {}).get("code")
if error_code != 0:
print("エラー応答:", response)
break
except Exception as e:
print("コマンド送信中に例外発生:", e)
break
await asyncio.sleep(0.5)
print("初期化完了。セッションは維持し、受信待ち状態に入ります。")
try:
初期化後も接続を維持して常時受信待ち
await receiver_loop(reader)
except KeyboardInterrupt:
print("KeyboardInterruptを受信、受信ループ終了。")
finally:
writer.close()
print("Telnet接続をクローズしました。")
if __name__ == "__main__":
asyncio.run(main())
実行。
root@m5stack-LLM:~# systemctl restart llm-*
root@m5stack-LLM:~# ./llm.py
Telnet接続確立: 127.0.0.1:10001
送信: {"request_id": "1", "work_id": "audio", "action": "setup", "object": "audio.setup", "data": {"capcard": 0, "capdevice": 0, "capVolume": 0.5, "playcard": 0, "playdevice": 1, "playVolume": 0.5}}
受信: {'created': 1740817538, 'data': 'None', 'error': {'code': 0, 'message': ''}, 'object': 'None', 'request_id': '1', 'work_id': 'audio'}
送信: {"request_id": "2", "work_id": "kws", "action": "setup", "object": "kws.setup", "data": {"model": "sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01", "response_format": "kws.bool", "input": "sys.pcm", "enoutput": true, "kws": "ECHO"}}
受信: {'created': 1740817560, 'data': 'None', 'error': {'code': 0, 'message': ''}, 'object': 'None', 'request_id': '2', 'work_id': 'kws.1001'}
送信: {"request_id": "asr_setup", "work_id": "asr", "action": "setup", "object": "asr.setup", "data": {"model": "sherpa-ncnn-streaming-zipformer-20M-2023-02-17", "response_format": "asr.utf-8.stream", "enoutput": true, "enkws": true, "rule1": 2.4, "rule2": 1.2, "rule3": 30, "input": ["sys.pcm", "kws.1001"]}}
受信: {'created': 1740817561, 'data': 'None', 'error': {'code': 0, 'message': ''}, 'object': 'None', 'request_id': 'asr_setup', 'work_id': 'asr.1002'}
送信: {"request_id": "llm_setup", "work_id": "llm", "action": "setup", "object": "llm.setup", "data": {"model": "qwen2.5-0.5B-prefill-20e", "response_format": "llm.utf-8.stream", "enoutput": true, "enkws": true, "max_token_len": 127, "prompt": "", "input": ["asr.1002", "kws.1001"]}}
受信: {'created': 1740817565, 'data': 'None', 'error': {'code': 0, 'message': ''}, 'object': 'None', 'request_id': 'llm_setup', 'work_id': 'llm.1003'}
送信: {"request_id": "tts_setup", "work_id": "melotts", "action": "setup", "object": "melotts.setup", "data": {"model": "melotts_zh-cn", "response_format": "sys.pcm", "input": ["llm.1003", "kws.1001"], "enoutput": false, "enaudio": true}}
受信: {'created': 1740817578, 'data': 'None', 'error': {'code': 0, 'message': ''}, 'object': 'None', 'request_id': 'tts_setup', 'work_id': 'melotts.1004'}
初期化完了。セッションは維持し、受信待ち状態に入ります。
受信ループ開始:常時メッセージ待機中...
うまくいった。
ECHOと話しかけると、応答も表示される。
非同期受信: {'created': 1740817620, 'data': True, 'error': {'code': 0, 'message': ''}, 'object': 'kws.bool', 'request_id': '2', 'work_id': 'kws.1001'}
非同期受信: {'created': 1740817624, 'data': {'delta': ' only', 'finish': False, 'index': 0}, 'error': {'code': 0, 'message': ''}, 'object': 'asr.utf-8.stream', 'request_id': 'asr_setup', 'work_id': 'asr.1002'}
(snip)
オリジナル投稿:
#M5StackLLM セッションをローカル実行する -2-|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/9414188



