enkryptai-sdk 0.1.6__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,30 @@ 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 ModelResponse:
43
+ class ModelResponse(BaseDTO):
19
44
  message: Optional[str] = None
20
45
  data: Optional[Dict] = None
21
46
 
@@ -28,7 +53,7 @@ class ModelResponse:
28
53
 
29
54
 
30
55
  @dataclass
31
- class EndpointConfig:
56
+ class EndpointConfig(BaseDTO):
32
57
  scheme: str = "https"
33
58
  host: str = "api.openai.com"
34
59
  port: int = 443
@@ -36,16 +61,19 @@ class EndpointConfig:
36
61
 
37
62
 
38
63
  @dataclass
39
- class PathsConfig:
64
+ class PathsConfig(BaseDTO):
40
65
  completions: str = "/chat/completions"
41
66
  chat: str = "chat/completions"
67
+ vision: str = "images"
68
+ embeddings: str = "embeddings"
42
69
 
43
70
 
44
71
  @dataclass
45
- class AuthData:
72
+ class AuthData(BaseDTO):
46
73
  header_name: str = "Authorization"
47
74
  header_prefix: str = "Bearer"
48
75
  space_after_prefix: bool = True
76
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
49
77
 
50
78
  def to_dict(self):
51
79
  return asdict(self)
@@ -59,7 +87,8 @@ class AuthData:
59
87
  class ModelDetailConfig:
60
88
  model_version: Optional[str] = None
61
89
  model_source: str = ""
62
- model_provider: str = "openai"
90
+ # model_provider: str = "openai"
91
+ model_provider: ModelProviders = ModelProviders.OPENAI
63
92
  system_prompt: str = ""
64
93
 
65
94
  endpoint_url: str = "https://api.openai.com/v1/chat/completions"
@@ -77,26 +106,53 @@ class DetailModelConfig:
77
106
 
78
107
 
79
108
  @dataclass
80
- class ModelConfigDetails:
109
+ class ModelConfigDetails(BaseDTO):
110
+ model_id: str = ""
81
111
  model_version: Optional[str] = None
82
112
  model_source: str = ""
83
- 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 = ""
84
124
  system_prompt: str = ""
85
125
  conversation_template: str = ""
86
- is_compatible_with: str = "openai"
87
126
  hosting_type: str = "External"
88
127
  endpoint_url: str = "https://api.openai.com/v1/chat/completions"
128
+ paths: Optional[PathsConfig] = None
89
129
  auth_data: AuthData = field(default_factory=AuthData)
90
130
  apikey: Optional[str] = None
91
131
  default_request_options: Dict[str, Any] = field(default_factory=dict)
132
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
92
133
 
93
134
  @classmethod
94
135
  def from_dict(cls, data: dict):
95
136
  # Create a copy of the data to avoid modifying the original
96
137
  data = data.copy()
97
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
+
98
154
  # Remove known fields that we don't want in our model
99
- unwanted_fields = ["queryParams", "paths"]
155
+ unwanted_fields = ["queryParams"]
100
156
  for field in unwanted_fields:
101
157
  data.pop(field, None)
102
158
 
@@ -106,8 +162,8 @@ class ModelConfigDetails:
106
162
  if apikeys and not data.get("apikey"):
107
163
  data["apikey"] = apikeys[0]
108
164
 
109
- # Convert endpoint dict to endpoint_url if present
110
- 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"):
111
167
  endpoint = data.pop("endpoint")
112
168
  scheme = endpoint.get("scheme", "https")
113
169
  host = endpoint.get("host", "")
@@ -127,14 +183,16 @@ class ModelConfigDetails:
127
183
  auth_data = data.pop("auth_data", {})
128
184
  auth_data_obj = AuthData.from_dict(auth_data)
129
185
 
130
- # Only keep fields that are defined in the dataclass
131
- valid_fields = cls.__dataclass_fields__.keys()
132
- 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
+ )
133
191
 
134
- return cls(**filtered_data, auth_data=auth_data_obj)
192
+ return cls(**data, auth_data=auth_data_obj, paths=paths_obj)
135
193
 
136
194
  def to_dict(self):
137
- d = asdict(self)
195
+ d = super().to_dict()
138
196
  # Handle AuthData specifically
139
197
  d["auth_data"] = self.auth_data.to_dict()
140
198
  return d
@@ -148,7 +206,7 @@ class ModelConfigDetails:
148
206
 
149
207
 
150
208
  @dataclass
151
- class ModelConfig:
209
+ class ModelConfig(BaseDTO):
152
210
  created_at: str = ""
153
211
  updated_at: str = ""
154
212
  model_id: str = ""
@@ -157,36 +215,21 @@ class ModelConfig:
157
215
  model_name: str = "gpt-4o-mini"
158
216
  model_type: str = "text_2_text"
159
217
  modality: Modality = Modality.TEXT
218
+ project_name: str = ""
160
219
  certifications: List[str] = field(default_factory=list)
161
220
  model_config: ModelConfigDetails = field(default_factory=ModelConfigDetails)
162
-
163
- def to_dict(self) -> dict:
164
- """Convert the ModelConfig instance to a dictionary."""
165
- # First create a shallow copy of self as dict
166
- d = {}
167
- for field in self.__dataclass_fields__:
168
- value = getattr(self, field)
169
- if field == "modality":
170
- d[field] = value.value
171
- elif field == "model_config":
172
- if isinstance(value, ModelConfigDetails):
173
- d[field] = value.to_dict()
174
- else:
175
- d[field] = value
176
- else:
177
- d[field] = value
178
- return d
179
-
180
- def to_json(self) -> str:
181
- """Convert the ModelConfig instance to a JSON string."""
182
- return json.dumps(self.to_dict())
221
+ is_sample: bool = False
222
+ _extra_fields: Dict[str, Any] = field(default_factory=dict)
183
223
 
184
224
  @classmethod
185
225
  def from_dict(cls, data: dict):
186
226
  """Create a ModelConfig instance from a dictionary."""
187
227
  # Handle nested ModelConfigDetails
188
228
  model_config_data = data.pop("model_config", {})
189
- 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)}")
190
233
 
191
234
  # Handle Modality enum
192
235
  modality_value = data.pop("modality", "text")
@@ -195,11 +238,6 @@ class ModelConfig:
195
238
  return cls(**data, modality=modality, model_config=model_config)
196
239
 
197
240
  @classmethod
198
- def from_json(cls, json_str: str):
199
- """Create a ModelConfig instance from a JSON string."""
200
- data = json.loads(json_str)
201
- return cls.from_dict(data)
202
-
203
241
  def __str__(self):
204
242
  """String representation of the ModelConfig."""
205
243
  return f"ModelConfig(name={self.model_saved_name}, model={self.model_name})"
@@ -211,5 +249,120 @@ class ModelConfig:
211
249
  )
212
250
 
213
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
+
214
367
  # Default configuration
215
368
  DETAIL_MODEL_CONFIG = ModelConfig()