isa-model 0.3.7__py3-none-any.whl → 0.3.9__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.
isa_model/__init__.py CHANGED
@@ -6,7 +6,7 @@ Main Components:
6
6
  - AIFactory: Legacy factory pattern (still supported)
7
7
  """
8
8
 
9
- __version__ = "0.3.5"
9
+ __version__ = "0.3.9"
10
10
 
11
11
  # Main unified client interface
12
12
  from isa_model.client import ISAModelClient, create_client
isa_model/client.py CHANGED
@@ -138,6 +138,7 @@ class ISAModelClient:
138
138
  model_hint: Optional[str] = None,
139
139
  provider_hint: Optional[str] = None,
140
140
  stream: bool = False,
141
+ tools: Optional[List[Any]] = None,
141
142
  **kwargs
142
143
  ) -> Union[Dict[str, Any], object]:
143
144
  """
@@ -150,6 +151,7 @@ class ISAModelClient:
150
151
  model_hint: Optional model preference
151
152
  provider_hint: Optional provider preference
152
153
  stream: Enable streaming for text services (returns AsyncGenerator)
154
+ tools: Optional list of tools for function calling (only for text services)
153
155
  **kwargs: Additional task-specific parameters
154
156
 
155
157
  Returns:
@@ -174,6 +176,13 @@ class ISAModelClient:
174
176
  async for token in await client.invoke("Hello", "chat", "text", stream=True):
175
177
  print(token, end="", flush=True)
176
178
 
179
+ # Text with tools
180
+ await client.invoke("What's 5+3?", "chat", "text", tools=[calculator_function])
181
+
182
+ # Streaming with tools
183
+ async for token in await client.invoke("What's 5+3?", "chat", "text", stream=True, tools=[calculator_function]):
184
+ print(token, end="")
185
+
177
186
  # Image generation
178
187
  await client.invoke("A beautiful sunset", "generate_image", "image")
179
188
 
@@ -193,6 +202,7 @@ class ISAModelClient:
193
202
  service_type=service_type,
194
203
  model_hint=model_hint,
195
204
  provider_hint=provider_hint,
205
+ tools=tools,
196
206
  **kwargs
197
207
  )
198
208
  else:
@@ -202,6 +212,7 @@ class ISAModelClient:
202
212
  service_type=service_type,
203
213
  model_hint=model_hint,
204
214
  provider_hint=provider_hint,
215
+ tools=tools,
205
216
  **kwargs
206
217
  )
207
218
 
@@ -213,6 +224,7 @@ class ISAModelClient:
213
224
  service_type=service_type,
214
225
  model_hint=model_hint,
215
226
  provider_hint=provider_hint,
227
+ tools=tools,
216
228
  **kwargs
217
229
  )
218
230
  else:
@@ -222,6 +234,7 @@ class ISAModelClient:
222
234
  service_type=service_type,
223
235
  model_hint=model_hint,
224
236
  provider_hint=provider_hint,
237
+ tools=tools,
225
238
  **kwargs
226
239
  )
227
240
 
@@ -349,7 +362,8 @@ class ISAModelClient:
349
362
  service_type: str,
350
363
  model_name: str,
351
364
  provider: str,
352
- task: str
365
+ task: str,
366
+ tools: Optional[List[Any]] = None
353
367
  ) -> Any:
354
368
  """Get appropriate service instance"""
355
369
 
@@ -357,7 +371,11 @@ class ISAModelClient:
357
371
 
358
372
  # Check cache first
359
373
  if cache_key in self._service_cache:
360
- return self._service_cache[cache_key]
374
+ service = self._service_cache[cache_key]
375
+ # If tools are needed, bind them to the service
376
+ if tools and service_type == "text":
377
+ return service.bind_tools(tools)
378
+ return service
361
379
 
362
380
  try:
363
381
  # Route to appropriate AIFactory method
@@ -387,6 +405,11 @@ class ISAModelClient:
387
405
 
388
406
  # Cache the service
389
407
  self._service_cache[cache_key] = service
408
+
409
+ # If tools are needed, bind them to the service
410
+ if tools and service_type == "text":
411
+ return service.bind_tools(tools)
412
+
390
413
  return service
391
414
 
392
415
  except Exception as e:
@@ -499,11 +522,20 @@ class ISAModelClient:
499
522
  unified_task = task_mapping.get(task, task)
500
523
 
501
524
  # Use unified invoke method
502
- return await service.invoke(
525
+ result = await service.invoke(
503
526
  input_data=input_data,
504
527
  task=unified_task,
505
528
  **kwargs
506
529
  )
530
+
531
+ # Handle the new response format from LLM services
532
+ # LLM services now return {"message": ..., "success": ..., "metadata": ...}
533
+ if isinstance(result, dict) and "message" in result:
534
+ # Extract the message object (AIMessage or string)
535
+ return result["message"]
536
+
537
+ # Fallback for other service types or legacy format
538
+ return result
507
539
 
508
540
  async def _execute_image_task(self, service, input_data, task, **kwargs):
509
541
  """Execute image generation tasks using unified invoke method"""
@@ -616,6 +648,7 @@ class ISAModelClient:
616
648
  service_type: str,
617
649
  model_hint: Optional[str] = None,
618
650
  provider_hint: Optional[str] = None,
651
+ tools: Optional[List[Any]] = None,
619
652
  **kwargs
620
653
  ) -> Dict[str, Any]:
621
654
  """Local invoke using AI Factory (original logic)"""
@@ -634,7 +667,8 @@ class ISAModelClient:
634
667
  service_type=service_type,
635
668
  model_name=selected_model["model_id"],
636
669
  provider=selected_model["provider"],
637
- task=task
670
+ task=task,
671
+ tools=tools
638
672
  )
639
673
 
640
674
  # Step 3: Execute task with unified interface
@@ -823,6 +857,7 @@ class ISAModelClient:
823
857
  service_type: str,
824
858
  model_hint: Optional[str] = None,
825
859
  provider_hint: Optional[str] = None,
860
+ tools: Optional[List[Any]] = None,
826
861
  **kwargs
827
862
  ):
828
863
  """Local streaming using AI Factory"""
@@ -840,7 +875,8 @@ class ISAModelClient:
840
875
  service_type=service_type,
841
876
  model_name=selected_model["model_id"],
842
877
  provider=selected_model["provider"],
843
- task=task
878
+ task=task,
879
+ tools=tools
844
880
  )
845
881
 
846
882
  # Step 3: Yield tokens from the stream
@@ -15,6 +15,7 @@ from datetime import datetime, timedelta
15
15
  from dataclasses import dataclass, field
16
16
 
17
17
  from .types import Provider
18
+ from .config import config_manager
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -77,7 +78,17 @@ class PricingManager:
77
78
 
78
79
  def _load_pricing_data(self):
79
80
  """Load pricing data from configuration files"""
80
- # Try to load from specified config path first
81
+ # Try to load from Supabase first
82
+ if self._load_from_supabase():
83
+ logger.info("Loaded pricing data from Supabase")
84
+ return
85
+
86
+ # Try to load from provider configurations
87
+ if self._load_from_provider_configs():
88
+ logger.info("Loaded pricing data from provider configurations")
89
+ return
90
+
91
+ # Try to load from specified config path
81
92
  if self.config_path and self.config_path.exists():
82
93
  self._load_from_file(self.config_path)
83
94
  return
@@ -187,6 +198,242 @@ class PricingManager:
187
198
  self._parse_pricing_data({"providers": default_pricing})
188
199
  logger.info("Loaded default pricing data")
189
200
 
201
+ def _load_from_supabase(self) -> bool:
202
+ """Try to load pricing data from Supabase models table"""
203
+ try:
204
+ global_config = config_manager.get_global_config()
205
+ if not global_config.use_supabase:
206
+ return False
207
+
208
+ # Import Supabase client
209
+ try:
210
+ from supabase import create_client, Client
211
+ except ImportError:
212
+ logger.debug("Supabase library not available")
213
+ return False
214
+
215
+ # Get Supabase credentials
216
+ supabase_url = global_config.supabase_url or os.getenv('SUPABASE_URL')
217
+ supabase_key = global_config.supabase_key or os.getenv('SUPABASE_ANON_KEY')
218
+
219
+ if not supabase_url or not supabase_key:
220
+ logger.debug("Supabase credentials not configured")
221
+ return False
222
+
223
+ # Create Supabase client
224
+ supabase: Client = create_client(supabase_url, supabase_key)
225
+
226
+ # Query models table for pricing information
227
+ result = supabase.table('models').select('model_id, provider, metadata').execute()
228
+
229
+ if not result.data:
230
+ logger.debug("No models found in Supabase")
231
+ return False
232
+
233
+ self.pricing_data = {}
234
+ loaded_count = 0
235
+
236
+ for model_record in result.data:
237
+ model_id = model_record.get('model_id')
238
+ provider = model_record.get('provider')
239
+ metadata = model_record.get('metadata', {})
240
+
241
+ if not model_id or not provider:
242
+ continue
243
+
244
+ # Extract pricing from metadata
245
+ pricing = self._extract_pricing_from_supabase_metadata(metadata, provider, model_id)
246
+ if pricing:
247
+ if provider not in self.pricing_data:
248
+ self.pricing_data[provider] = {}
249
+ self.pricing_data[provider][model_id] = pricing
250
+ loaded_count += 1
251
+
252
+ if loaded_count > 0:
253
+ logger.info(f"Loaded pricing for {loaded_count} models from Supabase")
254
+ return True
255
+ else:
256
+ logger.debug("No pricing data found in Supabase models")
257
+ return False
258
+
259
+ except Exception as e:
260
+ logger.debug(f"Failed to load pricing from Supabase: {e}")
261
+ return False
262
+
263
+ def _load_from_provider_configs(self) -> bool:
264
+ """Load pricing data from provider configuration files"""
265
+ try:
266
+ providers_dir = self._find_project_root() / "isa_model" / "core" / "config" / "providers"
267
+ if not providers_dir.exists():
268
+ return False
269
+
270
+ self.pricing_data = {}
271
+ loaded_any = False
272
+
273
+ # Load all provider config files
274
+ for config_file in providers_dir.glob("*.yaml"):
275
+ if self._load_provider_config_file(config_file):
276
+ loaded_any = True
277
+
278
+ return loaded_any
279
+
280
+ except Exception as e:
281
+ logger.error(f"Failed to load pricing from provider configs: {e}")
282
+ return False
283
+
284
+ def _load_provider_config_file(self, config_file: Path) -> bool:
285
+ """Load pricing data from a single provider config file"""
286
+ try:
287
+ with open(config_file, 'r') as f:
288
+ provider_data = yaml.safe_load(f)
289
+
290
+ provider_name = provider_data.get("provider")
291
+ if not provider_name:
292
+ return False
293
+
294
+ models = provider_data.get("models", [])
295
+ if not models:
296
+ return False
297
+
298
+ self.pricing_data[provider_name] = {}
299
+
300
+ for model in models:
301
+ model_id = model.get("model_id")
302
+ metadata = model.get("metadata", {})
303
+
304
+ if not model_id:
305
+ continue
306
+
307
+ # Extract pricing information from metadata
308
+ pricing = self._extract_pricing_from_metadata(metadata, provider_name, model_id)
309
+ if pricing:
310
+ self.pricing_data[provider_name][model_id] = pricing
311
+
312
+ logger.debug(f"Loaded pricing for {len(self.pricing_data[provider_name])} models from {provider_name}")
313
+ return True
314
+
315
+ except Exception as e:
316
+ logger.error(f"Failed to load provider config {config_file}: {e}")
317
+ return False
318
+
319
+ def _extract_pricing_from_metadata(self, metadata: Dict[str, Any], provider: str, model_name: str) -> Optional[ModelPricing]:
320
+ """Extract pricing information from model metadata"""
321
+ try:
322
+ # Map different pricing field formats to our standard format
323
+ pricing_fields = {
324
+ "cost_per_1000_chars": ("character", 1000),
325
+ "cost_per_1000_tokens": ("token", 1000000), # Convert to cost per 1M tokens
326
+ "cost_per_minute": ("minute", 1),
327
+ "cost_per_image": ("image", 1),
328
+ "cost_per_request": ("request", 1),
329
+ }
330
+
331
+ input_cost = 0.0
332
+ output_cost = 0.0
333
+ unit_type = "token"
334
+ base_cost = 0.0
335
+
336
+ for field, (unit, multiplier) in pricing_fields.items():
337
+ if field in metadata:
338
+ cost = float(metadata[field])
339
+ if unit == "character":
340
+ # Convert cost per 1K chars to cost per 1K chars
341
+ input_cost = cost
342
+ unit_type = "character"
343
+ elif unit == "token":
344
+ # Cost per 1M tokens
345
+ input_cost = cost
346
+ unit_type = "token"
347
+ elif unit == "minute":
348
+ input_cost = cost
349
+ unit_type = "minute"
350
+ elif unit == "image":
351
+ input_cost = cost
352
+ unit_type = "image"
353
+ elif unit == "request":
354
+ base_cost = cost
355
+ break
356
+
357
+ # If no pricing found, skip this model
358
+ if input_cost == 0.0 and base_cost == 0.0:
359
+ return None
360
+
361
+ return ModelPricing(
362
+ provider=provider,
363
+ model_name=model_name,
364
+ input_cost=input_cost,
365
+ output_cost=output_cost,
366
+ unit_type=unit_type,
367
+ base_cost=base_cost,
368
+ last_updated=datetime.now()
369
+ )
370
+
371
+ except Exception as e:
372
+ logger.warning(f"Failed to extract pricing for {provider}/{model_name}: {e}")
373
+ return None
374
+
375
+ def _extract_pricing_from_supabase_metadata(self, metadata: Dict[str, Any], provider: str, model_name: str) -> Optional[ModelPricing]:
376
+ """Extract pricing information from Supabase model metadata"""
377
+ try:
378
+ # Check for pricing information in metadata
379
+ pricing_info = metadata.get('pricing', {})
380
+
381
+ # If no pricing object, look for direct pricing fields
382
+ if not pricing_info:
383
+ # Look for various pricing field formats in metadata
384
+ pricing_fields = [
385
+ 'cost_per_1000_chars', 'cost_per_1000_tokens', 'cost_per_minute',
386
+ 'cost_per_image', 'cost_per_request', 'input_cost', 'output_cost',
387
+ 'cost_per_1k_tokens', 'cost_per_1k_chars'
388
+ ]
389
+
390
+ for field in pricing_fields:
391
+ if field in metadata:
392
+ # Create a pricing object from the field
393
+ if 'char' in field:
394
+ pricing_info = {'input': metadata[field], 'unit_type': 'character'}
395
+ elif 'token' in field:
396
+ pricing_info = {'input': metadata[field], 'unit_type': 'token'}
397
+ elif 'minute' in field:
398
+ pricing_info = {'input': metadata[field], 'unit_type': 'minute'}
399
+ elif 'image' in field:
400
+ pricing_info = {'input': metadata[field], 'unit_type': 'image'}
401
+ elif 'request' in field:
402
+ pricing_info = {'base_cost': metadata[field], 'unit_type': 'request'}
403
+ break
404
+
405
+ if not pricing_info:
406
+ return None
407
+
408
+ # Extract standard pricing fields
409
+ input_cost = float(pricing_info.get('input', pricing_info.get('input_cost', 0.0)))
410
+ output_cost = float(pricing_info.get('output', pricing_info.get('output_cost', 0.0)))
411
+ unit_type = pricing_info.get('unit_type', 'token')
412
+ base_cost = float(pricing_info.get('base_cost', 0.0))
413
+ infrastructure_cost_per_hour = float(pricing_info.get('infrastructure_cost_per_hour', 0.0))
414
+ currency = pricing_info.get('currency', 'USD')
415
+
416
+ # If no pricing found, skip this model
417
+ if input_cost == 0.0 and output_cost == 0.0 and base_cost == 0.0:
418
+ return None
419
+
420
+ return ModelPricing(
421
+ provider=provider,
422
+ model_name=model_name,
423
+ input_cost=input_cost,
424
+ output_cost=output_cost,
425
+ unit_type=unit_type,
426
+ base_cost=base_cost,
427
+ infrastructure_cost_per_hour=infrastructure_cost_per_hour,
428
+ currency=currency,
429
+ last_updated=datetime.now(),
430
+ metadata=pricing_info
431
+ )
432
+
433
+ except Exception as e:
434
+ logger.warning(f"Failed to extract pricing from Supabase metadata for {provider}/{model_name}: {e}")
435
+ return None
436
+
190
437
  def get_model_pricing(self, provider: str, model_name: str) -> Optional[ModelPricing]:
191
438
  """Get pricing information for a specific model"""
192
439
  self._refresh_if_needed()
@@ -140,6 +140,49 @@ class OllamaLLMService(BaseLLMService):
140
140
  """Use adapter manager to format response (consistent with OpenAI service)"""
141
141
  return self.adapter_manager.format_response(response, original_input)
142
142
 
143
+ async def chat(
144
+ self,
145
+ input_data: Union[str, List[Dict[str, str]], Any],
146
+ max_tokens: Optional[int] = None
147
+ ) -> Dict[str, Any]:
148
+ """
149
+ Chat method that wraps ainvoke for compatibility with base class
150
+
151
+ Args:
152
+ input_data: Input messages
153
+ max_tokens: Maximum tokens to generate
154
+
155
+ Returns:
156
+ Dict containing chat response with properly formatted message object
157
+ """
158
+ try:
159
+ # Call ainvoke and get the response (already processed by adapter)
160
+ response = await self.ainvoke(input_data)
161
+
162
+ # Return the response as-is (adapter already formatted it correctly)
163
+ # For LangChain inputs, this will be an AIMessage object
164
+ # For standard inputs, this will be a string
165
+ return {
166
+ "message": response, # Use "message" to preserve object type
167
+ "success": True,
168
+ "metadata": {
169
+ "model": self.model_name,
170
+ "provider": self.provider_name,
171
+ "max_tokens": max_tokens or self.max_tokens
172
+ }
173
+ }
174
+ except Exception as e:
175
+ logger.error(f"Chat method failed: {e}")
176
+ return {
177
+ "message": None,
178
+ "success": False,
179
+ "error": str(e),
180
+ "metadata": {
181
+ "model": self.model_name,
182
+ "provider": self.provider_name
183
+ }
184
+ }
185
+
143
186
 
144
187
  async def _stream_response(self, payload: Dict[str, Any]) -> AsyncGenerator[str, None]:
145
188
  """Handle streaming responses"""
@@ -269,15 +269,17 @@ class OpenAILLMService(BaseLLMService):
269
269
  max_tokens: Maximum tokens to generate
270
270
 
271
271
  Returns:
272
- Dict containing chat response
272
+ Dict containing chat response with properly formatted message object
273
273
  """
274
274
  try:
275
- # Call ainvoke and get the response
275
+ # Call ainvoke and get the response (already processed by adapter)
276
276
  response = await self.ainvoke(input_data)
277
277
 
278
- # Return in expected format
278
+ # Return the response as-is (adapter already formatted it correctly)
279
+ # For LangChain inputs, this will be an AIMessage object
280
+ # For standard inputs, this will be a string
279
281
  return {
280
- "text": response if isinstance(response, str) else str(response),
282
+ "message": response, # Changed from "text" to "message" to preserve object
281
283
  "success": True,
282
284
  "metadata": {
283
285
  "model": self.model_name,
@@ -288,7 +290,7 @@ class OpenAILLMService(BaseLLMService):
288
290
  except Exception as e:
289
291
  logger.error(f"Chat method failed: {e}")
290
292
  return {
291
- "text": "",
293
+ "message": None,
292
294
  "success": False,
293
295
  "error": str(e),
294
296
  "metadata": {
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Dict, Any, List, Union, AsyncGenerator
2
+ from typing import Dict, Any, List, Union, AsyncGenerator, Optional
3
3
 
4
4
  # (�� OpenAI �
5
5
  from openai import AsyncOpenAI
@@ -249,6 +249,48 @@ class YydsLLMService(BaseLLMService):
249
249
  }
250
250
  }
251
251
 
252
+ async def chat(
253
+ self,
254
+ input_data: Union[str, List[Dict[str, str]], Any],
255
+ max_tokens: Optional[int] = None
256
+ ) -> Dict[str, Any]:
257
+ """
258
+ Chat method that wraps ainvoke for compatibility with base class
259
+
260
+ Args:
261
+ input_data: Input messages
262
+ max_tokens: Maximum tokens to generate
263
+
264
+ Returns:
265
+ Dict containing chat response with properly formatted message object
266
+ """
267
+ try:
268
+ # Call ainvoke and get the response (already processed by adapter)
269
+ response = await self.ainvoke(input_data)
270
+
271
+ # Return the response as-is (adapter already formatted it correctly)
272
+ # For LangChain inputs, this will be an AIMessage object
273
+ # For standard inputs, this will be a string
274
+ return {
275
+ "message": response, # Use "message" to preserve object type
276
+ "success": True,
277
+ "metadata": {
278
+ "model": self.model_name,
279
+ "provider": self.provider_name,
280
+ "max_tokens": max_tokens or self.max_tokens
281
+ }
282
+ }
283
+ except Exception as e:
284
+ logger.error(f"Chat method failed: {e}")
285
+ return {
286
+ "message": None,
287
+ "success": False,
288
+ "error": str(e),
289
+ "metadata": {
290
+ "model": self.model_name,
291
+ "provider": self.provider_name
292
+ }
293
+ }
252
294
 
253
295
  async def close(self):
254
296
  """Close the backend client"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isa_model
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: Unified AI model serving framework
5
5
  Author: isA_Model Contributors
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -1,7 +1,7 @@
1
- isa_model/__init__.py,sha256=bAbHdrDVQ-mySC_GJtgfLNI8KPcs2LfReBkIOOtpaQQ,867
2
- isa_model/client.py,sha256=ly4614_LIz5Csg1qG7M-eXtN8VR36ClsMWqsgz111BE,34285
1
+ isa_model/__init__.py,sha256=73ibr8BcJyUmtEj-c86brXCY9BjZPYfnXpMbD1ashwQ,867
2
+ isa_model/client.py,sha256=xJt_wlaCZwv4fG053diFKMVpGCv3Qx0vGyFFPXow9y8,35862
3
3
  isa_model/core/config.py,sha256=h9GVTEEMlaJYSCDd0W9q1KtaWTV5V5TawMsKtGuphds,15686
4
- isa_model/core/pricing_manager.py,sha256=b7HcZsBQ8ZSCzMepOhqN-J9kU43vhTxX5NabQS0aM70,17125
4
+ isa_model/core/pricing_manager.py,sha256=W9VRHGsJVxs3EcPD2zRP0lvOYlxydb6E74RS-sLn_UA,27745
5
5
  isa_model/core/types.py,sha256=XLUs442WGNc8E0gF2M-nb6dutD_s-XCfpr2BfGBCA2M,8445
6
6
  isa_model/core/config/__init__.py,sha256=SLeHQtYGDHl64NDVyb3ECQXOKepGM8YNHEoM8CVEWus,350
7
7
  isa_model/core/config/config_manager.py,sha256=hx0qcdvYEE_cCp-qb8tnVkXnpsTXEuRM1108DoAiUnE,19905
@@ -50,16 +50,6 @@ isa_model/inference/__init__.py,sha256=usfuQJ4zYY2RRtHkE-V6LuJ5aN7WJogtPUj9Qmy4W
50
50
  isa_model/inference/ai_factory.py,sha256=oGtRd4wp6IZOTyI3GVKBNN4AtlnrLS7yFZuq2wvkaUg,19784
51
51
  isa_model/inference/base.py,sha256=qwOddnSGI0GUdD6qIdGBPQpkW7UjU3Y-zaZvu70B4WA,1278
52
52
  isa_model/inference/adapter/unified_api.py,sha256=67_Ok8W20m6Otf6r9WyOEVpnxondP4UAxOASk9ozDk4,8668
53
- isa_model/inference/providers/__init__.py,sha256=a83q-LMFv8u47wf0XtxvqOw_mlVgA_90wtuwy02qdDE,581
54
- isa_model/inference/providers/base_provider.py,sha256=PT-YnGwBu-Jn_4T3iAphkAJw_mYmKVLjUID62vf2_Ow,2711
55
- isa_model/inference/providers/ml_provider.py,sha256=4oGGF7lVWQ91Qh3h7olyPFoACLxCROaMxUZlDiZrRL4,1661
56
- isa_model/inference/providers/modal_provider.py,sha256=klRYXECD5TJicodHIElsGNGMAsAWRFhvn4yfCRcqdVs,3654
57
- isa_model/inference/providers/model_cache_manager.py,sha256=dLRpx7OJweQ5LcSAkU7D0DQRfLtIhG6nGvg4W_gau80,15315
58
- isa_model/inference/providers/ollama_provider.py,sha256=IfM9XhdzfE1faguzS2-4GfhK30v5kDPecD3l4z2eB1w,3620
59
- isa_model/inference/providers/openai_provider.py,sha256=tB8FMsMivlRx0cfPJ0Yrxh1DCvuXyyjNFXrO4lMkkhA,5366
60
- isa_model/inference/providers/replicate_provider.py,sha256=0oi_BglIE6-HYgzLau9ifP8OdpAMO-QkwYk0OXRUzPk,4490
61
- isa_model/inference/providers/triton_provider.py,sha256=GKlth7cTOx6ERbsXXJ0gDNby3kVGQNULBDt098BXBSU,15258
62
- isa_model/inference/providers/yyds_provider.py,sha256=KbDsopShs11_G9oX3b2i2NgHIqkZV7HYWe9K9uZLccc,4284
63
53
  isa_model/inference/services/__init__.py,sha256=yfLz0YGl8ixk6LfTRL6cRTvZMb9F_Pv1QRgGyNc9xYM,386
64
54
  isa_model/inference/services/base_service.py,sha256=fVaSx0CogHK71UEsNJeSyM8mhqmq5_9ePbbSZVi3Al8,5085
65
55
  isa_model/inference/services/audio/base_stt_service.py,sha256=sfzAfreFdvEOBHtphoTrQSjb-gCoCOW4WCj6iIe51oU,5804
@@ -80,9 +70,9 @@ isa_model/inference/services/img/replicate_image_gen_service.py,sha256=QLjgrXNmt
80
70
  isa_model/inference/services/img/helpers/base_stacked_service.py,sha256=Y2g2Hz3n2Uwo4RoCbsC33IXxTeQ2TeT6T-2HnXd-2B0,10546
81
71
  isa_model/inference/services/llm/__init__.py,sha256=hSdfeqE0463CtQ6ZzREqPBvtzXNuzi3W5PFKS0nwhvo,336
82
72
  isa_model/inference/services/llm/base_llm_service.py,sha256=fg79J5mKy27qahvtLscMcquOe4O2L-EoNjE33yPRI9E,22196
83
- isa_model/inference/services/llm/ollama_llm_service.py,sha256=c0i9TLce6YcPlsLpj11kvwd-H2Uvw23G0ACuNShGyAM,16009
84
- isa_model/inference/services/llm/openai_llm_service.py,sha256=yhqsExCWvVs6G7EhwZnoXMtKncpwY1VPeZqgLibMSX0,11922
85
- isa_model/inference/services/llm/yyds_llm_service.py,sha256=WA5vwK9j7PrEEffdvP4thNwBlZ5Z13vFXX_F3Kd5V-Y,10475
73
+ isa_model/inference/services/llm/ollama_llm_service.py,sha256=PfsMesjdtpqseLa2OUUg8WWyiIdIUhu9L5s5DkZl040,17580
74
+ isa_model/inference/services/llm/openai_llm_service.py,sha256=40FYFb0bnVQrPwTg10CAKytKDj4zeZvp517do00Y_Ok,12174
75
+ isa_model/inference/services/llm/yyds_llm_service.py,sha256=I8fBCd1dk56hlpnkToh-aAE77hP5YanHRVVEcXHYasE,12051
86
76
  isa_model/inference/services/llm/helpers/llm_adapter.py,sha256=gkKND55EoizRxsaGOCEazUmL-2yTIBI-_njpEOXt-4k,21779
87
77
  isa_model/inference/services/llm/helpers/llm_prompts.py,sha256=4ZOovr_Jx5bwPiMkgO1lZF7GMyEFbITP3ZrhhI48QMs,10964
88
78
  isa_model/inference/services/llm/helpers/llm_utils.py,sha256=LNfB3qzREyD2TyleOyVa20FU8HbhdxA8G6QV-N-wfZs,10016
@@ -142,7 +132,7 @@ isa_model/training/core/config.py,sha256=oqgKpBvtzrN6jwLIQYQ2707lH6nmjrktRiSxp9i
142
132
  isa_model/training/core/dataset.py,sha256=XCFsnf0NUMU1dJpdvo_CAMyvXB-9_RCUEiy8TU50e20,7802
143
133
  isa_model/training/core/trainer.py,sha256=h5TjqjdFr0Fsv5y4-0siy1KmOlqLfliVaUXybvuoeXU,26932
144
134
  isa_model/training/core/utils.py,sha256=Nik0M2ssfNbWqP6fKO0Kfyhzr_H6Q19ioxB-qCYbn5E,8387
145
- isa_model-0.3.7.dist-info/METADATA,sha256=yjnMzsQji2XQeqdlohiHFdWkXahAuXr9aQJOd6tOnQ0,12326
146
- isa_model-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
147
- isa_model-0.3.7.dist-info/top_level.txt,sha256=eHSy_Xb3kNkh2kK11mi1mZh0Wz91AQ5b8k2KFYO-rE8,10
148
- isa_model-0.3.7.dist-info/RECORD,,
135
+ isa_model-0.3.9.dist-info/METADATA,sha256=SAC2G5ZmyJ0KvNcE_8ONOGCI53bx691wWFAwb-KQghU,12326
136
+ isa_model-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
137
+ isa_model-0.3.9.dist-info/top_level.txt,sha256=eHSy_Xb3kNkh2kK11mi1mZh0Wz91AQ5b8k2KFYO-rE8,10
138
+ isa_model-0.3.9.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- """
2
- Providers - Components for integrating with different model providers
3
-
4
- File: isa_model/inference/providers/__init__.py
5
- This module contains provider implementations for different AI model backends.
6
- """
7
-
8
- from .base_provider import BaseProvider
9
-
10
- __all__ = [
11
- "BaseProvider",
12
- ]
13
-
14
- # Provider implementations can be imported individually as needed
15
- # from .triton_provider import TritonProvider
16
- # from .ollama_provider import OllamaProvider
17
- # from .yyds_provider import YYDSProvider
18
- # from .openai_provider import OpenAIProvider
19
- # from .replicate_provider import ReplicateProvider