llumo 0.2.13__py3-none-any.whl → 0.2.14b1__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
@@ -80,17 +80,16 @@ class LlumoClient:
80
80
  raise LlumoAIError.InvalidApiResponse()
81
81
 
82
82
  try:
83
- self.hitsAvailable = data["data"]["data"].get("remainingHits", 0)
83
+ self.hitsAvailable = data['data']["data"].get("remainingHits", 0)
84
84
  self.workspaceID = data["data"]["data"].get("workspaceID")
85
- self.evalDefinition = data["data"]["data"].get("analyticsMapping")
85
+ self.evalDefinition = data["data"]["data"]["analyticsMapping"]
86
86
  self.socketToken = data["data"]["data"].get("token")
87
87
  self.hasSubscribed = data["data"]["data"].get("hasSubscribed", False)
88
88
  self.trialEndDate = data["data"]["data"].get("trialEndDate", None)
89
89
  self.subscriptionEndDate = data["data"]["data"].get("subscriptionEndDate", None)
90
90
  self.email = data["data"]["data"].get("email", None)
91
91
 
92
- self.definationMapping[evalName] = self.evalDefinition
93
-
92
+ self.definationMapping[evalName] = data["data"]["data"]["analyticsMapping"][evalName]
94
93
  except Exception as e:
95
94
  # print(f"Error extracting data from response: {str(e)}")
96
95
  raise LlumoAIError.UnexpectedError(detail=str(e))
@@ -159,12 +158,21 @@ class LlumoClient:
159
158
  # this function allows the users to run exactl one eval at a time
160
159
  def evaluate(
161
160
  self,
162
- dataframe,
161
+ data,
163
162
  eval="Response Completeness",
164
163
  prompt_template="",
165
164
  outputColName="output",
166
165
  createExperiment: bool = False,
166
+ _tocheck = True,
167
167
  ):
168
+
169
+ # converting it into a pandas dataframe object
170
+ dataframe = pd.DataFrame(data)
171
+
172
+ # check for dependencies for the selected eval metric
173
+ metricDependencies = checkDependency(eval,columns=list(dataframe.columns),tocheck=_tocheck)
174
+ if metricDependencies["status"] == False:
175
+ raise LlumoAIError.dependencyError(metricDependencies["message"])
168
176
 
169
177
  results = {}
170
178
  try:
@@ -206,7 +214,7 @@ class LlumoClient:
206
214
  # if self.hitsAvailable == 0 or len(dataframe) > self.hitsAvailable:
207
215
  # raise LlumoAIError.InsufficientCredits()
208
216
 
209
- evalDefinition = self.evalDefinition[eval]
217
+ evalDefinition = self.evalDefinition[eval].get("definition")
210
218
  model = "GPT_4"
211
219
  provider = "OPENAI"
212
220
  evalType = "LLM"
@@ -324,7 +332,7 @@ class LlumoClient:
324
332
  except Exception as e:
325
333
  continue
326
334
 
327
- time.sleep(1)
335
+ time.sleep(3)
328
336
 
329
337
  timeout = max(50, min(600, totalItems * 10))
330
338
 
@@ -377,31 +385,71 @@ class LlumoClient:
377
385
  # this function allows the users to run multiple evals at once
378
386
  def evaluateMultiple(
379
387
  self,
380
- dataframe,
388
+ data,
381
389
  eval=["Response Completeness"],
382
- prompt_template="",
390
+ prompt_template="Give answer to the given query:{{query}} , using the given context: {{context}}",
383
391
  outputColName="output",
384
392
  createExperiment: bool = False,
393
+ _tocheck = True,
385
394
  ):
386
- resultdf = dataframe.copy()
395
+ """
396
+ Runs multiple evaluation metrics on the same input dataset.
397
+
398
+ Parameters:
399
+ data (list of dict): Input data, where each dict represents a row.
400
+ eval (list of str): List of evaluation metric names to run.
401
+ prompt_template (str): Optional prompt template used in evaluation.
402
+ outputColName (str): Column name in data that holds the model output.
403
+ createExperiment (bool): Whether to log the results to Llumo playground.
404
+
405
+ Returns:
406
+ pandas.DataFrame: Final dataframe with all evaluation results.
407
+ """
408
+
409
+ # Convert input dict list into a DataFrame
410
+ dataframe = pd.DataFrame(data)
411
+
412
+ # Copy to hold final results
413
+ resultdf = dataframe.copy()
414
+
415
+ # Run each evaluation metric one by one
387
416
  for evalName in eval:
388
- resultdf = self.evaluate(dataframe = resultdf,eval=evalName,prompt_template=prompt_template,outputColName=outputColName,createExperiment = False)
417
+ time.sleep(2) # small delay to avoid overload or rate limits
418
+
419
+ # Call evaluate (assumes evaluate takes dict, not dataframe)
420
+ resultdf = self.evaluate(
421
+ data=resultdf.to_dict(orient="records"), # convert df back to dict list
422
+ eval=evalName,
423
+ prompt_template=prompt_template,
424
+ outputColName=outputColName,
425
+ createExperiment=False,
426
+ _tocheck=_tocheck,
427
+ )
389
428
 
429
+ # Save to playground if requested
390
430
  if createExperiment:
391
431
  pd.set_option("future.no_silent_downcasting", True)
392
432
  df = resultdf.fillna("Some error occured").astype(object)
393
433
 
394
- if createPlayground(self.email, self.workspaceID, df,definationMapping=self.definationMapping,outputColName=outputColName,promptText=prompt_template):
434
+ if createPlayground(
435
+ self.email,
436
+ self.workspaceID,
437
+ df,
438
+ definationMapping=self.definationMapping,
439
+ outputColName=outputColName,
440
+ promptText=prompt_template
441
+ ):
395
442
  print(
396
- "Your data has been saved in the Llumo Experiment. Visit https://app.llumo.ai/evallm to see the results.Please rerun the experiment to see the results on playground."
443
+ "Your data has been saved in the Llumo Experiment. "
444
+ "Visit https://app.llumo.ai/evallm to see the results. "
445
+ "Please rerun the experiment to see the results on playground."
397
446
  )
398
447
  else:
399
448
  return resultdf
400
449
 
401
-
402
- def evaluateCompressor(self, dataframe, prompt_template):
450
+ def evaluateCompressor(self, data, prompt_template):
403
451
  results = []
404
-
452
+ dataframe = pd.DataFrame(data)
405
453
  try:
406
454
  socketID = self.socket.connect(timeout=150)
407
455
  max_wait_secs = 20
@@ -608,10 +656,11 @@ class LlumoClient:
608
656
  outputColName = f"output_{i}"
609
657
  try:
610
658
  res = self.evaluateMultiple(
611
- df,
659
+ df.to_dict("records"),
612
660
  eval=eval,
613
661
  prompt_template=str(templates[0]),
614
662
  outputColName=outputColName,
663
+ _tocheck=False,
615
664
  )
616
665
 
617
666
  # Rename all new columns with _i+1 (e.g., _1, _2)
@@ -633,7 +682,7 @@ class LlumoClient:
633
682
  if createExperiment:
634
683
  pd.set_option("future.no_silent_downcasting", True)
635
684
  dfWithEvals = dfWithEvals.fillna("Some error occurred")
636
- if createPlayground(email, workspaceID, dfWithEvals, promptText=templates[0]):
685
+ if createPlayground(email, workspaceID, dfWithEvals, promptText=templates[0],definationMapping=self.definationMapping):
637
686
 
638
687
  print("Your data has been saved in the Llumo Experiment. Visit https://app.llumo.ai/evallm to see the results.")
639
688
  else:
@@ -652,33 +701,37 @@ class LlumoClient:
652
701
  # this function generates an output using llm and tools and evaluate that output
653
702
  def evaluateAgents(
654
703
  self,
655
- dataframe,
704
+ data,
656
705
  model,
657
706
  agents,
658
707
  model_api_key=None,
708
+ evals=["Final Task Alignment"],
659
709
  prompt_template="Give answer for the given query: {{query}}",
660
710
  createExperiment: bool = False,
661
711
  ):
662
712
  if model.lower() not in ["openai", "google"]:
663
713
  raise ValueError("Model must be 'openai' or 'google'")
664
714
 
715
+ # converting into pandas dataframe object
716
+ dataframe = pd.DataFrame(data)
717
+
665
718
  # Run unified agent execution
666
719
  toolResponseDf = LlumoAgentExecutor.run(
667
720
  dataframe, agents, model=model, model_api_key=model_api_key
668
721
  )
669
722
 
670
723
 
671
- evals = [
672
- "Tool Reliability",
673
- "Stepwise Progression",
674
- "Tool Selection Accuracy",
675
- "Final Task Alignment",
676
- ]
724
+ # evals = [
725
+ # "Tool Reliability",
726
+ # "Stepwise Progression",
727
+ # "Tool Selection Accuracy",
728
+ # "Final Task Alignment",
729
+ # ]
677
730
 
678
731
  for eval in evals:
679
732
  # Perform evaluation
680
733
  toolResponseDf = self.evaluate(
681
- toolResponseDf,
734
+ toolResponseDf.to_dict(orient = "records"),
682
735
  eval=eval,
683
736
  prompt_template=prompt_template,
684
737
  createExperiment=False,
@@ -696,32 +749,34 @@ class LlumoClient:
696
749
  # this function evaluate that tools output given by the user
697
750
  def evaluateAgentResponses(
698
751
  self,
699
- dataframe,
752
+ data,
700
753
  evals=["Final Task Alignment"],
701
754
  outputColName="output",
702
755
  createExperiment: bool = False,
703
756
  ):
757
+ dataframe = pd.DataFrame(data)
758
+
704
759
  try:
705
760
  if "query" and "messageHistory" and "tools" not in dataframe.columns:
706
761
  raise ValueError(
707
762
  "DataFrame must contain 'query', 'messageHistory','output' ,and 'tools' columns. Make sure the columns names are same as mentioned here."
708
763
  )
709
- prompt_template="Give answer for the given query: {{query}}"
710
-
764
+
765
+
711
766
  # evals = [
712
767
  # "Tool Reliability",
713
768
  # "Stepwise Progression",
714
769
  # "Tool Selection Accuracy",
715
770
  # "Final Task Alignment",
716
771
  # ]
772
+
717
773
  toolResponseDf = dataframe.copy()
718
774
  for eval in evals:
719
775
  # Perform evaluation
720
776
  toolResponseDf = self.evaluate(
721
- toolResponseDf, eval=eval, prompt_template=prompt_template,outputColName=outputColName
777
+ toolResponseDf.to_dict(orient = "records"), eval=eval, prompt_template="Give answer for the given query: {{query}}",outputColName=outputColName
722
778
  )
723
-
724
-
779
+
725
780
  return toolResponseDf
726
781
 
727
782
  except Exception as e:
llumo/exceptions.py CHANGED
@@ -46,6 +46,10 @@ class LlumoAIError(Exception):
46
46
  def modelHitsExhausted(details = "Your credits for the selected model exhausted."):
47
47
  return LlumoAIError(details)
48
48
 
49
+ @staticmethod
50
+ def dependencyError(details):
51
+ return LlumoAIError(details)
52
+
49
53
  # @staticmethod
50
54
  # def dateNotFound():
51
55
  # return LlumoAIError("Trial end date or subscription end date not found for the given user.")
llumo/helpingFuntions.py CHANGED
@@ -303,8 +303,8 @@ def createColumn(workspaceID, dataframe, playgroundID, promptText=None,queryColN
303
303
  dependencies.append(columnIDMapping[varName])
304
304
 
305
305
  dependencies.append(columnIDMapping[outputColName]) # Add the output column ID
306
- longDef = definationMapping.get(col, {}).get(col, "")
307
- shortDef ="You have run this from SDK"
306
+ longDef = definationMapping.get(col, {}).get('definition', "")
307
+ shortDef =definationMapping.get(col, {}).get('briefDefinition', "")
308
308
  enum = col.upper().replace(" ","_")
309
309
 
310
310
  template = {
@@ -312,7 +312,7 @@ def createColumn(workspaceID, dataframe, playgroundID, promptText=None,queryColN
312
312
  col.lower().replace(" ","_")
313
313
  ],
314
314
  "evaluationMetric": "ALL",
315
- "evaluationModel": "GEMINI_PRO",
315
+ "evaluationModel": "LLUMO_EVALLM",
316
316
  "selectPrompt": columnIDMapping[outputColName],
317
317
  "scoreCondition": "GREATER_THAN",
318
318
  "scoreValue": "50",
@@ -336,7 +336,7 @@ def createColumn(workspaceID, dataframe, playgroundID, promptText=None,queryColN
336
336
  "analyticsENUM": enum,
337
337
  "prompt": shortDef,
338
338
  "analyticsName": col,
339
- "columnID": str(uuid.uuid4().hex[:8]),
339
+ "columnID": columnID,
340
340
  "label": col,
341
341
  "order": indx
342
342
  }
@@ -371,9 +371,24 @@ def createColumn(workspaceID, dataframe, playgroundID, promptText=None,queryColN
371
371
 
372
372
  # For each column, we need to map the column ID to the corresponding value in the row
373
373
  for col in dataframe.columns:
374
- columnID = columnIDMapping[col] # Get the columnID from the mapping
375
- row_dict[columnID] = row[col] # Map the columnID to the value in the row
376
-
374
+ columnID = columnIDMapping[col]
375
+
376
+ if col in allEvals:
377
+ row_dict[columnID] = {
378
+
379
+ "value": row[col],
380
+ "type": "EVAL",
381
+ "isValid": True,
382
+ "reasoning": row[col+" Reason"],
383
+ "edgeCase": "minorHallucinationDetailNotInContext",
384
+ "kpi": col
385
+
386
+ }
387
+ else:# Get the columnID from the mapping
388
+ row_dict[columnID] = {
389
+ "value": row[col],
390
+ "type":"VARIABLE"# Map the columnID to the value in the row
391
+ }
377
392
  # Add the row index (if necessary)
378
393
  row_dict["pIndex"] = indx
379
394
  rowTemplate["dataToUploadList"].append(row_dict)
@@ -430,6 +445,9 @@ def createPlayground(email, workspaceID, df, promptText=None,queryColName=None,d
430
445
  payload1, payload2 = createColumn(
431
446
  workspaceID=workspaceID, dataframe=df, playgroundID=playgroundId, promptText=promptText,queryColName=queryColName,dataStreamName=dataStreamName,definationMapping=definationMapping,outputColName=outputColName
432
447
  )
448
+
449
+
450
+
433
451
  deleteExistingRows = deleteColumnListInPlayground(
434
452
  workspaceID=workspaceID, playgroundID=playgroundId
435
453
  )
@@ -490,4 +508,58 @@ def getPlaygroundInsights(workspaceID: str, activePlayground: str):
490
508
  else:
491
509
  print(f"Error generating insight: {responseGenerate.status_code} - {responseGenerate.text}")
492
510
  return None
493
-
511
+ def checkDependency(selectedEval, columns,tocheck=True):
512
+ """
513
+ Checks if all the required input columns for the selected evaluation metric are present.
514
+
515
+ Parameters:
516
+ - selectedEval (str): The name of the selected evaluation metric.
517
+ - columns (list): List of column names present in the dataset.
518
+
519
+ Raises:
520
+ - LlumoAIError.dependencyError: If any required column is missing.
521
+ """
522
+ if tocheck:
523
+ # Define required dependencies for each evaluation metric
524
+ metricDependencies = {
525
+ 'Response Completeness': ['context', 'query', 'output'],
526
+ 'Response Bias': ['output'],
527
+ 'Response Harmfulness': ['output'],
528
+ 'Input Toxicity': ['query'],
529
+ 'Input Harmfulness': ['query'],
530
+ 'Context Utilization': ['output', 'context'],
531
+ 'Relevance Retention': ['context', 'query'],
532
+ 'Semantic Cohesion': ['context'],
533
+ 'Final Task Alignment': ['messageHistory'],
534
+ 'Tool Reliability': ['messageHistory'],
535
+ 'Response Correctness': ['output', 'query', 'context'],
536
+ 'Response Toxicity': ['output'],
537
+ 'Input Bias': ['query'],
538
+ 'Input Relevancy': ['context', 'query'],
539
+ 'Redundancy Reduction': ['context'],
540
+ 'Response Sentiment': ['output'],
541
+ 'Tool Selection Accuracy': ['tools', 'messageHistory'],
542
+ 'Stepwise Progression': ['tools', 'messageHistory'],
543
+ 'Hallucination': ['query', 'context', 'output'],
544
+ 'Groundedness': ['groundTruth', 'output'],
545
+ 'Memory Utilization': ['context', 'messageHistory'],
546
+ 'Input Relevancy (Multi-turn)': ['context', 'query']
547
+ }
548
+
549
+ # Check if the selected evaluation metric is known
550
+ if selectedEval not in metricDependencies:
551
+ return {"status": False,"message":f"Unknown evaluation metric: {selectedEval}"}
552
+
553
+ # Get the required columns for the selected evaluation
554
+ columnsRequired = metricDependencies[selectedEval]
555
+
556
+ # Check if each required column is present in the provided columns
557
+ for requirement in columnsRequired:
558
+ if requirement not in columns:
559
+ return {"status":False,
560
+ "message":f"'{selectedEval}' requires columns: {columnsRequired}. "
561
+ f"Missing: '{requirement}'. Please ensure your data includes all required columns."
562
+ }
563
+ return {"status":True,"message":"success"}
564
+ else:
565
+ return {"status":True,"message":"success"}
llumo/sockets.py CHANGED
@@ -101,8 +101,8 @@ class LlumoSocketClient:
101
101
  raise RuntimeError(f"WebSocket connection failed: {e}")
102
102
 
103
103
  def listenForResults(self, min_wait=30, max_wait=300, inactivity_timeout=50, expected_results=None):
104
- if not self._connected:
105
- raise RuntimeError("WebSocket is not connected. Call connect() first.")
104
+ # if not self._connected:
105
+ # raise RuntimeError("WebSocket is not connected. Call connect() first.")
106
106
 
107
107
  self._expected_results = expected_results # NEW
108
108
  start_time = time.time()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llumo
3
- Version: 0.2.13
3
+ Version: 0.2.14b1
4
4
  Summary: Python SDK for interacting with the Llumo ai API.
5
5
  Home-page: https://www.llumo.ai/
6
6
  Author: Llumo
@@ -0,0 +1,13 @@
1
+ llumo/__init__.py,sha256=O04b4yW1BnOvcHzxWFddAKhtdBEhBNhLdb6xgnpHH_Q,205
2
+ llumo/client.py,sha256=KbvBokbeINsEv2bJ9S3Zys6GYmpA7BIsjchmYZJx5C0,38133
3
+ llumo/exceptions.py,sha256=i3Qv4_g7XjRuho7-b7ybjw2bwSh_NhvICR6ZAgiLQX8,1944
4
+ llumo/execution.py,sha256=x88wQV8eL99wNN5YtjFaAMCIfN1PdfQVlAZQb4vzgQ0,1413
5
+ llumo/functionCalling.py,sha256=D5jYapu1rIvdIJNUYPYMTyhQ1H-6nkwoOLMi6eekfUE,7241
6
+ llumo/helpingFuntions.py,sha256=FOHDxnofS316u6fnuPDVzM-fIrTzAGkMTAjoiadlKVw,20230
7
+ llumo/models.py,sha256=YH-qAMnShmUpmKE2LQAzQdpRsaXkFSlOqMxHwU4zBUI,1560
8
+ llumo/sockets.py,sha256=0BCcdCaiXDR7LO_9NIYA6urtpgdmyWW2M1US67G9Eus,5583
9
+ llumo-0.2.14b1.dist-info/licenses/LICENSE,sha256=tF9yAcfPV9xGT3ViWmC8hPvOo8BEk4ZICbUfcEo8Dlk,182
10
+ llumo-0.2.14b1.dist-info/METADATA,sha256=TxKTceUWuxS1UkZT1vd_3yVbR98_ntHSEU1yq2HW_bg,1493
11
+ llumo-0.2.14b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ llumo-0.2.14b1.dist-info/top_level.txt,sha256=d5zUTMI99llPtLRB8rtSrqELm_bOqX-bNC5IcwlDk88,6
13
+ llumo-0.2.14b1.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- llumo/__init__.py,sha256=O04b4yW1BnOvcHzxWFddAKhtdBEhBNhLdb6xgnpHH_Q,205
2
- llumo/client.py,sha256=mVqxNyYMbHlL9lnkpw_H6_n98WYO38ZcLZNnQX1TjUE,35948
3
- llumo/exceptions.py,sha256=iCj7HhtO_ckC2EaVBdXbAudNpuMDsYmmMEV5lwynZ-E,1854
4
- llumo/execution.py,sha256=x88wQV8eL99wNN5YtjFaAMCIfN1PdfQVlAZQb4vzgQ0,1413
5
- llumo/functionCalling.py,sha256=D5jYapu1rIvdIJNUYPYMTyhQ1H-6nkwoOLMi6eekfUE,7241
6
- llumo/helpingFuntions.py,sha256=ah0FUQcRV3gfguvjQQ_aZzq59hpJttqAPJdjJVNYdFc,17110
7
- llumo/models.py,sha256=YH-qAMnShmUpmKE2LQAzQdpRsaXkFSlOqMxHwU4zBUI,1560
8
- llumo/sockets.py,sha256=i90l2rr08paa-ifKy2E5YMIS8r3yRBmu2CUOjhFKork,5579
9
- llumo-0.2.13.dist-info/licenses/LICENSE,sha256=tF9yAcfPV9xGT3ViWmC8hPvOo8BEk4ZICbUfcEo8Dlk,182
10
- llumo-0.2.13.dist-info/METADATA,sha256=W-ZVsTKhiPw6strlNQEqyufgOLfV9ZCjCpY6Dj3Qc94,1491
11
- llumo-0.2.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- llumo-0.2.13.dist-info/top_level.txt,sha256=d5zUTMI99llPtLRB8rtSrqELm_bOqX-bNC5IcwlDk88,6
13
- llumo-0.2.13.dist-info/RECORD,,