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.
- isa_model/__init__.py +1 -1
- isa_model/core/storage/hf_storage.py +419 -0
- isa_model/deployment/__init__.py +52 -0
- isa_model/deployment/core/__init__.py +34 -0
- isa_model/deployment/core/deployment_config.py +356 -0
- isa_model/deployment/core/deployment_manager.py +549 -0
- isa_model/deployment/core/isa_deployment_service.py +401 -0
- isa_model/eval/factory.py +381 -140
- isa_model/inference/ai_factory.py +142 -240
- isa_model/inference/providers/ml_provider.py +50 -0
- isa_model/inference/services/audio/openai_tts_service.py +104 -3
- isa_model/inference/services/embedding/base_embed_service.py +112 -0
- isa_model/inference/services/embedding/ollama_embed_service.py +28 -2
- isa_model/inference/services/llm/__init__.py +2 -0
- isa_model/inference/services/llm/base_llm_service.py +111 -1
- isa_model/inference/services/llm/ollama_llm_service.py +234 -26
- isa_model/inference/services/llm/openai_llm_service.py +243 -28
- isa_model/inference/services/llm/triton_llm_service.py +481 -0
- isa_model/inference/services/ml/base_ml_service.py +78 -0
- isa_model/inference/services/ml/sklearn_ml_service.py +140 -0
- isa_model/inference/services/vision/__init__.py +3 -3
- isa_model/inference/services/vision/base_image_gen_service.py +161 -0
- isa_model/inference/services/vision/base_vision_service.py +177 -0
- isa_model/inference/services/vision/ollama_vision_service.py +143 -17
- isa_model/inference/services/vision/replicate_image_gen_service.py +139 -7
- isa_model/training/__init__.py +62 -32
- isa_model/training/cloud/__init__.py +22 -0
- isa_model/training/cloud/job_orchestrator.py +402 -0
- isa_model/training/cloud/runpod_trainer.py +454 -0
- isa_model/training/cloud/storage_manager.py +482 -0
- isa_model/training/core/__init__.py +23 -0
- isa_model/training/core/config.py +181 -0
- isa_model/training/core/dataset.py +222 -0
- isa_model/training/core/trainer.py +720 -0
- isa_model/training/core/utils.py +213 -0
- isa_model/training/factory.py +229 -198
- isa_model-0.2.9.dist-info/METADATA +465 -0
- isa_model-0.2.9.dist-info/RECORD +86 -0
- isa_model/core/model_router.py +0 -226
- isa_model/core/model_version.py +0 -0
- isa_model/core/resource_manager.py +0 -202
- isa_model/deployment/gpu_fp16_ds8/models/deepseek_r1/1/model.py +0 -120
- isa_model/deployment/gpu_fp16_ds8/scripts/download_model.py +0 -18
- isa_model/training/engine/llama_factory/__init__.py +0 -39
- isa_model/training/engine/llama_factory/config.py +0 -115
- isa_model/training/engine/llama_factory/data_adapter.py +0 -284
- isa_model/training/engine/llama_factory/examples/__init__.py +0 -6
- isa_model/training/engine/llama_factory/examples/finetune_with_tracking.py +0 -185
- isa_model/training/engine/llama_factory/examples/rlhf_with_tracking.py +0 -163
- isa_model/training/engine/llama_factory/factory.py +0 -331
- isa_model/training/engine/llama_factory/rl.py +0 -254
- isa_model/training/engine/llama_factory/trainer.py +0 -171
- isa_model/training/image_model/configs/create_config.py +0 -37
- isa_model/training/image_model/configs/create_flux_config.py +0 -26
- isa_model/training/image_model/configs/create_lora_config.py +0 -21
- isa_model/training/image_model/prepare_massed_compute.py +0 -97
- isa_model/training/image_model/prepare_upload.py +0 -17
- isa_model/training/image_model/raw_data/create_captions.py +0 -16
- isa_model/training/image_model/raw_data/create_lora_captions.py +0 -20
- isa_model/training/image_model/raw_data/pre_processing.py +0 -200
- isa_model/training/image_model/train/train.py +0 -42
- isa_model/training/image_model/train/train_flux.py +0 -41
- isa_model/training/image_model/train/train_lora.py +0 -57
- isa_model/training/image_model/train_main.py +0 -25
- isa_model-0.2.0.dist-info/METADATA +0 -327
- isa_model-0.2.0.dist-info/RECORD +0 -92
- isa_model-0.2.0.dist-info/licenses/LICENSE +0 -21
- /isa_model/training/{llm_model/annotation → annotation}/annotation_schema.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/processors/annotation_processor.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/storage/dataset_manager.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/storage/dataset_schema.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/tests/test_annotation_flow.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/tests/test_minio copy.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/tests/test_minio_upload.py +0 -0
- /isa_model/training/{llm_model/annotation → annotation}/views/annotation_controller.py +0 -0
- {isa_model-0.2.0.dist-info → isa_model-0.2.9.dist-info}/WHEEL +0 -0
- {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
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
55
|
-
model
|
56
|
-
messages
|
57
|
-
temperature
|
58
|
-
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
|
-
|
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
|
-
|
86
|
-
model
|
87
|
-
messages
|
88
|
-
temperature
|
89
|
-
max_tokens
|
90
|
-
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
|
-
|
112
|
-
model
|
113
|
-
messages
|
114
|
-
temperature
|
115
|
-
max_tokens
|
116
|
-
stream
|
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
|
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.
|
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.
|
353
|
+
await self.client.close()
|