mira-network 0.1.3__tar.gz → 0.1.5__tar.gz
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.
- mira_network-0.1.5/PKG-INFO +186 -0
- mira_network-0.1.5/README.md +172 -0
- {mira_network-0.1.3 → mira_network-0.1.5}/pyproject.toml +1 -1
- {mira_network-0.1.3/src/mira_sdk → mira_network-0.1.5/src/mira_network}/__init__.py +1 -6
- {mira_network-0.1.3/src/mira_sdk → mira_network-0.1.5/src/mira_network}/client.py +70 -75
- {mira_network-0.1.3/src/mira_sdk → mira_network-0.1.5/src/mira_network}/models.py +26 -24
- mira_network-0.1.5/src/mira_network/sync_client.py +111 -0
- {mira_network-0.1.3 → mira_network-0.1.5}/tests/test_client.py +16 -18
- mira_network-0.1.5/tests/test_sync_client.py +100 -0
- mira_network-0.1.3/PKG-INFO +0 -108
- mira_network-0.1.3/README.md +0 -94
- {mira_network-0.1.3 → mira_network-0.1.5}/tests/__init__.py +0 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: mira-network
|
3
|
+
Version: 0.1.5
|
4
|
+
Summary: Python SDK for Mira Network API
|
5
|
+
Author-Email: sarim2000 <sarimbleedblue@gmail.com>
|
6
|
+
License: MIT
|
7
|
+
Requires-Python: ==3.10.*
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
9
|
+
Requires-Dist: pydantic>=2.10.4
|
10
|
+
Requires-Dist: typing-extensions>=4.8.0
|
11
|
+
Requires-Dist: requests>=2.32.3
|
12
|
+
Requires-Dist: pytest-cov>=6.0.0
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
|
15
|
+
# Mira Network SDK
|
16
|
+
|
17
|
+
A Python SDK for interacting with the Mira Network API. This SDK provides both synchronous and asynchronous interfaces to access Mira API endpoints for model inference, API token management, and credit system operations.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
```bash
|
22
|
+
pip install mira-network
|
23
|
+
```
|
24
|
+
|
25
|
+
## Quick Start
|
26
|
+
|
27
|
+
### Synchronous Usage
|
28
|
+
|
29
|
+
```python
|
30
|
+
from mira_network.sync_client import MiraSyncClient
|
31
|
+
from mira_network.models import AiRequest, Message
|
32
|
+
|
33
|
+
# Using context manager (recommended)
|
34
|
+
with MiraSyncClient(api_token="your-api-token") as client: # base_url defaults to https://apis.mira.network/
|
35
|
+
# Example 1: Non-streaming response
|
36
|
+
request = AiRequest(
|
37
|
+
messages=[
|
38
|
+
Message(role="system", content="You are a helpful assistant."),
|
39
|
+
Message(role="user", content="Hello!")
|
40
|
+
],
|
41
|
+
stream=False
|
42
|
+
)
|
43
|
+
response = client.generate(request)
|
44
|
+
print(response)
|
45
|
+
|
46
|
+
# Example 2: Streaming response
|
47
|
+
stream_request = AiRequest(
|
48
|
+
messages=[
|
49
|
+
Message(role="system", content="You are a helpful assistant."),
|
50
|
+
Message(role="user", content="Tell me a story!")
|
51
|
+
],
|
52
|
+
stream=True
|
53
|
+
)
|
54
|
+
for chunk in client.generate(stream_request):
|
55
|
+
print(chunk)
|
56
|
+
```
|
57
|
+
|
58
|
+
### Asynchronous Usage
|
59
|
+
|
60
|
+
```python
|
61
|
+
import asyncio
|
62
|
+
from mira_network.client import MiraClient
|
63
|
+
from mira_network.models import AiRequest, Message
|
64
|
+
|
65
|
+
async def main():
|
66
|
+
# Using async context manager (recommended)
|
67
|
+
async with MiraClient(api_token="your-api-token") as client: # base_url defaults to https://apis.mira.network/
|
68
|
+
# Example 1: Non-streaming response
|
69
|
+
request = AiRequest(
|
70
|
+
messages=[
|
71
|
+
Message(role="system", content="You are a helpful assistant."),
|
72
|
+
Message(role="user", content="Hello!")
|
73
|
+
],
|
74
|
+
model="gpt-4o",
|
75
|
+
model_provider=None,
|
76
|
+
stream=False
|
77
|
+
)
|
78
|
+
response = await client.generate(request)
|
79
|
+
print(response)
|
80
|
+
|
81
|
+
# Example 2: Streaming response
|
82
|
+
stream_request = AiRequest(
|
83
|
+
messages=[
|
84
|
+
Message(role="system", content="You are a helpful assistant."),
|
85
|
+
Message(role="user", content="Tell me a story!")
|
86
|
+
],
|
87
|
+
stream=True
|
88
|
+
)
|
89
|
+
async for chunk in await client.generate(stream_request):
|
90
|
+
print(chunk)
|
91
|
+
|
92
|
+
if __name__ == "__main__":
|
93
|
+
asyncio.run(main())
|
94
|
+
```
|
95
|
+
|
96
|
+
## API Reference
|
97
|
+
|
98
|
+
### Client Initialization
|
99
|
+
|
100
|
+
The SDK provides two client classes:
|
101
|
+
- `MiraSyncClient`: Synchronous client using `requests`
|
102
|
+
- `MiraClient`: Asynchronous client using `httpx`
|
103
|
+
|
104
|
+
Both clients support context managers for proper resource cleanup:
|
105
|
+
|
106
|
+
```python
|
107
|
+
# Synchronous
|
108
|
+
with MiraSyncClient(
|
109
|
+
api_token="your-api-token",
|
110
|
+
base_url="https://apis.mira.network/" # Optional, this is the default
|
111
|
+
) as client:
|
112
|
+
# Your sync code here
|
113
|
+
|
114
|
+
# Asynchronous
|
115
|
+
async with MiraClient(
|
116
|
+
api_token="your-api-token",
|
117
|
+
base_url="https://apis.mira.network/" # Optional, this is the default
|
118
|
+
) as client:
|
119
|
+
# Your async code here
|
120
|
+
```
|
121
|
+
|
122
|
+
### Models
|
123
|
+
|
124
|
+
- `Message`: Represents a chat message
|
125
|
+
- `role`: String ("system", "user", or "assistant")
|
126
|
+
- `content`: String content of the message
|
127
|
+
|
128
|
+
- `AiRequest`: Configuration for model inference
|
129
|
+
- `model`: Model identifier (default: "mira/llama3.1")
|
130
|
+
- `messages`: List of Message objects
|
131
|
+
- `stream`: Boolean to enable streaming responses (default: False)
|
132
|
+
- `model_provider`: Optional ModelProvider configuration
|
133
|
+
|
134
|
+
- `ModelProvider`: Custom provider configuration
|
135
|
+
- `base_url`: Provider's base URL
|
136
|
+
- `api_key`: Provider's API key
|
137
|
+
|
138
|
+
- `ApiTokenRequest`: Request for creating API tokens
|
139
|
+
- `description`: Optional description for the token
|
140
|
+
|
141
|
+
### Available Methods
|
142
|
+
|
143
|
+
Both sync and async clients provide the same methods with identical parameters. The only difference is that async methods must be awaited.
|
144
|
+
|
145
|
+
#### Model Operations
|
146
|
+
```python
|
147
|
+
# Sync
|
148
|
+
models = client.list_models()
|
149
|
+
response = client.generate(AiRequest(messages=[...], stream=False))
|
150
|
+
for chunk in client.generate(AiRequest(messages=[...], stream=True)):
|
151
|
+
print(chunk)
|
152
|
+
|
153
|
+
# Async
|
154
|
+
models = await client.list_models()
|
155
|
+
response = await client.generate(AiRequest(messages=[...], stream=False))
|
156
|
+
async for chunk in await client.generate(AiRequest(messages=[...], stream=True)):
|
157
|
+
print(chunk)
|
158
|
+
```
|
159
|
+
|
160
|
+
#### API Token Operations
|
161
|
+
```python
|
162
|
+
# Sync
|
163
|
+
token = client.create_api_token(ApiTokenRequest(description="My Token"))
|
164
|
+
tokens = client.list_api_tokens()
|
165
|
+
client.delete_api_token("token-to-delete")
|
166
|
+
|
167
|
+
# Async
|
168
|
+
token = await client.create_api_token(ApiTokenRequest(description="My Token"))
|
169
|
+
tokens = await client.list_api_tokens()
|
170
|
+
await client.delete_api_token("token-to-delete")
|
171
|
+
```
|
172
|
+
|
173
|
+
#### Credit Operations
|
174
|
+
```python
|
175
|
+
# Sync
|
176
|
+
credits = client.get_user_credits()
|
177
|
+
history = client.get_credits_history()
|
178
|
+
|
179
|
+
# Async
|
180
|
+
credits = await client.get_user_credits()
|
181
|
+
history = await client.get_credits_history()
|
182
|
+
```
|
183
|
+
|
184
|
+
## License
|
185
|
+
|
186
|
+
MIT License
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# Mira Network SDK
|
2
|
+
|
3
|
+
A Python SDK for interacting with the Mira Network API. This SDK provides both synchronous and asynchronous interfaces to access Mira API endpoints for model inference, API token management, and credit system operations.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
pip install mira-network
|
9
|
+
```
|
10
|
+
|
11
|
+
## Quick Start
|
12
|
+
|
13
|
+
### Synchronous Usage
|
14
|
+
|
15
|
+
```python
|
16
|
+
from mira_network.sync_client import MiraSyncClient
|
17
|
+
from mira_network.models import AiRequest, Message
|
18
|
+
|
19
|
+
# Using context manager (recommended)
|
20
|
+
with MiraSyncClient(api_token="your-api-token") as client: # base_url defaults to https://apis.mira.network/
|
21
|
+
# Example 1: Non-streaming response
|
22
|
+
request = AiRequest(
|
23
|
+
messages=[
|
24
|
+
Message(role="system", content="You are a helpful assistant."),
|
25
|
+
Message(role="user", content="Hello!")
|
26
|
+
],
|
27
|
+
stream=False
|
28
|
+
)
|
29
|
+
response = client.generate(request)
|
30
|
+
print(response)
|
31
|
+
|
32
|
+
# Example 2: Streaming response
|
33
|
+
stream_request = AiRequest(
|
34
|
+
messages=[
|
35
|
+
Message(role="system", content="You are a helpful assistant."),
|
36
|
+
Message(role="user", content="Tell me a story!")
|
37
|
+
],
|
38
|
+
stream=True
|
39
|
+
)
|
40
|
+
for chunk in client.generate(stream_request):
|
41
|
+
print(chunk)
|
42
|
+
```
|
43
|
+
|
44
|
+
### Asynchronous Usage
|
45
|
+
|
46
|
+
```python
|
47
|
+
import asyncio
|
48
|
+
from mira_network.client import MiraClient
|
49
|
+
from mira_network.models import AiRequest, Message
|
50
|
+
|
51
|
+
async def main():
|
52
|
+
# Using async context manager (recommended)
|
53
|
+
async with MiraClient(api_token="your-api-token") as client: # base_url defaults to https://apis.mira.network/
|
54
|
+
# Example 1: Non-streaming response
|
55
|
+
request = AiRequest(
|
56
|
+
messages=[
|
57
|
+
Message(role="system", content="You are a helpful assistant."),
|
58
|
+
Message(role="user", content="Hello!")
|
59
|
+
],
|
60
|
+
model="gpt-4o",
|
61
|
+
model_provider=None,
|
62
|
+
stream=False
|
63
|
+
)
|
64
|
+
response = await client.generate(request)
|
65
|
+
print(response)
|
66
|
+
|
67
|
+
# Example 2: Streaming response
|
68
|
+
stream_request = AiRequest(
|
69
|
+
messages=[
|
70
|
+
Message(role="system", content="You are a helpful assistant."),
|
71
|
+
Message(role="user", content="Tell me a story!")
|
72
|
+
],
|
73
|
+
stream=True
|
74
|
+
)
|
75
|
+
async for chunk in await client.generate(stream_request):
|
76
|
+
print(chunk)
|
77
|
+
|
78
|
+
if __name__ == "__main__":
|
79
|
+
asyncio.run(main())
|
80
|
+
```
|
81
|
+
|
82
|
+
## API Reference
|
83
|
+
|
84
|
+
### Client Initialization
|
85
|
+
|
86
|
+
The SDK provides two client classes:
|
87
|
+
- `MiraSyncClient`: Synchronous client using `requests`
|
88
|
+
- `MiraClient`: Asynchronous client using `httpx`
|
89
|
+
|
90
|
+
Both clients support context managers for proper resource cleanup:
|
91
|
+
|
92
|
+
```python
|
93
|
+
# Synchronous
|
94
|
+
with MiraSyncClient(
|
95
|
+
api_token="your-api-token",
|
96
|
+
base_url="https://apis.mira.network/" # Optional, this is the default
|
97
|
+
) as client:
|
98
|
+
# Your sync code here
|
99
|
+
|
100
|
+
# Asynchronous
|
101
|
+
async with MiraClient(
|
102
|
+
api_token="your-api-token",
|
103
|
+
base_url="https://apis.mira.network/" # Optional, this is the default
|
104
|
+
) as client:
|
105
|
+
# Your async code here
|
106
|
+
```
|
107
|
+
|
108
|
+
### Models
|
109
|
+
|
110
|
+
- `Message`: Represents a chat message
|
111
|
+
- `role`: String ("system", "user", or "assistant")
|
112
|
+
- `content`: String content of the message
|
113
|
+
|
114
|
+
- `AiRequest`: Configuration for model inference
|
115
|
+
- `model`: Model identifier (default: "mira/llama3.1")
|
116
|
+
- `messages`: List of Message objects
|
117
|
+
- `stream`: Boolean to enable streaming responses (default: False)
|
118
|
+
- `model_provider`: Optional ModelProvider configuration
|
119
|
+
|
120
|
+
- `ModelProvider`: Custom provider configuration
|
121
|
+
- `base_url`: Provider's base URL
|
122
|
+
- `api_key`: Provider's API key
|
123
|
+
|
124
|
+
- `ApiTokenRequest`: Request for creating API tokens
|
125
|
+
- `description`: Optional description for the token
|
126
|
+
|
127
|
+
### Available Methods
|
128
|
+
|
129
|
+
Both sync and async clients provide the same methods with identical parameters. The only difference is that async methods must be awaited.
|
130
|
+
|
131
|
+
#### Model Operations
|
132
|
+
```python
|
133
|
+
# Sync
|
134
|
+
models = client.list_models()
|
135
|
+
response = client.generate(AiRequest(messages=[...], stream=False))
|
136
|
+
for chunk in client.generate(AiRequest(messages=[...], stream=True)):
|
137
|
+
print(chunk)
|
138
|
+
|
139
|
+
# Async
|
140
|
+
models = await client.list_models()
|
141
|
+
response = await client.generate(AiRequest(messages=[...], stream=False))
|
142
|
+
async for chunk in await client.generate(AiRequest(messages=[...], stream=True)):
|
143
|
+
print(chunk)
|
144
|
+
```
|
145
|
+
|
146
|
+
#### API Token Operations
|
147
|
+
```python
|
148
|
+
# Sync
|
149
|
+
token = client.create_api_token(ApiTokenRequest(description="My Token"))
|
150
|
+
tokens = client.list_api_tokens()
|
151
|
+
client.delete_api_token("token-to-delete")
|
152
|
+
|
153
|
+
# Async
|
154
|
+
token = await client.create_api_token(ApiTokenRequest(description="My Token"))
|
155
|
+
tokens = await client.list_api_tokens()
|
156
|
+
await client.delete_api_token("token-to-delete")
|
157
|
+
```
|
158
|
+
|
159
|
+
#### Credit Operations
|
160
|
+
```python
|
161
|
+
# Sync
|
162
|
+
credits = client.get_user_credits()
|
163
|
+
history = client.get_credits_history()
|
164
|
+
|
165
|
+
# Async
|
166
|
+
credits = await client.get_user_credits()
|
167
|
+
history = await client.get_credits_history()
|
168
|
+
```
|
169
|
+
|
170
|
+
## License
|
171
|
+
|
172
|
+
MIT License
|
@@ -1,12 +1,10 @@
|
|
1
1
|
from .client import MiraClient
|
2
|
+
from .sync_client import MiraSyncClient
|
2
3
|
from .models import (
|
3
4
|
Message,
|
4
5
|
ModelProvider,
|
5
6
|
AiRequest,
|
6
|
-
FlowChatCompletion,
|
7
|
-
FlowRequest,
|
8
7
|
ApiTokenRequest,
|
9
|
-
AddCreditRequest,
|
10
8
|
)
|
11
9
|
|
12
10
|
__all__ = [
|
@@ -14,8 +12,5 @@ __all__ = [
|
|
14
12
|
"Message",
|
15
13
|
"ModelProvider",
|
16
14
|
"AiRequest",
|
17
|
-
"FlowChatCompletion",
|
18
|
-
"FlowRequest",
|
19
15
|
"ApiTokenRequest",
|
20
|
-
"AddCreditRequest",
|
21
16
|
]
|
@@ -1,13 +1,8 @@
|
|
1
1
|
from typing import AsyncIterator, Optional, List, Dict, AsyncGenerator, Union
|
2
2
|
import httpx
|
3
3
|
from .models import (
|
4
|
-
Message,
|
5
|
-
ModelProvider,
|
6
4
|
AiRequest,
|
7
|
-
FlowChatCompletion,
|
8
|
-
FlowRequest,
|
9
5
|
ApiTokenRequest,
|
10
|
-
AddCreditRequest,
|
11
6
|
)
|
12
7
|
|
13
8
|
|
@@ -15,7 +10,7 @@ class MiraClient:
|
|
15
10
|
|
16
11
|
def __init__(
|
17
12
|
self,
|
18
|
-
base_url: str = "https://mira
|
13
|
+
base_url: str = "https://apis.mira.network",
|
19
14
|
api_token: Optional[str] = None,
|
20
15
|
):
|
21
16
|
"""Initialize Mira client.
|
@@ -64,63 +59,63 @@ class MiraClient:
|
|
64
59
|
else:
|
65
60
|
return response.json()
|
66
61
|
|
67
|
-
async def generate_with_flow(
|
68
|
-
|
69
|
-
) -> Union[str, AsyncGenerator[str, None]]:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
async def list_flows(self) -> List[Dict]:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
async def get_flow(self, flow_id: str) -> Dict:
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
async def create_flow(self, request: FlowRequest) -> Dict:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
async def update_flow(self, flow_id: str, request: FlowRequest) -> Dict:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
async def delete_flow(self, flow_id: str) -> None:
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
62
|
+
# async def generate_with_flow(
|
63
|
+
# self, flow_id: str, request: FlowChatCompletion
|
64
|
+
# ) -> Union[str, AsyncGenerator[str, None]]:
|
65
|
+
# """Generate text using a specific flow."""
|
66
|
+
# response = await self._client.post(
|
67
|
+
# f"{self.base_url}/v1/flows/{flow_id}/chat/completions",
|
68
|
+
# headers=self._get_headers(),
|
69
|
+
# json=request.model_dump(),
|
70
|
+
# )
|
71
|
+
# response.raise_for_status()
|
72
|
+
# return response.json()
|
73
|
+
|
74
|
+
# async def list_flows(self) -> List[Dict]:
|
75
|
+
# """List all flows."""
|
76
|
+
# response = await self._client.get(
|
77
|
+
# f"{self.base_url}/flows",
|
78
|
+
# headers=self._get_headers(),
|
79
|
+
# )
|
80
|
+
# response.raise_for_status()
|
81
|
+
# return response.json()
|
82
|
+
|
83
|
+
# async def get_flow(self, flow_id: str) -> Dict:
|
84
|
+
# """Get details of a specific flow."""
|
85
|
+
# response = await self._client.get(
|
86
|
+
# f"{self.base_url}/flows/{flow_id}",
|
87
|
+
# headers=self._get_headers(),
|
88
|
+
# )
|
89
|
+
# response.raise_for_status()
|
90
|
+
# return response.json()
|
91
|
+
|
92
|
+
# async def create_flow(self, request: FlowRequest) -> Dict:
|
93
|
+
# """Create a new flow."""
|
94
|
+
# response = await self._client.post(
|
95
|
+
# f"{self.base_url}/flows",
|
96
|
+
# headers=self._get_headers(),
|
97
|
+
# json=request.model_dump(),
|
98
|
+
# )
|
99
|
+
# response.raise_for_status()
|
100
|
+
# return response.json()
|
101
|
+
|
102
|
+
# async def update_flow(self, flow_id: str, request: FlowRequest) -> Dict:
|
103
|
+
# """Update an existing flow."""
|
104
|
+
# response = await self._client.put(
|
105
|
+
# f"{self.base_url}/flows/{flow_id}",
|
106
|
+
# headers=self._get_headers(),
|
107
|
+
# json=request.model_dump(),
|
108
|
+
# )
|
109
|
+
# response.raise_for_status()
|
110
|
+
# return response.json()
|
111
|
+
|
112
|
+
# async def delete_flow(self, flow_id: str) -> None:
|
113
|
+
# """Delete a flow."""
|
114
|
+
# response = await self._client.delete(
|
115
|
+
# f"{self.base_url}/flows/{flow_id}",
|
116
|
+
# headers=self._get_headers(),
|
117
|
+
# )
|
118
|
+
# response.raise_for_status()
|
124
119
|
|
125
120
|
async def create_api_token(self, request: ApiTokenRequest) -> Dict:
|
126
121
|
"""Create a new API token."""
|
@@ -135,7 +130,7 @@ class MiraClient:
|
|
135
130
|
async def list_api_tokens(self) -> List[Dict]:
|
136
131
|
"""List all API tokens."""
|
137
132
|
response = await self._client.get(
|
138
|
-
f"{self.base_url}/tokens",
|
133
|
+
f"{self.base_url}/api-tokens",
|
139
134
|
headers=self._get_headers(),
|
140
135
|
)
|
141
136
|
response.raise_for_status()
|
@@ -144,7 +139,7 @@ class MiraClient:
|
|
144
139
|
async def delete_api_token(self, token: str) -> None:
|
145
140
|
"""Delete an API token."""
|
146
141
|
response = await self._client.delete(
|
147
|
-
f"{self.base_url}/tokens/{token}",
|
142
|
+
f"{self.base_url}/api-tokens/{token}",
|
148
143
|
headers=self._get_headers(),
|
149
144
|
)
|
150
145
|
response.raise_for_status()
|
@@ -158,20 +153,20 @@ class MiraClient:
|
|
158
153
|
response.raise_for_status()
|
159
154
|
return response.json()
|
160
155
|
|
161
|
-
async def add_credit(self, request: AddCreditRequest) -> Dict:
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
156
|
+
# async def add_credit(self, request: AddCreditRequest) -> Dict:
|
157
|
+
# """Add credits to a user account."""
|
158
|
+
# response = await self._client.post(
|
159
|
+
# f"{self.base_url}/credits",
|
160
|
+
# headers=self._get_headers(),
|
161
|
+
# json=request.model_dump(),
|
162
|
+
# )
|
163
|
+
# response.raise_for_status()
|
164
|
+
# return response.json()
|
170
165
|
|
171
166
|
async def get_credits_history(self) -> List[Dict]:
|
172
167
|
"""Get user credits history."""
|
173
168
|
response = await self._client.get(
|
174
|
-
f"{self.base_url}/credits
|
169
|
+
f"{self.base_url}/user-credits-history",
|
175
170
|
headers=self._get_headers(),
|
176
171
|
)
|
177
172
|
response.raise_for_status()
|
@@ -22,7 +22,9 @@ class ModelProvider(BaseModel):
|
|
22
22
|
|
23
23
|
class AiRequest(BaseModel):
|
24
24
|
model: str = Field("mira/llama3.1", title="Model")
|
25
|
-
model_provider: Optional[ModelProvider] = Field(
|
25
|
+
model_provider: Optional[ModelProvider] = Field(
|
26
|
+
None, title="Model Provider (optional)"
|
27
|
+
)
|
26
28
|
messages: List[Message] = Field([], title="Messages")
|
27
29
|
stream: Optional[bool] = Field(False, title="Stream")
|
28
30
|
|
@@ -34,34 +36,34 @@ class AiRequest(BaseModel):
|
|
34
36
|
return v
|
35
37
|
|
36
38
|
|
37
|
-
class FlowChatCompletion(BaseModel):
|
38
|
-
|
39
|
+
# class FlowChatCompletion(BaseModel):
|
40
|
+
# variables: Optional[Dict] = Field(None, title="Variables")
|
39
41
|
|
40
42
|
|
41
|
-
class FlowRequest(BaseModel):
|
42
|
-
|
43
|
-
|
43
|
+
# class FlowRequest(BaseModel):
|
44
|
+
# system_prompt: str
|
45
|
+
# name: str
|
44
46
|
|
45
47
|
|
46
48
|
class ApiTokenRequest(BaseModel):
|
47
49
|
description: Optional[str] = None
|
48
50
|
|
49
51
|
|
50
|
-
class AddCreditRequest(BaseModel):
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
# class AddCreditRequest(BaseModel):
|
53
|
+
# user_id: str
|
54
|
+
# amount: float
|
55
|
+
# description: Optional[str] = None
|
56
|
+
|
57
|
+
# @field_validator("amount")
|
58
|
+
# @classmethod
|
59
|
+
# def validate_amount(cls, v: float) -> float:
|
60
|
+
# if v <= 0:
|
61
|
+
# raise ValueError("Amount must be greater than 0")
|
62
|
+
# return v
|
63
|
+
|
64
|
+
# @field_validator("user_id")
|
65
|
+
# @classmethod
|
66
|
+
# def validate_user_id(cls, v: str) -> str:
|
67
|
+
# if not v.strip():
|
68
|
+
# raise ValueError("User ID cannot be empty")
|
69
|
+
# return v
|
@@ -0,0 +1,111 @@
|
|
1
|
+
from typing import Optional, List, Dict, Iterator, Union
|
2
|
+
import requests
|
3
|
+
from .models import (
|
4
|
+
AiRequest,
|
5
|
+
ApiTokenRequest,
|
6
|
+
)
|
7
|
+
|
8
|
+
|
9
|
+
class MiraSyncClient:
|
10
|
+
def __init__(
|
11
|
+
self,
|
12
|
+
base_url: str = "https://apis.mira.network",
|
13
|
+
api_token: Optional[str] = None,
|
14
|
+
):
|
15
|
+
"""Initialize Mira synchronous client.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
base_url: Base URL of the Mira API
|
19
|
+
api_token: Optional API token for authentication
|
20
|
+
"""
|
21
|
+
self.base_url = base_url
|
22
|
+
self.api_token = api_token
|
23
|
+
self._session = requests.Session()
|
24
|
+
|
25
|
+
def __enter__(self):
|
26
|
+
return self
|
27
|
+
|
28
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
29
|
+
self._session.close()
|
30
|
+
|
31
|
+
def _get_headers(self) -> Dict[str, str]:
|
32
|
+
headers = {"Content-Type": "application/json"}
|
33
|
+
if self.api_token:
|
34
|
+
headers["Authorization"] = f"Bearer {self.api_token}"
|
35
|
+
return headers
|
36
|
+
|
37
|
+
def list_models(self) -> List[str]:
|
38
|
+
"""List available models."""
|
39
|
+
response = self._session.get(
|
40
|
+
f"{self.base_url}/v1/models",
|
41
|
+
headers=self._get_headers(),
|
42
|
+
)
|
43
|
+
response.raise_for_status()
|
44
|
+
return response.json()
|
45
|
+
|
46
|
+
def generate(self, request: AiRequest) -> Union[str, Iterator[str]]:
|
47
|
+
"""Generate text using the specified model.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
request: The AI request configuration
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Either a string response (when stream=False) or an iterator of string chunks (when stream=True)
|
54
|
+
"""
|
55
|
+
response = self._session.post(
|
56
|
+
f"{self.base_url}/v1/chat/completions",
|
57
|
+
headers=self._get_headers(),
|
58
|
+
json=request.model_dump(),
|
59
|
+
stream=request.stream,
|
60
|
+
)
|
61
|
+
response.raise_for_status()
|
62
|
+
|
63
|
+
if request.stream:
|
64
|
+
return response.iter_lines(decode_unicode=True)
|
65
|
+
else:
|
66
|
+
return response.json()
|
67
|
+
|
68
|
+
def create_api_token(self, request: ApiTokenRequest) -> Dict:
|
69
|
+
"""Create a new API token."""
|
70
|
+
response = self._session.post(
|
71
|
+
f"{self.base_url}/api-tokens",
|
72
|
+
headers=self._get_headers(),
|
73
|
+
json=request.model_dump(),
|
74
|
+
)
|
75
|
+
response.raise_for_status()
|
76
|
+
return response.json()
|
77
|
+
|
78
|
+
def list_api_tokens(self) -> List[Dict]:
|
79
|
+
"""List all API tokens."""
|
80
|
+
response = self._session.get(
|
81
|
+
f"{self.base_url}/api-tokens",
|
82
|
+
headers=self._get_headers(),
|
83
|
+
)
|
84
|
+
response.raise_for_status()
|
85
|
+
return response.json()
|
86
|
+
|
87
|
+
def delete_api_token(self, token: str) -> None:
|
88
|
+
"""Delete an API token."""
|
89
|
+
response = self._session.delete(
|
90
|
+
f"{self.base_url}/api-tokens/{token}",
|
91
|
+
headers=self._get_headers(),
|
92
|
+
)
|
93
|
+
response.raise_for_status()
|
94
|
+
|
95
|
+
def get_user_credits(self) -> Dict:
|
96
|
+
"""Get user credits information."""
|
97
|
+
response = self._session.get(
|
98
|
+
f"{self.base_url}/user-credits",
|
99
|
+
headers=self._get_headers(),
|
100
|
+
)
|
101
|
+
response.raise_for_status()
|
102
|
+
return response.json()
|
103
|
+
|
104
|
+
def get_credits_history(self) -> List[Dict]:
|
105
|
+
"""Get user credits history."""
|
106
|
+
response = self._session.get(
|
107
|
+
f"{self.base_url}/user-credits-history",
|
108
|
+
headers=self._get_headers(),
|
109
|
+
)
|
110
|
+
response.raise_for_status()
|
111
|
+
return response.json()
|
@@ -1,12 +1,10 @@
|
|
1
1
|
import pytest
|
2
2
|
import httpx
|
3
|
-
from src.
|
4
|
-
from src.
|
3
|
+
from src.mira_network.client import MiraClient
|
4
|
+
from src.mira_network.models import (
|
5
5
|
Message,
|
6
6
|
AiRequest,
|
7
|
-
FlowRequest,
|
8
7
|
ApiTokenRequest,
|
9
|
-
AddCreditRequest,
|
10
8
|
)
|
11
9
|
|
12
10
|
|
@@ -32,7 +30,7 @@ async def test_list_models(client):
|
|
32
30
|
@pytest.mark.asyncio
|
33
31
|
async def test_generate(client):
|
34
32
|
request = AiRequest(
|
35
|
-
model="
|
33
|
+
model="gpt-4o",
|
36
34
|
messages=[Message(role="user", content="Hi Who are you!")],
|
37
35
|
stream=False,
|
38
36
|
model_provider=None,
|
@@ -70,17 +68,17 @@ async def test_list_flows(client):
|
|
70
68
|
assert isinstance(result, list)
|
71
69
|
|
72
70
|
|
73
|
-
@pytest.mark.asyncio
|
74
|
-
async def test_create_and_delete_flow(client):
|
75
|
-
|
76
|
-
|
71
|
+
# @pytest.mark.asyncio
|
72
|
+
# async def test_create_and_delete_flow(client):
|
73
|
+
# # Create flow
|
74
|
+
# request = FlowRequest(system_prompt="You are a helpful assistant", name="test_flow")
|
77
75
|
|
78
|
-
|
79
|
-
|
76
|
+
# flow = await client.create_flow(request)
|
77
|
+
# assert flow.get("name") == "test_flow"
|
80
78
|
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
# # Delete the created flow
|
80
|
+
# flow_id = flow.get("id")
|
81
|
+
# await client.delete_flow(flow_id)
|
84
82
|
|
85
83
|
|
86
84
|
@pytest.mark.asyncio
|
@@ -109,7 +107,7 @@ async def test_error_handling(client):
|
|
109
107
|
await client.generate(request)
|
110
108
|
|
111
109
|
|
112
|
-
@pytest.mark.asyncio
|
113
|
-
async def test_client_context_manager():
|
114
|
-
|
115
|
-
|
110
|
+
# @pytest.mark.asyncio
|
111
|
+
# async def test_client_context_manager():
|
112
|
+
# async with MiraClient("https://mira-client-balancer.alts.dev") as client:
|
113
|
+
# assert isinstance(client._client, httpx.AsyncClient)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import pytest
|
2
|
+
import requests
|
3
|
+
from src.mira_network.sync_client import MiraSyncClient
|
4
|
+
from src.mira_network.models import (
|
5
|
+
Message,
|
6
|
+
AiRequest,
|
7
|
+
ApiTokenRequest,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture
|
12
|
+
def client():
|
13
|
+
return MiraSyncClient(
|
14
|
+
base_url="https://mira-network.alts.dev",
|
15
|
+
api_token="sk-mira-b9ecd5f43ef0363e691322df3295c2b98bebd1c1edb0b6d8",
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
def test_list_models(client):
|
20
|
+
result = client.list_models()
|
21
|
+
assert isinstance(result, dict)
|
22
|
+
assert result["object"] == "list"
|
23
|
+
assert isinstance(result["data"], list)
|
24
|
+
assert len(result["data"]) > 0
|
25
|
+
assert all(isinstance(model, dict) for model in result["data"])
|
26
|
+
assert all("id" in model and "object" in model for model in result["data"])
|
27
|
+
|
28
|
+
|
29
|
+
def test_generate(client):
|
30
|
+
request = AiRequest(
|
31
|
+
model="gpt-4o",
|
32
|
+
messages=[Message(role="user", content="Hi Who are you!")],
|
33
|
+
stream=False,
|
34
|
+
model_provider=None,
|
35
|
+
)
|
36
|
+
|
37
|
+
result = client.generate(request)
|
38
|
+
assert isinstance(result, str)
|
39
|
+
assert len(result) > 0
|
40
|
+
|
41
|
+
|
42
|
+
def test_generate_stream(client):
|
43
|
+
request = AiRequest(
|
44
|
+
model="gpt-4o",
|
45
|
+
messages=[Message(role="user", content="Hi!")],
|
46
|
+
stream=True,
|
47
|
+
model_provider=None,
|
48
|
+
)
|
49
|
+
print("Making generate request with streaming...")
|
50
|
+
response = client.generate(request=request)
|
51
|
+
chunks = []
|
52
|
+
print("Starting to receive stream chunks...")
|
53
|
+
for chunk in response:
|
54
|
+
print(f"Received chunk: {chunk}")
|
55
|
+
assert isinstance(chunk, str)
|
56
|
+
assert len(chunk) > 0
|
57
|
+
chunks.append(chunk)
|
58
|
+
print(f"Received {len(chunks)} total chunks")
|
59
|
+
assert len(chunks) > 0
|
60
|
+
|
61
|
+
|
62
|
+
def test_create_api_token(client):
|
63
|
+
request = ApiTokenRequest(description="Test token")
|
64
|
+
result = client.create_api_token(request)
|
65
|
+
assert "token" in result
|
66
|
+
|
67
|
+
|
68
|
+
def test_get_user_credits(client):
|
69
|
+
result = client.get_user_credits()
|
70
|
+
assert "amount" in result
|
71
|
+
|
72
|
+
|
73
|
+
def test_error_handling(client):
|
74
|
+
with pytest.raises(requests.HTTPError):
|
75
|
+
# Test with invalid model name to trigger error
|
76
|
+
request = AiRequest(
|
77
|
+
model="invalid_model",
|
78
|
+
messages=[Message(role="user", content="Hi!")],
|
79
|
+
stream=False,
|
80
|
+
model_provider=None,
|
81
|
+
)
|
82
|
+
client.generate(request)
|
83
|
+
|
84
|
+
|
85
|
+
def test_client_context_manager():
|
86
|
+
with MiraSyncClient("https://mira-network.alts.dev") as client:
|
87
|
+
assert isinstance(client._session, requests.Session)
|
88
|
+
# Make a test request to ensure session works
|
89
|
+
result = client.list_models()
|
90
|
+
assert isinstance(result, dict)
|
91
|
+
|
92
|
+
|
93
|
+
def test_list_api_tokens(client):
|
94
|
+
tokens = client.list_api_tokens()
|
95
|
+
assert isinstance(tokens, list)
|
96
|
+
|
97
|
+
|
98
|
+
def test_get_credits_history(client):
|
99
|
+
history = client.get_credits_history()
|
100
|
+
assert isinstance(history, list)
|
mira_network-0.1.3/PKG-INFO
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: mira-network
|
3
|
-
Version: 0.1.3
|
4
|
-
Summary: Python SDK for Mira Network API
|
5
|
-
Author-Email: sarim2000 <sarimbleedblue@gmail.com>
|
6
|
-
License: MIT
|
7
|
-
Requires-Python: ==3.10.*
|
8
|
-
Requires-Dist: httpx>=0.28.1
|
9
|
-
Requires-Dist: pydantic>=2.10.4
|
10
|
-
Requires-Dist: typing-extensions>=4.8.0
|
11
|
-
Requires-Dist: requests>=2.32.3
|
12
|
-
Requires-Dist: pytest-cov>=6.0.0
|
13
|
-
Description-Content-Type: text/markdown
|
14
|
-
|
15
|
-
# Mira Network SDK
|
16
|
-
|
17
|
-
A Python SDK for interacting with the Mira Network API. This SDK provides a simple interface to access all Mira API endpoints including model inference, flow management, and credit system.
|
18
|
-
|
19
|
-
## Installation
|
20
|
-
|
21
|
-
```bash
|
22
|
-
pip install mira-network
|
23
|
-
```
|
24
|
-
|
25
|
-
## Quick Start
|
26
|
-
|
27
|
-
```python
|
28
|
-
import asyncio
|
29
|
-
from mira_sdk import MiraClient, Message, AiRequest
|
30
|
-
|
31
|
-
async def main():
|
32
|
-
# Initialize client
|
33
|
-
client = MiraClient(
|
34
|
-
base_url="https://api.mira.example.com",
|
35
|
-
api_token="your-api-token"
|
36
|
-
)
|
37
|
-
|
38
|
-
# List available models
|
39
|
-
models = await client.list_models()
|
40
|
-
print("Available models:", models)
|
41
|
-
|
42
|
-
# Generate text
|
43
|
-
request = AiRequest(
|
44
|
-
model="gpt-4o",
|
45
|
-
messages=[
|
46
|
-
Message(role="system", content="You are a helpful assistant."),
|
47
|
-
Message(role="user", content="Hello!")
|
48
|
-
],
|
49
|
-
model_provider=None
|
50
|
-
)
|
51
|
-
|
52
|
-
response = await client.generate(request)
|
53
|
-
print("Response:", response)
|
54
|
-
|
55
|
-
if __name__ == "__main__":
|
56
|
-
asyncio.run(main())
|
57
|
-
```
|
58
|
-
|
59
|
-
## Features
|
60
|
-
|
61
|
-
- Asynchronous API using `httpx`
|
62
|
-
- Full type hints support
|
63
|
-
- Pydantic models for request/response validation
|
64
|
-
- Support for all Mira API endpoints:
|
65
|
-
- Model inference
|
66
|
-
- Flow management
|
67
|
-
- API token management
|
68
|
-
- Credit system
|
69
|
-
|
70
|
-
## API Reference
|
71
|
-
|
72
|
-
### Models
|
73
|
-
|
74
|
-
- `Message`: Represents a chat message
|
75
|
-
- `ModelProvider`: Configuration for custom model providers
|
76
|
-
- `AiRequest`: Request for model inference
|
77
|
-
- `FlowChatCompletion`: Request for flow-based chat completion
|
78
|
-
- `FlowRequest`: Request for creating/updating flows
|
79
|
-
- `ApiTokenRequest`: Request for creating API tokens
|
80
|
-
- `AddCreditRequest`: Request for adding credits
|
81
|
-
|
82
|
-
### Client Methods
|
83
|
-
|
84
|
-
#### Model Operations
|
85
|
-
- `list_models()`: List available models
|
86
|
-
- `generate(request: AiRequest)`: Generate text using specified model
|
87
|
-
|
88
|
-
#### Flow Operations
|
89
|
-
- `list_flows()`: List all flows
|
90
|
-
- `get_flow(flow_id: str)`: Get flow details
|
91
|
-
- `create_flow(request: FlowRequest)`: Create new flow
|
92
|
-
- `update_flow(flow_id: str, request: FlowRequest)`: Update flow
|
93
|
-
- `delete_flow(flow_id: str)`: Delete flow
|
94
|
-
- `generate_with_flow(flow_id: str, request: FlowChatCompletion)`: Generate using flow
|
95
|
-
|
96
|
-
#### Token Operations
|
97
|
-
- `create_api_token(request: ApiTokenRequest)`: Create API token
|
98
|
-
- `list_api_tokens()`: List API tokens
|
99
|
-
- `delete_api_token(token: str)`: Delete API token
|
100
|
-
|
101
|
-
#### Credit Operations
|
102
|
-
- `get_user_credits()`: Get credit information
|
103
|
-
- `add_credit(request: AddCreditRequest)`: Add credits
|
104
|
-
- `get_credits_history()`: Get credit history
|
105
|
-
|
106
|
-
## License
|
107
|
-
|
108
|
-
MIT License
|
mira_network-0.1.3/README.md
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
# Mira Network SDK
|
2
|
-
|
3
|
-
A Python SDK for interacting with the Mira Network API. This SDK provides a simple interface to access all Mira API endpoints including model inference, flow management, and credit system.
|
4
|
-
|
5
|
-
## Installation
|
6
|
-
|
7
|
-
```bash
|
8
|
-
pip install mira-network
|
9
|
-
```
|
10
|
-
|
11
|
-
## Quick Start
|
12
|
-
|
13
|
-
```python
|
14
|
-
import asyncio
|
15
|
-
from mira_sdk import MiraClient, Message, AiRequest
|
16
|
-
|
17
|
-
async def main():
|
18
|
-
# Initialize client
|
19
|
-
client = MiraClient(
|
20
|
-
base_url="https://api.mira.example.com",
|
21
|
-
api_token="your-api-token"
|
22
|
-
)
|
23
|
-
|
24
|
-
# List available models
|
25
|
-
models = await client.list_models()
|
26
|
-
print("Available models:", models)
|
27
|
-
|
28
|
-
# Generate text
|
29
|
-
request = AiRequest(
|
30
|
-
model="gpt-4o",
|
31
|
-
messages=[
|
32
|
-
Message(role="system", content="You are a helpful assistant."),
|
33
|
-
Message(role="user", content="Hello!")
|
34
|
-
],
|
35
|
-
model_provider=None
|
36
|
-
)
|
37
|
-
|
38
|
-
response = await client.generate(request)
|
39
|
-
print("Response:", response)
|
40
|
-
|
41
|
-
if __name__ == "__main__":
|
42
|
-
asyncio.run(main())
|
43
|
-
```
|
44
|
-
|
45
|
-
## Features
|
46
|
-
|
47
|
-
- Asynchronous API using `httpx`
|
48
|
-
- Full type hints support
|
49
|
-
- Pydantic models for request/response validation
|
50
|
-
- Support for all Mira API endpoints:
|
51
|
-
- Model inference
|
52
|
-
- Flow management
|
53
|
-
- API token management
|
54
|
-
- Credit system
|
55
|
-
|
56
|
-
## API Reference
|
57
|
-
|
58
|
-
### Models
|
59
|
-
|
60
|
-
- `Message`: Represents a chat message
|
61
|
-
- `ModelProvider`: Configuration for custom model providers
|
62
|
-
- `AiRequest`: Request for model inference
|
63
|
-
- `FlowChatCompletion`: Request for flow-based chat completion
|
64
|
-
- `FlowRequest`: Request for creating/updating flows
|
65
|
-
- `ApiTokenRequest`: Request for creating API tokens
|
66
|
-
- `AddCreditRequest`: Request for adding credits
|
67
|
-
|
68
|
-
### Client Methods
|
69
|
-
|
70
|
-
#### Model Operations
|
71
|
-
- `list_models()`: List available models
|
72
|
-
- `generate(request: AiRequest)`: Generate text using specified model
|
73
|
-
|
74
|
-
#### Flow Operations
|
75
|
-
- `list_flows()`: List all flows
|
76
|
-
- `get_flow(flow_id: str)`: Get flow details
|
77
|
-
- `create_flow(request: FlowRequest)`: Create new flow
|
78
|
-
- `update_flow(flow_id: str, request: FlowRequest)`: Update flow
|
79
|
-
- `delete_flow(flow_id: str)`: Delete flow
|
80
|
-
- `generate_with_flow(flow_id: str, request: FlowChatCompletion)`: Generate using flow
|
81
|
-
|
82
|
-
#### Token Operations
|
83
|
-
- `create_api_token(request: ApiTokenRequest)`: Create API token
|
84
|
-
- `list_api_tokens()`: List API tokens
|
85
|
-
- `delete_api_token(token: str)`: Delete API token
|
86
|
-
|
87
|
-
#### Credit Operations
|
88
|
-
- `get_user_credits()`: Get credit information
|
89
|
-
- `add_credit(request: AddCreditRequest)`: Add credits
|
90
|
-
- `get_credits_history()`: Get credit history
|
91
|
-
|
92
|
-
## License
|
93
|
-
|
94
|
-
MIT License
|
File without changes
|