enkryptai-sdk 0.1.5__py3-none-any.whl → 0.1.7__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.
@@ -1,7 +1,10 @@
1
+ import json
2
+ import pandas as pd
3
+ from enum import Enum
4
+ from .base import BaseDTO
5
+ from tabulate import tabulate
1
6
  from dataclasses import dataclass, field, asdict
2
7
  from typing import Optional, List, Set, Dict, Any
3
- from enum import Enum
4
- import json
5
8
 
6
9
 
7
10
  class Modality(Enum):
@@ -14,8 +17,43 @@ class Modality(Enum):
14
17
  return self.value
15
18
 
16
19
 
20
+ class ModelProviders(str, Enum):
21
+ OPENAI = "openai"
22
+ AZURE_OPENAI = "azure_openai"
23
+ ANTHROPIC = "anthropic"
24
+ COHERE = "cohere"
25
+ MISTRAL = "mistral"
26
+ LLAMA = "llama"
27
+ BEDROCK = "bedrock"
28
+ GEMINI = "gemini"
29
+ HUGGINGFACE = "huggingface"
30
+ TOGETHER = "together"
31
+ GROQ = "groq"
32
+ AI21 = "ai21"
33
+ FIREWORKS = "fireworks"
34
+ ALIBABA = "alibaba"
35
+ PORTKEY = "portkey"
36
+ DEEPSEEK = "deepseek"
37
+ OPENAI_COMPATIBLE = "openai_compatible"
38
+ COHERE_COMPATIBLE = "cohere_compatible"
39
+ ANTHROPIC_COMPATIBLE = "anthropic_compatible"
40
+
41
+
17
42
  @dataclass
18
- class EndpointConfig:
43
+ class ModelResponse(BaseDTO):
44
+ message: Optional[str] = None
45
+ data: Optional[Dict] = None
46
+
47
+ def to_dict(self):
48
+ return asdict(self)
49
+
50
+ @classmethod
51
+ def from_dict(cls, data: dict):
52
+ return cls(**data)
53
+
54
+
55
+ @dataclass
56
+ class EndpointConfig(BaseDTO):
19
57
  scheme: str = "https"
20
58
  host: str = "api.openai.com"
21
59
  port: int = 443
@@ -23,16 +61,19 @@ class EndpointConfig:
23
61
 
24
62
 
25
63
  @dataclass
26
- class PathsConfig:
64
+ class PathsConfig(BaseDTO):
27
65
  completions: str = "/chat/completions"
28
66
  chat: str = "chat/completions"
67
+ vision: str = "images"
68
+ embeddings: str = "embeddings"
29
69
 
30
70
 
31
71
  @dataclass
32
- class AuthData:
72
+ class AuthData(BaseDTO):
33
73
  header_name: str = "Authorization"
34
74
  header_prefix: str = "Bearer"
35
75
  space_after_prefix: bool = True
76
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
36
77
 
37
78
  def to_dict(self):
38
79
  return asdict(self)
@@ -46,7 +87,8 @@ class AuthData:
46
87
  class ModelDetailConfig:
47
88
  model_version: Optional[str] = None
48
89
  model_source: str = ""
49
- model_provider: str = "openai"
90
+ # model_provider: str = "openai"
91
+ model_provider: ModelProviders = ModelProviders.OPENAI
50
92
  system_prompt: str = ""
51
93
 
52
94
  endpoint_url: str = "https://api.openai.com/v1/chat/completions"
@@ -64,26 +106,53 @@ class DetailModelConfig:
64
106
 
65
107
 
66
108
  @dataclass
67
- class ModelConfigDetails:
109
+ class ModelConfigDetails(BaseDTO):
110
+ model_id: str = ""
68
111
  model_version: Optional[str] = None
69
112
  model_source: str = ""
70
- model_provider: str = "openai"
113
+ model_name: str = ""
114
+ # model_provider: str = "openai"
115
+ model_provider: ModelProviders = ModelProviders.OPENAI
116
+ model_api_value: str = ""
117
+ model_bearer_token: str = ""
118
+ model_auth_type: str = ""
119
+ model_api_key: str = ""
120
+ model_endpoint_url: str = ""
121
+ rate_per_min: int = 20
122
+ testing_for: str = "LLM"
123
+ headers: str = ""
71
124
  system_prompt: str = ""
72
125
  conversation_template: str = ""
73
- is_compatible_with: str = "openai"
74
126
  hosting_type: str = "External"
75
127
  endpoint_url: str = "https://api.openai.com/v1/chat/completions"
128
+ paths: Optional[PathsConfig] = None
76
129
  auth_data: AuthData = field(default_factory=AuthData)
77
130
  apikey: Optional[str] = None
78
131
  default_request_options: Dict[str, Any] = field(default_factory=dict)
132
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
79
133
 
80
134
  @classmethod
81
135
  def from_dict(cls, data: dict):
82
136
  # Create a copy of the data to avoid modifying the original
83
137
  data = data.copy()
84
138
 
139
+ # Validate model_provider if present
140
+ if "model_provider" in data:
141
+ provider = data["model_provider"]
142
+ # If it's a string, try to convert it to enum
143
+ if isinstance(provider, str):
144
+ try:
145
+ data["model_provider"] = ModelProviders(provider)
146
+ except ValueError:
147
+ valid_providers = [p.value for p in ModelProviders]
148
+ raise ValueError(f"Invalid model_provider: '{provider}'. Must be one of: {valid_providers}")
149
+ # If it's already an enum instance, keep it as is
150
+ elif not isinstance(provider, ModelProviders):
151
+ valid_providers = [p.value for p in ModelProviders]
152
+ raise ValueError(f"Invalid model_provider type. Valid values: {valid_providers}")
153
+
85
154
  # Remove known fields that we don't want in our model
86
- unwanted_fields = ["queryParams", "paths"]
155
+ unwanted_fields = ["queryParams"]
87
156
  for field in unwanted_fields:
88
157
  data.pop(field, None)
89
158
 
@@ -93,8 +162,8 @@ class ModelConfigDetails:
93
162
  if apikeys and not data.get("apikey"):
94
163
  data["apikey"] = apikeys[0]
95
164
 
96
- # Convert endpoint dict to endpoint_url if present
97
- if "endpoint" in data:
165
+ # Convert endpoint dict to endpoint_url if present and endpoint_url is not already set
166
+ if "endpoint" in data and not data.get("endpoint_url"):
98
167
  endpoint = data.pop("endpoint")
99
168
  scheme = endpoint.get("scheme", "https")
100
169
  host = endpoint.get("host", "")
@@ -114,14 +183,16 @@ class ModelConfigDetails:
114
183
  auth_data = data.pop("auth_data", {})
115
184
  auth_data_obj = AuthData.from_dict(auth_data)
116
185
 
117
- # Only keep fields that are defined in the dataclass
118
- valid_fields = cls.__dataclass_fields__.keys()
119
- filtered_data = {k: v for k, v in data.items() if k in valid_fields}
186
+ # Handle nested PathsConfig only if present in data
187
+ paths_data = data.pop("paths", None)
188
+ paths_obj = (
189
+ PathsConfig.from_dict(paths_data) if paths_data is not None else None
190
+ )
120
191
 
121
- return cls(**filtered_data, auth_data=auth_data_obj)
192
+ return cls(**data, auth_data=auth_data_obj, paths=paths_obj)
122
193
 
123
194
  def to_dict(self):
124
- d = asdict(self)
195
+ d = super().to_dict()
125
196
  # Handle AuthData specifically
126
197
  d["auth_data"] = self.auth_data.to_dict()
127
198
  return d
@@ -135,7 +206,7 @@ class ModelConfigDetails:
135
206
 
136
207
 
137
208
  @dataclass
138
- class ModelConfig:
209
+ class ModelConfig(BaseDTO):
139
210
  created_at: str = ""
140
211
  updated_at: str = ""
141
212
  model_id: str = ""
@@ -144,36 +215,21 @@ class ModelConfig:
144
215
  model_name: str = "gpt-4o-mini"
145
216
  model_type: str = "text_2_text"
146
217
  modality: Modality = Modality.TEXT
218
+ project_name: str = ""
147
219
  certifications: List[str] = field(default_factory=list)
148
220
  model_config: ModelConfigDetails = field(default_factory=ModelConfigDetails)
149
-
150
- def to_dict(self) -> dict:
151
- """Convert the ModelConfig instance to a dictionary."""
152
- # First create a shallow copy of self as dict
153
- d = {}
154
- for field in self.__dataclass_fields__:
155
- value = getattr(self, field)
156
- if field == "modality":
157
- d[field] = value.value
158
- elif field == "model_config":
159
- if isinstance(value, ModelConfigDetails):
160
- d[field] = value.to_dict()
161
- else:
162
- d[field] = value
163
- else:
164
- d[field] = value
165
- return d
166
-
167
- def to_json(self) -> str:
168
- """Convert the ModelConfig instance to a JSON string."""
169
- return json.dumps(self.to_dict())
221
+ is_sample: bool = False
222
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
170
223
 
171
224
  @classmethod
172
225
  def from_dict(cls, data: dict):
173
226
  """Create a ModelConfig instance from a dictionary."""
174
227
  # Handle nested ModelConfigDetails
175
228
  model_config_data = data.pop("model_config", {})
176
- model_config = ModelConfigDetails.from_dict(model_config_data)
229
+ try:
230
+ model_config = ModelConfigDetails.from_dict(model_config_data)
231
+ except ValueError as e:
232
+ raise ValueError(f"Error in model_config: {str(e)}")
177
233
 
178
234
  # Handle Modality enum
179
235
  modality_value = data.pop("modality", "text")
@@ -182,11 +238,6 @@ class ModelConfig:
182
238
  return cls(**data, modality=modality, model_config=model_config)
183
239
 
184
240
  @classmethod
185
- def from_json(cls, json_str: str):
186
- """Create a ModelConfig instance from a JSON string."""
187
- data = json.loads(json_str)
188
- return cls.from_dict(data)
189
-
190
241
  def __str__(self):
191
242
  """String representation of the ModelConfig."""
192
243
  return f"ModelConfig(name={self.model_saved_name}, model={self.model_name})"
@@ -198,5 +249,120 @@ class ModelConfig:
198
249
  )
199
250
 
200
251
 
252
+ @dataclass
253
+ class ModelCollection(BaseDTO):
254
+ models: List[ModelConfig] = field(default_factory=list)
255
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
256
+
257
+ @classmethod
258
+ def from_dict(cls, data: dict):
259
+ """Create a ModelCollection instance from a dictionary."""
260
+ models_data = data.get("models", [])
261
+ models = [ModelConfig.from_dict(model_data) for model_data in models_data]
262
+ return cls(models=models)
263
+
264
+ def to_dict(self) -> dict:
265
+ return {"models": [model.to_dict() for model in self.models]}
266
+
267
+ def to_json(self) -> str:
268
+ """Convert the ModelCollection instance to a JSON string."""
269
+ return json.dumps(self.to_dict())
270
+
271
+ def to_dataframe(self) -> pd.DataFrame:
272
+ """
273
+ Convert the model collection to a pandas DataFrame.
274
+
275
+ Returns:
276
+ pd.DataFrame: DataFrame containing model data
277
+ """
278
+ data = [model.get_all_fields() for model in self.models]
279
+ return pd.DataFrame(data)
280
+
281
+ def display_table(self, style: str = "default") -> str:
282
+ """
283
+ Create a formatted table representation using pandas.
284
+
285
+ Args:
286
+ style (str): Style of the output. Options:
287
+ - 'default': Standard pandas HTML table
288
+ - 'styled': Styled HTML table with custom formatting
289
+ - 'markdown': Markdown formatted table
290
+
291
+ Returns:
292
+ str: Formatted table string
293
+ """
294
+ if not self.models:
295
+ return "No models available"
296
+
297
+ try:
298
+ df = self.to_dataframe()
299
+
300
+ if style == "styled":
301
+ styled_df = df.style.set_properties(
302
+ **{
303
+ "text-align": "left",
304
+ "padding": "8px",
305
+ "border": "1px solid #ddd",
306
+ }
307
+ )
308
+ styled_df = styled_df.set_table_styles(
309
+ [
310
+ {
311
+ "selector": "thead th",
312
+ "props": [
313
+ ("background-color", "#f4f4f4"),
314
+ ("color", "black"),
315
+ ("font-weight", "bold"),
316
+ ("padding", "10px"),
317
+ ("border", "1px solid #ddd"),
318
+ ],
319
+ },
320
+ {
321
+ "selector": "tbody tr:nth-child(even)",
322
+ "props": [("background-color", "#f8f8f8")],
323
+ },
324
+ ]
325
+ )
326
+ return styled_df.hide(axis="index").to_html()
327
+
328
+ elif style == "markdown":
329
+ return df.to_markdown(index=False)
330
+
331
+ else: # default
332
+ return df.to_html(index=False, classes="model-table")
333
+
334
+ except Exception as e:
335
+ return f"Error creating table: {str(e)}"
336
+
337
+
338
+ @dataclass
339
+ class Task(BaseDTO):
340
+ """Represents an individual task in a task list."""
341
+
342
+ task_id: str
343
+ status: str
344
+ model_name: str
345
+ test_name: Optional[str] = None
346
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
347
+
348
+
349
+ @dataclass
350
+ class TaskList(BaseDTO):
351
+ """Represents a list of tasks."""
352
+
353
+ tasks: List[Task] = field(default_factory=list)
354
+
355
+ @classmethod
356
+ def from_dict(cls, data: Dict[str, Any]):
357
+ """Create a TaskList instance from a dictionary."""
358
+ tasks_data = data.get("tasks", [])
359
+ tasks = [Task.from_dict(task_data) for task_data in tasks_data]
360
+ return cls(tasks=tasks)
361
+
362
+ def to_dict(self) -> Dict[str, Any]:
363
+ """Convert the TaskList instance to a dictionary."""
364
+ return {"tasks": [task.to_dict() for task in self.tasks]}
365
+
366
+
201
367
  # Default configuration
202
368
  DETAIL_MODEL_CONFIG = ModelConfig()