From 6c3ab16e96ff875e33153952a74a8d4c5c67a2d3 Mon Sep 17 00:00:00 2001 From: MohammedMaaz Date: Thu, 11 Jan 2024 21:16:02 +0500 Subject: [PATCH 1/8] GET /evaluations/evaluation_ids route added --- .../routers/evaluation_router.py | 45 +++++++++++++++++++ .../services/evaluation_service.py | 17 +++++++ 2 files changed, 62 insertions(+) diff --git a/agenta-backend/agenta_backend/routers/evaluation_router.py b/agenta-backend/agenta_backend/routers/evaluation_router.py index 3cc5a572fc..23bef1693b 100644 --- a/agenta-backend/agenta_backend/routers/evaluation_router.py +++ b/agenta-backend/agenta_backend/routers/evaluation_router.py @@ -279,3 +279,48 @@ async def fetch_evaluation_scenarios( ) return eval_scenarios + + +# Write a GET endpoint that takes in a query param type = "variant" or "testset" or "evaluator config" +# and a query param id = "variant_id" or "testset_id" or "evaluator_config_id" and returns the evaluation ids +@router.get( + "/evaluation_ids/", + response_model=any, +) +async def fetch_evaluation_ids( + app_id: str, + resourceType: str, + resourceId: str, + request: Request, +): + print("resourceType: ", resourceType) + print("resourceId: ", resourceId) + """Fetches evaluation ids for a given type and id. + + Arguments: + resourceType (str): The type of the object for which to fetch evaluations. + resourceId (str): The ID of the object for which to fetch evaluations. + + Raises: + HTTPException: If the evaluation is not found or access is denied. + + Returns: + List[str]: A list of evaluation ids. + """ + # user_org_data: dict = await get_user_and_org_id(request.state.user_id) + # access_app = await check_access_to_app( + # user_org_data=user_org_data, + # app_id=app_id, + # ) + # if not access_app: + # raise HTTPException( + # status_code=403, + # detail=f"You do not have access to this app: {str(app_id)}", + # ) + + evaluations = await evaluation_service.fetch_evaluations(resourceType, resourceId) + print("evaluations: ", evaluations) + evaluation_ids = list(map(lambda x: x.id, evaluations)) + print("evaluation_ids: ", evaluation_ids) + + return evaluation_ids diff --git a/agenta-backend/agenta_backend/services/evaluation_service.py b/agenta-backend/agenta_backend/services/evaluation_service.py index 3182b8d393..9a25db7f53 100644 --- a/agenta-backend/agenta_backend/services/evaluation_service.py +++ b/agenta-backend/agenta_backend/services/evaluation_service.py @@ -34,6 +34,7 @@ ) from beanie import PydanticObjectId as ObjectId +from beanie.operators import Eq logger = logging.getLogger(__name__) @@ -798,3 +799,19 @@ def remove_duplicates(csvdata): unique_entries.append(entry) return unique_entries + + +def fetch_evaluations(resourceType: str, resourceId: str): + if resourceType == "variant": + return EvaluationDB.find(EvaluationDB.variant == ObjectId(resourceId)).to_list() + elif resourceType == "testset": + return EvaluationDB.find(EvaluationDB.testset == ObjectId(resourceId)).to_list() + elif resourceType == "evaluator_config": + return EvaluationDB.find( + Eq(EvaluationDB.evaluators_configs, ObjectId(resourceId)) + ).to_list() + else: + raise HTTPException( + status_code=400, + detail=f"resourceType {resourceType} is not supported", + ) From 7b9dccd74ddc010a5d7562b03a1774c98ec1f25d Mon Sep 17 00:00:00 2001 From: MohammedMaaz Date: Fri, 12 Jan 2024 12:22:52 +0500 Subject: [PATCH 2/8] check for data inconsistencies before deletion --- .../agenta_backend/models/converters.py | 17 +++- .../routers/evaluation_router.py | 87 +++++++++---------- .../services/evaluation_service.py | 22 +++-- .../src/components/Playground/Playground.tsx | 12 +++ .../evaluations/evaluators/EvaluatorCard.tsx | 20 +++-- agenta-web/src/lib/helpers/evaluate.ts | 30 +++++++ .../pages/apps/[app_id]/testsets/index.tsx | 8 ++ agenta-web/src/services/evaluations/index.ts | 18 ++++ 8 files changed, 150 insertions(+), 64 deletions(-) diff --git a/agenta-backend/agenta_backend/models/converters.py b/agenta-backend/agenta_backend/models/converters.py index f74acebe8e..6dcb130a7b 100644 --- a/agenta-backend/agenta_backend/models/converters.py +++ b/agenta-backend/agenta_backend/models/converters.py @@ -52,6 +52,7 @@ ) import logging +from beanie import Link logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -85,8 +86,12 @@ async def evaluation_db_to_pydantic( status=evaluation_db.status, variant_ids=[str(evaluation_db.variant)], variant_names=[variant_name], - testset_id=str(evaluation_db.testset.id), - testset_name=evaluation_db.testset.name, + testset_id="" + if type(evaluation_db.testset) is Link + else str(evaluation_db.testset.id), + testset_name="" + if type(evaluation_db.testset) is Link + else str(evaluation_db.testset.name), aggregated_results=await aggregated_result_to_pydantic( evaluation_db.aggregated_results ), @@ -113,8 +118,12 @@ async def human_evaluation_db_to_pydantic( evaluation_type=evaluation_db.evaluation_type, variant_ids=[str(variant) for variant in evaluation_db.variants], variant_names=variant_names, - testset_id=str(evaluation_db.testset.id), - testset_name=evaluation_db.testset.name, + testset_id="" + if type(evaluation_db.testset) is Link + else str(evaluation_db.testset.id), + testset_name="" + if type(evaluation_db.testset) is Link + else str(evaluation_db.testset.name), created_at=evaluation_db.created_at, updated_at=evaluation_db.updated_at, ) diff --git a/agenta-backend/agenta_backend/routers/evaluation_router.py b/agenta-backend/agenta_backend/routers/evaluation_router.py index 23bef1693b..4e5a147679 100644 --- a/agenta-backend/agenta_backend/routers/evaluation_router.py +++ b/agenta-backend/agenta_backend/routers/evaluation_router.py @@ -4,7 +4,7 @@ from fastapi.responses import JSONResponse from fastapi.encoders import jsonable_encoder -from fastapi import HTTPException, Request, status, Response +from fastapi import HTTPException, Request, status, Response, Query from agenta_backend.utils.common import APIRouter from agenta_backend.models.api.evaluation_model import ( @@ -36,6 +36,46 @@ router = APIRouter() +@router.get( + "/by_resource/", + response_model=Any, +) +async def fetch_evaluation_ids( + app_id: str, + resource_type: str, + request: Request, + resource_ids: List[str] = Query(None), +): + """Fetches evaluation ids for a given resource type and id. + + Arguments: + app_id (str): The ID of the app for which to fetch evaluations. + resource_type (str): The type of resource for which to fetch evaluations. + resource_ids List[str]: The IDs of resource for which to fetch evaluations. + + Raises: + HTTPException: If the resource_type is invalid or access is denied. + + Returns: + List[str]: A list of evaluation ids. + """ + user_org_data: dict = await get_user_and_org_id(request.state.user_id) + access_app = await check_access_to_app( + user_org_data=user_org_data, + app_id=app_id, + ) + if not access_app: + raise HTTPException( + status_code=403, + detail=f"You do not have access to this app: {str(app_id)}", + ) + + evaluations = await evaluation_service.fetch_evaluations_by_resource( + resource_type, resource_ids + ) + return list(map(lambda x: x.id, evaluations)) + + @router.post("/", response_model=List[Evaluation], operation_id="create_evaluation") async def create_evaluation( payload: NewEvaluation, @@ -279,48 +319,3 @@ async def fetch_evaluation_scenarios( ) return eval_scenarios - - -# Write a GET endpoint that takes in a query param type = "variant" or "testset" or "evaluator config" -# and a query param id = "variant_id" or "testset_id" or "evaluator_config_id" and returns the evaluation ids -@router.get( - "/evaluation_ids/", - response_model=any, -) -async def fetch_evaluation_ids( - app_id: str, - resourceType: str, - resourceId: str, - request: Request, -): - print("resourceType: ", resourceType) - print("resourceId: ", resourceId) - """Fetches evaluation ids for a given type and id. - - Arguments: - resourceType (str): The type of the object for which to fetch evaluations. - resourceId (str): The ID of the object for which to fetch evaluations. - - Raises: - HTTPException: If the evaluation is not found or access is denied. - - Returns: - List[str]: A list of evaluation ids. - """ - # user_org_data: dict = await get_user_and_org_id(request.state.user_id) - # access_app = await check_access_to_app( - # user_org_data=user_org_data, - # app_id=app_id, - # ) - # if not access_app: - # raise HTTPException( - # status_code=403, - # detail=f"You do not have access to this app: {str(app_id)}", - # ) - - evaluations = await evaluation_service.fetch_evaluations(resourceType, resourceId) - print("evaluations: ", evaluations) - evaluation_ids = list(map(lambda x: x.id, evaluations)) - print("evaluation_ids: ", evaluation_ids) - - return evaluation_ids diff --git a/agenta-backend/agenta_backend/services/evaluation_service.py b/agenta-backend/agenta_backend/services/evaluation_service.py index 9a25db7f53..07aaa797dd 100644 --- a/agenta-backend/agenta_backend/services/evaluation_service.py +++ b/agenta-backend/agenta_backend/services/evaluation_service.py @@ -34,7 +34,7 @@ ) from beanie import PydanticObjectId as ObjectId -from beanie.operators import Eq +from beanie.operators import In logger = logging.getLogger(__name__) @@ -801,17 +801,21 @@ def remove_duplicates(csvdata): return unique_entries -def fetch_evaluations(resourceType: str, resourceId: str): - if resourceType == "variant": - return EvaluationDB.find(EvaluationDB.variant == ObjectId(resourceId)).to_list() - elif resourceType == "testset": - return EvaluationDB.find(EvaluationDB.testset == ObjectId(resourceId)).to_list() - elif resourceType == "evaluator_config": +def fetch_evaluations_by_resource(resource_type: str, resource_ids: List[str]): + ids = list(map(lambda x: ObjectId(x), resource_ids)) + if resource_type == "variant": + return EvaluationDB.find(In(EvaluationDB.variant, ids)).to_list() + elif resource_type == "testset": + return EvaluationDB.find(In(EvaluationDB.testset.id, ids)).to_list() + elif resource_type == "evaluator_config": return EvaluationDB.find( - Eq(EvaluationDB.evaluators_configs, ObjectId(resourceId)) + In( + EvaluationDB.evaluators_configs, + ids, + ) ).to_list() else: raise HTTPException( status_code=400, - detail=f"resourceType {resourceType} is not supported", + detail=f"resource_type {resource_type} is not supported", ) diff --git a/agenta-web/src/components/Playground/Playground.tsx b/agenta-web/src/components/Playground/Playground.tsx index 4a8bcc3bc2..a629895d43 100644 --- a/agenta-web/src/components/Playground/Playground.tsx +++ b/agenta-web/src/components/Playground/Playground.tsx @@ -15,6 +15,7 @@ import {arrayMove, SortableContext, horizontalListSortingStrategy} from "@dnd-ki import DraggableTabNode from "../DraggableTabNode/DraggableTabNode" import {useLocalStorage} from "usehooks-ts" import TestContextProvider from "./TestContextProvider" +import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" const Playground: React.FC = () => { const router = useRouter() @@ -198,6 +199,17 @@ const Playground: React.FC = () => { }, onOk: async () => { try { + const variantId = + variants.find((item) => item.variantId === tabID.current)?.variantId || + variants.find((item) => item.variantName === activeKey)?.variantId + if ( + variantId && + !(await checkIfResourceValidForDeletion({ + resourceType: "variant", + resourceIds: [variantId], + })) + ) + return if (deleteAction) await deleteAction() removeTab() messageApi.open({ diff --git a/agenta-web/src/components/pages/evaluations/evaluators/EvaluatorCard.tsx b/agenta-web/src/components/pages/evaluations/evaluators/EvaluatorCard.tsx index d3aba48c20..b68b3b5d1a 100644 --- a/agenta-web/src/components/pages/evaluations/evaluators/EvaluatorCard.tsx +++ b/agenta-web/src/components/pages/evaluations/evaluators/EvaluatorCard.tsx @@ -9,6 +9,7 @@ import AlertPopup from "@/components/AlertPopup/AlertPopup" import {deleteEvaluatorConfig} from "@/services/evaluations" import {useAtom} from "jotai" import {evaluatorsAtom} from "@/lib/atoms/evaluation" +import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" const useStyles = createUseStyles((theme: JSSTheme) => ({ card: { @@ -57,14 +58,23 @@ const EvaluatorCard: React.FC = ({evaluatorConfig, onEdit, onSuccessDelet const [evaluators] = useAtom(evaluatorsAtom) const evaluator = evaluators.find((item) => item.key === evaluatorConfig.evaluator_key)! - const onDelete = () => { + const onDelete = async () => { AlertPopup({ title: "Delete evaluator", message: "Are you sure you want to delete this evaluator?", - onOk: () => - deleteEvaluatorConfig(evaluatorConfig.id) - .then(onSuccessDelete) - .catch(console.error), + onOk: async () => { + if ( + !(await checkIfResourceValidForDeletion({ + resourceType: "evaluator_config", + resourceIds: [evaluatorConfig.id], + })) + ) + return + try { + await deleteEvaluatorConfig(evaluatorConfig.id) + onSuccessDelete?.() + } catch (error) {} + }, }) } diff --git a/agenta-web/src/lib/helpers/evaluate.ts b/agenta-web/src/lib/helpers/evaluate.ts index fb1b932da6..162ad14576 100644 --- a/agenta-web/src/lib/helpers/evaluate.ts +++ b/agenta-web/src/lib/helpers/evaluate.ts @@ -1,6 +1,9 @@ import {HumanEvaluationListTableDataType} from "@/components/Evaluations/HumanEvaluationResult" import {Evaluation, GenericObject, Variant} from "../Types" import {convertToCsv, downloadCsv} from "./fileManipulations" +import {fetchEvaluatonIdsByResource} from "@/services/evaluations" +import {getAppValues} from "@/contexts/app.context" +import AlertPopup from "@/components/AlertPopup/AlertPopup" export const exportABTestingEvaluationData = (evaluation: Evaluation, rows: GenericObject[]) => { const exportRow = rows.map((data, ix) => { @@ -64,3 +67,30 @@ export const getVotesPercentage = (record: HumanEvaluationListTableDataType, ind const variant = record.votesData.variants[index] return record.votesData.variants_votes_data[variant]?.percentage } + +export const checkIfResourceValidForDeletion = async ( + data: Omit[0], "appId">, +) => { + const appId = getAppValues().currentApp?.app_id + if (!appId) return false + + const response = await fetchEvaluatonIdsByResource({...data, appId}) + if (response.data.length > 0) { + const name = + (data.resourceType === "testset" + ? "Testset" + : data.resourceType === "evaluator_config" + ? "Evaluator" + : "Variant") + (data.resourceIds.length > 1 ? "s" : "") + + const suffix = response.data.length > 1 ? "s" : "" + AlertPopup({ + title: `${name} is in use`, + message: `The ${name} is currently in used by ${response.data.length} evaluation${suffix}. Please delete the evaluation${suffix} first.`, + cancelText: null, + okText: "Ok", + }) + return false + } + return true +} diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index b9221f5726..08431406f0 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -10,6 +10,7 @@ import {deleteTestsets, useLoadTestsetsList} from "@/lib/services/api" import {createUseStyles} from "react-jss" import {testset} from "@/lib/Types" import {isDemo} from "@/lib/helpers/utils" +import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" const useStyles = createUseStyles({ container: { @@ -71,6 +72,13 @@ export default function Testsets() { const onDelete = async () => { const testsetsIds = selectedRowKeys.map((key) => key.toString()) try { + if ( + !(await checkIfResourceValidForDeletion({ + resourceType: "testset", + resourceIds: testsetsIds, + })) + ) + return await deleteTestsets(testsetsIds) mutate() setSelectedRowKeys([]) diff --git a/agenta-web/src/services/evaluations/index.ts b/agenta-web/src/services/evaluations/index.ts index 875fbb57f3..07e4c7f860 100644 --- a/agenta-web/src/services/evaluations/index.ts +++ b/agenta-web/src/services/evaluations/index.ts @@ -263,3 +263,21 @@ export const fetchAllComparisonResults = async (evaluationIds: string[]) => { evaluations: scenarioGroups.map((group) => group[0].evaluation), } } + +// Evaluation IDs by resource +export const fetchEvaluatonIdsByResource = async ({ + resourceIds, + resourceType, + appId, +}: { + resourceIds: string[] + resourceType: "testset" | "evaluator_config" | "variant" + appId: string +}) => { + return axios.get(`/api/evaluations/by_resource`, { + params: {resource_ids: resourceIds, resource_type: resourceType, app_id: appId}, + paramsSerializer: { + indexes: null, //no brackets in query params + }, + }) +} From fce53603d8683d5c658e2c5b0e961bf9b520cbac Mon Sep 17 00:00:00 2001 From: MohammedMaaz Date: Tue, 16 Jan 2024 14:02:35 +0500 Subject: [PATCH 3/8] return type | async/await introduced --- .../agenta_backend/routers/evaluation_router.py | 6 +++--- .../agenta_backend/services/evaluation_service.py | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/agenta-backend/agenta_backend/routers/evaluation_router.py b/agenta-backend/agenta_backend/routers/evaluation_router.py index 4e5a147679..551704a319 100644 --- a/agenta-backend/agenta_backend/routers/evaluation_router.py +++ b/agenta-backend/agenta_backend/routers/evaluation_router.py @@ -3,8 +3,8 @@ from typing import Any, List from fastapi.responses import JSONResponse -from fastapi.encoders import jsonable_encoder from fastapi import HTTPException, Request, status, Response, Query +from beanie import PydanticObjectId as ObjectId from agenta_backend.utils.common import APIRouter from agenta_backend.models.api.evaluation_model import ( @@ -38,7 +38,7 @@ @router.get( "/by_resource/", - response_model=Any, + response_model=List[ObjectId], ) async def fetch_evaluation_ids( app_id: str, @@ -51,7 +51,7 @@ async def fetch_evaluation_ids( Arguments: app_id (str): The ID of the app for which to fetch evaluations. resource_type (str): The type of resource for which to fetch evaluations. - resource_ids List[str]: The IDs of resource for which to fetch evaluations. + resource_ids List[ObjectId]: The IDs of resource for which to fetch evaluations. Raises: HTTPException: If the resource_type is invalid or access is denied. diff --git a/agenta-backend/agenta_backend/services/evaluation_service.py b/agenta-backend/agenta_backend/services/evaluation_service.py index 07aaa797dd..39d5ef7c4d 100644 --- a/agenta-backend/agenta_backend/services/evaluation_service.py +++ b/agenta-backend/agenta_backend/services/evaluation_service.py @@ -801,14 +801,14 @@ def remove_duplicates(csvdata): return unique_entries -def fetch_evaluations_by_resource(resource_type: str, resource_ids: List[str]): +async def fetch_evaluations_by_resource(resource_type: str, resource_ids: List[str]): ids = list(map(lambda x: ObjectId(x), resource_ids)) if resource_type == "variant": - return EvaluationDB.find(In(EvaluationDB.variant, ids)).to_list() + res = await EvaluationDB.find(In(EvaluationDB.variant, ids)).to_list() elif resource_type == "testset": - return EvaluationDB.find(In(EvaluationDB.testset.id, ids)).to_list() + res = await EvaluationDB.find(In(EvaluationDB.testset.id, ids)).to_list() elif resource_type == "evaluator_config": - return EvaluationDB.find( + res = await EvaluationDB.find( In( EvaluationDB.evaluators_configs, ids, @@ -819,3 +819,4 @@ def fetch_evaluations_by_resource(resource_type: str, resource_ids: List[str]): status_code=400, detail=f"resource_type {resource_type} is not supported", ) + return res From 2fe23f5c134f1a0fdefc141b6caf0ec54f20407a Mon Sep 17 00:00:00 2001 From: Abram Date: Thu, 8 Feb 2024 12:03:18 +0100 Subject: [PATCH 4/8] Update - modified model to allow none values --- .../agenta_backend/models/api/evaluation_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/agenta-backend/agenta_backend/models/api/evaluation_model.py b/agenta-backend/agenta_backend/models/api/evaluation_model.py index 4023c0fcae..05f78f83e1 100644 --- a/agenta-backend/agenta_backend/models/api/evaluation_model.py +++ b/agenta-backend/agenta_backend/models/api/evaluation_model.py @@ -1,6 +1,6 @@ from enum import Enum from datetime import datetime -from pydantic import BaseModel, Field +from pydantic import BaseModel from typing import Optional, List, Dict, Any, Union from agenta_backend.models.api.api_models import Result @@ -39,7 +39,7 @@ class EvaluationScenarioStatusEnum(str, Enum): class AggregatedResult(BaseModel): - evaluator_config: EvaluatorConfig + evaluator_config: Union[EvaluatorConfig, Dict[str, Any]] result: Result @@ -66,8 +66,8 @@ class Evaluation(BaseModel): variant_names: List[str] variant_revision_ids: List[str] revisions: List[str] - testset_id: str - testset_name: str + testset_id: Optional[str] + testset_name: Optional[str] status: Result aggregated_results: List[AggregatedResult] created_at: datetime From cb5679c044499fd5efd327b7b6cdb1dfbfcad48f Mon Sep 17 00:00:00 2001 From: Abram Date: Thu, 8 Feb 2024 12:03:41 +0100 Subject: [PATCH 5/8] Update - handle safe-fail in case of deleted evaluator config --- agenta-backend/agenta_backend/models/converters.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/agenta-backend/agenta_backend/models/converters.py b/agenta-backend/agenta_backend/models/converters.py index 0344d5071b..6a73e4cd70 100644 --- a/agenta-backend/agenta_backend/models/converters.py +++ b/agenta-backend/agenta_backend/models/converters.py @@ -88,6 +88,9 @@ async def evaluation_db_to_pydantic( str(evaluation_db.variant_revision) ) revision = str(variant_revision.revision) + aggregated_results = await aggregated_result_to_pydantic( + evaluation_db.aggregated_results + ) return Evaluation( id=str(evaluation_db.id), app_id=str(evaluation_db.app.id), @@ -106,9 +109,7 @@ async def evaluation_db_to_pydantic( if type(evaluation_db.testset) is Link else str(evaluation_db.testset.name) ), - aggregated_results=await aggregated_result_to_pydantic( - evaluation_db.aggregated_results - ), + aggregated_results=aggregated_results, created_at=evaluation_db.created_at, updated_at=evaluation_db.updated_at, ) @@ -184,7 +185,11 @@ async def aggregated_result_to_pydantic(results: List[AggregatedResult]) -> List ) transformed_results.append( { - "evaluator_config": json.loads(evaluator_config_dict), + "evaluator_config": ( + {} + if evaluator_config_dict is None + else json.loads(evaluator_config_dict) + ), "result": result.result.dict(), } ) From 2ee77a8b4538e29e580b3d9e03381fbe744bf431 Mon Sep 17 00:00:00 2001 From: Abram Date: Thu, 8 Feb 2024 13:24:09 +0100 Subject: [PATCH 6/8] Update - cover edge case to return empty data in case testsetId not found --- agenta-web/src/lib/services/api.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/agenta-web/src/lib/services/api.ts b/agenta-web/src/lib/services/api.ts index 13728732b7..542999d5f7 100644 --- a/agenta-web/src/lib/services/api.ts +++ b/agenta-web/src/lib/services/api.ts @@ -284,7 +284,16 @@ export async function updateTestset(testsetId: String, testsetName: string, test return response } -export const loadTestset = async (testsetId: string) => { +export const loadTestset = async (testsetId: string | null) => { + if (!testsetId) { + return { + id: undefined, + name: "No Test Set Associated", + created_at: "", + updated_at: "", + csvdata: [] + } + } const response = await axios.get(`${getAgentaApiUrl()}/api/testsets/${testsetId}/`) return response.data } From d28f3fff6017c47803dad5f87873b8676837df89 Mon Sep 17 00:00:00 2001 From: Abram Date: Thu, 8 Feb 2024 13:28:19 +0100 Subject: [PATCH 7/8] Update - allow null to pass through loadTestset logic --- .../evaluations/evaluationScenarios/EvaluationScenarios.tsx | 6 +++--- agenta-web/src/services/evaluations/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agenta-web/src/components/pages/evaluations/evaluationScenarios/EvaluationScenarios.tsx b/agenta-web/src/components/pages/evaluations/evaluationScenarios/EvaluationScenarios.tsx index 884d1f4803..7112828a52 100644 --- a/agenta-web/src/components/pages/evaluations/evaluationScenarios/EvaluationScenarios.tsx +++ b/agenta-web/src/components/pages/evaluations/evaluationScenarios/EvaluationScenarios.tsx @@ -101,14 +101,14 @@ const EvaluationScenarios: React.FC = () => { }) scenarios[0]?.evaluators_configs.forEach((config) => { colDefs.push({ - headerName: config.name, + headerName: config?.name, headerComponent: (props: any) => { - const evaluator = evaluators.find((item) => item.key === config.evaluator_key)! + const evaluator = evaluators.find((item) => item.key === config?.evaluator_key)! return ( {config.name} - {evaluator.name} + {evaluator?.name} ) diff --git a/agenta-web/src/services/evaluations/index.ts b/agenta-web/src/services/evaluations/index.ts index 74368d6e20..54d7b3fa0f 100644 --- a/agenta-web/src/services/evaluations/index.ts +++ b/agenta-web/src/services/evaluations/index.ts @@ -207,7 +207,7 @@ export const updateAnnotationScenario = async ( // Comparison export const fetchAllComparisonResults = async (evaluationIds: string[]) => { const scenarioGroups = await Promise.all(evaluationIds.map(fetchAllEvaluationScenarios)) - const testset: TestSet = await loadTestset(scenarioGroups[0][0].evaluation.testset.id) + const testset: TestSet = await loadTestset(scenarioGroups[0][0].evaluation?.testset?.id) const inputsNameSet = new Set() scenarioGroups.forEach((group) => { From ba1beedfd161b3457cc989f83ba5c673222f0218 Mon Sep 17 00:00:00 2001 From: Abram Date: Thu, 8 Feb 2024 13:31:32 +0100 Subject: [PATCH 8/8] :art: Format - ran black and prettier --- agenta-backend/agenta_backend/models/converters.py | 4 ++-- agenta-web/src/lib/services/api.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/agenta-backend/agenta_backend/models/converters.py b/agenta-backend/agenta_backend/models/converters.py index 6a73e4cd70..3c4f27202d 100644 --- a/agenta-backend/agenta_backend/models/converters.py +++ b/agenta-backend/agenta_backend/models/converters.py @@ -89,8 +89,8 @@ async def evaluation_db_to_pydantic( ) revision = str(variant_revision.revision) aggregated_results = await aggregated_result_to_pydantic( - evaluation_db.aggregated_results - ) + evaluation_db.aggregated_results + ) return Evaluation( id=str(evaluation_db.id), app_id=str(evaluation_db.app.id), diff --git a/agenta-web/src/lib/services/api.ts b/agenta-web/src/lib/services/api.ts index 542999d5f7..559cd3b4df 100644 --- a/agenta-web/src/lib/services/api.ts +++ b/agenta-web/src/lib/services/api.ts @@ -291,7 +291,7 @@ export const loadTestset = async (testsetId: string | null) => { name: "No Test Set Associated", created_at: "", updated_at: "", - csvdata: [] + csvdata: [], } } const response = await axios.get(`${getAgentaApiUrl()}/api/testsets/${testsetId}/`)