inferencesh 0.1.23__py3-none-any.whl → 0.2.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.

Potentially problematic release.


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

inferencesh/sdk.py CHANGED
@@ -1,17 +1,20 @@
1
- from typing import Optional, Union, ClassVar
2
- from pydantic import BaseModel, ConfigDict, PrivateAttr, model_validator
1
+ from typing import Optional, Union
2
+ from pydantic import BaseModel, ConfigDict, PrivateAttr, model_validator, Field, field_validator
3
3
  import mimetypes
4
4
  import os
5
5
  import urllib.request
6
6
  import urllib.parse
7
7
  import tempfile
8
- from pydantic import Field
9
8
  from typing import Any, Dict, List
10
9
 
11
10
  import inspect
12
11
  import ast
13
12
  import textwrap
14
13
  from collections import OrderedDict
14
+ from enum import Enum
15
+ import shutil
16
+ from pathlib import Path
17
+ import hashlib
15
18
 
16
19
 
17
20
  # inspired by https://github.com/pydantic/pydantic/issues/7580
@@ -102,20 +105,35 @@ class BaseApp(BaseModel):
102
105
 
103
106
  class File(BaseModel):
104
107
  """A class representing a file in the inference.sh ecosystem."""
105
- uri: Optional[str] = None # Original location (URL or file path)
108
+ uri: Optional[str] = Field(default=None) # Original location (URL or file path)
106
109
  path: Optional[str] = None # Resolved local file path
107
110
  content_type: Optional[str] = None # MIME type of the file
108
111
  size: Optional[int] = None # File size in bytes
109
112
  filename: Optional[str] = None # Original filename if available
110
113
  _tmp_path: Optional[str] = PrivateAttr(default=None) # Internal storage for temporary file path
111
114
 
112
- model_config = ConfigDict(
113
- arbitrary_types_allowed=True,
114
- populate_by_name=True
115
- )
116
-
115
+ def __init__(self, initializer=None, **data):
116
+ if initializer is not None:
117
+ if isinstance(initializer, str):
118
+ data['uri'] = initializer
119
+ elif isinstance(initializer, File):
120
+ data = initializer.model_dump()
121
+ else:
122
+ raise ValueError(f'Invalid input for File: {initializer}')
123
+ super().__init__(**data)
124
+
125
+ @model_validator(mode='before')
126
+ @classmethod
127
+ def convert_str_to_file(cls, values):
128
+ print(f"check_uri_or_path input: {values}")
129
+ if isinstance(values, str): # Only accept strings
130
+ return {"uri": values}
131
+ elif isinstance(values, dict):
132
+ return values
133
+ raise ValueError(f'Invalid input for File: {values}')
134
+
117
135
  @model_validator(mode='after')
118
- def check_uri_or_path(self) -> 'File':
136
+ def validate_required_fields(self) -> 'File':
119
137
  """Validate that either uri or path is provided."""
120
138
  if not self.uri and not self.path:
121
139
  raise ValueError("Either 'uri' or 'path' must be provided")
@@ -128,7 +146,10 @@ class File(BaseModel):
128
146
  self.path = os.path.abspath(self.uri)
129
147
  elif self.uri:
130
148
  self.path = self.uri
131
- self._populate_metadata()
149
+ if self.path:
150
+ self._populate_metadata()
151
+ else:
152
+ raise ValueError("Either 'uri' or 'path' must be provided")
132
153
 
133
154
  def _is_url(self, path: str) -> bool:
134
155
  """Check if the path is a URL."""
@@ -170,7 +191,7 @@ class File(BaseModel):
170
191
  if tmp_file is not None and hasattr(self, '_tmp_path'):
171
192
  try:
172
193
  os.unlink(self._tmp_path)
173
- except:
194
+ except (OSError, IOError):
174
195
  pass
175
196
  raise RuntimeError(f"Error downloading URL {original_url}: {str(e)}")
176
197
 
@@ -179,7 +200,7 @@ class File(BaseModel):
179
200
  if hasattr(self, '_tmp_path') and self._tmp_path:
180
201
  try:
181
202
  os.unlink(self._tmp_path)
182
- except:
203
+ except (OSError, IOError):
183
204
  pass
184
205
 
185
206
  def _populate_metadata(self) -> None:
@@ -215,13 +236,24 @@ class File(BaseModel):
215
236
 
216
237
  def refresh_metadata(self) -> None:
217
238
  """Refresh all metadata from the file."""
218
- self._populate_metadata()
239
+ if os.path.exists(self.path):
240
+ self.content_type = self._guess_content_type()
241
+ self.size = self._get_file_size() # Always update size
242
+ self.filename = self._get_filename()
243
+
219
244
 
245
+ class ContextMessageRole(str, Enum):
246
+ USER = "user"
247
+ ASSISTANT = "assistant"
248
+ SYSTEM = "system"
249
+
250
+ class Message(BaseModel):
251
+ role: ContextMessageRole
252
+ content: str
220
253
 
221
254
  class ContextMessage(BaseModel):
222
- role: str = Field(
255
+ role: ContextMessageRole = Field(
223
256
  description="The role of the message",
224
- enum=["user", "assistant", "system"]
225
257
  )
226
258
  text: str = Field(
227
259
  description="The text content of the message"
@@ -281,4 +313,51 @@ class LLMInputWithImage(LLMInput):
281
313
  image: Optional[File] = Field(
282
314
  description="The image to use for the model",
283
315
  default=None
284
- )
316
+ )
317
+
318
+ class DownloadDir(str, Enum):
319
+ """Standard download directories used by the SDK."""
320
+ DATA = "./data" # Persistent storage/cache directory
321
+ TEMP = "./tmp" # Temporary storage directory
322
+ CACHE = "./cache" # Cache directory
323
+
324
+ def download(url: str, directory: Union[str, Path, DownloadDir]) -> str:
325
+ """Download a file to the specified directory and return its path.
326
+
327
+ Args:
328
+ url: The URL to download from
329
+ directory: The directory to save the file to. Can be a string path,
330
+ Path object, or DownloadDir enum value.
331
+
332
+ Returns:
333
+ str: The path to the downloaded file
334
+ """
335
+ # Convert directory to Path
336
+ dir_path = Path(directory)
337
+ dir_path.mkdir(exist_ok=True)
338
+
339
+ # Create hash directory from URL
340
+ url_hash = hashlib.sha256(url.encode()).hexdigest()[:12]
341
+ hash_dir = dir_path / url_hash
342
+ hash_dir.mkdir(exist_ok=True)
343
+
344
+ # Keep original filename
345
+ filename = os.path.basename(urllib.parse.urlparse(url).path)
346
+ if not filename:
347
+ filename = 'download'
348
+
349
+ output_path = hash_dir / filename
350
+
351
+ # If file exists in directory and it's not a temp directory, return it
352
+ if output_path.exists() and directory != DownloadDir.TEMP:
353
+ return str(output_path)
354
+
355
+ # Download the file
356
+ file = File(url)
357
+ if file.path:
358
+ shutil.copy2(file.path, output_path)
359
+ # Prevent the File instance from deleting its temporary file
360
+ file._tmp_path = None
361
+ return str(output_path)
362
+
363
+ raise RuntimeError(f"Failed to download {url}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inferencesh
3
- Version: 0.1.23
3
+ Version: 0.2.0
4
4
  Summary: inference.sh Python SDK
5
5
  Author: Inference Shell Inc.
6
6
  Author-email: "Inference Shell Inc." <hello@inference.sh>
@@ -13,6 +13,9 @@ Requires-Python: >=3.7
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: pydantic>=2.0.0
16
+ Provides-Extra: test
17
+ Requires-Dist: pytest>=7.0.0; extra == "test"
18
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
16
19
  Dynamic: author
17
20
  Dynamic: license-file
18
21
  Dynamic: requires-python
@@ -0,0 +1,8 @@
1
+ inferencesh/__init__.py,sha256=hbKkgHCh0lCdhWyHs3FHHRd8JfLeHkTd1bT4v79Fi8M,192
2
+ inferencesh/sdk.py,sha256=Yebi85zvWYHVnnf5CARHg-eOpOPM2mZ7SafRlaJuwdA,14554
3
+ inferencesh-0.2.0.dist-info/licenses/LICENSE,sha256=OsgqEWIh2el_QMj0y8O1A5Q5Dl-dxqqYbFE6fszuR4s,1086
4
+ inferencesh-0.2.0.dist-info/METADATA,sha256=AHDRrj_mW__FIxMgCPu1CRReJrTbk4uUZ0Ra60Cst1s,2728
5
+ inferencesh-0.2.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
6
+ inferencesh-0.2.0.dist-info/entry_points.txt,sha256=6IC-fyozAqW3ljsMLGCXxJ0_ui2Jb-2fLHtoH1RTnEE,45
7
+ inferencesh-0.2.0.dist-info/top_level.txt,sha256=TSMHg3T1ThMl1HGAWmzBClwOYH1ump5neof9BfHIwaA,12
8
+ inferencesh-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,8 +0,0 @@
1
- inferencesh/__init__.py,sha256=hbKkgHCh0lCdhWyHs3FHHRd8JfLeHkTd1bT4v79Fi8M,192
2
- inferencesh/sdk.py,sha256=MdGlTaZITc9nuE94jLU01L1LWsC5RKj-OpFre-x6CeI,11738
3
- inferencesh-0.1.23.dist-info/licenses/LICENSE,sha256=OsgqEWIh2el_QMj0y8O1A5Q5Dl-dxqqYbFE6fszuR4s,1086
4
- inferencesh-0.1.23.dist-info/METADATA,sha256=_S9CelUY7dd_6ECy-n3Dj-K562rN3cvQ5f1WLvXP5HQ,2612
5
- inferencesh-0.1.23.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
6
- inferencesh-0.1.23.dist-info/entry_points.txt,sha256=6IC-fyozAqW3ljsMLGCXxJ0_ui2Jb-2fLHtoH1RTnEE,45
7
- inferencesh-0.1.23.dist-info/top_level.txt,sha256=TSMHg3T1ThMl1HGAWmzBClwOYH1ump5neof9BfHIwaA,12
8
- inferencesh-0.1.23.dist-info/RECORD,,