limi-sdk 0.1.0__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.
- limi/__init__.py +5 -0
- limi/audio_utils.py +2 -0
- limi/client.py +105 -0
- limi/exceptions.py +15 -0
- limi_sdk-0.1.0.dist-info/METADATA +9 -0
- limi_sdk-0.1.0.dist-info/RECORD +8 -0
- limi_sdk-0.1.0.dist-info/WHEEL +5 -0
- limi_sdk-0.1.0.dist-info/top_level.txt +1 -0
limi/__init__.py
ADDED
limi/audio_utils.py
ADDED
limi/client.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import base64
|
|
4
|
+
import websockets
|
|
5
|
+
from typing import Optional, Callable
|
|
6
|
+
from .exceptions import LimiAuthError, LimiConnectionError
|
|
7
|
+
|
|
8
|
+
class LimiClient:
|
|
9
|
+
"""
|
|
10
|
+
Limi API uchun rasmiy Python klienti.
|
|
11
|
+
|
|
12
|
+
Misol:
|
|
13
|
+
client = LimiClient(api_key="limi_...")
|
|
14
|
+
client.on_transcript(lambda text: print(f"Siz: {text}"))
|
|
15
|
+
client.on_response(lambda text: print(f"Limi: {text}"))
|
|
16
|
+
await client.start()
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
_BASE_URL = "wss://sotalimi.onrender.com/api/v2/live-brain" # ICHKI, mijoz KO'RMAYDI
|
|
20
|
+
|
|
21
|
+
def __init__(self, api_key: str, embodiment_preset_id: Optional[str] = None):
|
|
22
|
+
if not api_key or not api_key.startswith("limi_"):
|
|
23
|
+
raise ValueError("Noto'g'ri API kalit formati.")
|
|
24
|
+
self.api_key = api_key
|
|
25
|
+
self.embodiment_preset_id = embodiment_preset_id
|
|
26
|
+
self._ws = None
|
|
27
|
+
self._on_transcript_cb: Optional[Callable] = None
|
|
28
|
+
self._on_response_cb: Optional[Callable] = None
|
|
29
|
+
self._on_error_cb: Optional[Callable] = None
|
|
30
|
+
|
|
31
|
+
def on_transcript(self, callback: Callable[[str], None]):
|
|
32
|
+
"""Foydalanuvchi gapi matnga aylantirilganda chaqiriladi."""
|
|
33
|
+
self._on_transcript_cb = callback
|
|
34
|
+
|
|
35
|
+
def on_response(self, callback: Callable[[str], None]):
|
|
36
|
+
"""Limi javob berganda chaqiriladi."""
|
|
37
|
+
self._on_response_cb = callback
|
|
38
|
+
|
|
39
|
+
def on_error(self, callback: Callable[[str], None]):
|
|
40
|
+
"""Xato yuz berganda chaqiriladi."""
|
|
41
|
+
self._on_error_cb = callback
|
|
42
|
+
|
|
43
|
+
async def _connect(self):
|
|
44
|
+
try:
|
|
45
|
+
self._ws = await websockets.connect(self._BASE_URL)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
raise LimiConnectionError(f"Serverga ulanib bo'lmadi: {e}")
|
|
48
|
+
|
|
49
|
+
init_msg = {"type": "init", "api_key": self.api_key}
|
|
50
|
+
if self.embodiment_preset_id:
|
|
51
|
+
init_msg["embodiment_preset_id"] = self.embodiment_preset_id
|
|
52
|
+
|
|
53
|
+
await self._ws.send(json.dumps(init_msg))
|
|
54
|
+
|
|
55
|
+
# ready wait
|
|
56
|
+
raw = await asyncio.wait_for(self._ws.recv(), timeout=10.0)
|
|
57
|
+
response = json.loads(raw)
|
|
58
|
+
|
|
59
|
+
if response.get("type") != "ready":
|
|
60
|
+
raise LimiAuthError(
|
|
61
|
+
response.get("error", "Noma'lum autentifikatsiya xatosi")
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
async def send_audio(self, audio_bytes: bytes):
|
|
65
|
+
"""Xom audio ma'lumotni serverga yuboradi (16kHz, mono, PCM)."""
|
|
66
|
+
if not self._ws:
|
|
67
|
+
raise LimiConnectionError("Avval start() chaqiring.")
|
|
68
|
+
await self._ws.send(audio_bytes)
|
|
69
|
+
|
|
70
|
+
async def send_image(self, image_bytes: bytes):
|
|
71
|
+
"""Kamera freymini serverga yuboradi (JPEG)."""
|
|
72
|
+
if not self._ws:
|
|
73
|
+
raise LimiConnectionError("Avval start() chaqiring.")
|
|
74
|
+
image_b64 = base64.b64encode(image_bytes).decode()
|
|
75
|
+
await self._ws.send(json.dumps({"type": "image", "image_b64": image_b64}))
|
|
76
|
+
|
|
77
|
+
async def send_text(self, text: str):
|
|
78
|
+
"""Matnli xabar yuboradi (Telegram/SMS integratsiyasi uchun)."""
|
|
79
|
+
if not self._ws:
|
|
80
|
+
raise LimiConnectionError("Avval start() chaqiring.")
|
|
81
|
+
await self._ws.send(json.dumps({"type": "text", "text": text}))
|
|
82
|
+
|
|
83
|
+
async def _listen_loop(self):
|
|
84
|
+
async for message in self._ws:
|
|
85
|
+
if isinstance(message, bytes):
|
|
86
|
+
# Audio javob — mijoz o'z audio-pleyeriga uzatishi mumkin
|
|
87
|
+
pass
|
|
88
|
+
else:
|
|
89
|
+
data = json.loads(message)
|
|
90
|
+
msg_type = data.get("type")
|
|
91
|
+
if msg_type == "transcript" and self._on_transcript_cb:
|
|
92
|
+
self._on_transcript_cb(data.get("text", ""))
|
|
93
|
+
elif msg_type == "token" and self._on_response_cb:
|
|
94
|
+
self._on_response_cb(data.get("text", ""))
|
|
95
|
+
elif msg_type == "error" and self._on_error_cb:
|
|
96
|
+
self._on_error_cb(data.get("text", ""))
|
|
97
|
+
|
|
98
|
+
async def start(self):
|
|
99
|
+
"""Ulanishni boshlaydi va xabarlarni tinglashni boshlaydi."""
|
|
100
|
+
await self._connect()
|
|
101
|
+
await self._listen_loop()
|
|
102
|
+
|
|
103
|
+
async def close(self):
|
|
104
|
+
if self._ws:
|
|
105
|
+
await self._ws.close()
|
limi/exceptions.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class LimiError(Exception):
|
|
2
|
+
"""Barcha Limi xatolarining bazaviy klassi."""
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
class LimiAuthError(LimiError):
|
|
6
|
+
"""API kalit noto'g'ri yoki muddati tugagan."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
class LimiConnectionError(LimiError):
|
|
10
|
+
"""Serverga ulanib bo'lmadi."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
class LimiCreditError(LimiError):
|
|
14
|
+
"""Kredit/balans yetarli emas."""
|
|
15
|
+
pass
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
limi/__init__.py,sha256=YLcqoo8pBNc8SymyLdSGIPbpzqcCVkXEofOqzCZMKb0,238
|
|
2
|
+
limi/audio_utils.py,sha256=MMjvx1xNz2Nk0LfdgElTgTm0lu-CnIQGXpg062N8gfE,118
|
|
3
|
+
limi/client.py,sha256=lg67VH3tcylinecvgszD7yLfCmZSSOe3ZQMdaenosbE,4055
|
|
4
|
+
limi/exceptions.py,sha256=qyR2N-S2Gsw3jq3-gNC9AjLodvte7fwVxdKwsZsNv2o,348
|
|
5
|
+
limi_sdk-0.1.0.dist-info/METADATA,sha256=X7nGnWt9vpnl652rsS9etIFVENWaCbatLbWKE576_2Y,212
|
|
6
|
+
limi_sdk-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
7
|
+
limi_sdk-0.1.0.dist-info/top_level.txt,sha256=Yb1CNQEYGBiCj_VBBxlKunQ5-iR8iCBEVBqrK-0VsN4,5
|
|
8
|
+
limi_sdk-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
limi
|