llumo 0.2.24__py3-none-any.whl → 0.2.26__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/client.py CHANGED
@@ -16,11 +16,11 @@ from .exceptions import LlumoAIError
16
16
  from .helpingFuntions import *
17
17
  from .sockets import LlumoSocketClient
18
18
  from .functionCalling import LlumoAgentExecutor
19
- from .chains import LlumoDataFrameResults,LlumoDictResults
19
+ from .chains import LlumoDataFrameResults, LlumoDictResults
20
20
  import threading
21
21
  from tqdm import tqdm
22
22
 
23
- pd.set_option('future.no_silent_downcasting', True)
23
+ pd.set_option("future.no_silent_downcasting", True)
24
24
 
25
25
  postUrl = (
26
26
  "https://red-skull-service-392377961931.us-central1.run.app/api/process-playground"
@@ -39,10 +39,11 @@ socketUrl = "https://red-skull-service-392377961931.us-central1.run.app/"
39
39
 
40
40
  class LlumoClient:
41
41
 
42
- def __init__(self, api_key):
42
+ def __init__(self, api_key, playground_id=None):
43
43
  self.apiKey = api_key
44
- self.evalData=[]
45
- self.evals=[]
44
+ self.playgroundID = playground_id
45
+ self.evalData = []
46
+ self.evals = []
46
47
  self.processMapping = {}
47
48
  self.definationMapping = {}
48
49
 
@@ -54,7 +55,7 @@ class LlumoClient:
54
55
  reqBody = {"analytics": [evalName]}
55
56
 
56
57
  try:
57
-
58
+
58
59
  response = requests.post(url=validateUrl, json=reqBody, headers=headers)
59
60
 
60
61
  except requests.exceptions.RequestException as e:
@@ -99,20 +100,90 @@ class LlumoClient:
99
100
  )
100
101
  self.email = data["data"]["data"].get("email", None)
101
102
 
102
- self.definationMapping[evalName] = data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "")
103
- self.categories = data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("categories", {})
104
- self.evaluationStrictness=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("evaluationStrictness", {})
105
- self.grammarCheckOutput=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("grammarCheckOutput", {})
106
- self.insightsLength=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("insightsLength", {})
107
- self.insightsLevel=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("insightsLevel", {})
108
- self.executionDependency=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("executionDependency", {})
109
- self.sampleData=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("sampleData", {})
110
- self.numJudges=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("numJudges", {})
111
- self.penaltyBonusInstructions=data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("penaltyBonusInstructions", [])
112
- self.probableEdgeCases= data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("probableEdgeCases", [])
113
- self.fieldMapping= data.get("data", {}).get("data", {}).get("analyticsMapping", {}).get(evalName, "").get("fieldMapping", [])
114
-
115
-
103
+ self.definationMapping[evalName] = (
104
+ data.get("data", {})
105
+ .get("data", {})
106
+ .get("analyticsMapping", {})
107
+ .get(evalName, "")
108
+ )
109
+ self.categories = (
110
+ data.get("data", {})
111
+ .get("data", {})
112
+ .get("analyticsMapping", {})
113
+ .get(evalName, "")
114
+ .get("categories", {})
115
+ )
116
+ self.evaluationStrictness = (
117
+ data.get("data", {})
118
+ .get("data", {})
119
+ .get("analyticsMapping", {})
120
+ .get(evalName, "")
121
+ .get("evaluationStrictness", {})
122
+ )
123
+ self.grammarCheckOutput = (
124
+ data.get("data", {})
125
+ .get("data", {})
126
+ .get("analyticsMapping", {})
127
+ .get(evalName, "")
128
+ .get("grammarCheckOutput", {})
129
+ )
130
+ self.insightsLength = (
131
+ data.get("data", {})
132
+ .get("data", {})
133
+ .get("analyticsMapping", {})
134
+ .get(evalName, "")
135
+ .get("insightsLength", {})
136
+ )
137
+ self.insightsLevel = (
138
+ data.get("data", {})
139
+ .get("data", {})
140
+ .get("analyticsMapping", {})
141
+ .get(evalName, "")
142
+ .get("insightsLevel", {})
143
+ )
144
+ self.executionDependency = (
145
+ data.get("data", {})
146
+ .get("data", {})
147
+ .get("analyticsMapping", {})
148
+ .get(evalName, "")
149
+ .get("executionDependency", {})
150
+ )
151
+ self.sampleData = (
152
+ data.get("data", {})
153
+ .get("data", {})
154
+ .get("analyticsMapping", {})
155
+ .get(evalName, "")
156
+ .get("sampleData", {})
157
+ )
158
+ self.numJudges = (
159
+ data.get("data", {})
160
+ .get("data", {})
161
+ .get("analyticsMapping", {})
162
+ .get(evalName, "")
163
+ .get("numJudges", {})
164
+ )
165
+ self.penaltyBonusInstructions = (
166
+ data.get("data", {})
167
+ .get("data", {})
168
+ .get("analyticsMapping", {})
169
+ .get(evalName, "")
170
+ .get("penaltyBonusInstructions", [])
171
+ )
172
+ self.probableEdgeCases = (
173
+ data.get("data", {})
174
+ .get("data", {})
175
+ .get("analyticsMapping", {})
176
+ .get(evalName, "")
177
+ .get("probableEdgeCases", [])
178
+ )
179
+ self.fieldMapping = (
180
+ data.get("data", {})
181
+ .get("data", {})
182
+ .get("analyticsMapping", {})
183
+ .get(evalName, "")
184
+ .get("fieldMapping", [])
185
+ )
186
+
116
187
  except Exception as e:
117
188
  # print(f"Error extracting data from response: {str(e)}")
118
189
  raise LlumoAIError.UnexpectedError(detail=evalName)
@@ -548,7 +619,7 @@ class LlumoClient:
548
619
  "playgroundID": activePlayground,
549
620
  }
550
621
 
551
- rowIdMapping[f'{rowID}-{columnID}-{columnID}'] = index
622
+ rowIdMapping[f"{rowID}-{columnID}-{columnID}"] = index
552
623
  # print("__________________________TEMPLATE__________________________________")
553
624
  # print(templateData)
554
625
 
@@ -628,11 +699,11 @@ class LlumoClient:
628
699
  def evaluateMultiple(
629
700
  self,
630
701
  data,
631
- evals: list, # list of eval metric names
702
+ evals: list,
632
703
  prompt_template="Give answer to the given query: {{query}} using the given context: {{context}}.",
633
704
  outputColName="output",
634
705
  createExperiment: bool = False,
635
- getDataFrame:bool =False,
706
+ getDataFrame: bool = False,
636
707
  _tocheck=True,
637
708
  ):
638
709
  if isinstance(data, dict):
@@ -647,10 +718,10 @@ class LlumoClient:
647
718
  try:
648
719
  socketID = self.socket.connect(timeout=250)
649
720
  except Exception as e:
650
- socketID="DummySocketID"
651
-
652
- self.evalData=[]
653
- self.evals=evals
721
+ socketID = "DummySocketID"
722
+
723
+ self.evalData = []
724
+ self.evals = evals
654
725
  self.allBatches = []
655
726
  rowIdMapping = {} # (rowID-columnID-columnID -> (index, evalName))
656
727
 
@@ -679,21 +750,18 @@ class LlumoClient:
679
750
  )
680
751
  listener_thread.start()
681
752
  self.validateApiKey(evalName=evals[0])
682
- if createExperiment:
683
- activePlayground = str(createEvalPlayground(email=self.email, workspaceID=self.workspaceID))
684
-
685
- else:
686
- activePlayground = f"{int(time.time() * 1000)}{uuid.uuid4()}".replace(
687
- "-", ""
688
- )
753
+ activePlayground = self.playgroundID
689
754
  for evalName in evals:
690
755
  # print(f"\n======= Running evaluation for: {evalName} =======")
691
756
 
692
757
  # Validate API and dependencies
693
758
  self.validateApiKey(evalName=evalName)
694
- customAnalytics=getCustomAnalytics(self.workspaceID)
759
+ customAnalytics = getCustomAnalytics(self.workspaceID)
695
760
  metricDependencies = checkDependency(
696
- evalName, list(dataframe.columns), tocheck=_tocheck,customevals=customAnalytics
761
+ evalName,
762
+ list(dataframe.columns),
763
+ tocheck=_tocheck,
764
+ customevals=customAnalytics,
697
765
  )
698
766
  if not metricDependencies["status"]:
699
767
  raise LlumoAIError.dependencyError(metricDependencies["message"])
@@ -704,15 +772,14 @@ class LlumoClient:
704
772
  evalType = "LLM"
705
773
  workspaceID = self.workspaceID
706
774
  email = self.email
707
- categories=self.categories
708
- evaluationStrictness=self.evaluationStrictness
709
- grammarCheckOutput=self.grammarCheckOutput
710
- insightLength=self.insightsLength
711
- numJudges=self.numJudges
712
- penaltyBonusInstructions=self.penaltyBonusInstructions
713
- probableEdgeCases=self.probableEdgeCases
714
- fieldMapping=self.fieldMapping
715
-
775
+ categories = self.categories
776
+ evaluationStrictness = self.evaluationStrictness
777
+ grammarCheckOutput = self.grammarCheckOutput
778
+ insightLength = self.insightsLength
779
+ numJudges = self.numJudges
780
+ penaltyBonusInstructions = self.penaltyBonusInstructions
781
+ probableEdgeCases = self.probableEdgeCases
782
+ fieldMapping = self.fieldMapping
716
783
 
717
784
  userHits = checkUserHits(
718
785
  self.workspaceID,
@@ -744,7 +811,6 @@ class LlumoClient:
744
811
  output = row.get(outputColName, "")
745
812
  intermediateSteps = row.get("intermediateSteps", "")
746
813
 
747
-
748
814
  rowID = f"{int(time.time() * 1000)}{uuid.uuid4()}".replace("-", "")
749
815
  columnID = f"{int(time.time() * 1000)}{uuid.uuid4()}".replace("-", "")
750
816
 
@@ -774,7 +840,7 @@ class LlumoClient:
774
840
  "MessageHistory": messageHistory,
775
841
  "IntermediateSteps": intermediateSteps,
776
842
  },
777
- "categories":categories,
843
+ "categories": categories,
778
844
  "evaluationStrictness": evaluationStrictness,
779
845
  "grammarCheckOutput": grammarCheckOutput,
780
846
  "insightLength": insightLength,
@@ -786,7 +852,7 @@ class LlumoClient:
786
852
  },
787
853
  "type": "EVAL",
788
854
  "kpi": evalName,
789
- "fieldMappig":fieldMapping,
855
+ "fieldMappig": fieldMapping,
790
856
  }
791
857
 
792
858
  query = ""
@@ -846,25 +912,23 @@ class LlumoClient:
846
912
  time.sleep(3)
847
913
  listener_thread.join()
848
914
 
849
-
850
915
  rawResults = self.socket.getReceivedData()
851
-
916
+
852
917
  # print("data from db #####################",dataFromDb)
853
918
  # Fix here: keep full keys, do not split keys
854
919
  receivedRowIDs = {key for item in rawResults for key in item.keys()}
855
920
  expectedRowIDs = set(rowIdMapping.keys())
856
- missingRowIDs = expectedRowIDs - receivedRowIDs
921
+ missingRowIDs = expectedRowIDs - receivedRowIDs
857
922
  # print("All expected keys:", expected_rowIDs)
858
923
  # print("All received keys:", received_rowIDs)
859
924
  # print("Missing keys:", len(missingRowIDs))
860
- missingRowIDs=list(missingRowIDs)
925
+ missingRowIDs = list(missingRowIDs)
861
926
  if len(missingRowIDs) > 0:
862
- dataFromDb=fetchData(workspaceID,activePlayground,missingRowIDs)
927
+ dataFromDb = fetchData(workspaceID, activePlayground, missingRowIDs)
863
928
  rawResults.extend(dataFromDb)
864
-
865
-
929
+
866
930
  self.evalData = rawResults
867
-
931
+
868
932
  # Initialize dataframe columns for each eval
869
933
  for eval in evals:
870
934
  dataframe[eval] = None
@@ -879,14 +943,37 @@ class LlumoClient:
879
943
  dataframe.at[index, evalName] = value.get("value")
880
944
  dataframe.at[index, f"{evalName} Reason"] = value.get("reasoning")
881
945
 
946
+ # Log the evaluation step
947
+ if hasattr(self, "logEvalStep"):
948
+ try:
949
+ start_time = time.time()
950
+ self.logEvalStep(
951
+ stepName=f"EVAL-{evalName}",
952
+ output=value.get("value"),
953
+ context=row.get("context", ""),
954
+ query=row.get("query", ""),
955
+ messageHistory=row.get("messageHistory", ""),
956
+ tools=row.get("tools", ""),
957
+ intermediateSteps=row.get("intermediateSteps", ""),
958
+ groundTruth=row.get("groundTruth", ""),
959
+ analyticsScore=value.get("analyticsScore", {}),
960
+ reasoning=value.get("reasoning", {}),
961
+ classification=value.get("classification", {}),
962
+ evalLabel=value.get("evalLabel", {}),
963
+ latencyMs=int((time.time() - start_time) * 1000),
964
+ status="SUCCESS",
965
+ message="",
966
+ )
967
+ except Exception as e:
968
+ print(f"Error logging eval step: {e}")
969
+
882
970
  self.socket.disconnect()
883
-
884
971
 
885
972
  if createExperiment:
886
973
  pd.set_option("future.no_silent_downcasting", True)
887
974
  # df = dataframe.fillna("Some error occured").astype(object)
888
975
  with warnings.catch_warnings():
889
- warnings.simplefilter(action='ignore', category=FutureWarning)
976
+ warnings.simplefilter(action="ignore", category=FutureWarning)
890
977
  df = dataframe.fillna("Some error occurred").astype(str)
891
978
 
892
979
  df = dataframe.fillna("Some error occured").infer_objects(copy=False)
@@ -897,42 +984,60 @@ class LlumoClient:
897
984
  promptText=prompt_template,
898
985
  definationMapping=self.definationMapping,
899
986
  outputColName=outputColName,
900
- activePlayground= activePlayground,
901
- customAnalytics=customAnalytics
987
+ activePlayground=activePlayground,
988
+ customAnalytics=customAnalytics,
902
989
  ):
903
990
  print(
904
991
  "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
905
992
  )
906
993
  if getDataFrame:
907
- return LlumoDataFrameResults(dataframe,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
994
+ return LlumoDataFrameResults(
995
+ dataframe,
996
+ evals=self.evals,
997
+ evalData=self.evalData,
998
+ definationMapping=self.definationMapping,
999
+ )
908
1000
  else:
909
- data=dataframe.to_dict(orient="records")
910
- return LlumoDictResults(data,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
1001
+ data = dataframe.to_dict(orient="records")
1002
+ return LlumoDictResults(
1003
+ data,
1004
+ evals=self.evals,
1005
+ evalData=self.evalData,
1006
+ definationMapping=self.definationMapping,
1007
+ )
911
1008
 
912
1009
  else:
913
1010
  if getDataFrame:
914
- return LlumoDataFrameResults(dataframe,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
1011
+ return LlumoDataFrameResults(
1012
+ dataframe,
1013
+ evals=self.evals,
1014
+ evalData=self.evalData,
1015
+ definationMapping=self.definationMapping,
1016
+ )
915
1017
  else:
916
- data=dataframe.to_dict(orient="records")
917
- return LlumoDictResults(data,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
1018
+ data = dataframe.to_dict(orient="records")
1019
+ return LlumoDictResults(
1020
+ data,
1021
+ evals=self.evals,
1022
+ evalData=self.evalData,
1023
+ definationMapping=self.definationMapping,
1024
+ )
918
1025
 
919
-
920
1026
  def promptSweep(
921
1027
  self,
922
1028
  templates: List[str],
923
1029
  data,
924
1030
  model_aliases: List[AVAILABLEMODELS],
925
- apiKey: str,
926
1031
  evals=["Response Correctness"],
927
1032
  toEvaluate: bool = False,
928
1033
  createExperiment: bool = False,
929
- getDataFrame=False
1034
+ getDataFrame=False,
930
1035
  ) -> pd.DataFrame:
931
1036
  if isinstance(data, dict):
932
- data = [data]
933
- # Check if data is now a list of dictionaries
1037
+ data = [data]
1038
+ # Check if data is now a list of dictionaries
934
1039
  if isinstance(data, list) and all(isinstance(item, dict) for item in data):
935
- working_df= pd.DataFrame(data).astype(str)
1040
+ working_df = pd.DataFrame(data).astype(str)
936
1041
  else:
937
1042
  raise ValueError("Data must be a dictionary or a list of dictionaries.")
938
1043
  modelStatus = validateModels(model_aliases=model_aliases)
@@ -942,10 +1047,10 @@ class LlumoClient:
942
1047
  self.validateApiKey()
943
1048
  workspaceID = self.workspaceID
944
1049
  email = self.email
945
- executor = ModelExecutor(apiKey)
1050
+ executor = ModelExecutor(self.apiKey)
946
1051
  prompt_template = templates[0]
947
-
948
- working_df = self._outputForStream(working_df, model_aliases, prompt_template, apiKey)
1052
+
1053
+ working_df = self._outputForStream(working_df, model_aliases, prompt_template)
949
1054
 
950
1055
  # Optional evaluation
951
1056
  outputEvalMapping = None
@@ -959,40 +1064,49 @@ class LlumoClient:
959
1064
  if not metricDependencies["status"]:
960
1065
  raise LlumoAIError.dependencyError(metricDependencies["message"])
961
1066
 
962
- working_df, outputEvalMapping = self._evaluateForStream(working_df, evals, model_aliases, prompt_template,generateOutput=True)
1067
+ working_df, outputEvalMapping = self._evaluateForStream(
1068
+ working_df, evals, model_aliases, prompt_template, generateOutput=True
1069
+ )
963
1070
  if createExperiment:
964
1071
  # df = working_df.fillna("Some error occured").astype(object)
965
1072
  with warnings.catch_warnings():
966
- warnings.simplefilter(action='ignore', category=FutureWarning)
1073
+ warnings.simplefilter(action="ignore", category=FutureWarning)
967
1074
  df = working_df.fillna("Some error occurred").astype(str)
968
1075
  if createPlayground(
969
- email, workspaceID, df,
970
- promptText=prompt_template,
971
- definationMapping=self.definationMapping,
972
- evalOutputMap=outputEvalMapping
1076
+ email,
1077
+ workspaceID,
1078
+ df,
1079
+ promptText=prompt_template,
1080
+ definationMapping=self.definationMapping,
1081
+ evalOutputMap=outputEvalMapping,
973
1082
  ):
974
1083
  print(
975
- "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results.")
976
-
1084
+ "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
1085
+ )
1086
+
977
1087
  else:
978
1088
  if getDataFrame == True and toEvaluate == True:
979
- return LlumoDataFrameResults(working_df, evals=self.evals, evalData=self.evalData,
980
- definationMapping=self.definationMapping)
1089
+ return LlumoDataFrameResults(
1090
+ working_df,
1091
+ evals=self.evals,
1092
+ evalData=self.evalData,
1093
+ definationMapping=self.definationMapping,
1094
+ )
981
1095
 
982
1096
  elif getDataFrame == False and toEvaluate == True:
983
1097
  data = working_df.to_dict(orient="records")
984
- return LlumoDictResults(data, evals=self.evals, evalData=self.evalData,
985
- definationMapping=self.definationMapping)
1098
+ return LlumoDictResults(
1099
+ data,
1100
+ evals=self.evals,
1101
+ evalData=self.evalData,
1102
+ definationMapping=self.definationMapping,
1103
+ )
986
1104
 
987
- elif getDataFrame== True and toEvaluate == False:
1105
+ elif getDataFrame == True and toEvaluate == False:
988
1106
  return working_df
989
1107
 
990
- elif getDataFrame == False and toEvaluate == False :
991
- return working_df.to_dict(orient = "records")
992
-
993
-
994
-
995
-
1108
+ elif getDataFrame == False and toEvaluate == False:
1109
+ return working_df.to_dict(orient="records")
996
1110
 
997
1111
  # this function generates an output using llm and tools and evaluate that output
998
1112
  def evaluateAgents(
@@ -1004,8 +1118,7 @@ class LlumoClient:
1004
1118
  evals=["Final Task Alignment"],
1005
1119
  prompt_template="Give answer for the given query: {{query}}",
1006
1120
  createExperiment: bool = False,
1007
- getDataFrame:bool = False
1008
-
1121
+ getDataFrame: bool = False,
1009
1122
  ):
1010
1123
  if isinstance(data, dict):
1011
1124
  data = [data]
@@ -1036,8 +1149,7 @@ class LlumoClient:
1036
1149
  evals=evals,
1037
1150
  prompt_template=prompt_template,
1038
1151
  createExperiment=createExperiment,
1039
- getDataFrame=getDataFrame
1040
-
1152
+ getDataFrame=getDataFrame,
1041
1153
  )
1042
1154
 
1043
1155
  return toolResponseDf
@@ -1057,9 +1169,8 @@ class LlumoClient:
1057
1169
  data,
1058
1170
  evals=["Final Task Alignment"],
1059
1171
  createExperiment: bool = False,
1060
- getDataFrame = False,
1061
- outputColName="output"
1062
-
1172
+ getDataFrame=False,
1173
+ outputColName="output",
1063
1174
  ):
1064
1175
  if isinstance(data, dict):
1065
1176
  data = [data]
@@ -1086,8 +1197,7 @@ class LlumoClient:
1086
1197
  prompt_template="Give answer for the given query: {{query}}",
1087
1198
  outputColName=outputColName,
1088
1199
  createExperiment=createExperiment,
1089
- getDataFrame = getDataFrame
1090
-
1200
+ getDataFrame=getDataFrame,
1091
1201
  )
1092
1202
  if createExperiment:
1093
1203
  pass
@@ -1098,18 +1208,17 @@ class LlumoClient:
1098
1208
  raise e
1099
1209
 
1100
1210
  def ragSweep(
1101
- self,
1102
- data,
1103
- streamName: str,
1104
- queryColName: str = "query",
1105
- createExperiment: bool = False,
1106
- modelAliases=[],
1107
- apiKey="",
1108
- prompt_template="Give answer to the given: {{query}} using the context:{{context}}",
1109
- evals=["Context Utilization"],
1110
- toEvaluate=False,
1111
- generateOutput=True,
1112
- getDataFrame = False
1211
+ self,
1212
+ data,
1213
+ streamName: str,
1214
+ queryColName: str = "query",
1215
+ createExperiment: bool = False,
1216
+ modelAliases=[],
1217
+ prompt_template="Give answer to the given: {{query}} using the context:{{context}}",
1218
+ evals=["Context Utilization"],
1219
+ toEvaluate=False,
1220
+ generateOutput=True,
1221
+ getDataFrame=False,
1113
1222
  ):
1114
1223
  if isinstance(data, dict):
1115
1224
  data = [data]
@@ -1119,13 +1228,21 @@ class LlumoClient:
1119
1228
  # Validate required parameters
1120
1229
  if generateOutput:
1121
1230
  if not modelAliases:
1122
- raise ValueError("Model aliases must be provided when generateOutput is True.")
1123
- if not apiKey or not isinstance(apiKey, str) or apiKey.strip() == "":
1124
- raise ValueError("Valid API key must be provided when generateOutput is True.")
1231
+ raise ValueError(
1232
+ "Model aliases must be provided when generateOutput is True."
1233
+ )
1234
+ if (
1235
+ not self.apiKey
1236
+ or not isinstance(self.apiKey, str)
1237
+ or self.apiKey.strip() == ""
1238
+ ):
1239
+ raise ValueError(
1240
+ "Valid API key must be provided when generateOutput is True."
1241
+ )
1125
1242
 
1126
1243
  modelStatus = validateModels(model_aliases=modelAliases)
1127
- if modelStatus["status"]== False:
1128
- if len(modelAliases) == 0:
1244
+ if modelStatus["status"] == False:
1245
+ if len(modelAliases) == 0:
1129
1246
  raise LlumoAIError.providerError("No model selected.")
1130
1247
  else:
1131
1248
  raise LlumoAIError.providerError(modelStatus["message"])
@@ -1139,7 +1256,7 @@ class LlumoClient:
1139
1256
  try:
1140
1257
  socketID = self.socket.connect(timeout=150)
1141
1258
  except Exception as e:
1142
- socketID="DummySocketID"
1259
+ socketID = "DummySocketID"
1143
1260
  # waited_secs = 0
1144
1261
  # while not self.socket._connection_established.is_set():
1145
1262
  # time.sleep(0.1)
@@ -1151,8 +1268,12 @@ class LlumoClient:
1151
1268
 
1152
1269
  # Check user credits
1153
1270
  userHits = checkUserHits(
1154
- self.workspaceID, self.hasSubscribed, self.trialEndDate,
1155
- self.subscriptionEndDate, self.hitsAvailable, len(working_df)
1271
+ self.workspaceID,
1272
+ self.hasSubscribed,
1273
+ self.trialEndDate,
1274
+ self.subscriptionEndDate,
1275
+ self.hitsAvailable,
1276
+ len(working_df),
1156
1277
  )
1157
1278
  if not userHits["success"]:
1158
1279
  raise LlumoAIError.InsufficientCredits(userHits["message"])
@@ -1178,7 +1299,7 @@ class LlumoClient:
1178
1299
  "inactivity_timeout": 10,
1179
1300
  "expected_results": expectedResults,
1180
1301
  },
1181
- daemon=True
1302
+ daemon=True,
1182
1303
  )
1183
1304
  listener_thread.start()
1184
1305
 
@@ -1207,7 +1328,13 @@ class LlumoClient:
1207
1328
  self.allBatches.append(currentBatch)
1208
1329
  currentBatch = []
1209
1330
 
1210
- for batch in tqdm(self.allBatches, desc="Processing Batches", unit="batch", colour="magenta", ncols=80):
1331
+ for batch in tqdm(
1332
+ self.allBatches,
1333
+ desc="Processing Batches",
1334
+ unit="batch",
1335
+ colour="magenta",
1336
+ ncols=80,
1337
+ ):
1211
1338
  try:
1212
1339
  self.postDataStream(batch=batch, workspaceID=workspaceID)
1213
1340
  time.sleep(3)
@@ -1236,7 +1363,9 @@ class LlumoClient:
1236
1363
 
1237
1364
  # Output generation
1238
1365
  if generateOutput == True:
1239
- working_df = self._outputForStream(working_df, modelAliases, prompt_template, apiKey)
1366
+ working_df = self._outputForStream(
1367
+ working_df, modelAliases, prompt_template
1368
+ )
1240
1369
 
1241
1370
  # Optional evaluation
1242
1371
  outputEvalMapping = None
@@ -1250,58 +1379,78 @@ class LlumoClient:
1250
1379
  if not metricDependencies["status"]:
1251
1380
  raise LlumoAIError.dependencyError(metricDependencies["message"])
1252
1381
 
1253
- working_df, outputEvalMapping = self._evaluateForStream(working_df, evals, modelAliases, prompt_template,generateOutput)
1382
+ working_df, outputEvalMapping = self._evaluateForStream(
1383
+ working_df, evals, modelAliases, prompt_template, generateOutput
1384
+ )
1254
1385
 
1255
-
1256
1386
  self.socket.disconnect()
1257
1387
  # Create experiment if required
1258
1388
  if createExperiment:
1259
1389
  # df = working_df.fillna("Some error occured").astype(object)
1260
1390
  with warnings.catch_warnings():
1261
- warnings.simplefilter(action='ignore', category=FutureWarning)
1391
+ warnings.simplefilter(action="ignore", category=FutureWarning)
1262
1392
  df = working_df.fillna("Some error occurred").astype(str)
1263
1393
  if createPlayground(
1264
- email, workspaceID, df,
1265
- queryColName=queryColName,
1266
- dataStreamName=streamId,
1267
- promptText=prompt_template,
1268
- definationMapping=self.definationMapping,
1269
- evalOutputMap=outputEvalMapping
1394
+ email,
1395
+ workspaceID,
1396
+ df,
1397
+ queryColName=queryColName,
1398
+ dataStreamName=streamId,
1399
+ promptText=prompt_template,
1400
+ definationMapping=self.definationMapping,
1401
+ evalOutputMap=outputEvalMapping,
1270
1402
  ):
1271
1403
  print(
1272
- "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results.")
1404
+ "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
1405
+ )
1273
1406
  if getDataFrame == True and toEvaluate == True:
1274
- return LlumoDataFrameResults(working_df, evals=self.evals, evalData=self.evalData,
1275
- definationMapping=self.definationMapping)
1407
+ return LlumoDataFrameResults(
1408
+ working_df,
1409
+ evals=self.evals,
1410
+ evalData=self.evalData,
1411
+ definationMapping=self.definationMapping,
1412
+ )
1276
1413
 
1277
1414
  elif getDataFrame == False and toEvaluate == True:
1278
1415
  data = working_df.to_dict(orient="records")
1279
- return LlumoDictResults(data, evals=self.evals, evalData=self.evalData,
1280
- definationMapping=self.definationMapping)
1416
+ return LlumoDictResults(
1417
+ data,
1418
+ evals=self.evals,
1419
+ evalData=self.evalData,
1420
+ definationMapping=self.definationMapping,
1421
+ )
1281
1422
 
1282
- elif getDataFrame== True and toEvaluate == False:
1423
+ elif getDataFrame == True and toEvaluate == False:
1283
1424
  return working_df
1284
1425
 
1285
- elif getDataFrame == False and toEvaluate == False :
1286
- return working_df.to_dict(orient = "records")
1426
+ elif getDataFrame == False and toEvaluate == False:
1427
+ return working_df.to_dict(orient="records")
1287
1428
  else:
1288
1429
  if getDataFrame == True and toEvaluate == True:
1289
- return LlumoDataFrameResults(working_df, evals=self.evals, evalData=self.evalData,
1290
- definationMapping=self.definationMapping)
1430
+ return LlumoDataFrameResults(
1431
+ working_df,
1432
+ evals=self.evals,
1433
+ evalData=self.evalData,
1434
+ definationMapping=self.definationMapping,
1435
+ )
1291
1436
 
1292
1437
  elif getDataFrame == False and toEvaluate == True:
1293
1438
  data = working_df.to_dict(orient="records")
1294
- return LlumoDictResults(data, evals=self.evals, evalData=self.evalData,
1295
- definationMapping=self.definationMapping)
1439
+ return LlumoDictResults(
1440
+ data,
1441
+ evals=self.evals,
1442
+ evalData=self.evalData,
1443
+ definationMapping=self.definationMapping,
1444
+ )
1296
1445
 
1297
- elif getDataFrame== True and toEvaluate == False:
1446
+ elif getDataFrame == True and toEvaluate == False:
1298
1447
  return working_df
1299
1448
 
1300
- elif getDataFrame == False and toEvaluate == False :
1301
- return working_df.to_dict(orient = "records")
1449
+ elif getDataFrame == False and toEvaluate == False:
1450
+ return working_df.to_dict(orient="records")
1302
1451
 
1303
- def _outputForStream(self, df, modelAliases, prompt_template, apiKey):
1304
- executor = ModelExecutor(apiKey)
1452
+ def _outputForStream(self, df, modelAliases, prompt_template):
1453
+ executor = ModelExecutor(self.apiKey)
1305
1454
 
1306
1455
  for indx, row in df.iterrows():
1307
1456
  inputVariables = re.findall(r"{{(.*?)}}", prompt_template)
@@ -1314,21 +1463,25 @@ class LlumoClient:
1314
1463
 
1315
1464
  provider = getProviderFromModel(model)
1316
1465
  if provider == Provider.OPENAI:
1317
- validateOpenaiKey(apiKey)
1466
+ validateOpenaiKey(self.apiKey)
1318
1467
  elif provider == Provider.GOOGLE:
1319
- validateGoogleKey(apiKey)
1468
+ validateGoogleKey(self.apiKey)
1320
1469
 
1321
- filled_template = getInputPopulatedPrompt(prompt_template, inputDict)
1322
- response = executor.execute(provider, model.value, filled_template, apiKey)
1470
+ filled_template = getInputPopulatedPrompt(
1471
+ prompt_template, inputDict
1472
+ )
1473
+ response = executor.execute(provider, model.value, filled_template)
1323
1474
  df.at[indx, f"output_{i}"] = response
1324
-
1475
+
1325
1476
  except Exception as e:
1326
1477
  # df.at[indx, f"output_{i}"] = str(e)
1327
1478
  raise e
1328
1479
 
1329
1480
  return df
1330
1481
 
1331
- def _evaluateForStream(self, df, evals, modelAliases, prompt_template, generateOutput):
1482
+ def _evaluateForStream(
1483
+ self, df, evals, modelAliases, prompt_template, generateOutput
1484
+ ):
1332
1485
  dfWithEvals = df.copy()
1333
1486
  outputColMapping = {}
1334
1487
 
@@ -1344,7 +1497,7 @@ class LlumoClient:
1344
1497
  outputColName=outputColName,
1345
1498
  _tocheck=False,
1346
1499
  getDataFrame=True,
1347
- createExperiment=False
1500
+ createExperiment=False,
1348
1501
  )
1349
1502
 
1350
1503
  for evalMetric in evals:
@@ -1353,11 +1506,15 @@ class LlumoClient:
1353
1506
  if scoreCol in res.columns:
1354
1507
  res = res.rename(columns={scoreCol: f"{scoreCol}_{i}"})
1355
1508
  if reasonCol in res.columns:
1356
- res = res.rename(columns={reasonCol: f"{evalMetric}_{i} Reason"})
1509
+ res = res.rename(
1510
+ columns={reasonCol: f"{evalMetric}_{i} Reason"}
1511
+ )
1357
1512
 
1358
1513
  outputColMapping[f"{scoreCol}_{i}"] = outputColName
1359
1514
 
1360
- newCols = [col for col in res.columns if col not in dfWithEvals.columns]
1515
+ newCols = [
1516
+ col for col in res.columns if col not in dfWithEvals.columns
1517
+ ]
1361
1518
  dfWithEvals = pd.concat([dfWithEvals, res[newCols]], axis=1)
1362
1519
 
1363
1520
  except Exception as e:
@@ -1374,7 +1531,7 @@ class LlumoClient:
1374
1531
  outputColName=outputColName,
1375
1532
  _tocheck=False,
1376
1533
  getDataFrame=True,
1377
- createExperiment=False
1534
+ createExperiment=False,
1378
1535
  )
1379
1536
  for evalMetric in evals:
1380
1537
  scoreCol = f"{evalMetric}"
@@ -1389,13 +1546,13 @@ class LlumoClient:
1389
1546
  return dfWithEvals, outputColMapping
1390
1547
 
1391
1548
  def runDataStream(
1392
- self,
1393
- data,
1394
- streamName: str,
1395
- queryColName: str = "query",
1396
- createExperiment: bool = False,
1397
- getDataFrame = False
1398
- ):
1549
+ self,
1550
+ data,
1551
+ streamName: str,
1552
+ queryColName: str = "query",
1553
+ createExperiment: bool = False,
1554
+ getDataFrame=False,
1555
+ ):
1399
1556
 
1400
1557
  if isinstance(data, dict):
1401
1558
  data = [data]
@@ -1411,7 +1568,7 @@ class LlumoClient:
1411
1568
  try:
1412
1569
  socketID = self.socket.connect(timeout=150)
1413
1570
  except Exception as e:
1414
- socketID="DummySocketID"
1571
+ socketID = "DummySocketID"
1415
1572
  # waited_secs = 0
1416
1573
  # while not self.socket._connection_established.is_set():
1417
1574
  # time.sleep(0.1)
@@ -1423,8 +1580,12 @@ class LlumoClient:
1423
1580
 
1424
1581
  # Check user credits
1425
1582
  userHits = checkUserHits(
1426
- self.workspaceID, self.hasSubscribed, self.trialEndDate,
1427
- self.subscriptionEndDate, self.hitsAvailable, len(working_df)
1583
+ self.workspaceID,
1584
+ self.hasSubscribed,
1585
+ self.trialEndDate,
1586
+ self.subscriptionEndDate,
1587
+ self.hitsAvailable,
1588
+ len(working_df),
1428
1589
  )
1429
1590
  if not userHits["success"]:
1430
1591
  raise LlumoAIError.InsufficientCredits(userHits["message"])
@@ -1450,7 +1611,7 @@ class LlumoClient:
1450
1611
  "inactivity_timeout": 10,
1451
1612
  "expected_results": expectedResults,
1452
1613
  },
1453
- daemon=True
1614
+ daemon=True,
1454
1615
  )
1455
1616
  listener_thread.start()
1456
1617
 
@@ -1479,7 +1640,13 @@ class LlumoClient:
1479
1640
  self.allBatches.append(currentBatch)
1480
1641
  currentBatch = []
1481
1642
 
1482
- for batch in tqdm(self.allBatches, desc="Processing Batches", unit="batch", colour="magenta", ncols=80):
1643
+ for batch in tqdm(
1644
+ self.allBatches,
1645
+ desc="Processing Batches",
1646
+ unit="batch",
1647
+ colour="magenta",
1648
+ ncols=80,
1649
+ ):
1483
1650
  try:
1484
1651
  self.postDataStream(batch=batch, workspaceID=workspaceID)
1485
1652
  time.sleep(3)
@@ -1506,21 +1673,22 @@ class LlumoClient:
1506
1673
  idx = rowIdMapping[compound_key]["index"]
1507
1674
  working_df.at[idx, "context"] = value.get("value")
1508
1675
 
1509
-
1510
-
1511
1676
  self.socket.disconnect()
1512
1677
 
1513
1678
  # Create experiment if required
1514
1679
  if createExperiment:
1515
1680
  df = working_df.fillna("Some error occured").astype(object)
1516
1681
  if createPlayground(
1517
- email, workspaceID, df,
1518
- queryColName=queryColName,
1519
- dataStreamName=streamId,
1520
- definationMapping=self.definationMapping,
1682
+ email,
1683
+ workspaceID,
1684
+ df,
1685
+ queryColName=queryColName,
1686
+ dataStreamName=streamId,
1687
+ definationMapping=self.definationMapping,
1521
1688
  ):
1522
1689
  print(
1523
- "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results.")
1690
+ "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
1691
+ )
1524
1692
  if getDataFrame:
1525
1693
  return working_df
1526
1694
 
@@ -1537,7 +1705,6 @@ class LlumoClient:
1537
1705
  # self.latestDataframe = working_df
1538
1706
  # return working_df
1539
1707
 
1540
-
1541
1708
  def createExperiment(self, dataframe):
1542
1709
  try:
1543
1710
  self.validateApiKey()
@@ -1555,7 +1722,6 @@ class LlumoClient:
1555
1722
  workspaceID = None
1556
1723
  email = None
1557
1724
 
1558
-
1559
1725
  try:
1560
1726
  self.validateApiKey()
1561
1727
  except Exception as e:
@@ -1583,17 +1749,17 @@ class LlumoClient:
1583
1749
  # If successfully loaded, call createPlayground
1584
1750
  df = df.astype(str)
1585
1751
  if createPlayground(self.email, self.workspaceID, df):
1586
-
1752
+
1587
1753
  print(
1588
1754
  "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
1589
1755
  )
1590
-
1756
+
1591
1757
  return True
1592
1758
 
1593
1759
  except Exception as e:
1594
1760
  print(f"Error: {e}")
1595
-
1596
- def upload(self,data):
1761
+
1762
+ def upload(self, data):
1597
1763
  try:
1598
1764
  if isinstance(data, dict):
1599
1765
  data = [data]
@@ -1613,7 +1779,6 @@ class LlumoClient:
1613
1779
  print(f"Error: {e}")
1614
1780
  return False
1615
1781
 
1616
-
1617
1782
  def createExperimentWithEvals(
1618
1783
  self,
1619
1784
  data,
@@ -1621,7 +1786,7 @@ class LlumoClient:
1621
1786
  prompt_template="Give answer to the given query: {{query}} using the given context: {{context}}.",
1622
1787
  outputColName="output",
1623
1788
  createExperiment: bool = False,
1624
- getDataFrame:bool =False,
1789
+ getDataFrame: bool = False,
1625
1790
  _tocheck=True,
1626
1791
  ):
1627
1792
  if isinstance(data, dict):
@@ -1631,27 +1796,31 @@ class LlumoClient:
1631
1796
  dataframe = pd.DataFrame(data).astype(str)
1632
1797
  workspaceID = None
1633
1798
  email = None
1634
- self.evalData=[]
1635
- self.evals=evals
1799
+ self.evalData = []
1800
+ self.evals = evals
1636
1801
  self.allBatches = []
1637
1802
  rowIdMapping = {} # (rowID-columnID-columnID -> (index, evalName))
1638
1803
  self.validateApiKey(evalName=evals[0])
1639
1804
  if createExperiment:
1640
- activePlayground = str(createEvalPlayground(email=self.email, workspaceID=self.workspaceID))
1641
-
1642
- else:
1805
+ if playgroundID:
1806
+ activePlayground = playgroundID
1807
+ else:
1808
+ activePlayground = str(
1809
+ createEvalPlayground(email=self.email, workspaceID=self.workspaceID)
1810
+ )
1811
+ else:
1643
1812
  activePlayground = f"{int(time.time() * 1000)}{uuid.uuid4()}".replace(
1644
- "-", ""
1645
- )
1813
+ "-", ""
1814
+ )
1646
1815
  for evalName in evals:
1647
1816
  self.validateApiKey(evalName=evalName)
1648
- self.evalData =dataframe.to_dict(orient="records")
1817
+ self.evalData = dataframe.to_dict(orient="records")
1649
1818
  if createExperiment:
1650
1819
  print("heading to upload")
1651
1820
  pd.set_option("future.no_silent_downcasting", True)
1652
1821
  # df = dataframe.fillna("Some error occured").astype(object)
1653
1822
  with warnings.catch_warnings():
1654
- warnings.simplefilter(action='ignore', category=FutureWarning)
1823
+ warnings.simplefilter(action="ignore", category=FutureWarning)
1655
1824
  df = dataframe.fillna("Some error occurred").astype(str)
1656
1825
 
1657
1826
  df = dataframe.fillna("Some error occured").infer_objects(copy=False)
@@ -1662,20 +1831,30 @@ class LlumoClient:
1662
1831
  promptText=prompt_template,
1663
1832
  definationMapping=self.definationMapping,
1664
1833
  outputColName=outputColName,
1665
- activePlayground= activePlayground
1834
+ activePlayground=activePlayground,
1666
1835
  ):
1667
1836
  print(
1668
1837
  "LLUMO’s intuitive UI is ready—start exploring and experimenting with your logs now. Visit https://app.llumo.ai/evallm to see the results."
1669
1838
  )
1670
-
1839
+
1671
1840
  else:
1672
1841
  if getDataFrame:
1673
- return LlumoDataFrameResults(dataframe,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
1842
+ return LlumoDataFrameResults(
1843
+ dataframe,
1844
+ evals=self.evals,
1845
+ evalData=self.evalData,
1846
+ definationMapping=self.definationMapping,
1847
+ )
1674
1848
  else:
1675
- data=dataframe.to_dict(orient="records")
1676
- return LlumoDictResults(data,evals=self.evals,evalData=self.evalData,definationMapping=self.definationMapping)
1849
+ data = dataframe.to_dict(orient="records")
1850
+ return LlumoDictResults(
1851
+ data,
1852
+ evals=self.evals,
1853
+ evalData=self.evalData,
1854
+ definationMapping=self.definationMapping,
1855
+ )
1856
+
1677
1857
 
1678
-
1679
1858
  class SafeDict(dict):
1680
1859
  def __missing__(self, key):
1681
1860
  return ""