inferencesh 0.4.1__tar.gz → 0.4.3__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.

Potentially problematic release.


This version of inferencesh might be problematic. Click here for more details.

Files changed (24) hide show
  1. {inferencesh-0.4.1/src/inferencesh.egg-info → inferencesh-0.4.3}/PKG-INFO +77 -36
  2. inferencesh-0.4.3/README.md +172 -0
  3. {inferencesh-0.4.1 → inferencesh-0.4.3}/pyproject.toml +1 -1
  4. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/models/base.py +69 -2
  5. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/models/file.py +6 -9
  6. {inferencesh-0.4.1 → inferencesh-0.4.3/src/inferencesh.egg-info}/PKG-INFO +77 -36
  7. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh.egg-info/SOURCES.txt +0 -1
  8. inferencesh-0.4.1/README.md +0 -128
  9. inferencesh-0.4.1/setup.py +0 -22
  10. {inferencesh-0.4.1 → inferencesh-0.4.3}/LICENSE +0 -0
  11. {inferencesh-0.4.1 → inferencesh-0.4.3}/setup.cfg +0 -0
  12. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/__init__.py +0 -0
  13. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/client.py +0 -0
  14. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/models/__init__.py +0 -0
  15. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/models/llm.py +0 -0
  16. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/utils/__init__.py +0 -0
  17. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/utils/download.py +0 -0
  18. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh/utils/storage.py +0 -0
  19. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh.egg-info/dependency_links.txt +0 -0
  20. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh.egg-info/entry_points.txt +0 -0
  21. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh.egg-info/requires.txt +0 -0
  22. {inferencesh-0.4.1 → inferencesh-0.4.3}/src/inferencesh.egg-info/top_level.txt +0 -0
  23. {inferencesh-0.4.1 → inferencesh-0.4.3}/tests/test_client.py +0 -0
  24. {inferencesh-0.4.1 → inferencesh-0.4.3}/tests/test_sdk.py +0 -0
@@ -1,8 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inferencesh
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: inference.sh Python SDK
5
- Author: Inference Shell Inc.
6
5
  Author-email: "Inference Shell Inc." <hello@inference.sh>
7
6
  Project-URL: Homepage, https://github.com/inference-sh/sdk
8
7
  Project-URL: Bug Tracker, https://github.com/inference-sh/sdk/issues
@@ -21,9 +20,7 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
21
20
  Provides-Extra: async
22
21
  Requires-Dist: aiohttp>=3.9.0; python_version >= "3.8" and extra == "async"
23
22
  Requires-Dist: aiofiles>=23.2.1; python_version >= "3.8" and extra == "async"
24
- Dynamic: author
25
23
  Dynamic: license-file
26
- Dynamic: requires-python
27
24
 
28
25
  # inference.sh sdk
29
26
 
@@ -38,47 +35,91 @@ pip install infsh
38
35
  ## client usage
39
36
 
40
37
  ```python
41
- from infsh import Inference, TaskStatus
38
+ from inferencesh import Inference, TaskStatus
42
39
 
43
- # create client
40
+ # Create client
44
41
  client = Inference(api_key="your-api-key")
45
42
 
46
- # simple usage - wait for result
47
- result = client.run({
48
- "app": "your-app",
49
- "input": {"key": "value"},
50
- "variant": "default"
51
- })
52
- print(f"output: {result['output']}")
53
-
54
- # get task info without waiting
55
- task = client.run(params, wait=False)
56
- print(f"task id: {task['id']}")
57
-
58
- # stream updates (recommended)
59
- for update in client.run(params, stream=True):
60
- status = update.get("status")
61
- print(f"status: {TaskStatus(status).name}")
43
+ # Simple synchronous usage
44
+ try:
45
+ task = client.run({
46
+ "app": "your-app",
47
+ "input": {"key": "value"},
48
+ "infra": "cloud",
49
+ "variant": "default"
50
+ })
62
51
 
63
- if status == TaskStatus.COMPLETED:
64
- print(f"output: {update.get('output')}")
65
- break
66
- elif status == TaskStatus.FAILED:
67
- print(f"error: {update.get('error')}")
68
- break
69
-
70
- # async support
52
+ print(f"Task ID: {task.get('id')}")
53
+
54
+ if task.get("status") == TaskStatus.COMPLETED:
55
+ print("✓ Task completed successfully!")
56
+ print(f"Output: {task.get('output')}")
57
+ else:
58
+ status = task.get("status")
59
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
60
+ print(f"✗ Task did not complete. Final status: {status_name}")
61
+
62
+ except Exception as exc:
63
+ print(f"Error: {type(exc).__name__}: {exc}")
64
+ raise # Re-raise to see full traceback
65
+
66
+ # Streaming updates (recommended)
67
+ try:
68
+ for update in client.run(
69
+ {
70
+ "app": "your-app",
71
+ "input": {"key": "value"},
72
+ "infra": "cloud",
73
+ "variant": "default"
74
+ },
75
+ stream=True # Enable streaming updates
76
+ ):
77
+ status = update.get("status")
78
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
79
+ print(f"Status: {status_name}")
80
+
81
+ if status == TaskStatus.COMPLETED:
82
+ print("✓ Task completed!")
83
+ print(f"Output: {update.get('output')}")
84
+ break
85
+ elif status == TaskStatus.FAILED:
86
+ print(f"✗ Task failed: {update.get('error')}")
87
+ break
88
+ elif status == TaskStatus.CANCELLED:
89
+ print("✗ Task was cancelled")
90
+ break
91
+
92
+ except Exception as exc:
93
+ print(f"Error: {type(exc).__name__}: {exc}")
94
+ raise # Re-raise to see full traceback
95
+
96
+ # Async support
71
97
  async def run_async():
72
- from infsh import AsyncInference
98
+ from inferencesh import AsyncInference
73
99
 
74
100
  client = AsyncInference(api_key="your-api-key")
75
101
 
76
- # simple usage
77
- result = await client.run(params)
102
+ # Simple usage
103
+ result = await client.run({
104
+ "app": "your-app",
105
+ "input": {"key": "value"},
106
+ "infra": "cloud",
107
+ "variant": "default"
108
+ })
78
109
 
79
- # stream updates
80
- async for update in await client.run(params, stream=True):
81
- print(f"status: {TaskStatus(update['status']).name}")
110
+ # Stream updates
111
+ async for update in await client.run(
112
+ {
113
+ "app": "your-app",
114
+ "input": {"key": "value"},
115
+ "infra": "cloud",
116
+ "variant": "default"
117
+ },
118
+ stream=True
119
+ ):
120
+ status = update.get("status")
121
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
122
+ print(f"Status: {status_name}")
82
123
  ```
83
124
 
84
125
  ## file handling
@@ -0,0 +1,172 @@
1
+ # inference.sh sdk
2
+
3
+ helper package for inference.sh python applications.
4
+
5
+ ## installation
6
+
7
+ ```bash
8
+ pip install infsh
9
+ ```
10
+
11
+ ## client usage
12
+
13
+ ```python
14
+ from inferencesh import Inference, TaskStatus
15
+
16
+ # Create client
17
+ client = Inference(api_key="your-api-key")
18
+
19
+ # Simple synchronous usage
20
+ try:
21
+ task = client.run({
22
+ "app": "your-app",
23
+ "input": {"key": "value"},
24
+ "infra": "cloud",
25
+ "variant": "default"
26
+ })
27
+
28
+ print(f"Task ID: {task.get('id')}")
29
+
30
+ if task.get("status") == TaskStatus.COMPLETED:
31
+ print("✓ Task completed successfully!")
32
+ print(f"Output: {task.get('output')}")
33
+ else:
34
+ status = task.get("status")
35
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
36
+ print(f"✗ Task did not complete. Final status: {status_name}")
37
+
38
+ except Exception as exc:
39
+ print(f"Error: {type(exc).__name__}: {exc}")
40
+ raise # Re-raise to see full traceback
41
+
42
+ # Streaming updates (recommended)
43
+ try:
44
+ for update in client.run(
45
+ {
46
+ "app": "your-app",
47
+ "input": {"key": "value"},
48
+ "infra": "cloud",
49
+ "variant": "default"
50
+ },
51
+ stream=True # Enable streaming updates
52
+ ):
53
+ status = update.get("status")
54
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
55
+ print(f"Status: {status_name}")
56
+
57
+ if status == TaskStatus.COMPLETED:
58
+ print("✓ Task completed!")
59
+ print(f"Output: {update.get('output')}")
60
+ break
61
+ elif status == TaskStatus.FAILED:
62
+ print(f"✗ Task failed: {update.get('error')}")
63
+ break
64
+ elif status == TaskStatus.CANCELLED:
65
+ print("✗ Task was cancelled")
66
+ break
67
+
68
+ except Exception as exc:
69
+ print(f"Error: {type(exc).__name__}: {exc}")
70
+ raise # Re-raise to see full traceback
71
+
72
+ # Async support
73
+ async def run_async():
74
+ from inferencesh import AsyncInference
75
+
76
+ client = AsyncInference(api_key="your-api-key")
77
+
78
+ # Simple usage
79
+ result = await client.run({
80
+ "app": "your-app",
81
+ "input": {"key": "value"},
82
+ "infra": "cloud",
83
+ "variant": "default"
84
+ })
85
+
86
+ # Stream updates
87
+ async for update in await client.run(
88
+ {
89
+ "app": "your-app",
90
+ "input": {"key": "value"},
91
+ "infra": "cloud",
92
+ "variant": "default"
93
+ },
94
+ stream=True
95
+ ):
96
+ status = update.get("status")
97
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
98
+ print(f"Status: {status_name}")
99
+ ```
100
+
101
+ ## file handling
102
+
103
+ the `File` class provides a standardized way to handle files in the inference.sh ecosystem:
104
+
105
+ ```python
106
+ from infsh import File
107
+
108
+ # Basic file creation
109
+ file = File(path="/path/to/file.png")
110
+
111
+ # File with explicit metadata
112
+ file = File(
113
+ path="/path/to/file.png",
114
+ content_type="image/png",
115
+ filename="custom_name.png",
116
+ size=1024 # in bytes
117
+ )
118
+
119
+ # Create from path (automatically populates metadata)
120
+ file = File.from_path("/path/to/file.png")
121
+
122
+ # Check if file exists
123
+ exists = file.exists()
124
+
125
+ # Access file metadata
126
+ print(file.content_type) # automatically detected if not specified
127
+ print(file.size) # file size in bytes
128
+ print(file.filename) # basename of the file
129
+
130
+ # Refresh metadata (useful if file has changed)
131
+ file.refresh_metadata()
132
+ ```
133
+
134
+ the `File` class automatically handles:
135
+ - mime type detection
136
+ - file size calculation
137
+ - filename extraction from path
138
+ - file existence checking
139
+
140
+ ## creating an app
141
+
142
+ to create an inference app, inherit from `BaseApp` and define your input/output types:
143
+
144
+ ```python
145
+ from infsh import BaseApp, BaseAppInput, BaseAppOutput, File
146
+
147
+ class AppInput(BaseAppInput):
148
+ image: str # URL or file path to image
149
+ mask: str # URL or file path to mask
150
+
151
+ class AppOutput(BaseAppOutput):
152
+ image: File
153
+
154
+ class MyApp(BaseApp):
155
+ async def setup(self):
156
+ # Initialize your model here
157
+ pass
158
+
159
+ async def run(self, app_input: AppInput) -> AppOutput:
160
+ # Process input and return output
161
+ result_path = "/tmp/result.png"
162
+ return AppOutput(image=File(path=result_path))
163
+
164
+ async def unload(self):
165
+ # Clean up resources
166
+ pass
167
+ ```
168
+
169
+ app lifecycle has three main methods:
170
+ - `setup()`: called when the app starts, use it to initialize models
171
+ - `run()`: called for each inference request
172
+ - `unload()`: called when shutting down, use it to free resources
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "inferencesh"
7
- version = "0.4.1"
7
+ version = "0.4.3"
8
8
  description = "inference.sh Python SDK"
9
9
  authors = [
10
10
  {name = "Inference Shell Inc.", email = "hello@inference.sh"},
@@ -1,9 +1,11 @@
1
- from typing import Any, Dict, List
1
+ from typing import Any, Dict, List, Optional
2
2
  from pydantic import BaseModel, ConfigDict
3
3
  import inspect
4
4
  import ast
5
5
  import textwrap
6
6
  from collections import OrderedDict
7
+ from inferencesh.models.file import File
8
+ from pydantic import Field
7
9
 
8
10
 
9
11
  class OrderedSchemaModel(BaseModel):
@@ -91,4 +93,69 @@ class BaseApp(BaseModel):
91
93
  raise NotImplementedError("run method must be implemented")
92
94
 
93
95
  async def unload(self):
94
- pass
96
+ pass
97
+
98
+
99
+ # Mixins
100
+
101
+ class OptionalImageFieldMixin(BaseModel):
102
+ image: Optional[File] = Field(
103
+ description="the image to use for the model",
104
+ default=None,
105
+ contentMediaType="image/*",
106
+ )
107
+
108
+ class RequiredImageFieldMixin(BaseModel):
109
+ image: File = Field(
110
+ description="the image to use for the model",
111
+ contentMediaType="image/*",
112
+ )
113
+
114
+ class OptionalVideoFieldMixin(BaseModel):
115
+ video: Optional[File] = Field(
116
+ description="the video to use for the model",
117
+ default=None,
118
+ contentMediaType="video/*",
119
+ )
120
+
121
+ class RequiredVideoFieldMixin(BaseModel):
122
+ video: File = Field(
123
+ description="the video to use for the model",
124
+ contentMediaType="video/*",
125
+ )
126
+
127
+ class OptionalAudioFieldMixin(BaseModel):
128
+ audio: Optional[File] = Field(
129
+ description="the audio to use for the model",
130
+ default=None,
131
+ contentMediaType="audio/*",
132
+ )
133
+
134
+ class RequiredAudioFieldMixin(BaseModel):
135
+ audio: File = Field(
136
+ description="the audio to use for the model",
137
+ contentMediaType="audio/*",
138
+ )
139
+
140
+ class OptionalTextFieldMixin(BaseModel):
141
+ text: Optional[str] = Field(
142
+ description="the text to use for the model",
143
+ default=None,
144
+ )
145
+
146
+ class RequiredTextFieldMixin(BaseModel):
147
+ text: str = Field(
148
+ description="the text to use for the model",
149
+ )
150
+
151
+ class OptionalFileFieldMixin(BaseModel):
152
+ file: Optional[File] = Field(
153
+ description="the file to use for the model",
154
+ default=None,
155
+ )
156
+
157
+ class RequiredFileFieldMixin(BaseModel):
158
+ file: Optional[File] = Field(
159
+ description="the file to use for the model",
160
+ default=None,
161
+ )
@@ -4,7 +4,6 @@ import mimetypes
4
4
  import os
5
5
  import urllib.request
6
6
  import urllib.parse
7
- import tempfile
8
7
  import hashlib
9
8
  from pathlib import Path
10
9
  from tqdm import tqdm
@@ -119,12 +118,10 @@ class File(BaseModel):
119
118
  return
120
119
 
121
120
  print(f"Downloading URL: {original_url} to {cache_path}")
122
- tmp_file = None
123
121
  try:
124
- # Download to temporary file first to avoid partial downloads in cache
125
- suffix = os.path.splitext(urllib.parse.urlparse(original_url).path)[1]
126
- tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
127
- self._tmp_path = tmp_file.name
122
+ # Download to a temporary filename in the final directory
123
+ tmp_path = str(cache_path) + '.tmp'
124
+ self._tmp_path = tmp_path
128
125
 
129
126
  # Set up request with user agent
130
127
  headers = {
@@ -176,8 +173,8 @@ class File(BaseModel):
176
173
  # If we read the whole body at once, exit loop
177
174
  break
178
175
 
179
- # Move the temporary file to the cache location
180
- os.replace(self._tmp_path, cache_path)
176
+ # Rename the temporary file to the final name
177
+ os.rename(self._tmp_path, cache_path)
181
178
  self._tmp_path = None # Prevent deletion in __del__
182
179
  self.path = str(cache_path)
183
180
  except (urllib.error.URLError, urllib.error.HTTPError) as e:
@@ -186,7 +183,7 @@ class File(BaseModel):
186
183
  raise RuntimeError(f"Failed to write downloaded file to {self._tmp_path}: {str(e)}")
187
184
  except Exception as e:
188
185
  # Clean up temp file if something went wrong
189
- if tmp_file is not None and hasattr(self, '_tmp_path'):
186
+ if hasattr(self, '_tmp_path') and self._tmp_path:
190
187
  try:
191
188
  os.unlink(self._tmp_path)
192
189
  except (OSError, IOError):
@@ -1,8 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inferencesh
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: inference.sh Python SDK
5
- Author: Inference Shell Inc.
6
5
  Author-email: "Inference Shell Inc." <hello@inference.sh>
7
6
  Project-URL: Homepage, https://github.com/inference-sh/sdk
8
7
  Project-URL: Bug Tracker, https://github.com/inference-sh/sdk/issues
@@ -21,9 +20,7 @@ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
21
20
  Provides-Extra: async
22
21
  Requires-Dist: aiohttp>=3.9.0; python_version >= "3.8" and extra == "async"
23
22
  Requires-Dist: aiofiles>=23.2.1; python_version >= "3.8" and extra == "async"
24
- Dynamic: author
25
23
  Dynamic: license-file
26
- Dynamic: requires-python
27
24
 
28
25
  # inference.sh sdk
29
26
 
@@ -38,47 +35,91 @@ pip install infsh
38
35
  ## client usage
39
36
 
40
37
  ```python
41
- from infsh import Inference, TaskStatus
38
+ from inferencesh import Inference, TaskStatus
42
39
 
43
- # create client
40
+ # Create client
44
41
  client = Inference(api_key="your-api-key")
45
42
 
46
- # simple usage - wait for result
47
- result = client.run({
48
- "app": "your-app",
49
- "input": {"key": "value"},
50
- "variant": "default"
51
- })
52
- print(f"output: {result['output']}")
53
-
54
- # get task info without waiting
55
- task = client.run(params, wait=False)
56
- print(f"task id: {task['id']}")
57
-
58
- # stream updates (recommended)
59
- for update in client.run(params, stream=True):
60
- status = update.get("status")
61
- print(f"status: {TaskStatus(status).name}")
43
+ # Simple synchronous usage
44
+ try:
45
+ task = client.run({
46
+ "app": "your-app",
47
+ "input": {"key": "value"},
48
+ "infra": "cloud",
49
+ "variant": "default"
50
+ })
62
51
 
63
- if status == TaskStatus.COMPLETED:
64
- print(f"output: {update.get('output')}")
65
- break
66
- elif status == TaskStatus.FAILED:
67
- print(f"error: {update.get('error')}")
68
- break
69
-
70
- # async support
52
+ print(f"Task ID: {task.get('id')}")
53
+
54
+ if task.get("status") == TaskStatus.COMPLETED:
55
+ print("✓ Task completed successfully!")
56
+ print(f"Output: {task.get('output')}")
57
+ else:
58
+ status = task.get("status")
59
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
60
+ print(f"✗ Task did not complete. Final status: {status_name}")
61
+
62
+ except Exception as exc:
63
+ print(f"Error: {type(exc).__name__}: {exc}")
64
+ raise # Re-raise to see full traceback
65
+
66
+ # Streaming updates (recommended)
67
+ try:
68
+ for update in client.run(
69
+ {
70
+ "app": "your-app",
71
+ "input": {"key": "value"},
72
+ "infra": "cloud",
73
+ "variant": "default"
74
+ },
75
+ stream=True # Enable streaming updates
76
+ ):
77
+ status = update.get("status")
78
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
79
+ print(f"Status: {status_name}")
80
+
81
+ if status == TaskStatus.COMPLETED:
82
+ print("✓ Task completed!")
83
+ print(f"Output: {update.get('output')}")
84
+ break
85
+ elif status == TaskStatus.FAILED:
86
+ print(f"✗ Task failed: {update.get('error')}")
87
+ break
88
+ elif status == TaskStatus.CANCELLED:
89
+ print("✗ Task was cancelled")
90
+ break
91
+
92
+ except Exception as exc:
93
+ print(f"Error: {type(exc).__name__}: {exc}")
94
+ raise # Re-raise to see full traceback
95
+
96
+ # Async support
71
97
  async def run_async():
72
- from infsh import AsyncInference
98
+ from inferencesh import AsyncInference
73
99
 
74
100
  client = AsyncInference(api_key="your-api-key")
75
101
 
76
- # simple usage
77
- result = await client.run(params)
102
+ # Simple usage
103
+ result = await client.run({
104
+ "app": "your-app",
105
+ "input": {"key": "value"},
106
+ "infra": "cloud",
107
+ "variant": "default"
108
+ })
78
109
 
79
- # stream updates
80
- async for update in await client.run(params, stream=True):
81
- print(f"status: {TaskStatus(update['status']).name}")
110
+ # Stream updates
111
+ async for update in await client.run(
112
+ {
113
+ "app": "your-app",
114
+ "input": {"key": "value"},
115
+ "infra": "cloud",
116
+ "variant": "default"
117
+ },
118
+ stream=True
119
+ ):
120
+ status = update.get("status")
121
+ status_name = TaskStatus(status).name if status is not None else "UNKNOWN"
122
+ print(f"Status: {status_name}")
82
123
  ```
83
124
 
84
125
  ## file handling
@@ -1,7 +1,6 @@
1
1
  LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
- setup.py
5
4
  src/inferencesh/__init__.py
6
5
  src/inferencesh/client.py
7
6
  src/inferencesh.egg-info/PKG-INFO
@@ -1,128 +0,0 @@
1
- # inference.sh sdk
2
-
3
- helper package for inference.sh python applications.
4
-
5
- ## installation
6
-
7
- ```bash
8
- pip install infsh
9
- ```
10
-
11
- ## client usage
12
-
13
- ```python
14
- from infsh import Inference, TaskStatus
15
-
16
- # create client
17
- client = Inference(api_key="your-api-key")
18
-
19
- # simple usage - wait for result
20
- result = client.run({
21
- "app": "your-app",
22
- "input": {"key": "value"},
23
- "variant": "default"
24
- })
25
- print(f"output: {result['output']}")
26
-
27
- # get task info without waiting
28
- task = client.run(params, wait=False)
29
- print(f"task id: {task['id']}")
30
-
31
- # stream updates (recommended)
32
- for update in client.run(params, stream=True):
33
- status = update.get("status")
34
- print(f"status: {TaskStatus(status).name}")
35
-
36
- if status == TaskStatus.COMPLETED:
37
- print(f"output: {update.get('output')}")
38
- break
39
- elif status == TaskStatus.FAILED:
40
- print(f"error: {update.get('error')}")
41
- break
42
-
43
- # async support
44
- async def run_async():
45
- from infsh import AsyncInference
46
-
47
- client = AsyncInference(api_key="your-api-key")
48
-
49
- # simple usage
50
- result = await client.run(params)
51
-
52
- # stream updates
53
- async for update in await client.run(params, stream=True):
54
- print(f"status: {TaskStatus(update['status']).name}")
55
- ```
56
-
57
- ## file handling
58
-
59
- the `File` class provides a standardized way to handle files in the inference.sh ecosystem:
60
-
61
- ```python
62
- from infsh import File
63
-
64
- # Basic file creation
65
- file = File(path="/path/to/file.png")
66
-
67
- # File with explicit metadata
68
- file = File(
69
- path="/path/to/file.png",
70
- content_type="image/png",
71
- filename="custom_name.png",
72
- size=1024 # in bytes
73
- )
74
-
75
- # Create from path (automatically populates metadata)
76
- file = File.from_path("/path/to/file.png")
77
-
78
- # Check if file exists
79
- exists = file.exists()
80
-
81
- # Access file metadata
82
- print(file.content_type) # automatically detected if not specified
83
- print(file.size) # file size in bytes
84
- print(file.filename) # basename of the file
85
-
86
- # Refresh metadata (useful if file has changed)
87
- file.refresh_metadata()
88
- ```
89
-
90
- the `File` class automatically handles:
91
- - mime type detection
92
- - file size calculation
93
- - filename extraction from path
94
- - file existence checking
95
-
96
- ## creating an app
97
-
98
- to create an inference app, inherit from `BaseApp` and define your input/output types:
99
-
100
- ```python
101
- from infsh import BaseApp, BaseAppInput, BaseAppOutput, File
102
-
103
- class AppInput(BaseAppInput):
104
- image: str # URL or file path to image
105
- mask: str # URL or file path to mask
106
-
107
- class AppOutput(BaseAppOutput):
108
- image: File
109
-
110
- class MyApp(BaseApp):
111
- async def setup(self):
112
- # Initialize your model here
113
- pass
114
-
115
- async def run(self, app_input: AppInput) -> AppOutput:
116
- # Process input and return output
117
- result_path = "/tmp/result.png"
118
- return AppOutput(image=File(path=result_path))
119
-
120
- async def unload(self):
121
- # Clean up resources
122
- pass
123
- ```
124
-
125
- app lifecycle has three main methods:
126
- - `setup()`: called when the app starts, use it to initialize models
127
- - `run()`: called for each inference request
128
- - `unload()`: called when shutting down, use it to free resources
@@ -1,22 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name="inferencesh",
5
- version="0.1.2",
6
- description="inference.sh Python SDK",
7
- author="Inference Shell Inc.",
8
- author_email="hello@inference.sh",
9
- packages=find_packages(where="src"),
10
- package_dir={"": "src"},
11
- install_requires=[
12
- "pydantic>=2.0.0",
13
- "tqdm>=4.67.0",
14
- "requests>=2.31.0",
15
- ],
16
- python_requires=">=3.7",
17
- classifiers=[
18
- "Programming Language :: Python :: 3",
19
- "License :: OSI Approved :: MIT License",
20
- "Operating System :: OS Independent",
21
- ],
22
- )
File without changes
File without changes