llumo 0.1.4__py3-none-any.whl → 0.1.6__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.
llumo/exceptions.py CHANGED
@@ -1,31 +1,45 @@
1
- class LlumoAPIError(Exception):
2
- """Base class for all Llumo SDK-related errors."""
3
-
4
- def __init__(self, message):
5
- self.message = message
6
- super().__init__(self.message)
7
-
8
- @staticmethod
9
- def InvalidApiKey():
10
- return LlumoAPIError("The provided API key is invalid or unauthorized")
11
-
12
- @staticmethod
13
- def InvalidApiResponse():
14
- return LlumoAPIError("Invalid or UnexpectedError response from the API")
15
-
16
- @staticmethod
17
- def RequestFailed(detail="The request to the API failed"):
18
- return LlumoAPIError(f"Request to the API failed: {detail}")
19
-
20
- @staticmethod
21
- def InvalidJsonResponse():
22
- return LlumoAPIError("The API response is not in valid JSON format")
23
-
24
- @staticmethod
25
- def UnexpectedError(detail="An UnexpectedError error occurred"):
26
- return LlumoAPIError(f"UnexpectedError error: {detail}")
27
-
28
- @staticmethod
29
- def EvalError(detail="Some error occured while processing"):
30
- return LlumoAPIError(f"error: {detail}")
31
-
1
+ class LlumoAIError(Exception):
2
+ """Base class for all Llumo SDK-related errors."""
3
+
4
+ def __init__(self, message):
5
+ self.message = message
6
+ super().__init__(self.message)
7
+
8
+ @staticmethod
9
+ def InvalidApiKey():
10
+ return LlumoAIError("The provided API key is invalid or unauthorized")
11
+
12
+ @staticmethod
13
+ def InvalidApiResponse():
14
+ return LlumoAIError("Invalid or UnexpectedError response from the API")
15
+
16
+ @staticmethod
17
+ def RequestFailed(detail="The request to the API failed"):
18
+ return LlumoAIError(f"Request to the API failed: {detail}")
19
+
20
+ @staticmethod
21
+ def InvalidJsonResponse():
22
+ return LlumoAIError("The API response is not in valid JSON format")
23
+
24
+ @staticmethod
25
+ def UnexpectedError(detail="An UnexpectedError error occurred"):
26
+ return LlumoAIError(f"UnexpectedError error: {detail}")
27
+
28
+ @staticmethod
29
+ def EvalError(detail="Some error occured while processing"):
30
+ return LlumoAIError(f"error: {detail}")
31
+
32
+ @staticmethod
33
+ def InsufficientCredits():
34
+ return LlumoAIError("LLumo hits exhausted")
35
+
36
+ @staticmethod
37
+ def InvalidPromptTemplate():
38
+ return LlumoAIError('''Make sure the prompt template fulfills the following criteria:
39
+ 1. All the variables should be inside double curly braces. Example: Give answer for the {{query}}, based on given {{context}}.
40
+ 2. The variables used in the prompt template must be present in the dataframe columns with the same name..
41
+ ''')
42
+
43
+ @staticmethod
44
+ def modelHitsExhausted(details = "Your credits for the selected model exhausted."):
45
+ return LlumoAIError(details)
llumo/execution.py CHANGED
@@ -1,39 +1,39 @@
1
- import openai
2
- import google.generativeai as genai
3
- from .models import Provider
4
-
5
- class ModelExecutor:
6
- def __init__(self, apiKey: str):
7
- self.apiKey = apiKey
8
-
9
- def execute(self, provider: Provider, modelName: str, prompt: str,api_key) -> str:
10
- if provider == Provider.OPENAI:
11
- return self._executeOpenAI(modelName, prompt,api_key)
12
- elif provider == Provider.GOOGLE:
13
- return self._executeGoogle(modelName, prompt,api_key)
14
- else:
15
- raise ValueError(f"Unsupported provider: {provider}")
16
-
17
- def _executeOpenAI(self, modelName: str, prompt: str,api_key) -> str:
18
- client = openai.OpenAI(api_key=api_key)
19
- response = client.chat.completions.create(model="gpt-4", # Replace with the desired model
20
- messages=[
21
- {"role": "system", "content": "You are a helpful assistant."},
22
- {"role": "user", "content": prompt} # User's prompt
23
- ]
24
- )
25
- return response.choices[0].message.content
26
-
27
- def _executeGoogle(self, modelName: str, prompt: str,api_key) -> str:
28
-
29
- # Configure GenAI with API Key
30
- genai.configure(api_key=api_key)
31
-
32
- # Select Generative Model
33
- model = genai.GenerativeModel("gemini-1.5-flash-latest")
34
- # Generate Response
35
- response = model.generate_content(prompt)
36
- return response.text
37
-
38
-
1
+ import openai
2
+ import google.generativeai as genai
3
+ from .models import Provider
4
+
5
+ class ModelExecutor:
6
+ def __init__(self, apiKey: str):
7
+ self.apiKey = apiKey
8
+
9
+ def execute(self, provider: Provider, modelName: str, prompt: str,api_key) -> str:
10
+ if provider == Provider.OPENAI:
11
+ return self._executeOpenAI(modelName, prompt,api_key)
12
+ elif provider == Provider.GOOGLE:
13
+ return self._executeGoogle(modelName, prompt,api_key)
14
+ else:
15
+ raise ValueError(f"Unsupported provider: {provider}")
16
+
17
+ def _executeOpenAI(self, modelName: str, prompt: str,api_key) -> str:
18
+ client = openai.OpenAI(api_key=api_key)
19
+ response = client.chat.completions.create(model="gpt-4", # Replace with the desired model
20
+ messages=[
21
+ {"role": "system", "content": "You are a helpful assistant."},
22
+ {"role": "user", "content": prompt} # User's prompt
23
+ ]
24
+ )
25
+ return response.choices[0].message.content
26
+
27
+ def _executeGoogle(self, modelName: str, prompt: str,api_key) -> str:
28
+
29
+ # Configure GenAI with API Key
30
+ genai.configure(api_key=api_key)
31
+
32
+ # Select Generative Model
33
+ model = genai.GenerativeModel("gemini-2.0-flash-lite")
34
+ # Generate Response
35
+ response = model.generate_content(prompt)
36
+ return response.text
37
+
38
+
39
39
 
@@ -0,0 +1,189 @@
1
+ import os
2
+ import json
3
+ import pandas as pd
4
+ from typing import Callable, List, Dict
5
+ from dotenv import load_dotenv
6
+ import google.generativeai as genai
7
+ from google.generativeai.types import FunctionDeclaration, Tool
8
+ from openai import OpenAI
9
+ from .exceptions import *
10
+ # Load environment variables
11
+ load_dotenv()
12
+ # openai_api = os.getenv("OPENAI_API_KEY")
13
+ # google_api_key = os.getenv("GOOGLE_API_KEY")
14
+
15
+
16
+ class LlumoAgent:
17
+ def __init__(self, name: str, description: str, parameters: Dict, function: Callable):
18
+ self.name = name
19
+ self.description = description
20
+ self.parameters = parameters
21
+ self.function = function
22
+
23
+ def run(self, **kwargs):
24
+ return self.function(**kwargs)
25
+
26
+ def createGoogleTool(self):
27
+ return FunctionDeclaration(
28
+ name=self.name,
29
+ description=self.description,
30
+ parameters={
31
+ "type": "object",
32
+ "properties": self.parameters,
33
+ "required": list(self.parameters.keys())
34
+ }
35
+ )
36
+
37
+ def createOpenaiTool(self):
38
+ return {
39
+ "type": "function",
40
+ "function": {
41
+ "name": self.name,
42
+ "description": self.description,
43
+ "parameters": {
44
+ "type": "object",
45
+ "properties": self.parameters,
46
+ "required": list(self.parameters.keys()),
47
+ }
48
+ }
49
+ }
50
+
51
+
52
+ class LlumoAgentExecutor:
53
+
54
+ @staticmethod
55
+ def run(df: pd.DataFrame, agents: List[LlumoAgent], model: str,model_api_key = None):
56
+ if model.lower() == "google":
57
+ return LlumoAgentExecutor.runWithGoogle(df, agents,model_api_key = model_api_key)
58
+ elif model.lower() == "openai":
59
+ return LlumoAgentExecutor.runWithOpenAI(df, agents,model_api_key = model_api_key)
60
+ else:
61
+ raise ValueError(f"Unsupported model: {model}. Use 'google' or 'openai'.")
62
+
63
+
64
+ @staticmethod
65
+ def runWithGoogle(df: pd.DataFrame, agents: List[LlumoAgent],model_api_key = None):
66
+ try:
67
+ genai.configure(api_key=model_api_key)
68
+ tool_defs = []
69
+ func_lookup = {}
70
+ for agent in agents:
71
+ tool_defs.append(agent.createGoogleTool())
72
+ func_lookup[agent.name] = agent
73
+
74
+ tool_wrapper = Tool(function_declarations=tool_defs)
75
+ model = genai.GenerativeModel("gemini-1.5-pro", tools=[tool_wrapper])
76
+
77
+ results = []
78
+ histories = []
79
+
80
+ for _, row in df.iterrows():
81
+ try:
82
+ query = row["query"]
83
+ chat = model.start_chat()
84
+ response = chat.send_message(query)
85
+ parts = response.candidates[0].content.parts
86
+ final_output = ""
87
+
88
+ for part in parts:
89
+ if hasattr(part, "function_call") and part.function_call:
90
+ func_call = part.function_call
91
+ agent = func_lookup.get(func_call.name)
92
+ result = agent.run(**(func_call.args or {}))
93
+
94
+ follow_up_msg = {
95
+ "function_response": {
96
+ "name": func_call.name,
97
+ "response": result
98
+ }
99
+ }
100
+
101
+ follow_up_response = chat.send_message(follow_up_msg)
102
+ final_output = follow_up_response.text
103
+ else:
104
+ final_output = part.text
105
+
106
+ results.append(final_output)
107
+ histories.append(str(chat.history))
108
+ except Exception as e:
109
+ raise LlumoAIError.modelHitsExhausted()
110
+ # results.append(f"Error during processing: {e}")
111
+ # histories.append("Error in conversation")
112
+
113
+ df["output"] = results
114
+ df["messageHistory"] = histories
115
+ df["tools"] = str({a.name: a.description for a in agents})
116
+ return df
117
+
118
+ except Exception as e:
119
+ raise RuntimeError(f"Error in runWithGoogle: {e}")
120
+
121
+ @staticmethod
122
+ def runWithOpenAI(df: pd.DataFrame, agents: List[LlumoAgent],model_api_key = None):
123
+ try:
124
+ client = OpenAI(api_key=model_api_key)
125
+ all_tools = [agent.createOpenaiTool() for agent in agents]
126
+ agent_lookup = {agent.name: agent for agent in agents}
127
+
128
+ results = []
129
+ messageHistories = []
130
+
131
+ for _, row in df.iterrows():
132
+ try:
133
+ query = row["query"]
134
+ messages = [{"role": "user", "content": query}]
135
+
136
+ initial_response = client.chat.completions.create(
137
+ model="gpt-4",
138
+ messages=messages,
139
+ tools=all_tools,
140
+ tool_choice="auto"
141
+ )
142
+
143
+ first_message = initial_response.choices[0].message
144
+ assistant_msg = {"role": "assistant"}
145
+
146
+ if first_message.content:
147
+ assistant_msg["content"] = first_message.content
148
+ if first_message.tool_calls:
149
+ assistant_msg["tool_calls"] = first_message.tool_calls
150
+
151
+ messages.append(assistant_msg)
152
+
153
+ if first_message.tool_calls:
154
+ for call in first_message.tool_calls:
155
+ tool_name = call.function.name
156
+ args = json.loads(call.function.arguments)
157
+ agent = agent_lookup[tool_name]
158
+ tool_result = agent.run(**args)
159
+
160
+ messages.append({
161
+ "role": "tool",
162
+ "tool_call_id": call.id,
163
+ "content": str(tool_result)
164
+ })
165
+
166
+ final_response = client.chat.completions.create(
167
+ model="gpt-4",
168
+ messages=messages
169
+ )
170
+ final_output = final_response.choices[0].message.content
171
+ messages.append({"role": "assistant", "content": final_output})
172
+ else:
173
+ final_output = first_message.content
174
+
175
+ results.append(final_output)
176
+ messageHistories.append(str(messages))
177
+
178
+ except Exception as e:
179
+ results.append(f"Error during processing: {e}")
180
+ messageHistories.append("Error in conversation")
181
+
182
+ df["output"] = results
183
+ df["messageHistory"] = messageHistories
184
+ df["tools"] = str({a.name: a.description for a in agents})
185
+ return df
186
+
187
+ except Exception as e:
188
+ raise RuntimeError(f"Error in runWithOpenAI: {e}")
189
+
llumo/helpingFuntions.py CHANGED
@@ -1,60 +1,50 @@
1
- import time
2
- import uuid
3
-
4
- def getProcessID():
5
- return f"{int(time.time() * 1000)}{uuid.uuid4()}"
6
-
7
-
8
- def getInputPopulatedPrompt(promptTemplate, tempObj):
9
- for key, value in tempObj.items():
10
- promptTemplate = promptTemplate.replace(f"{{{{{key}}}}}", value)
11
- return promptTemplate
12
-
13
-
14
-
15
- import time
16
- import uuid
17
-
18
- def getProcessID():
19
- return f"{int(time.time() * 1000)}{uuid.uuid4()}"
20
-
21
-
22
- def getInputPopulatedPrompt(promptTemplate, tempObj):
23
- for key, value in tempObj.items():
24
- promptTemplate = promptTemplate.replace(f"{{{{{key}}}}}", value)
25
- return promptTemplate
26
-
27
- def costColumnMapping(costResults,allProcess):
28
- # this dict will store cost column data for each row
29
- cost_cols = {}
30
- compressed_prompt = []
31
- compressed_prompt_output = []
32
- cost = []
33
- cost_saving = []
34
- print("BATCHES: ",allProcess)
35
- print("COST RESULTS :", costResults)
36
- # iterate through each batch
37
- for record in allProcess:
38
- cost_cols[record] = []
39
- # iterate through each record of cost saving results received from the api
40
- for item in costResults:
41
- # fetching all cost column data for a specific row. i.e each row will have 4 columns
42
- if list(item.keys())[0].split("-")[0] == record.split("-")[0]:
43
- cost_cols[record].append(list(item.values())[0])
44
-
45
- for ky, val in cost_cols.items():
46
- # compressed prompt column
47
- compressed_prompt.append(val[0])
48
- # compressed output
49
- compressed_prompt_output.append(val[1])
50
- # cost
51
- cost.append(val[2])
52
- # cost saved
53
- cost_saving.append(val[3])
54
-
55
- return compressed_prompt , compressed_prompt_output , cost , cost_saving
56
-
57
-
58
-
59
-
60
-
1
+ import time
2
+ import uuid
3
+ import numpy as np
4
+
5
+ def getProcessID():
6
+ return f"{int(time.time() * 1000)}{uuid.uuid4()}"
7
+
8
+
9
+ def getInputPopulatedPrompt(promptTemplate, tempObj):
10
+ for key, value in tempObj.items():
11
+ promptTemplate = promptTemplate.replace(f"{{{{{key}}}}}", value)
12
+ return promptTemplate
13
+
14
+ def costColumnMapping(costResults, allProcess):
15
+ # this dict will store cost column data for each row
16
+ cost_cols = {}
17
+
18
+ compressed_prompt = []
19
+ compressed_prompt_output = []
20
+ cost = []
21
+ cost_saving = []
22
+
23
+ for record in allProcess:
24
+ cost_cols[record] = []
25
+ for item in costResults:
26
+ if list(item.keys())[0].split("-")[0] == record.split("-")[0]:
27
+ cost_cols[record].append(list(item.values())[0])
28
+
29
+ for ky, val in cost_cols.items():
30
+ try:
31
+ compressed_prompt.append(val[0])
32
+ except IndexError:
33
+ compressed_prompt.append("error occured")
34
+
35
+ try:
36
+ compressed_prompt_output.append(val[1])
37
+ except IndexError:
38
+ compressed_prompt_output.append("error occured")
39
+
40
+ try:
41
+ cost.append(val[2])
42
+ except IndexError:
43
+ cost.append("error occured")
44
+
45
+ try:
46
+ cost_saving.append(val[3])
47
+ except IndexError:
48
+ cost_saving.append("error occured")
49
+
50
+ return compressed_prompt, compressed_prompt_output, cost, cost_saving
llumo/models.py CHANGED
@@ -1,43 +1,43 @@
1
- from enum import Enum
2
-
3
- class Provider(str, Enum):
4
- OPENAI = "OPENAI"
5
- GOOGLE = "GOOGLE"
6
-
7
- # Maps model aliases → (provider, actual model name for API)
8
- _MODEL_METADATA = {
9
- "GPT_4": (Provider.OPENAI, "gpt-4"),
10
- "GPT_4_32K": (Provider.OPENAI, "gpt-4-32k"),
11
- "GPT_35T": (Provider.OPENAI, "gpt-3.5-turbo"),
12
- "GPT_35T_INS": (Provider.OPENAI, "gpt-3.5-turbo-instruct"),
13
- "GPT_35T_16K": (Provider.OPENAI, "gpt-3.5-turbo-16k"),
14
- "GPT_35_TURBO": (Provider.OPENAI, "gpt-3.5-turbo"),
15
-
16
- "GOOGLE_15_FLASH": (Provider.GOOGLE, "gemini-1.5-flash-latest"),
17
- "GEMINI_PRO": (Provider.GOOGLE, "gemini-pro"),
18
- "TEXT_BISON": (Provider.GOOGLE, "text-bison-001"),
19
- "CHAT_BISON": (Provider.GOOGLE, "chat-bison-001"),
20
- "TEXT_BISON_32K": (Provider.GOOGLE, "text-bison-32k"),
21
- "TEXT_UNICORN": (Provider.GOOGLE, "text-unicorn-experimental"),
22
- }
23
-
24
- class AVAILABLEMODELS(str, Enum):
25
- GPT_4 = "gpt-4"
26
- GPT_4_32K = "gpt-4-32k"
27
- GPT_35T = "gpt-3.5-turbo"
28
- GPT_35T_INS = "gpt-3.5-turbo-instruct"
29
- GPT_35T_16K = "gpt-3.5-turbo-16k"
30
- GPT_35_TURBO = "gpt-3.5-turbo"
31
-
32
- GOOGLE_15_FLASH = "gemini-1.5-flash-latest"
33
- GEMINI_PRO = ""
34
- TEXT_BISON = "text-bison-001"
35
- CHAT_BISON = "chat-bison-001"
36
- TEXT_BISON_32K = "text-bison-32k"
37
- TEXT_UNICORN = "text-unicorn-experimental"
38
-
39
- def getProviderFromModel(model: AVAILABLEMODELS) -> Provider:
40
- for alias, (provider, apiName) in _MODEL_METADATA.items():
41
- if model.value == apiName:
42
- return provider
1
+ from enum import Enum
2
+
3
+ class Provider(str, Enum):
4
+ OPENAI = "OPENAI"
5
+ GOOGLE = "GOOGLE"
6
+
7
+ # Maps model aliases → (provider, actual model name for API)
8
+ _MODEL_METADATA = {
9
+ "GPT_4": (Provider.OPENAI, "gpt-4"),
10
+ "GPT_4_32K": (Provider.OPENAI, "gpt-4-32k"),
11
+ "GPT_35T": (Provider.OPENAI, "gpt-3.5-turbo"),
12
+ "GPT_35T_INS": (Provider.OPENAI, "gpt-3.5-turbo-instruct"),
13
+ "GPT_35T_16K": (Provider.OPENAI, "gpt-3.5-turbo-16k"),
14
+ "GPT_35_TURBO": (Provider.OPENAI, "gpt-3.5-turbo"),
15
+
16
+ "GOOGLE_15_FLASH": (Provider.GOOGLE, "gemini-1.5-flash-latest"),
17
+ "GEMINI_PRO": (Provider.GOOGLE, "gemini-pro"),
18
+ "TEXT_BISON": (Provider.GOOGLE, "text-bison-001"),
19
+ "CHAT_BISON": (Provider.GOOGLE, "chat-bison-001"),
20
+ "TEXT_BISON_32K": (Provider.GOOGLE, "text-bison-32k"),
21
+ "TEXT_UNICORN": (Provider.GOOGLE, "text-unicorn-experimental"),
22
+ }
23
+
24
+ class AVAILABLEMODELS(str, Enum):
25
+ GPT_4 = "gpt-4"
26
+ GPT_4_32K = "gpt-4-32k"
27
+ GPT_35T = "gpt-3.5-turbo"
28
+ GPT_35T_INS = "gpt-3.5-turbo-instruct"
29
+ GPT_35T_16K = "gpt-3.5-turbo-16k"
30
+ GPT_35_TURBO = "gpt-3.5-turbo"
31
+
32
+ GOOGLE_15_FLASH = "gemini-1.5-flash-latest"
33
+ GEMINI_PRO = ""
34
+ TEXT_BISON = "text-bison-001"
35
+ CHAT_BISON = "chat-bison-001"
36
+ TEXT_BISON_32K = "text-bison-32k"
37
+ TEXT_UNICORN = "text-unicorn-experimental"
38
+
39
+ def getProviderFromModel(model: AVAILABLEMODELS) -> Provider:
40
+ for alias, (provider, apiName) in _MODEL_METADATA.items():
41
+ if model.value == apiName:
42
+ return provider
43
43
  raise ValueError(f"Provider not found for model: {model}")