#M5StackLLM セッションをローカル実行する -2-

シリアルダメそうなので、もう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