isa-model 0.2.0__py3-none-any.whl → 0.2.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.
Files changed (77) hide show
  1. isa_model/__init__.py +1 -1
  2. isa_model/core/storage/hf_storage.py +419 -0
  3. isa_model/deployment/__init__.py +52 -0
  4. isa_model/deployment/core/__init__.py +34 -0
  5. isa_model/deployment/core/deployment_config.py +356 -0
  6. isa_model/deployment/core/deployment_manager.py +549 -0
  7. isa_model/deployment/core/isa_deployment_service.py +401 -0
  8. isa_model/eval/factory.py +381 -140
  9. isa_model/inference/ai_factory.py +142 -240
  10. isa_model/inference/providers/ml_provider.py +50 -0
  11. isa_model/inference/services/audio/openai_tts_service.py +104 -3
  12. isa_model/inference/services/embedding/base_embed_service.py +112 -0
  13. isa_model/inference/services/embedding/ollama_embed_service.py +28 -2
  14. isa_model/inference/services/llm/__init__.py +2 -0
  15. isa_model/inference/services/llm/base_llm_service.py +111 -1
  16. isa_model/inference/services/llm/ollama_llm_service.py +234 -26
  17. isa_model/inference/services/llm/openai_llm_service.py +243 -28
  18. isa_model/inference/services/llm/triton_llm_service.py +481 -0
  19. isa_model/inference/services/ml/base_ml_service.py +78 -0
  20. isa_model/inference/services/ml/sklearn_ml_service.py +140 -0
  21. isa_model/inference/services/vision/__init__.py +3 -3
  22. isa_model/inference/services/vision/base_image_gen_service.py +161 -0
  23. isa_model/inference/services/vision/base_vision_service.py +177 -0
  24. isa_model/inference/services/vision/ollama_vision_service.py +143 -17
  25. isa_model/inference/services/vision/replicate_image_gen_service.py +139 -7
  26. isa_model/training/__init__.py +62 -32
  27. isa_model/training/cloud/__init__.py +22 -0
  28. isa_model/training/cloud/job_orchestrator.py +402 -0
  29. isa_model/training/cloud/runpod_trainer.py +454 -0
  30. isa_model/training/cloud/storage_manager.py +482 -0
  31. isa_model/training/core/__init__.py +23 -0
  32. isa_model/training/core/config.py +181 -0
  33. isa_model/training/core/dataset.py +222 -0
  34. isa_model/training/core/trainer.py +720 -0
  35. isa_model/training/core/utils.py +213 -0
  36. isa_model/training/factory.py +229 -198
  37. isa_model-0.2.9.dist-info/METADATA +465 -0
  38. isa_model-0.2.9.dist-info/RECORD +86 -0
  39. isa_model/core/model_router.py +0 -226
  40. isa_model/core/model_version.py +0 -0
  41. isa_model/core/resource_manager.py +0 -202
  42. isa_model/deployment/gpu_fp16_ds8/models/deepseek_r1/1/model.py +0 -120
  43. isa_model/deployment/gpu_fp16_ds8/scripts/download_model.py +0 -18
  44. isa_model/training/engine/llama_factory/__init__.py +0 -39
  45. isa_model/training/engine/llama_factory/config.py +0 -115
  46. isa_model/training/engine/llama_factory/data_adapter.py +0 -284
  47. isa_model/training/engine/llama_factory/examples/__init__.py +0 -6
  48. isa_model/training/engine/llama_factory/examples/finetune_with_tracking.py +0 -185
  49. isa_model/training/engine/llama_factory/examples/rlhf_with_tracking.py +0 -163
  50. isa_model/training/engine/llama_factory/factory.py +0 -331
  51. isa_model/training/engine/llama_factory/rl.py +0 -254
  52. isa_model/training/engine/llama_factory/trainer.py +0 -171
  53. isa_model/training/image_model/configs/create_config.py +0 -37
  54. isa_model/training/image_model/configs/create_flux_config.py +0 -26
  55. isa_model/training/image_model/configs/create_lora_config.py +0 -21
  56. isa_model/training/image_model/prepare_massed_compute.py +0 -97
  57. isa_model/training/image_model/prepare_upload.py +0 -17
  58. isa_model/training/image_model/raw_data/create_captions.py +0 -16
  59. isa_model/training/image_model/raw_data/create_lora_captions.py +0 -20
  60. isa_model/training/image_model/raw_data/pre_processing.py +0 -200
  61. isa_model/training/image_model/train/train.py +0 -42
  62. isa_model/training/image_model/train/train_flux.py +0 -41
  63. isa_model/training/image_model/train/train_lora.py +0 -57
  64. isa_model/training/image_model/train_main.py +0 -25
  65. isa_model-0.2.0.dist-info/METADATA +0 -327
  66. isa_model-0.2.0.dist-info/RECORD +0 -92
  67. isa_model-0.2.0.dist-info/licenses/LICENSE +0 -21
  68. /isa_model/training/{llm_model/annotation → annotation}/annotation_schema.py +0 -0
  69. /isa_model/training/{llm_model/annotation → annotation}/processors/annotation_processor.py +0 -0
  70. /isa_model/training/{llm_model/annotation → annotation}/storage/dataset_manager.py +0 -0
  71. /isa_model/training/{llm_model/annotation → annotation}/storage/dataset_schema.py +0 -0
  72. /isa_model/training/{llm_model/annotation → annotation}/tests/test_annotation_flow.py +0 -0
  73. /isa_model/training/{llm_model/annotation → annotation}/tests/test_minio copy.py +0 -0
  74. /isa_model/training/{llm_model/annotation → annotation}/tests/test_minio_upload.py +0 -0
  75. /isa_model/training/{llm_model/annotation → annotation}/views/annotation_controller.py +0 -0
  76. {isa_model-0.2.0.dist-info → isa_model-0.2.9.dist-info}/WHEEL +0 -0
  77. {isa_model-0.2.0.dist-info → isa_model-0.2.9.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import os
3
- from typing import Dict, Any, List, Union, AsyncGenerator, Optional
3
+ import json
4
+ from typing import Dict, Any, List, Union, AsyncGenerator, Optional, Callable
4
5
 
5
6
  # 使用官方 OpenAI 库和 dotenv
6
7
  from openai import AsyncOpenAI
7
8
  from dotenv import load_dotenv
8
9
 
9
- from isa_model.inference.services.base_service import BaseLLMService
10
+ from isa_model.inference.services.llm.base_llm_service import BaseLLMService
10
11
  from isa_model.inference.providers.base_provider import BaseProvider
11
12
 
12
13
  # 加载 .env.local 文件中的环境变量
@@ -34,14 +35,103 @@ class OpenAILLMService(BaseLLMService):
34
35
  raise ValueError("OPENAI_API_KEY 未设置。") from e
35
36
 
36
37
  self.last_token_usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
38
+ self.total_token_usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0, "requests_count": 0}
39
+
40
+ # Tool binding attributes
41
+ self._bound_tools: List[Dict[str, Any]] = []
42
+ self._tool_binding_kwargs: Dict[str, Any] = {}
43
+ self._tool_functions: Dict[str, Callable] = {}
44
+
37
45
  logger.info(f"Initialized OpenAILLMService with model {self.model_name} and endpoint {self.client.base_url}")
38
46
 
39
- async def ainvoke(self, prompt: Union[str, List[Dict[str, str]], Any]) -> str:
47
+ def _create_bound_copy(self) -> 'OpenAILLMService':
48
+ """Create a copy of this service for tool binding"""
49
+ bound_service = OpenAILLMService(self.provider, self.model_name)
50
+ bound_service._bound_tools = self._bound_tools.copy()
51
+ bound_service._tool_binding_kwargs = self._tool_binding_kwargs.copy()
52
+ bound_service._tool_functions = self._tool_functions.copy()
53
+ return bound_service
54
+
55
+ def bind_tools(self, tools: List[Union[Dict[str, Any], Callable]], **kwargs) -> 'OpenAILLMService':
56
+ """Bind tools to this LLM service for function calling"""
57
+ bound_service = self._create_bound_copy()
58
+ bound_service._bound_tools = self._convert_tools_to_schema(tools)
59
+ bound_service._tool_binding_kwargs = kwargs
60
+
61
+ # Store the actual functions for execution
62
+ for tool in tools:
63
+ if callable(tool):
64
+ bound_service._tool_functions[tool.__name__] = tool
65
+
66
+ return bound_service
67
+
68
+ async def ainvoke(self, prompt: Union[str, List[Any], Any]) -> str:
40
69
  """Universal invocation method"""
41
70
  if isinstance(prompt, str):
42
71
  return await self.acompletion(prompt)
43
72
  elif isinstance(prompt, list):
44
- return await self.achat(prompt)
73
+ if not prompt:
74
+ raise ValueError("Empty message list provided")
75
+
76
+ # 检查是否是 LangGraph 消息对象
77
+ first_msg = prompt[0]
78
+ if hasattr(first_msg, 'content') and hasattr(first_msg, 'type'):
79
+ # 转换 LangGraph 消息对象为标准格式
80
+ converted_messages = []
81
+ for msg in prompt:
82
+ if hasattr(msg, 'type') and hasattr(msg, 'content'):
83
+ # LangGraph 消息对象
84
+ msg_dict = {"content": msg.content}
85
+
86
+ # 根据消息类型设置 role
87
+ if msg.type == "system":
88
+ msg_dict["role"] = "system"
89
+ elif msg.type == "human":
90
+ msg_dict["role"] = "user"
91
+ elif msg.type == "ai":
92
+ msg_dict["role"] = "assistant"
93
+ # 处理工具调用
94
+ if hasattr(msg, 'tool_calls') and msg.tool_calls:
95
+ msg_dict["tool_calls"] = [
96
+ {
97
+ "id": tc.get("id", f"call_{i}"),
98
+ "type": "function",
99
+ "function": {
100
+ "name": tc["name"],
101
+ "arguments": json.dumps(tc["args"])
102
+ }
103
+ } for i, tc in enumerate(msg.tool_calls)
104
+ ]
105
+ elif msg.type == "tool":
106
+ msg_dict["role"] = "tool"
107
+ if hasattr(msg, 'tool_call_id'):
108
+ msg_dict["tool_call_id"] = msg.tool_call_id
109
+ else:
110
+ msg_dict["role"] = "user" # 默认为用户消息
111
+
112
+ converted_messages.append(msg_dict)
113
+ elif isinstance(msg, dict):
114
+ # 已经是字典格式
115
+ converted_messages.append(msg)
116
+ else:
117
+ # 处理其他类型(如字符串)
118
+ converted_messages.append({"role": "user", "content": str(msg)})
119
+
120
+ return await self.achat(converted_messages)
121
+ elif isinstance(first_msg, dict):
122
+ # 标准字典格式的消息
123
+ return await self.achat(prompt)
124
+ else:
125
+ # 处理其他格式,如字符串列表
126
+ converted_messages = []
127
+ for msg in prompt:
128
+ if isinstance(msg, str):
129
+ converted_messages.append({"role": "user", "content": msg})
130
+ elif isinstance(msg, dict):
131
+ converted_messages.append(msg)
132
+ else:
133
+ converted_messages.append({"role": "user", "content": str(msg)})
134
+ return await self.achat(converted_messages)
45
135
  else:
46
136
  raise ValueError("Prompt must be a string or a list of messages")
47
137
 
@@ -51,12 +141,19 @@ class OpenAILLMService(BaseLLMService):
51
141
  temperature = self.config.get("temperature", 0.7)
52
142
  max_tokens = self.config.get("max_tokens", 1024)
53
143
 
54
- response = await self.client.chat.completions.create(
55
- model=self.model_name,
56
- messages=messages,
57
- temperature=temperature,
58
- max_tokens=max_tokens
59
- )
144
+ kwargs = {
145
+ "model": self.model_name,
146
+ "messages": messages,
147
+ "temperature": temperature,
148
+ "max_tokens": max_tokens
149
+ }
150
+
151
+ # Add tools if bound
152
+ if self._has_bound_tools():
153
+ kwargs["tools"] = self._get_bound_tools()
154
+ kwargs["tool_choice"] = "auto"
155
+
156
+ response = await self.client.chat.completions.create(**kwargs)
60
157
 
61
158
  if response.usage:
62
159
  self.last_token_usage = {
@@ -64,13 +161,87 @@ class OpenAILLMService(BaseLLMService):
64
161
  "completion_tokens": response.usage.completion_tokens,
65
162
  "total_tokens": response.usage.total_tokens
66
163
  }
164
+
165
+ # Update total usage
166
+ self.total_token_usage["prompt_tokens"] += self.last_token_usage["prompt_tokens"]
167
+ self.total_token_usage["completion_tokens"] += self.last_token_usage["completion_tokens"]
168
+ self.total_token_usage["total_tokens"] += self.last_token_usage["total_tokens"]
169
+ self.total_token_usage["requests_count"] += 1
67
170
 
68
- return response.choices[0].message.content or ""
171
+ # Handle tool calls if present
172
+ message = response.choices[0].message
173
+ if message.tool_calls:
174
+ return await self._handle_tool_calls(message, messages)
175
+
176
+ return message.content or ""
69
177
 
70
178
  except Exception as e:
71
179
  logger.error(f"Error in chat completion: {e}")
72
180
  raise
73
181
 
182
+ async def _handle_tool_calls(self, assistant_message, original_messages: List[Dict[str, str]]) -> str:
183
+ """Handle tool calls from the assistant"""
184
+ # Add assistant message with tool calls to conversation
185
+ messages = original_messages + [{
186
+ "role": "assistant",
187
+ "content": assistant_message.content or "",
188
+ "tool_calls": [
189
+ {
190
+ "id": tc.id,
191
+ "type": tc.type,
192
+ "function": {
193
+ "name": tc.function.name,
194
+ "arguments": tc.function.arguments
195
+ }
196
+ } for tc in assistant_message.tool_calls
197
+ ]
198
+ }]
199
+
200
+ # Execute each tool call
201
+ for tool_call in assistant_message.tool_calls:
202
+ function_name = tool_call.function.name
203
+ arguments = json.loads(tool_call.function.arguments)
204
+
205
+ try:
206
+ # Execute the tool
207
+ if function_name in self._tool_functions:
208
+ result = self._tool_functions[function_name](**arguments)
209
+ if hasattr(result, '__await__'): # Handle async functions
210
+ result = await result
211
+ else:
212
+ result = f"Error: Function {function_name} not found"
213
+
214
+ # Add tool result to messages
215
+ messages.append({
216
+ "role": "tool",
217
+ "content": str(result),
218
+ "tool_call_id": tool_call.id
219
+ })
220
+
221
+ except Exception as e:
222
+ logger.error(f"Error executing tool {function_name}: {e}")
223
+ messages.append({
224
+ "role": "tool",
225
+ "content": f"Error executing {function_name}: {str(e)}",
226
+ "tool_call_id": tool_call.id
227
+ })
228
+
229
+ # Get final response from the model with all context
230
+ try:
231
+ kwargs = {
232
+ "model": self.model_name,
233
+ "messages": messages,
234
+ "temperature": self.config.get("temperature", 0.7),
235
+ "max_tokens": self.config.get("max_tokens", 1024)
236
+ }
237
+
238
+ response = await self.client.chat.completions.create(**kwargs)
239
+ return response.choices[0].message.content or ""
240
+
241
+ except Exception as e:
242
+ logger.error(f"Error getting final response after tool calls: {e}")
243
+ raise
244
+
74
245
  async def acompletion(self, prompt: str) -> str:
75
246
  """Text completion method (using chat API)"""
76
247
  messages = [{"role": "user", "content": prompt}]
@@ -82,13 +253,20 @@ class OpenAILLMService(BaseLLMService):
82
253
  temperature = self.config.get("temperature", 0.7)
83
254
  max_tokens = self.config.get("max_tokens", 1024)
84
255
 
85
- response = await self.client.chat.completions.create(
86
- model=self.model_name,
87
- messages=messages,
88
- temperature=temperature,
89
- max_tokens=max_tokens,
90
- n=n
91
- )
256
+ kwargs = {
257
+ "model": self.model_name,
258
+ "messages": messages,
259
+ "temperature": temperature,
260
+ "max_tokens": max_tokens,
261
+ "n": n
262
+ }
263
+
264
+ # Add tools if bound
265
+ if self._has_bound_tools():
266
+ kwargs["tools"] = self._get_bound_tools()
267
+ kwargs["tool_choice"] = "auto"
268
+
269
+ response = await self.client.chat.completions.create(**kwargs)
92
270
 
93
271
  if response.usage:
94
272
  self.last_token_usage = {
@@ -96,6 +274,12 @@ class OpenAILLMService(BaseLLMService):
96
274
  "completion_tokens": response.usage.completion_tokens,
97
275
  "total_tokens": response.usage.total_tokens
98
276
  }
277
+
278
+ # Update total usage
279
+ self.total_token_usage["prompt_tokens"] += self.last_token_usage["prompt_tokens"]
280
+ self.total_token_usage["completion_tokens"] += self.last_token_usage["completion_tokens"]
281
+ self.total_token_usage["total_tokens"] += self.last_token_usage["total_tokens"]
282
+ self.total_token_usage["requests_count"] += 1
99
283
 
100
284
  return [choice.message.content or "" for choice in response.choices]
101
285
  except Exception as e:
@@ -108,13 +292,20 @@ class OpenAILLMService(BaseLLMService):
108
292
  temperature = self.config.get("temperature", 0.7)
109
293
  max_tokens = self.config.get("max_tokens", 1024)
110
294
 
111
- stream = await self.client.chat.completions.create(
112
- model=self.model_name,
113
- messages=messages,
114
- temperature=temperature,
115
- max_tokens=max_tokens,
116
- stream=True
117
- )
295
+ kwargs = {
296
+ "model": self.model_name,
297
+ "messages": messages,
298
+ "temperature": temperature,
299
+ "max_tokens": max_tokens,
300
+ "stream": True
301
+ }
302
+
303
+ # Add tools if bound
304
+ if self._has_bound_tools():
305
+ kwargs["tools"] = self._get_bound_tools()
306
+ kwargs["tool_choice"] = "auto"
307
+
308
+ stream = await self.client.chat.completions.create(**kwargs)
118
309
 
119
310
  async for chunk in stream:
120
311
  content = chunk.choices[0].delta.content
@@ -125,14 +316,38 @@ class OpenAILLMService(BaseLLMService):
125
316
  logger.error(f"Error in stream chat: {e}")
126
317
  raise
127
318
 
128
- def get_token_usage(self) -> Dict[str, int]:
319
+ async def astream_completion(self, prompt: str) -> AsyncGenerator[str, None]:
320
+ """Stream completion responses"""
321
+ messages = [{"role": "user", "content": prompt}]
322
+ async for chunk in self.astream_chat(messages):
323
+ yield chunk
324
+
325
+ def get_token_usage(self) -> Dict[str, Any]:
129
326
  """Get total token usage statistics"""
130
- return self.last_token_usage
327
+ return self.total_token_usage
131
328
 
132
329
  def get_last_token_usage(self) -> Dict[str, int]:
133
330
  """Get token usage from last request"""
134
331
  return self.last_token_usage
332
+
333
+ def get_model_info(self) -> Dict[str, Any]:
334
+ """Get information about the current model"""
335
+ return {
336
+ "name": self.model_name,
337
+ "max_tokens": self.config.get("max_tokens", 1024),
338
+ "supports_streaming": True,
339
+ "supports_functions": True,
340
+ "provider": "openai"
341
+ }
342
+
343
+ def _has_bound_tools(self) -> bool:
344
+ """Check if this service has bound tools"""
345
+ return bool(self._bound_tools)
346
+
347
+ def _get_bound_tools(self) -> List[Dict[str, Any]]:
348
+ """Get the bound tools schema"""
349
+ return self._bound_tools
135
350
 
136
351
  async def close(self):
137
352
  """Close the backend client"""
138
- await self.client.aclose()
353
+ await self.client.close()