itzam 1.0.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.
- itzam/__init__.py +40 -0
- itzam/base/__init__.py +3 -0
- itzam/base/client.py +34 -0
- itzam/models/__init__.py +6 -0
- itzam/models/__main__.py +28 -0
- itzam/models/client.py +18 -0
- itzam/models/models.py +16 -0
- itzam/runs/__init__.py +5 -0
- itzam/runs/client.py +18 -0
- itzam/runs/models.py +34 -0
- itzam/text/__init__.py +14 -0
- itzam/text/client.py +60 -0
- itzam/text/models.py +39 -0
- itzam/threads/__init__.py +7 -0
- itzam/threads/client.py +53 -0
- itzam/threads/models.py +11 -0
- itzam/utils/exceptions.py +187 -0
- itzam-1.0.0.dist-info/METADATA +131 -0
- itzam-1.0.0.dist-info/RECORD +21 -0
- itzam-1.0.0.dist-info/WHEEL +5 -0
- itzam-1.0.0.dist-info/top_level.txt +1 -0
itzam/__init__.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
"""
|
2
|
+
The Python sdk for the Itzam API.
|
3
|
+
Example usage:
|
4
|
+
|
5
|
+
```python
|
6
|
+
from itzam import Itzam
|
7
|
+
|
8
|
+
client = Itzam("your api key")
|
9
|
+
response = client.text.generate(
|
10
|
+
workflow_slug="your_workflow_slug",
|
11
|
+
input="your input text",
|
12
|
+
stream=False
|
13
|
+
)
|
14
|
+
print(response.text)
|
15
|
+
```
|
16
|
+
"""
|
17
|
+
from .text.client import TextClient
|
18
|
+
from .threads import ThreadsClient
|
19
|
+
from .runs import RunsClient
|
20
|
+
from .models import ModelsClient
|
21
|
+
import dotenv, os
|
22
|
+
|
23
|
+
class Itzam:
|
24
|
+
def __init__(self, api_key: str|None = None, base_url: str="https://itz.am"):
|
25
|
+
"""
|
26
|
+
Initialize the Itzam SDK with the base URL and API key. If no API key is provided, it will look for the `ITZAM_API_KEY` environment variable.
|
27
|
+
|
28
|
+
:param base_url: The base URL for the Itzam API.
|
29
|
+
:param api_key: The API key for authentication.
|
30
|
+
"""
|
31
|
+
if not api_key:
|
32
|
+
dotenv.load_dotenv()
|
33
|
+
api_key = os.getenv("ITZAM_API_KEY")
|
34
|
+
if not api_key:
|
35
|
+
raise ValueError("API key is required. Please provide it as an argument or set the ITZAM_API_KEY environment variable.")
|
36
|
+
|
37
|
+
self.text = TextClient(base_url=base_url, api_key=api_key)
|
38
|
+
self.threads = ThreadsClient(base_url=base_url, api_key=api_key)
|
39
|
+
self.runs = RunsClient(base_url=base_url, api_key=api_key)
|
40
|
+
self.models = ModelsClient(base_url=base_url, api_key=api_key)
|
itzam/base/__init__.py
ADDED
itzam/base/client.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
import requests
|
2
|
+
from ..utils.exceptions import raise_for_status
|
3
|
+
import logging
|
4
|
+
logger = logging.getLogger(__name__)
|
5
|
+
class BaseClient:
|
6
|
+
""" Base client for making HTTP requests to the Itzam API.
|
7
|
+
This class should be extended by specific API clients.
|
8
|
+
It handles the common functionality of making requests, including setting headers and handling errors.
|
9
|
+
"""
|
10
|
+
def __init__(self, api_key: str, base_url: str):
|
11
|
+
self.base_url = base_url
|
12
|
+
self.api_key = api_key
|
13
|
+
|
14
|
+
def request(self, method: str, endpoint: str, params: dict = None, data: dict = None, **kwargs):
|
15
|
+
url = f"{self.base_url}{endpoint}"
|
16
|
+
headers = {
|
17
|
+
"Content-Type": "application/json",
|
18
|
+
"User-Agent": "Itzam-Python-SDK/1.0",
|
19
|
+
"Api-Key": self.api_key
|
20
|
+
}
|
21
|
+
|
22
|
+
response = requests.request(method, url, headers=headers, params=params, json=data, **kwargs)
|
23
|
+
|
24
|
+
logger.debug(f"Request URL: {response.request.url}")
|
25
|
+
logger.debug(f"Request Method: {response.request.method}")
|
26
|
+
logger.debug(f"Request Headers: {response.request.headers}")
|
27
|
+
logger.debug(f"Request Body: {response.request.body}")
|
28
|
+
logger.debug(f"Response Status Code: {response.status_code}")
|
29
|
+
logger.debug(f"Response body: {response.text}")
|
30
|
+
|
31
|
+
if response.status_code != 200:
|
32
|
+
raise_for_status(response)
|
33
|
+
|
34
|
+
return response
|
itzam/models/__init__.py
ADDED
itzam/models/__main__.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
from .client import ModelsClient
|
2
|
+
|
3
|
+
if __name__ == "__main__":
|
4
|
+
from rich.console import Console
|
5
|
+
from rich.table import Table
|
6
|
+
import dotenv, os
|
7
|
+
dotenv.load_dotenv()
|
8
|
+
client = ModelsClient(base_url="https://itz.am", api_key=os.getenv("ITZAM_API_KEY"))
|
9
|
+
models = client.list()
|
10
|
+
console = Console()
|
11
|
+
|
12
|
+
table = Table(title="Models List")
|
13
|
+
table.add_column("Name", style="cyan", no_wrap=True)
|
14
|
+
table.add_column("Tag", style="magenta")
|
15
|
+
table.add_column("Deprecated", style="red")
|
16
|
+
table.add_column("Open Source", style="green")
|
17
|
+
table.add_column("Context Window Size", style="yellow")
|
18
|
+
|
19
|
+
for model in models:
|
20
|
+
table.add_row(
|
21
|
+
model.name,
|
22
|
+
model.tag,
|
23
|
+
"Yes" if model.deprecated else "No",
|
24
|
+
"Yes" if model.isOpenSource else "No",
|
25
|
+
str(model.contextWindowSize)
|
26
|
+
)
|
27
|
+
|
28
|
+
console.print(table)
|
itzam/models/client.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
from .models import Model
|
2
|
+
from ..base.client import BaseClient
|
3
|
+
|
4
|
+
class ModelsClient(BaseClient):
|
5
|
+
"""
|
6
|
+
Client for interacting with the Itzam Models API.
|
7
|
+
"""
|
8
|
+
|
9
|
+
def __init__(self, base_url: str, api_key: str):
|
10
|
+
super().__init__(base_url=base_url, api_key=api_key)
|
11
|
+
|
12
|
+
def list(self) -> list[Model]:
|
13
|
+
"""
|
14
|
+
List all available models.
|
15
|
+
"""
|
16
|
+
endpoint = "/api/v1/models"
|
17
|
+
response = self.request(method="GET", endpoint=endpoint)
|
18
|
+
return [Model.model_validate(model) for model in response.json().get("models", [])]
|
itzam/models/models.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
from pydantic import BaseModel, Field
|
2
|
+
|
3
|
+
class Provider(BaseModel):
|
4
|
+
name: str
|
5
|
+
|
6
|
+
class Model(BaseModel):
|
7
|
+
name: str
|
8
|
+
tag: str
|
9
|
+
deprecated: bool
|
10
|
+
hasVision: bool
|
11
|
+
hasReasoningCapability: bool
|
12
|
+
isOpenSource: bool
|
13
|
+
contextWindowSize: int
|
14
|
+
inputPerMillionTokenCost: float
|
15
|
+
outputPerMillionTokenCost: float
|
16
|
+
provider: Provider
|
itzam/runs/__init__.py
ADDED
itzam/runs/client.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
from .models import Run
|
2
|
+
from ..base.client import BaseClient
|
3
|
+
|
4
|
+
class RunsClient(BaseClient):
|
5
|
+
"""
|
6
|
+
Client for interacting with the Itzam Runs API.
|
7
|
+
"""
|
8
|
+
|
9
|
+
def __init__(self, base_url: str, api_key: str):
|
10
|
+
super().__init__(base_url=base_url, api_key=api_key)
|
11
|
+
|
12
|
+
def get(self, run_id: str) -> Run:
|
13
|
+
"""
|
14
|
+
Get a run by its ID.
|
15
|
+
"""
|
16
|
+
endpoint = f"/api/v1/runs/{run_id}"
|
17
|
+
response = self.request(method="GET", endpoint=endpoint)
|
18
|
+
return Run.model_validate(response.json())
|
itzam/runs/models.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
from pydantic import BaseModel, Field
|
2
|
+
from typing import List, Optional
|
3
|
+
from datetime import datetime
|
4
|
+
from ..text.models import ModelInput as Model, Attachment
|
5
|
+
|
6
|
+
|
7
|
+
class AttachmentResponse(Attachment):
|
8
|
+
id: str
|
9
|
+
|
10
|
+
|
11
|
+
class Knowledge(BaseModel):
|
12
|
+
id: str
|
13
|
+
title: str
|
14
|
+
url: str
|
15
|
+
type: str
|
16
|
+
|
17
|
+
|
18
|
+
class Run(BaseModel):
|
19
|
+
id: str
|
20
|
+
origin: str
|
21
|
+
status: str
|
22
|
+
input: str
|
23
|
+
output: str
|
24
|
+
prompt: str
|
25
|
+
input_tokens: int = Field(alias="inputTokens")
|
26
|
+
output_tokens: int = Field(alias="outputTokens")
|
27
|
+
cost: str
|
28
|
+
duration_in_ms: int = Field(alias="durationInMs")
|
29
|
+
thread_id: str|None = Field(alias="threadId", default=None)
|
30
|
+
model: Model
|
31
|
+
attachments: List[Attachment] = Field(default=[])
|
32
|
+
knowledge: List[Knowledge ] = Field(default=[])
|
33
|
+
workflow_id: str = Field(alias="workflowId")
|
34
|
+
created_at: datetime = Field(alias="createdAt")
|
itzam/text/__init__.py
ADDED
itzam/text/client.py
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
import requests
|
2
|
+
from .models import (
|
3
|
+
Attachment,
|
4
|
+
ModelInput,
|
5
|
+
ResponseMetadata,
|
6
|
+
Response
|
7
|
+
)
|
8
|
+
from ..base.client import BaseClient
|
9
|
+
import json
|
10
|
+
|
11
|
+
class TextClient(BaseClient):
|
12
|
+
"""
|
13
|
+
Client for interacting with the Itzam Text API.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def __init__(self, base_url: str, api_key: str):
|
17
|
+
super().__init__(base_url=base_url, api_key=api_key)
|
18
|
+
|
19
|
+
def generate(
|
20
|
+
self,
|
21
|
+
input: str,
|
22
|
+
workflow_slug: str | None = None,
|
23
|
+
thread_id: str | None = None,
|
24
|
+
attachments: list[Attachment] = None,
|
25
|
+
stream: bool = False
|
26
|
+
):
|
27
|
+
"""
|
28
|
+
Generate text using the specified model and prompt.
|
29
|
+
If stream=True, returns a generator yielding text deltas.
|
30
|
+
"""
|
31
|
+
if not workflow_slug and not thread_id:
|
32
|
+
raise ValueError("Either 'thread_id' or 'worflow_slug' must be provided.")
|
33
|
+
endpoint = "/api/v1/generate/text"
|
34
|
+
data = {
|
35
|
+
"input": input,
|
36
|
+
"workflowSlug": workflow_slug,
|
37
|
+
**({"threadId": thread_id} if thread_id else {}),
|
38
|
+
**({"attachments": [attachment.model_dump() for attachment in attachments]} if attachments else {})
|
39
|
+
}
|
40
|
+
|
41
|
+
if stream == True:
|
42
|
+
return self._stream_text("/api/v1/stream/text", data)
|
43
|
+
else:
|
44
|
+
response = self.request(method="POST", endpoint=endpoint, data=data)
|
45
|
+
return Response.model_validate(response.json())
|
46
|
+
|
47
|
+
def _stream_text(self, endpoint, data):
|
48
|
+
"""
|
49
|
+
Internal method to handle streaming text responses.
|
50
|
+
Yields text deltas as they arrive.
|
51
|
+
"""
|
52
|
+
response = self.request(method="POST", endpoint=endpoint, data=data, stream=True)
|
53
|
+
for line in response.iter_lines():
|
54
|
+
if line:
|
55
|
+
try:
|
56
|
+
event = json.loads(line.decode("utf-8").removeprefix("data: "))
|
57
|
+
if event.get("type") == "text-delta":
|
58
|
+
yield event.get("textDelta")
|
59
|
+
except Exception as e:
|
60
|
+
continue
|
itzam/text/models.py
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
from pydantic import BaseModel, Field
|
2
|
+
|
3
|
+
class Attachment(BaseModel):
|
4
|
+
"""
|
5
|
+
Represents an attachment in a text message.
|
6
|
+
"""
|
7
|
+
file: str = Field(
|
8
|
+
...,
|
9
|
+
description="The file path or URL of the attachment. Either a base64 encoded string or a URL."
|
10
|
+
)
|
11
|
+
mimetype: str = Field(
|
12
|
+
...,
|
13
|
+
description="The MIME type of the attachment, e.g., 'image/png', 'application/pdf'."
|
14
|
+
)
|
15
|
+
|
16
|
+
class ModelInput(BaseModel):
|
17
|
+
"""
|
18
|
+
Represents a model used for text generation.
|
19
|
+
"""
|
20
|
+
name: str = Field(..., description="The name of the model used for this generation.")
|
21
|
+
tag: str = Field(..., description="The tag of the model used for text generation.")
|
22
|
+
|
23
|
+
class ResponseMetadata(BaseModel):
|
24
|
+
"""
|
25
|
+
Metadata for the response.
|
26
|
+
"""
|
27
|
+
run_id: str = Field(alias="runId", description="The ID of the run created for this generation")
|
28
|
+
cost: str = Field(description="The cost of the generation in USD")
|
29
|
+
model: ModelInput
|
30
|
+
duration: int = Field( description="The duration of the generation in milliseconds", alias="durationInMs")
|
31
|
+
input_tokens: int = Field(alias="inputTokens", description="The number of input tokens used in the generation")
|
32
|
+
output_tokens: int = Field(alias="outputTokens", description="The number of output tokens used in this generation")
|
33
|
+
|
34
|
+
class Response(BaseModel):
|
35
|
+
"""
|
36
|
+
Represents the response from the text generation API.
|
37
|
+
"""
|
38
|
+
text: str = Field(description="The generated text")
|
39
|
+
metadata: ResponseMetadata = Field(description="Metadata about the generation process")
|
itzam/threads/client.py
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
from ..base.client import BaseClient
|
2
|
+
from .models import (
|
3
|
+
Thread
|
4
|
+
)
|
5
|
+
|
6
|
+
class ThreadsClient(BaseClient):
|
7
|
+
"""
|
8
|
+
Client for interacting with the Itzam Threads API.
|
9
|
+
"""
|
10
|
+
|
11
|
+
def __init__(self, base_url: str, api_key: str):
|
12
|
+
super().__init__(base_url=base_url, api_key=api_key)
|
13
|
+
|
14
|
+
def create(self, workflow_slug:str, name:str|None = None, lookup_keys:list[str] = [], context_slugs:list[str] = []) -> Thread:
|
15
|
+
"""
|
16
|
+
Create a new thread.
|
17
|
+
"""
|
18
|
+
endpoint = "/api/v1/threads"
|
19
|
+
data = {
|
20
|
+
"workflowSlug": workflow_slug,
|
21
|
+
"name": name,
|
22
|
+
}
|
23
|
+
if lookup_keys:
|
24
|
+
data["lookupKeys"] = lookup_keys
|
25
|
+
if context_slugs:
|
26
|
+
data["contextSlugs"] = context_slugs
|
27
|
+
response = self.request(method="POST", endpoint=endpoint, data=data)
|
28
|
+
return Thread.model_validate(response.json())
|
29
|
+
|
30
|
+
def get(self, thread_id: str) -> Thread:
|
31
|
+
"""
|
32
|
+
Get a thread by its ID.
|
33
|
+
"""
|
34
|
+
endpoint = f"/api/v1/threads/{thread_id}"
|
35
|
+
response = self.request(method="GET", endpoint=endpoint)
|
36
|
+
return Thread.model_validate(response.json())
|
37
|
+
|
38
|
+
def from_workflow(self, workflow_slug: str) -> list[Thread]:
|
39
|
+
"""
|
40
|
+
Get all threads for a specific workflow.
|
41
|
+
"""
|
42
|
+
endpoint = f"/api/v1/threads/workflow/{workflow_slug}"
|
43
|
+
response = self.request(method="GET", endpoint=endpoint)
|
44
|
+
return [Thread.model_validate(thread) for thread in response.json().get("threads", [])]
|
45
|
+
|
46
|
+
def runs_from_thread(self, thread_id: str) -> list[dict]:
|
47
|
+
"""
|
48
|
+
Get all runs for a specific thread.
|
49
|
+
"""
|
50
|
+
endpoint = f"/api/v1/threads/{thread_id}/runs"
|
51
|
+
response = self.request(method="GET", endpoint=endpoint)
|
52
|
+
return response.json().get("runs", [])
|
53
|
+
|
itzam/threads/models.py
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
from pydantic import BaseModel, Field
|
2
|
+
|
3
|
+
class Thread(BaseModel):
|
4
|
+
name: str | None = Field(default=None, description="The name of the thread (optional, will auto-generate if not provided)")
|
5
|
+
lookup_keys: list[str] | None = Field(default=None, description="Optional lookup keys for finding the thread later", alias="lookupKeys")
|
6
|
+
context_slugs: list[str] | None = Field(default=None, description="Optional context slugs to append the context to the thread", alias="contextSlugs")
|
7
|
+
created_at: str | None = Field(default=None, description="The date and time when the thread was created", alias="createdAt")
|
8
|
+
updated_at: str | None = Field(default=None, description="The date and time when the thread was last updated", alias="updatedAt")
|
9
|
+
id: str = Field(..., description="The unique identifier for the thread")
|
10
|
+
|
11
|
+
|
@@ -0,0 +1,187 @@
|
|
1
|
+
from http import HTTPStatus
|
2
|
+
from typing import Literal
|
3
|
+
|
4
|
+
import requests
|
5
|
+
|
6
|
+
|
7
|
+
class APIError(Exception):
|
8
|
+
"""The exception was raised due to an API error."""
|
9
|
+
|
10
|
+
message: str
|
11
|
+
request: str
|
12
|
+
|
13
|
+
def __init__(self, message: str, request: requests.Request) -> None:
|
14
|
+
super().__init__(message)
|
15
|
+
self.message = """The exception was raised due to an API error."""
|
16
|
+
self.request = request
|
17
|
+
|
18
|
+
def __str__(self) -> str:
|
19
|
+
if self.message:
|
20
|
+
return f'{self.message}'
|
21
|
+
return ''
|
22
|
+
|
23
|
+
|
24
|
+
class APIStatusError(APIError):
|
25
|
+
"""Raised when an API response has a status code of 4xx or 5xx."""
|
26
|
+
|
27
|
+
response: requests.Response
|
28
|
+
status_code: int
|
29
|
+
|
30
|
+
def __init__(
|
31
|
+
self, message: str = '', *, response: requests.Response
|
32
|
+
) -> None:
|
33
|
+
super().__init__(message, response.request)
|
34
|
+
self.response = response
|
35
|
+
self.status_code = response.status_code
|
36
|
+
|
37
|
+
|
38
|
+
class ForbiddenRequest(APIStatusError):
|
39
|
+
"""
|
40
|
+
Means that the request was unsuccessful due to a forbidden request.
|
41
|
+
Maybe your API key is wrong?
|
42
|
+
"""
|
43
|
+
|
44
|
+
status_code: Literal[HTTPStatus.FORBIDDEN]
|
45
|
+
|
46
|
+
def __init__(self, response: requests.Response, message: str = ''):
|
47
|
+
super().__init__(message, response=response)
|
48
|
+
self.message = (
|
49
|
+
'Means that the request was unsuccessful due to a '
|
50
|
+
'forbidden request. Maybe your API key is wrong?'
|
51
|
+
)
|
52
|
+
self.response = response
|
53
|
+
self.status_code = HTTPStatus.FORBIDDEN
|
54
|
+
|
55
|
+
def __str__(self) -> str:
|
56
|
+
if self.message:
|
57
|
+
return (
|
58
|
+
f'{self.message} \n Status Code: {self.response.status_code}'
|
59
|
+
f' | Response: {self.response.text}'
|
60
|
+
)
|
61
|
+
return str(self.response.content, 'utf-8')
|
62
|
+
|
63
|
+
|
64
|
+
class UnauthorizedRequest(APIStatusError):
|
65
|
+
"""
|
66
|
+
Means that the request was unsuccessful due to a forbidden request.
|
67
|
+
Maybe your API key doesn't have enought permissions
|
68
|
+
"""
|
69
|
+
|
70
|
+
status_code: Literal[HTTPStatus.UNAUTHORIZED]
|
71
|
+
|
72
|
+
def __init__(self, response: requests.Response, message: str = ''):
|
73
|
+
super().__init__(message, response=response)
|
74
|
+
self.message = (
|
75
|
+
'Means that the request was unsuccessful due to a forbidden '
|
76
|
+
"request. Maybe your API key doesn't have enought permissions"
|
77
|
+
)
|
78
|
+
self.response = response
|
79
|
+
self.status_code = HTTPStatus.UNAUTHORIZED
|
80
|
+
|
81
|
+
def __str__(self) -> str:
|
82
|
+
if self.message:
|
83
|
+
return (
|
84
|
+
f'{self.message} | Status Code: {self.response.status_code}'
|
85
|
+
f' | Response: {self.response.text}'
|
86
|
+
)
|
87
|
+
return str(self.response.content, 'utf-8')
|
88
|
+
|
89
|
+
|
90
|
+
class APIConnectionError(APIError):
|
91
|
+
"""The request was unsuccessful due to a connection error.
|
92
|
+
Check your internet connection"""
|
93
|
+
|
94
|
+
def __init__(
|
95
|
+
self,
|
96
|
+
*,
|
97
|
+
message: str = (
|
98
|
+
'The request was unsuccessful due to a connection error.'
|
99
|
+
' Check your internet connection'
|
100
|
+
),
|
101
|
+
request: requests.Request,
|
102
|
+
) -> None:
|
103
|
+
super().__init__(message, request)
|
104
|
+
|
105
|
+
|
106
|
+
class APITimeoutError(APIConnectionError):
|
107
|
+
"""The request got timed out. You might try checking
|
108
|
+
your internet connection."""
|
109
|
+
|
110
|
+
def __init__(self, request: requests.Request) -> None:
|
111
|
+
super().__init__(
|
112
|
+
message='Request timed out. Check your internet connection',
|
113
|
+
request=request,
|
114
|
+
)
|
115
|
+
|
116
|
+
|
117
|
+
class BadRequestError(APIStatusError):
|
118
|
+
"""The request was unsuccessful due to a bad request.
|
119
|
+
Maybe the request syntax is wrong"""
|
120
|
+
|
121
|
+
status_code: Literal[HTTPStatus.BAD_REQUEST]
|
122
|
+
|
123
|
+
def __init__(self, response: requests.Response) -> None:
|
124
|
+
self.response = response
|
125
|
+
self.status_code = HTTPStatus.BAD_REQUEST
|
126
|
+
|
127
|
+
def __str__(self) -> str:
|
128
|
+
return (
|
129
|
+
f'The request was unsuccessful due to a bad request. '
|
130
|
+
'Maybe the request syntax is wrong. Message error: '
|
131
|
+
f'{self.response.json()}'
|
132
|
+
)
|
133
|
+
|
134
|
+
|
135
|
+
class NotFoundError(APIStatusError):
|
136
|
+
status_code: Literal[HTTPStatus.NOT_FOUND]
|
137
|
+
|
138
|
+
def __init__(
|
139
|
+
self, message: str = '', *, response: requests.Response
|
140
|
+
) -> None:
|
141
|
+
super().__init__(message, response=response)
|
142
|
+
self.status_code = HTTPStatus.NOT_FOUND
|
143
|
+
|
144
|
+
def __str__(self) -> str:
|
145
|
+
return (
|
146
|
+
'The request was unsuccessful due to a not found error. '
|
147
|
+
f'Error status 404 | Requested URL: {self.response.url}'
|
148
|
+
)
|
149
|
+
|
150
|
+
|
151
|
+
class InternalServerError(APIStatusError):
|
152
|
+
"""The request was unsuccessful due to an internal server error."""
|
153
|
+
|
154
|
+
status_code: Literal[500] = 500
|
155
|
+
|
156
|
+
def __init__(self, response: requests.Response) -> None:
|
157
|
+
super().__init__(
|
158
|
+
message=(
|
159
|
+
'The request was unsuccessful due to an internal server error.'
|
160
|
+
" It's not your fault, just try again later."
|
161
|
+
),
|
162
|
+
response=response,
|
163
|
+
)
|
164
|
+
|
165
|
+
|
166
|
+
def raise_for_status(response: requests.Response) -> None:
|
167
|
+
code_exc_dict = {
|
168
|
+
HTTPStatus.BAD_REQUEST: BadRequestError(response=response),
|
169
|
+
HTTPStatus.UNAUTHORIZED: UnauthorizedRequest(response=response),
|
170
|
+
HTTPStatus.FORBIDDEN: ForbiddenRequest(response=response),
|
171
|
+
HTTPStatus.NOT_FOUND: NotFoundError(response=response),
|
172
|
+
HTTPStatus.INTERNAL_SERVER_ERROR: InternalServerError(
|
173
|
+
response=response
|
174
|
+
),
|
175
|
+
}
|
176
|
+
|
177
|
+
code = response.status_code
|
178
|
+
if code == HTTPStatus.OK:
|
179
|
+
return
|
180
|
+
|
181
|
+
if code not in code_exc_dict and code >= HTTPStatus.BAD_REQUEST:
|
182
|
+
raise APIStatusError(message=response.text, response=response)
|
183
|
+
|
184
|
+
raise code_exc_dict.get(
|
185
|
+
response.status_code,
|
186
|
+
APIError(message=response.text, request=response.request),
|
187
|
+
)
|
@@ -0,0 +1,131 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: itzam
|
3
|
+
Version: 1.0.0
|
4
|
+
Summary: Python SDK to interact with Itzam's API
|
5
|
+
Author-email: Joaquim Cassano <joaquim@cassano.com.br>
|
6
|
+
Requires-Python: <4.0,>=3.10
|
7
|
+
Description-Content-Type: text/markdown
|
8
|
+
Requires-Dist: pydantic
|
9
|
+
Requires-Dist: requests
|
10
|
+
Requires-Dist: rich
|
11
|
+
|
12
|
+
# Itzam python sdk
|
13
|
+

|
14
|
+
|
15
|
+
## Overview
|
16
|
+
|
17
|
+
Itzam Python SDK provides a simple interface to interact with the [Itzam API](https://itz.am) for text generation, thread management, model listing, and run inspection.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
```bash
|
22
|
+
pip install itzam
|
23
|
+
```
|
24
|
+
|
25
|
+
## Quick Start
|
26
|
+
|
27
|
+
```python
|
28
|
+
from itzam import Itzam
|
29
|
+
|
30
|
+
client = Itzam("your-api-key")
|
31
|
+
response = client.text.generate(
|
32
|
+
workflow_slug="your_workflow_slug",
|
33
|
+
input="Hello, Itzam!",
|
34
|
+
stream=False
|
35
|
+
)
|
36
|
+
print(response.text)
|
37
|
+
```
|
38
|
+
|
39
|
+
## Authentication
|
40
|
+
|
41
|
+
You can provide your API key directly or set it as an environment variable:
|
42
|
+
|
43
|
+
```bash
|
44
|
+
export ITZAM_API_KEY=your-api-key
|
45
|
+
```
|
46
|
+
|
47
|
+
Then initialize without arguments:
|
48
|
+
|
49
|
+
```python
|
50
|
+
from itzam import Itzam
|
51
|
+
client = Itzam()
|
52
|
+
```
|
53
|
+
|
54
|
+
## Features
|
55
|
+
|
56
|
+
- **Text Generation**: Generate text using your workflows.
|
57
|
+
- **Threads**: Create and manage threads for conversations.
|
58
|
+
- **Models**: List available models and their details.
|
59
|
+
- **Runs**: Inspect previous runs and their metadata.
|
60
|
+
|
61
|
+
## Usage Examples
|
62
|
+
|
63
|
+
### Generate Text
|
64
|
+
|
65
|
+
```python
|
66
|
+
response = client.text.generate(
|
67
|
+
workflow_slug="your_workflow_slug",
|
68
|
+
input="Write a poem about the sea."
|
69
|
+
)
|
70
|
+
print(response.text)
|
71
|
+
```
|
72
|
+
|
73
|
+
### Stream Text Generation
|
74
|
+
|
75
|
+
```python
|
76
|
+
for delta in client.text.generate(
|
77
|
+
workflow_slug="your_workflow_slug",
|
78
|
+
input="Tell me a story.",
|
79
|
+
stream=True
|
80
|
+
):
|
81
|
+
print(delta, end="", flush=True)
|
82
|
+
```
|
83
|
+
|
84
|
+
### List Models
|
85
|
+
|
86
|
+
```python
|
87
|
+
models = client.models.list()
|
88
|
+
for model in models:
|
89
|
+
print(model.name, model.tag)
|
90
|
+
```
|
91
|
+
|
92
|
+
### Create a Thread
|
93
|
+
|
94
|
+
```python
|
95
|
+
thread = client.threads.create(
|
96
|
+
workflow_slug="your_workflow_slug",
|
97
|
+
name="Support Conversation"
|
98
|
+
)
|
99
|
+
print(thread.id)
|
100
|
+
```
|
101
|
+
|
102
|
+
### Get a Run
|
103
|
+
|
104
|
+
```python
|
105
|
+
run = client.runs.get("run_id")
|
106
|
+
print(run.output)
|
107
|
+
```
|
108
|
+
|
109
|
+
## Advanced
|
110
|
+
|
111
|
+
You can specify a custom API base URL if needed:
|
112
|
+
|
113
|
+
```python
|
114
|
+
client = Itzam(api_key="your-api-key", base_url="https://itz.am")
|
115
|
+
```
|
116
|
+
|
117
|
+
## Requirements
|
118
|
+
|
119
|
+
- Python 3.10+
|
120
|
+
- `requests`
|
121
|
+
- `pydantic`
|
122
|
+
- `rich`
|
123
|
+
- `python-dotenv` (optional, for environment variable loading)
|
124
|
+
|
125
|
+
## License
|
126
|
+
|
127
|
+
MIT
|
128
|
+
|
129
|
+
---
|
130
|
+
|
131
|
+
For more details, see the [API documentation](https://itz.am).
|
@@ -0,0 +1,21 @@
|
|
1
|
+
itzam/__init__.py,sha256=bENDRFgjtSUMWgRRjdRH_EdCm6uABG1K9O16eDKc50M,1286
|
2
|
+
itzam/base/__init__.py,sha256=DalvyyupMefIabAm2Zr08bJEgMe_4YW18wZAghz9ng4,98
|
3
|
+
itzam/base/client.py,sha256=PoZ8qfSVOSKFEqQmspr0EcOdFHWHUkaAZryxJ7xrhYg,1395
|
4
|
+
itzam/models/__init__.py,sha256=zQnpPpnTxv1UN1nryKH0IbUPMRJj_-Z6GhIgT0Z0Dk8,69
|
5
|
+
itzam/models/__main__.py,sha256=A5m-oX_MYktOObynqzFNpzwzhFM-s7d3Dn0q_OP0l4I,868
|
6
|
+
itzam/models/client.py,sha256=oyzZbsbNTtQaEapiP-RPBgevBWeYDPwZ_hMmrjpGsoE,568
|
7
|
+
itzam/models/models.py,sha256=exr_ZgRSkERB_0-gJaWfYYcGxwa3dnVx69TkEbGrDzo,329
|
8
|
+
itzam/runs/__init__.py,sha256=krE8QnjXNZ-lhVAVnHh7kTSMiXJdCEJc1Jm7iu57A4k,63
|
9
|
+
itzam/runs/client.py,sha256=zgjCUghl4-a_FwYWOFe6n1hbX0kv66G2IS0XHxcz8w4,527
|
10
|
+
itzam/runs/models.py,sha256=feYO8lljmwoOk3IY1zXlZ_rZRYev890V1iQwbrVL6rs,828
|
11
|
+
itzam/text/__init__.py,sha256=q-zsrXjBOajDSzFIOma1ROssRAUN4qS0lTpiX9dBEz0,260
|
12
|
+
itzam/text/client.py,sha256=02bGNaJg1O9wz77rn8OO8AUEUhCWCpePg8GMdQxMDTo,2043
|
13
|
+
itzam/text/models.py,sha256=rgrQ3utoBHI-G6uWc9y-nlufn90mgARs1fwXWpXzqCc,1561
|
14
|
+
itzam/threads/__init__.py,sha256=-JGYGwOaiiozh3f-PWKZKIKWMN8WY4Wj1Y1SWbV74CA,109
|
15
|
+
itzam/threads/client.py,sha256=jXALIcUhiNi4kdmQNf3BGD_WjDGeXHSVknZ41tNwAi8,1816
|
16
|
+
itzam/threads/models.py,sha256=RYgiDmm9hsgJbuI88Zu3MGfNhmsE7-UMokrs7P9-Y1Y,829
|
17
|
+
itzam/utils/exceptions.py,sha256=Zmxn-ZQjNFwRqHFKTg2uxQf53f7cKi2sgbj65XXIHuE,5749
|
18
|
+
itzam-1.0.0.dist-info/METADATA,sha256=L8sBw3OyBohjzrW2zhX0O6S80y7rYWWNVH92jYbyjxc,2422
|
19
|
+
itzam-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
20
|
+
itzam-1.0.0.dist-info/top_level.txt,sha256=krzAg5bkN3qcDdhHvmUgpOOWct4KcdpwbfeR-p-QHJE,6
|
21
|
+
itzam-1.0.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
itzam
|