aisberg 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.
Files changed (43) hide show
  1. aisberg/__init__.py +7 -0
  2. aisberg/abstract/__init__.py +0 -0
  3. aisberg/abstract/modules.py +57 -0
  4. aisberg/api/__init__.py +0 -0
  5. aisberg/api/async_endpoints.py +333 -0
  6. aisberg/api/endpoints.py +328 -0
  7. aisberg/async_client.py +107 -0
  8. aisberg/client.py +108 -0
  9. aisberg/config.py +17 -0
  10. aisberg/exceptions.py +22 -0
  11. aisberg/models/__init__.py +0 -0
  12. aisberg/models/chat.py +143 -0
  13. aisberg/models/collections.py +36 -0
  14. aisberg/models/embeddings.py +92 -0
  15. aisberg/models/models.py +39 -0
  16. aisberg/models/requests.py +11 -0
  17. aisberg/models/token.py +11 -0
  18. aisberg/models/tools.py +73 -0
  19. aisberg/models/workflows.py +66 -0
  20. aisberg/modules/__init__.py +23 -0
  21. aisberg/modules/chat.py +403 -0
  22. aisberg/modules/collections.py +117 -0
  23. aisberg/modules/document.py +117 -0
  24. aisberg/modules/embeddings.py +309 -0
  25. aisberg/modules/me.py +77 -0
  26. aisberg/modules/models.py +108 -0
  27. aisberg/modules/tools.py +78 -0
  28. aisberg/modules/workflows.py +140 -0
  29. aisberg/requests/__init__.py +0 -0
  30. aisberg/requests/async_requests.py +85 -0
  31. aisberg/requests/sync_requests.py +85 -0
  32. aisberg/utils.py +111 -0
  33. aisberg-0.1.0.dist-info/METADATA +212 -0
  34. aisberg-0.1.0.dist-info/RECORD +43 -0
  35. aisberg-0.1.0.dist-info/WHEEL +5 -0
  36. aisberg-0.1.0.dist-info/licenses/LICENSE +9 -0
  37. aisberg-0.1.0.dist-info/top_level.txt +3 -0
  38. tests/integration/test_collections_integration.py +115 -0
  39. tests/unit/test_collections_sync.py +104 -0
  40. tmp/test.py +33 -0
  41. tmp/test_async.py +126 -0
  42. tmp/test_doc_parse.py +12 -0
  43. tmp/test_sync.py +146 -0
@@ -0,0 +1,140 @@
1
+ from typing import List, Union, Generator, AsyncGenerator, Coroutine, Any
2
+ from abc import ABC
3
+
4
+ from ..models.workflows import (
5
+ Workflow,
6
+ WorkflowDetails,
7
+ WorkflowRunChunk,
8
+ WorkflowRunResult,
9
+ )
10
+
11
+ from abc import abstractmethod
12
+ from ..abstract.modules import SyncModule, AsyncModule
13
+ from ..api import endpoints, async_endpoints
14
+
15
+
16
+ class AbstractWorkflowsModule(ABC):
17
+ def __init__(self, parent, client):
18
+ self._parent = parent
19
+ self._client = client
20
+
21
+ @abstractmethod
22
+ def get(self) -> List[Workflow]:
23
+ """Get a list of available workflows.
24
+
25
+ Returns:
26
+ List[dict]: A list of available workflows.
27
+
28
+ Raises:
29
+ Exception: If there is an error fetching the workflows.
30
+ """
31
+ pass
32
+
33
+ @abstractmethod
34
+ def details(self, workflow_id: str) -> WorkflowDetails:
35
+ """Get details of a specific workflow.
36
+
37
+ Args:
38
+ workflow_id (str): The ID of the workflow to retrieve.
39
+
40
+ Returns:
41
+ WorkflowDetails: The details of the specified workflow.
42
+
43
+ Raises:
44
+ ValueError: If the workflow with the specified ID is not found.
45
+ Exception: If there is an error fetching the workflow details.
46
+ """
47
+ pass
48
+
49
+ @abstractmethod
50
+ def run(self, workflow_id: str, data: dict = None, stream: bool = False):
51
+ """
52
+ Run a workflow with the given ID and data.
53
+ If `stream` is True, it will yield chunks of the workflow run.
54
+ If `stream` is False, it will return the final result of the workflow run.
55
+
56
+ Args:
57
+ workflow_id (str): The ID of the workflow to run.
58
+ data (dict, optional): The input data for the workflow. Defaults to None.
59
+ stream (bool, optional): If True, returns a generator yielding chunks of the workflow run. Defaults to False.
60
+
61
+ Returns:
62
+ Union[Generator[WorkflowRunChunk, None, None], WorkflowRunResult]:
63
+ If `stream` is True, a generator yielding chunks of the workflow run.
64
+ If `stream` is False, the final result of the workflow run.
65
+
66
+ Raises:
67
+ ValueError: If the workflow with the specified ID is not found.
68
+ Exception: If there is an error running the workflow.
69
+ """
70
+ pass
71
+
72
+
73
+ class SyncWorkflowsModule(SyncModule, AbstractWorkflowsModule):
74
+ def __init__(self, parent, client):
75
+ SyncModule.__init__(self, parent, client)
76
+ AbstractWorkflowsModule.__init__(self, parent, client)
77
+
78
+ def get(self) -> List[Workflow]:
79
+ return endpoints.workflows(self._client)
80
+
81
+ def details(self, workflow_id: str) -> WorkflowDetails:
82
+ return endpoints.workflow(self._client, workflow_id)
83
+
84
+ def run(
85
+ self, workflow_id: str, data: dict = None, stream: bool = False
86
+ ) -> Union[Generator[WorkflowRunChunk, None, None], WorkflowRunResult]:
87
+ if stream:
88
+ return self._run_stream(workflow_id, data)
89
+ else:
90
+ return self._run_once(workflow_id, data)
91
+
92
+ def _run_stream(
93
+ self, workflow_id: str, data: dict = None
94
+ ) -> Generator[WorkflowRunChunk, None, None]:
95
+ for chunk in endpoints.run_workflow(self._client, workflow_id, data):
96
+ yield WorkflowRunChunk.model_validate(chunk)
97
+
98
+ def _run_once(self, workflow_id: str, data: dict = None) -> WorkflowRunResult:
99
+ last_response = None
100
+ for chunk in endpoints.run_workflow(self._client, workflow_id, data):
101
+ last_response = chunk
102
+ return WorkflowRunResult.model_validate(last_response)
103
+
104
+
105
+ class AsyncWorkflowsModule(AsyncModule, AbstractWorkflowsModule):
106
+ def __init__(self, parent, client):
107
+ AsyncModule.__init__(self, parent, client)
108
+ AbstractWorkflowsModule.__init__(self, parent, client)
109
+
110
+ async def get(self) -> List[Workflow]:
111
+ return await async_endpoints.workflows(self._client)
112
+
113
+ async def details(self, workflow_id: str) -> WorkflowDetails:
114
+ return await async_endpoints.workflow(self._client, workflow_id)
115
+
116
+ def run(
117
+ self, workflow_id: str, data: dict = None, stream: bool = False
118
+ ) -> Union[
119
+ AsyncGenerator[WorkflowRunChunk, None], Coroutine[Any, Any, WorkflowRunResult]
120
+ ]:
121
+ if stream:
122
+ return self._run_stream(workflow_id, data)
123
+ else:
124
+ return self._run_once(workflow_id, data)
125
+
126
+ async def _run_stream(
127
+ self, workflow_id: str, data: dict = None
128
+ ) -> AsyncGenerator[WorkflowRunChunk, None]:
129
+ async for chunk in async_endpoints.run_workflow(
130
+ self._client, workflow_id, data
131
+ ):
132
+ yield WorkflowRunChunk.model_validate(chunk)
133
+
134
+ async def _run_once(self, workflow_id: str, data: dict = None) -> WorkflowRunResult:
135
+ last_response = None
136
+ async for chunk in async_endpoints.run_workflow(
137
+ self._client, workflow_id, data
138
+ ):
139
+ last_response = chunk
140
+ return WorkflowRunResult.model_validate(last_response)
File without changes
@@ -0,0 +1,85 @@
1
+ from typing import Type, TypeVar, Any, Dict, Optional, Callable
2
+ import httpx
3
+ from pydantic import ValidationError, BaseModel
4
+
5
+ T = TypeVar("T", bound=BaseModel)
6
+
7
+
8
+ async def areq(
9
+ client: httpx.AsyncClient,
10
+ method: str,
11
+ url: str,
12
+ response_model: Type[T],
13
+ *,
14
+ expected_status: int = 200,
15
+ handle_404_none: bool = False,
16
+ **kwargs,
17
+ ) -> Optional[T]:
18
+ """
19
+ Send an HTTP request asynchronously, parse the response.
20
+ Return None if 404 and handle_404_none=True, else raise.
21
+ """
22
+ try:
23
+ resp = await client.request(method, url, **kwargs)
24
+ if handle_404_none and resp.status_code == 404:
25
+ return None
26
+
27
+ if 400 <= resp.status_code < 500:
28
+ resp.read()
29
+ if resp.text == "Please specify a group":
30
+ raise httpx.HTTPStatusError(
31
+ "Bad Request: Please specify a group. Use `AisbergClient.me.groups()` to know which groups you are in.",
32
+ request=resp.request,
33
+ response=resp,
34
+ )
35
+ raise httpx.HTTPStatusError(
36
+ f"Bad Request: {resp.text}", request=resp.request, response=resp
37
+ )
38
+
39
+ resp.raise_for_status()
40
+ return response_model.model_validate(resp.json())
41
+ except httpx.HTTPStatusError as e:
42
+ if handle_404_none and e.response.status_code == 404:
43
+ return None
44
+ raise
45
+ except ValidationError as ve:
46
+ raise RuntimeError(f"Invalid response: {ve}") from ve
47
+
48
+
49
+ async def areq_stream(
50
+ client: httpx.AsyncClient,
51
+ method: str,
52
+ url: str,
53
+ parse_line: Callable[[str], Any],
54
+ *,
55
+ handle_status: Optional[Dict[int, Any]] = None,
56
+ **kwargs,
57
+ ) -> Any:
58
+ """
59
+ Wrapper to handle HTTP streams.
60
+ - parse_line: Function to parse each line of the stream.
61
+ """
62
+ async with client.stream(method, url, **kwargs) as resp:
63
+ if handle_status and resp.status_code in handle_status:
64
+ yield handle_status[resp.status_code]
65
+ return
66
+
67
+ if 400 <= resp.status_code < 500:
68
+ resp.read()
69
+ if resp.text == "Please specify a group":
70
+ raise httpx.HTTPStatusError(
71
+ "Bad Request: Please specify a group. Use `await AisbergAsyncClient.me.groups()` to know which groups you are in.",
72
+ request=resp.request,
73
+ response=resp,
74
+ )
75
+ raise httpx.HTTPStatusError(
76
+ f"Bad Request: {resp.text}", request=resp.request, response=resp
77
+ )
78
+
79
+ resp.raise_for_status()
80
+ async for raw_line in resp.aiter_lines():
81
+ if not raw_line:
82
+ continue
83
+ line = raw_line.decode() if isinstance(raw_line, bytes) else raw_line
84
+ for parsed in parse_line(line):
85
+ yield parsed
@@ -0,0 +1,85 @@
1
+ from typing import Type, TypeVar, Any, Dict, Optional, Generator, Callable
2
+ import httpx
3
+ from pydantic import BaseModel, ValidationError
4
+
5
+ T = TypeVar("T", bound=BaseModel)
6
+
7
+
8
+ def req(
9
+ client: httpx.Client,
10
+ method: str,
11
+ url: str,
12
+ response_model: Type[T],
13
+ *,
14
+ expected_status: int = 200,
15
+ handle_404_none: bool = False,
16
+ **kwargs,
17
+ ) -> Optional[T]:
18
+ """
19
+ Send an HTTP request synchronously, parse the response.
20
+ Return None if 404 and handle_404_none=True, else raise.
21
+ """
22
+ try:
23
+ resp = client.request(method, url, **kwargs)
24
+ if handle_404_none and resp.status_code == 404:
25
+ return None
26
+
27
+ if 400 <= resp.status_code < 500:
28
+ resp.read()
29
+ if resp.text == "Please specify a group":
30
+ raise httpx.HTTPStatusError(
31
+ "Bad Request: Please specify a group. Use `AisbergClient.me.groups()` to know which groups you are in.",
32
+ request=resp.request,
33
+ response=resp,
34
+ )
35
+ raise httpx.HTTPStatusError(
36
+ f"Bad Request: {resp.text}", request=resp.request, response=resp
37
+ )
38
+
39
+ resp.raise_for_status()
40
+ return response_model.model_validate(resp.json())
41
+ except httpx.HTTPStatusError as e:
42
+ if handle_404_none and e.response.status_code == 404:
43
+ return None
44
+ raise
45
+ except ValidationError as ve:
46
+ raise RuntimeError(f"Invalid response: {ve}") from ve
47
+
48
+
49
+ def req_stream(
50
+ client: httpx.Client,
51
+ method: str,
52
+ url: str,
53
+ parse_line: Callable[[str], Any],
54
+ *,
55
+ handle_status: Optional[Dict[int, Any]] = None,
56
+ **kwargs,
57
+ ) -> Generator[Any, None, None]:
58
+ """
59
+ Wrapper to handle HTTP streams.
60
+ - parse_line: Function to parse each line of the stream.
61
+ """
62
+ with client.stream(method, url, **kwargs) as resp:
63
+ if handle_status and resp.status_code in handle_status:
64
+ yield handle_status[resp.status_code]
65
+ return
66
+
67
+ if 400 <= resp.status_code < 500:
68
+ resp.read()
69
+ if resp.text == "Please specify a group":
70
+ raise httpx.HTTPStatusError(
71
+ "Bad Request: Please specify a group. Use `await AisbergAsyncClient.me.groups()` to know which groups you are in.",
72
+ request=resp.request,
73
+ response=resp,
74
+ )
75
+ raise httpx.HTTPStatusError(
76
+ f"Bad Request: {resp.text}", request=resp.request, response=resp
77
+ )
78
+
79
+ resp.raise_for_status()
80
+ for raw_line in resp.iter_lines():
81
+ if not raw_line:
82
+ continue
83
+ line = raw_line.decode() if isinstance(raw_line, bytes) else raw_line
84
+ for parsed in parse_line(line):
85
+ yield parsed
aisberg/utils.py ADDED
@@ -0,0 +1,111 @@
1
+ from typing import Iterator, Union, Dict
2
+ import json
3
+
4
+
5
+ def parse_chat_line(
6
+ line: str, *, full_chunk: bool = True
7
+ ) -> Iterator[Union[str, dict]]:
8
+ """
9
+ Parse une ligne de stream JSON (commençant par `data:`) et yield un ou plusieurs éléments utilisables.
10
+
11
+ Args:
12
+ line (str): Ligne du flux à traiter.
13
+ full_chunk (bool): Contrôle le format de sortie (chunk brut ou contenu transformé).
14
+
15
+ Yields:
16
+ Union[str, dict]: Le chunk complet ou un morceau de texte/fonction/tool_call.
17
+ """
18
+ if not line.startswith("data:"):
19
+ return
20
+
21
+ data = line[len("data:") :].strip()
22
+ if data == "[DONE]":
23
+ return
24
+
25
+ try:
26
+ chunk: dict = json.loads(data)
27
+
28
+ if chunk["object"] != "chat.completion.chunk":
29
+ raise ValueError(f"Unexpected object type: {chunk['object']}")
30
+
31
+ if chunk["choices"][0]["finish_reason"] == "stop":
32
+ return
33
+
34
+ if full_chunk:
35
+ yield chunk
36
+ return
37
+
38
+ delta = chunk.get("choices", [{}])[0].get("delta", {})
39
+
40
+ if "content" in delta and delta["content"]:
41
+ yield delta["content"]
42
+
43
+ elif "function_call" in delta and delta["function_call"]:
44
+ yield f"[FUNCTION_CALL]{delta['function_call']}"
45
+
46
+ elif "tool_calls" in delta and delta["tool_calls"]:
47
+ yield f"[TOOL_CALLS]{delta['tool_calls']}"
48
+
49
+ except json.JSONDecodeError:
50
+ return
51
+
52
+
53
+ class WorkflowLineParser:
54
+ def __init__(self, full_chunk: bool = True):
55
+ self.full_chunk = full_chunk
56
+ self._buckets: Dict[str, Dict] = {}
57
+
58
+ def __call__(self, line: str) -> Iterator[Union[str, dict]]:
59
+ if not line.startswith("data:"):
60
+ return
61
+ data = line[len("data:") :].strip()
62
+ if data == "[DONE]":
63
+ return
64
+
65
+ try:
66
+ payload = json.loads(data)
67
+
68
+ # Gestion des events chunk + slices
69
+ if payload.get("type") == "chunk":
70
+ self._buckets[payload["id"]] = {
71
+ "totalSlices": payload["totalSlices"],
72
+ "slices": [None] * payload["totalSlices"],
73
+ }
74
+
75
+ elif payload.get("type") == "chunk_slice":
76
+ bucket = self._buckets.get(payload["id"])
77
+ if bucket:
78
+ bucket["slices"][payload["index"]] = payload["slice"]
79
+
80
+ elif payload.get("type") == "chunk_end":
81
+ bucket = self._buckets.pop(payload["id"], None)
82
+ if bucket:
83
+ full_json = "".join(bucket["slices"])
84
+ try:
85
+ yield from self._yield_chunk(full_json)
86
+ except json.JSONDecodeError:
87
+ return
88
+
89
+ else:
90
+ # Message "normal" non splitté
91
+ yield from self._yield_chunk(data)
92
+
93
+ except json.JSONDecodeError:
94
+ return
95
+
96
+ def _yield_chunk(self, raw: str) -> Iterator[Union[str, dict]]:
97
+ chunk = json.loads(raw)
98
+
99
+ if "slice" in chunk:
100
+ try:
101
+ if isinstance(chunk["slice"], str):
102
+ # Si la slice est déjà un JSON string, on la parse
103
+ parsed_slice = json.loads(chunk["slice"])
104
+ yield parsed_slice
105
+ elif isinstance(chunk["slice"], dict):
106
+ # Si la slice est déjà un dict, on la yield directement
107
+ yield chunk["slice"]
108
+ except json.JSONDecodeError:
109
+ return
110
+ else:
111
+ return
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: aisberg
3
+ Version: 0.1.0
4
+ Summary: Aisberg SDK for Python - A simple and powerful SDK to interact with the Aisberg API
5
+ Author: Free Pro
6
+ Author-email: Mathis Lambert <mathis.lambert@freepro.com>
7
+ License: Private License
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: License :: Other/Proprietary License
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: httpx>=0.28.1
17
+ Requires-Dist: pydantic>=2.11.7
18
+ Requires-Dist: pydantic-settings>=2.10.1
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8.4.1; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=1.0.0; extra == "dev"
22
+ Requires-Dist: pytest-cov>=6.2.1; extra == "dev"
23
+ Requires-Dist: pytest-mock>=3.14.1; extra == "dev"
24
+ Requires-Dist: black>=25.1.0; extra == "dev"
25
+ Requires-Dist: isort>=6.0.1; extra == "dev"
26
+ Requires-Dist: mypy>=1.16.1; extra == "dev"
27
+ Requires-Dist: flake8>=7.3.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # Aisberg Python SDK
31
+
32
+ ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue)
33
+ ![License](https://img.shields.io/badge/license-Private-informational)
34
+
35
+ Aisberg SDK for Python is a robust and easy-to-use library for interacting with the Aisberg API.
36
+ It provides **synchronous** and **asynchronous** clients, advanced module abstractions, and built-in support for
37
+ conversational LLM workflows, collections, embeddings, and more.
38
+
39
+ ---
40
+
41
+ ## Features
42
+
43
+ - **Sync & Async clients**: Use with regular scripts or async frameworks
44
+ - **Auto tool execution** for LLM flows (tool calls, results integration)
45
+ - **Modular architecture**: Collections, chat, models, workflows, embeddings, and more
46
+ - **Strong typing** via Pydantic models
47
+ - **Environment-based configuration** (supports `.env` files and system environment variables)
48
+ - **Context manager support** for easy resource management
49
+ - **Custom tool registration**: Easily extend LLM capabilities with your own functions
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ ```sh
56
+ pip install aisberg
57
+ ````
58
+
59
+ Or, for local development:
60
+
61
+ ```sh
62
+ git clone https://your.git.repo/aisberg.git
63
+ cd aisberg
64
+ pip install -e .
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Quickstart
70
+
71
+ ### 1. **Configure your API key and base URL**
72
+
73
+ You can set them as environment variables, or in a `.env` file:
74
+
75
+ ```env
76
+ AISBERG_API_KEY=...
77
+ AISBERG_BASE_URL=https://url
78
+ ```
79
+
80
+ ### 2. **Synchronous Usage**
81
+
82
+ ```python
83
+ from aisberg import AisbergClient
84
+
85
+ with AisbergClient() as client:
86
+ me = client.me.info()
87
+ print(me)
88
+
89
+ chat_response = client.chat.complete(
90
+ input="Bonjour, qui es-tu ?",
91
+ model="llm-aisberg",
92
+ )
93
+ print(chat_response.choices[0].message.content)
94
+ ```
95
+
96
+ ### 3. **Asynchronous Usage**
97
+
98
+ ```python
99
+ import asyncio
100
+ from aisberg import AisbergAsyncClient
101
+
102
+
103
+ async def main():
104
+ async with AisbergAsyncClient() as client:
105
+ await client.initialize()
106
+ me = await client.me.info()
107
+ print(me)
108
+
109
+ chat_response = await client.chat.complete(
110
+ input="Hello, who are you?",
111
+ model="llm-aisberg",
112
+ )
113
+ print(chat_response.choices[0].message.content)
114
+
115
+
116
+ asyncio.run(main())
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Modules
122
+
123
+ * `client.me` — User/account info
124
+ * `client.chat` — Conversational LLM completions and streaming
125
+ * `client.collections` — Manage data collections
126
+ * `client.embeddings` — Encode texts to embeddings
127
+ * `client.models` — Model discovery & info
128
+ * `client.workflows` — Workflow management & execution
129
+ * `client.tools` — Register and execute tools for LLM tool calls
130
+
131
+ Each module is available both in the sync and async clients with similar APIs.
132
+
133
+ ---
134
+
135
+ ## Tool Calls and Automatic Execution
136
+
137
+ The SDK supports **tool-augmented LLM workflows**.
138
+ Register your own functions for use in chat:
139
+
140
+ ```python
141
+ def my_tool(args):
142
+ # Custom business logic
143
+ return {"result": "tool output"}
144
+
145
+
146
+ client.tools.register("my_tool", my_tool)
147
+ response = client.chat.complete(
148
+ input="Use the tool please.",
149
+ model="llm-aisberg",
150
+ tools=[{"name": "my_tool", ...}],
151
+ auto_execute_tools=True,
152
+ )
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Advanced Usage
158
+
159
+ ### **Custom Configuration**
160
+
161
+ You can override configuration when instantiating the client:
162
+
163
+ ```python
164
+ client = AisbergClient(
165
+ api_key="...",
166
+ base_url="https://url",
167
+ timeout=60,
168
+ )
169
+ ```
170
+
171
+ ### **Environment Variables Supported**
172
+
173
+ * `AISBERG_API_KEY`
174
+ * `AISBERG_BASE_URL`
175
+ * `AISBERG_TIMEOUT` (optional)
176
+
177
+ ### **Using in a Context Manager**
178
+
179
+ Both clients are context manager compatible:
180
+
181
+ ```python
182
+ with AisbergClient() as client:
183
+ # Sync usage
184
+ ...
185
+
186
+ async with AisbergAsyncClient() as client:
187
+ # Async usage
188
+ ...
189
+ ```
190
+
191
+ ---
192
+
193
+ ## License
194
+
195
+ **Private License — Not for public distribution or resale.**
196
+
197
+ For enterprise/commercial use, please contact [Mathis Lambert](mailto:mathis.lambert@freepro.com) or Free Pro.
198
+
199
+ ---
200
+
201
+ ## Authors
202
+
203
+ * Mathis Lambert
204
+ * Free Pro
205
+
206
+ ---
207
+
208
+ ## Support
209
+
210
+ For support, bug reports, or feature requests, please contact your technical representative.
211
+
212
+ ---
@@ -0,0 +1,43 @@
1
+ aisberg/__init__.py,sha256=jMX3F2Fh5JobAkRMKGAcOpmNdoxSthgR4v_oM-Yw1l0,141
2
+ aisberg/async_client.py,sha256=wxwkRUjxFbBlcj3D0aFspCVX5aACCksVhG9ZPVYrtx4,3547
3
+ aisberg/client.py,sha256=-UgM9pi-R_qeUmods8sWTxBVGM13pNUfLJv8Zq1vQto,3586
4
+ aisberg/config.py,sha256=tYuaE8WQFyyGhXEgF3kKLX7wM4PDIv6vDoezXaryOhk,441
5
+ aisberg/exceptions.py,sha256=T1ioitOczdkmW3-8XfPG0ta_O2WqzS1iQtzhDBucb5Y,515
6
+ aisberg/utils.py,sha256=4wkrpC5gz8PJWw3kZqaRbd3KekrI37zlDC__JiAVitw,3552
7
+ aisberg/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ aisberg/abstract/modules.py,sha256=aRmB21oiL9NCZsHUx8zB0Q8VvZAZBucsZxYv5l7JygY,1698
9
+ aisberg/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ aisberg/api/async_endpoints.py,sha256=cYOmUGBnMrvj8zaiek_Cjut6tB3paEIlJRHjRbggQBc,8279
11
+ aisberg/api/endpoints.py,sha256=Ni-boFbHpB4ZiCbBwLCzoy8bxRTie-LHmBddqbwVn7Q,8003
12
+ aisberg/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ aisberg/models/chat.py,sha256=LcvOgQm9Aan7pS4S90h4lrdzENX-NebA9pAKYdcDLB8,3667
14
+ aisberg/models/collections.py,sha256=gtcpyMfUVkfZkWP82AlsfNDT0mM_wREdjnR32i3DP20,806
15
+ aisberg/models/embeddings.py,sha256=gBGXR3DgyBCWB9Vky-iowWh_2Md7wa57I3fWxIrl77I,2409
16
+ aisberg/models/models.py,sha256=NcECFpeVjt9nzQEN8lggDy-SesDSDFgSAYhqWz0dupA,1206
17
+ aisberg/models/requests.py,sha256=9QXt9COo3GfubLQR5AgajxaDEr-ZOHrdjp-j9nyZrlw,205
18
+ aisberg/models/token.py,sha256=p3-uxCZMHbe4yryQdH21iDnPh-etJWgvUDUpCXV2xhk,190
19
+ aisberg/models/tools.py,sha256=dO8-O-tV9usakviEvWzT7Z-dG5s7EkVV8cg5CyoxZHg,1830
20
+ aisberg/models/workflows.py,sha256=CiqJdHsSFrOo2DAYNvYFvFOmO0hyg0xUehktkn3maSg,1258
21
+ aisberg/modules/__init__.py,sha256=i499QPWq-JB596dRVuBFNleYoldJshYXGmC4oed0f58,725
22
+ aisberg/modules/chat.py,sha256=WrMvq0O5gdBggoGm_dJcJywsHJvlKKYBUQ5HgPipQuU,13822
23
+ aisberg/modules/collections.py,sha256=kgV7zFHme6d2SXPKITJknxnk1yc6SoWz2LGnGoifon0,3947
24
+ aisberg/modules/document.py,sha256=twloRFq1wRS4j6fzth77IdceAaSrdDULzu3hlTiIsrA,3902
25
+ aisberg/modules/embeddings.py,sha256=wq7DlOXVQBP9-V5f4ytY4nnD60DAJ49v6JFlBuJwmEs,10470
26
+ aisberg/modules/me.py,sha256=yN4-ZYVDLViwz1oXbDpF1_1gULWiBf5GL0wj9-Pp-H4,2145
27
+ aisberg/modules/models.py,sha256=EIyWOkO2FaOYV-fNB-42-AEY2bob6yA1_4bqlwKs6JY,3048
28
+ aisberg/modules/tools.py,sha256=TnTIfjQuPhPImtWTjEy3UCmXeroPrYX3BRzTvT9nIkk,2424
29
+ aisberg/modules/workflows.py,sha256=TGDriJYy__dRBwP-MK-8zl6mlzZs22-0_TUqYYTeVfs,5004
30
+ aisberg/requests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ aisberg/requests/async_requests.py,sha256=4J6Gj6vY5AD9lXhSTdYdAKQIqsqH9m1uaKc7XLDKWx8,2849
32
+ aisberg/requests/sync_requests.py,sha256=ov7GDgx4C-oQ9xEZ7VQsGVY1fnuqRpPwjS0H_yH1yb8,2839
33
+ aisberg-0.1.0.dist-info/licenses/LICENSE,sha256=dCGgiGa4f14s5mzTYnj1wIZNqGRVG2bUYyyk7nzKlEo,406
34
+ tests/integration/test_collections_integration.py,sha256=HSs-Mhh5JNx2V6EeKo--G3xZq7pMk3z3gLReX7FJidg,3883
35
+ tests/unit/test_collections_sync.py,sha256=DyizG4MIYNtBOC9TlsFdLlH5vz7USA12K9Uydlcydoo,3199
36
+ tmp/test.py,sha256=8H3GxLztspwyt3_wLPtQkwdiLl--qqAn8ZaEUsXbwDE,743
37
+ tmp/test_async.py,sha256=BaY3MkOIDXsersjYgnfaI43kZ42KDj5Andq5u-yO82s,4168
38
+ tmp/test_doc_parse.py,sha256=b41Tsa1VkgNwyKwKoDRLNd05sIFGVaJncJGlFGiwYWY,324
39
+ tmp/test_sync.py,sha256=87QSz728gvjTXz2JykjF0U_mNsunDYrWsXYDjkBybI8,4929
40
+ aisberg-0.1.0.dist-info/METADATA,sha256=ETmG5wRMX4W_Xr_L8ZyAXyS2BgtQcOLiIIE03vYEatA,5053
41
+ aisberg-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
+ aisberg-0.1.0.dist-info/top_level.txt,sha256=7_CasmLkyF_h1CVRncNuAjam-DMIeMu1Rev_LpVcWoA,18
43
+ aisberg-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,9 @@
1
+ Copyright © 2025 Free Pro. All rights reserved.
2
+
3
+ This software and its source code are the exclusive property of Free Pro and are intended for internal use only.
4
+
5
+ Unauthorized copying, distribution, modification, or use of this software, in whole or in part, is strictly prohibited without prior written permission from Free Pro.
6
+
7
+ For questions or requests, contact:
8
+ Free Pro
9
+ [mathis.lambert@freepro.com]