inferencesh 0.3.0__py3-none-any.whl → 0.4.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/__init__.py +37 -1
- inferencesh/client.py +830 -0
- inferencesh/models/__init__.py +29 -0
- inferencesh/models/base.py +94 -0
- inferencesh/models/file.py +252 -0
- inferencesh/models/llm.py +729 -0
- inferencesh/utils/__init__.py +6 -0
- inferencesh/utils/download.py +59 -0
- inferencesh/utils/storage.py +16 -0
- {inferencesh-0.3.0.dist-info → inferencesh-0.4.0.dist-info}/METADATA +6 -1
- inferencesh-0.4.0.dist-info/RECORD +15 -0
- {inferencesh-0.3.0.dist-info → inferencesh-0.4.0.dist-info}/WHEEL +1 -1
- inferencesh/sdk.py +0 -363
- inferencesh-0.3.0.dist-info/RECORD +0 -8
- {inferencesh-0.3.0.dist-info → inferencesh-0.4.0.dist-info}/entry_points.txt +0 -0
- {inferencesh-0.3.0.dist-info → inferencesh-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {inferencesh-0.3.0.dist-info → inferencesh-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import os
|
|
3
|
+
import urllib.parse
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from ..models.file import File
|
|
9
|
+
from .storage import StorageDir
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def download(url: str, directory: Union[str, Path, StorageDir]) -> str:
|
|
13
|
+
"""Download a file to the specified directory and return its path.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
url: The URL to download from
|
|
17
|
+
directory: The directory to save the file to. Can be a string path,
|
|
18
|
+
Path object, or StorageDir enum value.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
str: The path to the downloaded file
|
|
22
|
+
"""
|
|
23
|
+
# Convert directory to Path
|
|
24
|
+
dir_path = Path(directory)
|
|
25
|
+
dir_path.mkdir(exist_ok=True)
|
|
26
|
+
|
|
27
|
+
# Parse URL components
|
|
28
|
+
parsed_url = urllib.parse.urlparse(url)
|
|
29
|
+
|
|
30
|
+
# Create hash from URL path and query parameters for uniqueness
|
|
31
|
+
url_components = parsed_url.netloc + parsed_url.path
|
|
32
|
+
if parsed_url.query:
|
|
33
|
+
url_components += '?' + parsed_url.query
|
|
34
|
+
url_hash = hashlib.sha256(url_components.encode()).hexdigest()[:12]
|
|
35
|
+
|
|
36
|
+
# Keep original filename or use a default
|
|
37
|
+
filename = os.path.basename(parsed_url.path)
|
|
38
|
+
if not filename:
|
|
39
|
+
filename = 'download'
|
|
40
|
+
|
|
41
|
+
# Create hash directory and store file
|
|
42
|
+
hash_dir = dir_path / url_hash
|
|
43
|
+
hash_dir.mkdir(exist_ok=True)
|
|
44
|
+
|
|
45
|
+
output_path = hash_dir / filename
|
|
46
|
+
|
|
47
|
+
# If file exists in directory and it's not a temp directory, return it
|
|
48
|
+
if output_path.exists() and directory != StorageDir.TEMP:
|
|
49
|
+
return str(output_path)
|
|
50
|
+
|
|
51
|
+
# Download the file
|
|
52
|
+
file = File(url)
|
|
53
|
+
if file.path:
|
|
54
|
+
shutil.copy2(file.path, output_path)
|
|
55
|
+
# Prevent the File instance from deleting its temporary file
|
|
56
|
+
file._tmp_path = None
|
|
57
|
+
return str(output_path)
|
|
58
|
+
|
|
59
|
+
raise RuntimeError(f"Failed to download {url}")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class StorageDir(str, Enum):
|
|
6
|
+
"""Standard storage directories used by the SDK."""
|
|
7
|
+
DATA = "/app/data" # Persistent storage/cache directory
|
|
8
|
+
TEMP = "/app/tmp" # Temporary storage directory
|
|
9
|
+
CACHE = "/app/cache" # Cache directory
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def path(self) -> Path:
|
|
13
|
+
"""Get the Path object for this storage directory, ensuring it exists."""
|
|
14
|
+
path = Path(self.value)
|
|
15
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
16
|
+
return path
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: inferencesh
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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,9 +13,14 @@ 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
|
+
Requires-Dist: tqdm>=4.67.0
|
|
17
|
+
Requires-Dist: requests>=2.31.0
|
|
16
18
|
Provides-Extra: test
|
|
17
19
|
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
18
20
|
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
|
|
21
|
+
Provides-Extra: async
|
|
22
|
+
Requires-Dist: aiohttp>=3.9.0; python_version >= "3.8" and extra == "async"
|
|
23
|
+
Requires-Dist: aiofiles>=23.2.1; python_version >= "3.8" and extra == "async"
|
|
19
24
|
Dynamic: author
|
|
20
25
|
Dynamic: license-file
|
|
21
26
|
Dynamic: requires-python
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
inferencesh/__init__.py,sha256=dY3l3yCkWoMtGX0gNXgxFnrprFRl6PPWjH8V7Qedx5g,772
|
|
2
|
+
inferencesh/client.py,sha256=cm7E-8LxP8jyb7JnANmcBtF1ya2i7sMBW2Pq-Oh-mcM,31318
|
|
3
|
+
inferencesh/models/__init__.py,sha256=FDwcdtT6c4hbRitymjmN-hZMlQa8RbKSftkZZyjtUXA,536
|
|
4
|
+
inferencesh/models/base.py,sha256=4gZQRi8J7y9U6PrGD9pRIehd1MJVJAqGakPQDs2AKFM,3251
|
|
5
|
+
inferencesh/models/file.py,sha256=uh1czgk0KFl_9RHTODX0PkdnI42MSU8QMJR_I4lVKI4,10556
|
|
6
|
+
inferencesh/models/llm.py,sha256=GLcEkDizBbgcfc-zC719wDe44th3EGf3FpKERjIAPE8,27755
|
|
7
|
+
inferencesh/utils/__init__.py,sha256=-xiD6uo2XzcrPAWFb_fUbaimmnW4KFKc-8IvBzaxNd4,148
|
|
8
|
+
inferencesh/utils/download.py,sha256=DRGBudiPVa5bDS35KfR-DYeGRk7gO03WOelnisecwMo,1815
|
|
9
|
+
inferencesh/utils/storage.py,sha256=E4J8emd4eFKdmdDgAqzz3TpaaDd3n0l8gYlMHuY8yIU,519
|
|
10
|
+
inferencesh-0.4.0.dist-info/licenses/LICENSE,sha256=OsgqEWIh2el_QMj0y8O1A5Q5Dl-dxqqYbFE6fszuR4s,1086
|
|
11
|
+
inferencesh-0.4.0.dist-info/METADATA,sha256=pHnblJABrxy5Iy81hpP7nV-J72Tp2JIUJ6D2UzVbSqo,2964
|
|
12
|
+
inferencesh-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
+
inferencesh-0.4.0.dist-info/entry_points.txt,sha256=6IC-fyozAqW3ljsMLGCXxJ0_ui2Jb-2fLHtoH1RTnEE,45
|
|
14
|
+
inferencesh-0.4.0.dist-info/top_level.txt,sha256=TSMHg3T1ThMl1HGAWmzBClwOYH1ump5neof9BfHIwaA,12
|
|
15
|
+
inferencesh-0.4.0.dist-info/RECORD,,
|
inferencesh/sdk.py
DELETED
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
from typing import Optional, Union
|
|
2
|
-
from pydantic import BaseModel, ConfigDict, PrivateAttr, model_validator, Field, field_validator
|
|
3
|
-
import mimetypes
|
|
4
|
-
import os
|
|
5
|
-
import urllib.request
|
|
6
|
-
import urllib.parse
|
|
7
|
-
import tempfile
|
|
8
|
-
from typing import Any, Dict, List
|
|
9
|
-
|
|
10
|
-
import inspect
|
|
11
|
-
import ast
|
|
12
|
-
import textwrap
|
|
13
|
-
from collections import OrderedDict
|
|
14
|
-
from enum import Enum
|
|
15
|
-
import shutil
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
import hashlib
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# inspired by https://github.com/pydantic/pydantic/issues/7580
|
|
21
|
-
class OrderedSchemaModel(BaseModel):
|
|
22
|
-
"""A base model that ensures the JSON schema properties and required fields are in the order of field definition."""
|
|
23
|
-
|
|
24
|
-
@classmethod
|
|
25
|
-
def model_json_schema(cls, by_alias: bool = True, **kwargs: Any) -> Dict[str, Any]:
|
|
26
|
-
schema = super().model_json_schema(by_alias=by_alias, **kwargs)
|
|
27
|
-
|
|
28
|
-
field_order = cls._get_field_order()
|
|
29
|
-
|
|
30
|
-
if field_order:
|
|
31
|
-
# Order properties
|
|
32
|
-
ordered_properties = OrderedDict()
|
|
33
|
-
for field_name in field_order:
|
|
34
|
-
if field_name in schema['properties']:
|
|
35
|
-
ordered_properties[field_name] = schema['properties'][field_name]
|
|
36
|
-
|
|
37
|
-
# Add any remaining properties that weren't in field_order
|
|
38
|
-
for field_name, field_schema in schema['properties'].items():
|
|
39
|
-
if field_name not in ordered_properties:
|
|
40
|
-
ordered_properties[field_name] = field_schema
|
|
41
|
-
|
|
42
|
-
schema['properties'] = ordered_properties
|
|
43
|
-
|
|
44
|
-
# Order required fields
|
|
45
|
-
if 'required' in schema:
|
|
46
|
-
ordered_required = [field for field in field_order if field in schema['required']]
|
|
47
|
-
# Add any remaining required fields that weren't in field_order
|
|
48
|
-
ordered_required.extend([field for field in schema['required'] if field not in ordered_required])
|
|
49
|
-
schema['required'] = ordered_required
|
|
50
|
-
|
|
51
|
-
return schema
|
|
52
|
-
|
|
53
|
-
@classmethod
|
|
54
|
-
def _get_field_order(cls) -> List[str]:
|
|
55
|
-
"""Get the order of fields as they were defined in the class."""
|
|
56
|
-
source = inspect.getsource(cls)
|
|
57
|
-
|
|
58
|
-
# Unindent the entire source code
|
|
59
|
-
source = textwrap.dedent(source)
|
|
60
|
-
|
|
61
|
-
try:
|
|
62
|
-
module = ast.parse(source)
|
|
63
|
-
except IndentationError:
|
|
64
|
-
# If we still get an IndentationError, wrap the class in a dummy module
|
|
65
|
-
source = f"class DummyModule:\n{textwrap.indent(source, ' ')}"
|
|
66
|
-
module = ast.parse(source)
|
|
67
|
-
# Adjust to look at the first class def inside DummyModule
|
|
68
|
-
# noinspection PyUnresolvedReferences
|
|
69
|
-
class_def = module.body[0].body[0]
|
|
70
|
-
else:
|
|
71
|
-
# Find the class definition
|
|
72
|
-
class_def = next(
|
|
73
|
-
node for node in module.body if isinstance(node, ast.ClassDef) and node.name == cls.__name__
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# Extract field names in the order they were defined
|
|
77
|
-
field_order = []
|
|
78
|
-
for node in class_def.body:
|
|
79
|
-
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
|
80
|
-
field_order.append(node.target.id)
|
|
81
|
-
|
|
82
|
-
return field_order
|
|
83
|
-
|
|
84
|
-
class BaseAppInput(OrderedSchemaModel):
|
|
85
|
-
pass
|
|
86
|
-
|
|
87
|
-
class BaseAppOutput(OrderedSchemaModel):
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
class BaseApp(BaseModel):
|
|
91
|
-
model_config = ConfigDict(
|
|
92
|
-
arbitrary_types_allowed=True,
|
|
93
|
-
extra='allow'
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
async def setup(self):
|
|
97
|
-
pass
|
|
98
|
-
|
|
99
|
-
async def run(self, app_input: BaseAppInput) -> BaseAppOutput:
|
|
100
|
-
raise NotImplementedError("run method must be implemented")
|
|
101
|
-
|
|
102
|
-
async def unload(self):
|
|
103
|
-
pass
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
class File(BaseModel):
|
|
107
|
-
"""A class representing a file in the inference.sh ecosystem."""
|
|
108
|
-
uri: Optional[str] = Field(default=None) # Original location (URL or file path)
|
|
109
|
-
path: Optional[str] = None # Resolved local file path
|
|
110
|
-
content_type: Optional[str] = None # MIME type of the file
|
|
111
|
-
size: Optional[int] = None # File size in bytes
|
|
112
|
-
filename: Optional[str] = None # Original filename if available
|
|
113
|
-
_tmp_path: Optional[str] = PrivateAttr(default=None) # Internal storage for temporary file path
|
|
114
|
-
|
|
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
|
-
|
|
135
|
-
@model_validator(mode='after')
|
|
136
|
-
def validate_required_fields(self) -> 'File':
|
|
137
|
-
"""Validate that either uri or path is provided."""
|
|
138
|
-
if not self.uri and not self.path:
|
|
139
|
-
raise ValueError("Either 'uri' or 'path' must be provided")
|
|
140
|
-
return self
|
|
141
|
-
|
|
142
|
-
def model_post_init(self, _: Any) -> None:
|
|
143
|
-
if self.uri and self._is_url(self.uri):
|
|
144
|
-
self._download_url()
|
|
145
|
-
elif self.uri and not os.path.isabs(self.uri):
|
|
146
|
-
self.path = os.path.abspath(self.uri)
|
|
147
|
-
elif self.uri:
|
|
148
|
-
self.path = self.uri
|
|
149
|
-
if self.path:
|
|
150
|
-
self._populate_metadata()
|
|
151
|
-
else:
|
|
152
|
-
raise ValueError("Either 'uri' or 'path' must be provided")
|
|
153
|
-
|
|
154
|
-
def _is_url(self, path: str) -> bool:
|
|
155
|
-
"""Check if the path is a URL."""
|
|
156
|
-
parsed = urllib.parse.urlparse(path)
|
|
157
|
-
return parsed.scheme in ('http', 'https')
|
|
158
|
-
|
|
159
|
-
def _download_url(self) -> None:
|
|
160
|
-
"""Download the URL to a temporary file and update the path."""
|
|
161
|
-
original_url = self.uri
|
|
162
|
-
tmp_file = None
|
|
163
|
-
try:
|
|
164
|
-
# Create a temporary file with a suffix based on the URL path
|
|
165
|
-
suffix = os.path.splitext(urllib.parse.urlparse(original_url).path)[1]
|
|
166
|
-
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
|
|
167
|
-
self._tmp_path = tmp_file.name
|
|
168
|
-
|
|
169
|
-
# Set up request with user agent
|
|
170
|
-
headers = {
|
|
171
|
-
'User-Agent': (
|
|
172
|
-
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
|
|
173
|
-
'AppleWebKit/537.36 (KHTML, like Gecko) '
|
|
174
|
-
'Chrome/91.0.4472.124 Safari/537.36'
|
|
175
|
-
)
|
|
176
|
-
}
|
|
177
|
-
req = urllib.request.Request(original_url, headers=headers)
|
|
178
|
-
|
|
179
|
-
# Download the file
|
|
180
|
-
print(f"Downloading URL: {original_url} to {self._tmp_path}")
|
|
181
|
-
try:
|
|
182
|
-
with urllib.request.urlopen(req) as response, open(self._tmp_path, 'wb') as out_file:
|
|
183
|
-
out_file.write(response.read())
|
|
184
|
-
self.path = self._tmp_path
|
|
185
|
-
except (urllib.error.URLError, urllib.error.HTTPError) as e:
|
|
186
|
-
raise RuntimeError(f"Failed to download URL {original_url}: {str(e)}")
|
|
187
|
-
except IOError as e:
|
|
188
|
-
raise RuntimeError(f"Failed to write downloaded file to {self._tmp_path}: {str(e)}")
|
|
189
|
-
except Exception as e:
|
|
190
|
-
# Clean up temp file if something went wrong
|
|
191
|
-
if tmp_file is not None and hasattr(self, '_tmp_path'):
|
|
192
|
-
try:
|
|
193
|
-
os.unlink(self._tmp_path)
|
|
194
|
-
except (OSError, IOError):
|
|
195
|
-
pass
|
|
196
|
-
raise RuntimeError(f"Error downloading URL {original_url}: {str(e)}")
|
|
197
|
-
|
|
198
|
-
def __del__(self):
|
|
199
|
-
"""Cleanup temporary file if it exists."""
|
|
200
|
-
if hasattr(self, '_tmp_path') and self._tmp_path:
|
|
201
|
-
try:
|
|
202
|
-
os.unlink(self._tmp_path)
|
|
203
|
-
except (OSError, IOError):
|
|
204
|
-
pass
|
|
205
|
-
|
|
206
|
-
def _populate_metadata(self) -> None:
|
|
207
|
-
"""Populate file metadata from the path if it exists."""
|
|
208
|
-
if os.path.exists(self.path):
|
|
209
|
-
if not self.content_type:
|
|
210
|
-
self.content_type = self._guess_content_type()
|
|
211
|
-
if not self.size:
|
|
212
|
-
self.size = self._get_file_size()
|
|
213
|
-
if not self.filename:
|
|
214
|
-
self.filename = self._get_filename()
|
|
215
|
-
|
|
216
|
-
@classmethod
|
|
217
|
-
def from_path(cls, path: Union[str, os.PathLike]) -> 'File':
|
|
218
|
-
"""Create a File instance from a file path."""
|
|
219
|
-
return cls(uri=str(path))
|
|
220
|
-
|
|
221
|
-
def _guess_content_type(self) -> Optional[str]:
|
|
222
|
-
"""Guess the MIME type of the file."""
|
|
223
|
-
return mimetypes.guess_type(self.path)[0]
|
|
224
|
-
|
|
225
|
-
def _get_file_size(self) -> int:
|
|
226
|
-
"""Get the size of the file in bytes."""
|
|
227
|
-
return os.path.getsize(self.path)
|
|
228
|
-
|
|
229
|
-
def _get_filename(self) -> str:
|
|
230
|
-
"""Get the base filename from the path."""
|
|
231
|
-
return os.path.basename(self.path)
|
|
232
|
-
|
|
233
|
-
def exists(self) -> bool:
|
|
234
|
-
"""Check if the file exists."""
|
|
235
|
-
return os.path.exists(self.path)
|
|
236
|
-
|
|
237
|
-
def refresh_metadata(self) -> None:
|
|
238
|
-
"""Refresh all metadata from the file."""
|
|
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
|
-
|
|
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
|
|
253
|
-
|
|
254
|
-
class ContextMessage(BaseModel):
|
|
255
|
-
role: ContextMessageRole = Field(
|
|
256
|
-
description="The role of the message",
|
|
257
|
-
)
|
|
258
|
-
text: str = Field(
|
|
259
|
-
description="The text content of the message"
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
class ContextMessageWithImage(ContextMessage):
|
|
263
|
-
image: Optional[File] = Field(
|
|
264
|
-
description="The image url of the message",
|
|
265
|
-
default=None
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
class LLMInput(BaseAppInput):
|
|
269
|
-
system_prompt: str = Field(
|
|
270
|
-
description="The system prompt to use for the model",
|
|
271
|
-
default="You are a helpful assistant that can answer questions and help with tasks.",
|
|
272
|
-
examples=[
|
|
273
|
-
"You are a helpful assistant that can answer questions and help with tasks.",
|
|
274
|
-
"You are a certified medical professional who can provide accurate health information.",
|
|
275
|
-
"You are a certified financial advisor who can give sound investment guidance.",
|
|
276
|
-
"You are a certified cybersecurity expert who can explain security best practices.",
|
|
277
|
-
"You are a certified environmental scientist who can discuss climate and sustainability.",
|
|
278
|
-
]
|
|
279
|
-
)
|
|
280
|
-
context: list[ContextMessage] = Field(
|
|
281
|
-
description="The context to use for the model",
|
|
282
|
-
examples=[
|
|
283
|
-
[
|
|
284
|
-
{"role": "user", "content": [{"type": "text", "text": "What is the capital of France?"}]},
|
|
285
|
-
{"role": "assistant", "content": [{"type": "text", "text": "The capital of France is Paris."}]}
|
|
286
|
-
],
|
|
287
|
-
[
|
|
288
|
-
{"role": "user", "content": [{"type": "text", "text": "What is the weather like today?"}]},
|
|
289
|
-
{"role": "assistant", "content": [{"type": "text", "text": "I apologize, but I don't have access to real-time weather information. You would need to check a weather service or app to get current weather conditions for your location."}]}
|
|
290
|
-
],
|
|
291
|
-
[
|
|
292
|
-
{"role": "user", "content": [{"type": "text", "text": "Can you help me write a poem about spring?"}]},
|
|
293
|
-
{"role": "assistant", "content": [{"type": "text", "text": "Here's a short poem about spring:\n\nGreen buds awakening,\nSoft rain gently falling down,\nNew life springs anew.\n\nWarm sun breaks through clouds,\nBirds return with joyful song,\nNature's sweet rebirth."}]}
|
|
294
|
-
],
|
|
295
|
-
[
|
|
296
|
-
{"role": "user", "content": [{"type": "text", "text": "Explain quantum computing in simple terms"}]},
|
|
297
|
-
{"role": "assistant", "content": [{"type": "text", "text": "Quantum computing is like having a super-powerful calculator that can solve many problems at once instead of one at a time. While regular computers use bits (0s and 1s), quantum computers use quantum bits or \"qubits\" that can be both 0 and 1 at the same time - kind of like being in two places at once! This allows them to process huge amounts of information much faster than regular computers for certain types of problems."}]}
|
|
298
|
-
]
|
|
299
|
-
],
|
|
300
|
-
default=[]
|
|
301
|
-
)
|
|
302
|
-
text: str = Field(
|
|
303
|
-
description="The user prompt to use for the model",
|
|
304
|
-
examples=[
|
|
305
|
-
"What is the capital of France?",
|
|
306
|
-
"What is the weather like today?",
|
|
307
|
-
"Can you help me write a poem about spring?",
|
|
308
|
-
"Explain quantum computing in simple terms"
|
|
309
|
-
],
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
class LLMInputWithImage(LLMInput):
|
|
313
|
-
image: Optional[File] = Field(
|
|
314
|
-
description="The image to use for the model",
|
|
315
|
-
default=None
|
|
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,8 +0,0 @@
|
|
|
1
|
-
inferencesh/__init__.py,sha256=hbKkgHCh0lCdhWyHs3FHHRd8JfLeHkTd1bT4v79Fi8M,192
|
|
2
|
-
inferencesh/sdk.py,sha256=Yebi85zvWYHVnnf5CARHg-eOpOPM2mZ7SafRlaJuwdA,14554
|
|
3
|
-
inferencesh-0.3.0.dist-info/licenses/LICENSE,sha256=OsgqEWIh2el_QMj0y8O1A5Q5Dl-dxqqYbFE6fszuR4s,1086
|
|
4
|
-
inferencesh-0.3.0.dist-info/METADATA,sha256=_06FcZ_2WJ7dS7DHhWmWDfmjR6rspTYZL7x9X0mUr5M,2728
|
|
5
|
-
inferencesh-0.3.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
6
|
-
inferencesh-0.3.0.dist-info/entry_points.txt,sha256=6IC-fyozAqW3ljsMLGCXxJ0_ui2Jb-2fLHtoH1RTnEE,45
|
|
7
|
-
inferencesh-0.3.0.dist-info/top_level.txt,sha256=TSMHg3T1ThMl1HGAWmzBClwOYH1ump5neof9BfHIwaA,12
|
|
8
|
-
inferencesh-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|