diff --git a/docs/source/specs/openapi.json b/docs/source/specs/openapi.json index d952a79c9..ead5a0614 100644 --- a/docs/source/specs/openapi.json +++ b/docs/source/specs/openapi.json @@ -1 +1 @@ -{"openapi": "3.1.0", "info": {"title": "Lumigator Backend", "description": "Backend server", "version": "0.0.1"}, "paths": {"/api/v1/health/": {"get": {"tags": ["health"], "summary": "Get Health", "operationId": "get_health_api_v1_health__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthResponse"}}}}}}}, "/api/v1/datasets/": {"post": {"tags": ["datasets"], "summary": "Upload Dataset", "description": "Uploads the dataset for use in Lumigator.\n\nAn uploaded dataset is parsed into HuggingFace format files and stored alongside a\nrecreated version of the input dataset.\n\nNOTE: The recreated version of the CSV file may not have identical delimiters as it will follow\nthe format that HuggingFace uses when it generates the CSV.", "operationId": "upload_dataset_api_v1_datasets__post", "requestBody": {"required": true, "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_dataset_api_v1_datasets__post"}}}}, "responses": {"201": {"description": "Dataset successfully uploaded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetResponse"}}}}, "413": {"description": "Max dataset size (50MB)"}, "422": {"description": "Invalid CSV file"}}}, "get": {"tags": ["datasets"], "summary": "List Datasets", "operationId": "list_datasets_api_v1_datasets__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_DatasetResponse_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/datasets/{dataset_id}": {"get": {"tags": ["datasets"], "summary": "Get Dataset", "operationId": "get_dataset_api_v1_datasets__dataset_id__get", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["datasets"], "summary": "Delete Dataset", "operationId": "delete_dataset_api_v1_datasets__dataset_id__delete", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/datasets/{dataset_id}/download": {"get": {"tags": ["datasets"], "summary": "Get Dataset Download", "description": "Returns a collection of pre-signed URLs which can be used to download the dataset.", "operationId": "get_dataset_download_api_v1_datasets__dataset_id__download_get", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}, {"name": "extension", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "When specified, will be used to return only URLs for files which have a matching file extension. Wildcards are not accepted. By default all files are returned. e.g. csv", "title": "Extension"}, "description": "When specified, will be used to return only URLs for files which have a matching file extension. Wildcards are not accepted. By default all files are returned. e.g. csv"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetDownloadResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/inference/": {"post": {"tags": ["jobs"], "summary": "Create Inference Job", "operationId": "create_inference_job_api_v1_jobs_inference__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobInferenceCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/annotate/": {"post": {"tags": ["jobs"], "summary": "Create Annotation Job", "description": "This uses a hardcoded model, that is, Lumigator's opinion on what\nreference model should be used to generate annotations.\nSee more: https://blog.mozilla.ai/lets-build-an-app-for-evaluating-llms/", "operationId": "create_annotation_job_api_v1_jobs_annotate__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobAnnotateCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/evaluator/": {"post": {"tags": ["jobs"], "summary": "Create Evaluation Job", "operationId": "create_evaluation_job_api_v1_jobs_evaluator__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobEvalCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/": {"get": {"tags": ["jobs"], "summary": "List Jobs", "description": "Retrieves job data from the Lumigator repository where Ray\nmetadata is also available.\n\nResults are a merged representation which form an augmented view of a 'job'.\n\nNOTE: Lumigator repository data takes precedence over Ray metadata.", "operationId": "list_jobs_api_v1_jobs__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}, {"name": "job_types", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}, "default": [], "title": "Job Types"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_Job_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}": {"get": {"tags": ["jobs"], "summary": "Get Job", "description": "Retrieves merged job data from the Lumigator repository and Ray\nfor a valid UUID.\n\nThe result is a merged representation which forms an augmented view of a 'job'.\n\nNOTE: Lumigator repository data takes precedence over Ray metadata.", "operationId": "get_job_api_v1_jobs__job_id__get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Job"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/logs": {"get": {"tags": ["jobs"], "summary": "Get Job Logs", "operationId": "get_job_logs_api_v1_jobs__job_id__logs_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobLogsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/result": {"get": {"tags": ["jobs"], "summary": "Get Job Result", "description": "Return job results metadata if available in the DB.", "operationId": "get_job_result_api_v1_jobs__job_id__result_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResultResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/dataset": {"get": {"tags": ["jobs"], "summary": "Get Job Dataset", "description": "Return the job-associated dataset if available in the DB.", "operationId": "get_job_dataset_api_v1_jobs__job_id__dataset_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/DatasetResponse"}, {"type": "null"}], "title": "Response Get Job Dataset Api V1 Jobs Job Id Dataset Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/result/download": {"get": {"tags": ["jobs"], "summary": "Get Job Result Download", "description": "Return job results file URL for downloading.", "operationId": "get_job_result_download_api_v1_jobs__job_id__result_download_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResultDownloadResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/experiments/": {"post": {"tags": ["experiments"], "summary": "Create Experiment Id", "description": "Create an experiment ID.", "operationId": "create_experiment_id_api_v1_experiments__post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExperimentCreate"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GetExperimentResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "get": {"tags": ["experiments"], "summary": "List Experiments", "description": "List all experiments.", "operationId": "list_experiments_api_v1_experiments__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_GetExperimentResponse_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/experiments/{experiment_id}": {"get": {"tags": ["experiments"], "summary": "Get Experiment", "description": "Get an experiment by ID.", "operationId": "get_experiment_api_v1_experiments__experiment_id__get", "parameters": [{"name": "experiment_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Experiment Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GetExperimentResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["experiments"], "summary": "Delete Experiment", "description": "Delete an experiment by ID.", "operationId": "delete_experiment_api_v1_experiments__experiment_id__delete", "parameters": [{"name": "experiment_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Experiment Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/models/": {"get": {"tags": ["models"], "summary": "Get Suggested Models", "description": "Get a list of suggested models for the given tasks.\n\nUsage: GET api/v1/models/?tasks=summarization&tasks=translation\n\nArgs:\n tasks (List[str], optional): The task names to filter by.\n\nReturns:\n ListingResponse[ModelsResponse]: A list of suggested models.", "operationId": "get_suggested_models_api_v1_models__get", "parameters": [{"name": "tasks", "in": "query", "required": false, "schema": {"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Filter models by task types", "title": "Tasks"}, "description": "Filter models by task types"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_ModelsResponse_"}}}}, "400": {"description": "Bad Request"}, "500": {"description": "Internal Server Error"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/": {"post": {"tags": ["workflows"], "summary": "Create Workflow", "description": "A workflow is a single execution for an experiment.\nA workflow is a collection of 1 or more jobs.\nIt must be associated with an experiment id,\nwhich means you must already have created an experiment and have that ID in the request.", "operationId": "create_workflow_api_v1_workflows__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateRequest"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}": {"get": {"tags": ["workflows"], "summary": "Get Workflow", "description": "Get a workflow by ID.", "operationId": "get_workflow_api_v1_workflows__workflow_id__get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["workflows"], "summary": "Delete Workflow", "description": "Delete a workflow by ID.\n\nArgs:\n service: Workflow service dependency\n workflow_id: ID of the workflow to delete\n force: If True, force deletion even if the workflow is active or has dependencies", "operationId": "delete_workflow_api_v1_workflows__workflow_id__delete", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}, {"name": "force", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Force"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}/logs": {"get": {"tags": ["workflows"], "summary": "Get Workflow Logs", "description": "Get the logs for a workflow.", "operationId": "get_workflow_logs_api_v1_workflows__workflow_id__logs_get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobLogsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}/result/download": {"get": {"tags": ["workflows"], "summary": "Get Workflow Result Download", "description": "Return workflow results file URL for downloading.\n\nArgs:\n service: Workflow service dependency\n workflow_id: ID of the workflow whose results will be returned", "operationId": "get_workflow_result_download_api_v1_workflows__workflow_id__result_download_get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "string", "title": "Response Get Workflow Result Download Api V1 Workflows Workflow Id Result Download Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/settings/secrets/": {"get": {"tags": ["settings"], "summary": "List Secrets", "description": "Lists all API configured secret names (and descriptions) stored in Lumigator.", "operationId": "list_secrets_api_v1_settings_secrets__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/SecretGetRequest"}, "type": "array", "title": "Response List Secrets Api V1 Settings Secrets Get"}}}}}}}, "/api/v1/settings/secrets/{secret_name}": {"delete": {"tags": ["settings"], "summary": "Delete Secret", "description": "Deletes a secret identified by its name.", "operationId": "delete_secret_api_v1_settings_secrets__secret_name__delete", "parameters": [{"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["settings"], "summary": "Upload Secret", "description": "Uploads a secret for use in Lumigator.\n\nLumigator uses different secrets for purposes such as external API calls.\nThe user can upload new values for these secrets, but they cannot retrieve\nthose values.", "operationId": "upload_secret_api_v1_settings_secrets__secret_name__put", "parameters": [{"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretUploadRequest"}}}}, "responses": {"201": {"description": "Secret successfully created", "content": {"application/json": {"schema": {}}}}, "204": {"description": "Secret successfully updated"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/": {"get": {"summary": "Get Root", "operationId": "get_root__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}}, "components": {"schemas": {"Body_upload_dataset_api_v1_datasets__post": {"properties": {"dataset": {"type": "string", "format": "binary", "title": "Dataset"}, "format": {"$ref": "#/components/schemas/DatasetFormat"}}, "type": "object", "required": ["dataset", "format"], "title": "Body_upload_dataset_api_v1_datasets__post"}, "DatasetDownloadResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "download_urls": {"items": {"type": "string"}, "type": "array", "title": "Download Urls"}}, "type": "object", "required": ["id", "download_urls"], "title": "DatasetDownloadResponse"}, "DatasetFormat": {"type": "string", "enum": ["job"], "title": "DatasetFormat"}, "DatasetResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "filename": {"type": "string", "title": "Filename"}, "format": {"$ref": "#/components/schemas/DatasetFormat"}, "size": {"type": "integer", "title": "Size"}, "ground_truth": {"type": "boolean", "title": "Ground Truth"}, "run_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Run Id"}, "generated": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Generated"}, "generated_by": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Generated By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "filename", "format", "size", "ground_truth", "run_id", "generated", "generated_by", "created_at"], "title": "DatasetResponse"}, "DeepEvalLocalModelConfig": {"properties": {"model_name": {"type": "string", "title": "Model Name"}, "model_base_url": {"type": "string", "title": "Model Base Url"}, "model_api_key": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Model Api Key", "default": "ollama"}}, "type": "object", "required": ["model_name", "model_base_url"], "title": "DeepEvalLocalModelConfig"}, "DeploymentType": {"type": "string", "enum": ["local", "development", "staging", "production"], "title": "DeploymentType"}, "ExperimentCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}}, "type": "object", "required": ["name", "dataset"], "title": "ExperimentCreate"}, "GenerationConfig": {"properties": {"max_new_tokens": {"type": "integer", "title": "Max New Tokens", "default": 1024}, "frequency_penalty": {"type": "number", "title": "Frequency Penalty", "default": 0.0}, "temperature": {"type": "number", "title": "Temperature", "default": 0.5}, "top_p": {"type": "number", "title": "Top P", "default": 0.5}}, "additionalProperties": false, "type": "object", "title": "GenerationConfig", "description": "Custom and limited configuration for generation.\nSort of a subset of HF GenerationConfig\nhttps://huggingface.co/docs/transformers/en/main_classes/text_generation#transformers.GenerationConfig"}, "GetExperimentResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "workflows": {"anyOf": [{"items": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}, "type": "array"}, {"type": "null"}], "title": "Workflows"}}, "type": "object", "required": ["id", "name", "description", "created_at", "task_definition", "dataset"], "title": "GetExperimentResponse"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "HealthResponse": {"properties": {"status": {"type": "string", "title": "Status"}, "deployment_type": {"$ref": "#/components/schemas/DeploymentType"}}, "type": "object", "required": ["status", "deployment_type"], "title": "HealthResponse"}, "Job": {"properties": {"type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Type"}, "submission_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Submission Id"}, "driver_info": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Info"}, "status": {"$ref": "#/components/schemas/JobStatus"}, "config": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Config"}, "message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Message"}, "error_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error Type"}, "start_time": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Start Time"}, "end_time": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "End Time"}, "metadata": {"type": "object", "title": "Metadata"}, "runtime_env": {"type": "object", "title": "Runtime Env"}, "driver_agent_http_address": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Agent Http Address"}, "driver_node_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Node Id"}, "driver_exit_code": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Driver Exit Code"}, "id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "job_type": {"$ref": "#/components/schemas/JobType"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "experiment_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Experiment Id"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["status", "id", "name", "description", "job_type", "created_at"], "title": "Job", "description": "Job represents the composition of JobResponse and JobSubmissionResponse.\n\nJobSubmissionResponse was formerly returned from some /health/jobs related\nendpoints, while JobResponse was used by /jobs related endpoints.\n\nThe only conflicting field in the two schemas is 'status' which is consistent\nin what it intends to represent, but uses different types (JobStatus/str).\n\nThe Job type has both id and submission_id which will contain the same data.\n\nNOTE: Job is intended to reduce breaking changes experienced by the UI and other\nconsumers. Tt was not conceived as a type that will be around for long, as\nthe API needs to be refactored to better support experiments."}, "JobAnnotateConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "model": {"type": "string", "title": "Model", "default": "facebook/bart-large-cnn"}, "provider": {"type": "string", "title": "Provider", "default": "hf"}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "accelerator": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accelerator", "default": "auto"}, "revision": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Revision", "default": "main"}, "use_fast": {"type": "boolean", "title": "Use Fast", "default": true}, "trust_remote_code": {"type": "boolean", "title": "Trust Remote Code", "default": false}, "torch_dtype": {"type": "string", "title": "Torch Dtype", "default": "auto"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "store_to_dataset": {"type": "boolean", "title": "Store To Dataset", "default": true}, "system_prompt": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "System Prompt", "description": "System prompt to use for the model inference.If not provided, a task-specific default prompt will be used.", "examples": ["You are an advanced AI trained to summarize documents accurately and concisely. Your goal is to extract key information while maintaining clarity and coherence."]}}, "type": "object", "title": "JobAnnotateConfig", "description": "Job configuration for the annotation job type\n\nAn annotation job is a special type of inference job that is used to\nannotate a dataset with predictions from a model. The predictions are\nstored in the dataset as a new field called `ground_truth`.\n\nJobAnnotateConfig inherits from JobInferenceConfig but fixes the following\nfields, using the `SkipJsonSchema` type to prevent them from being included\nin the JSON schema:\n- job_type: Literal[JobType.ANNOTATION]\n- output_field: \"ground_truth\"\n\nIt also sets sensible defaults for the following fields:\n- store_to_dataset: True\n- model: \"facebook/bart-large-cnn\"\n- provider: \"hf\"\n\nUsers can change the model and provider fields but cannot change the\njob_type or output_field fields.\n\nNote that, currently, ground truth generation is limited to summarization\ntasks from the UI. Users can run any ground truth generation task from the\nAPI."}, "JobAnnotateCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobAnnotateConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobAnnotateCreate"}, "JobEvalConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "job_type": {"type": "string", "const": "evaluator", "title": "Job Type", "default": "evaluator"}, "metrics": {"items": {"type": "string"}, "type": "array", "title": "Metrics", "default": ["rouge", "meteor", "bertscore", "bleu"]}, "llm_as_judge": {"anyOf": [{"$ref": "#/components/schemas/DeepEvalLocalModelConfig"}, {"type": "null"}]}}, "type": "object", "title": "JobEvalConfig"}, "JobEvalCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobEvalConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobEvalCreate"}, "JobInferenceConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "job_type": {"type": "string", "const": "inference", "title": "Job Type", "default": "inference"}, "model": {"type": "string", "title": "Model"}, "provider": {"type": "string", "title": "Provider"}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "accelerator": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accelerator", "default": "auto"}, "revision": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Revision", "default": "main"}, "use_fast": {"type": "boolean", "title": "Use Fast", "default": true}, "trust_remote_code": {"type": "boolean", "title": "Trust Remote Code", "default": false}, "torch_dtype": {"type": "string", "title": "Torch Dtype", "default": "auto"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "output_field": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Output Field", "default": "predictions"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "store_to_dataset": {"type": "boolean", "title": "Store To Dataset", "default": false}, "system_prompt": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "System Prompt", "description": "System prompt to use for the model inference.If not provided, a task-specific default prompt will be used.", "examples": ["You are an advanced AI trained to summarize documents accurately and concisely. Your goal is to extract key information while maintaining clarity and coherence."]}}, "type": "object", "required": ["model", "provider"], "title": "JobInferenceConfig"}, "JobInferenceCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobInferenceConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobInferenceCreate"}, "JobLogsResponse": {"properties": {"logs": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Logs"}}, "type": "object", "title": "JobLogsResponse"}, "JobResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "status": {"$ref": "#/components/schemas/JobStatus"}, "job_type": {"$ref": "#/components/schemas/JobType"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "experiment_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Experiment Id"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["id", "name", "description", "status", "job_type", "created_at"], "title": "JobResponse"}, "JobResultDownloadResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "download_url": {"type": "string", "title": "Download Url"}}, "type": "object", "required": ["id", "download_url"], "title": "JobResultDownloadResponse"}, "JobResultResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "job_id": {"type": "string", "format": "uuid", "title": "Job Id"}}, "type": "object", "required": ["id", "job_id"], "title": "JobResultResponse"}, "JobResults": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "metrics": {"anyOf": [{"items": {"type": "object"}, "type": "array"}, {"type": "null"}], "title": "Metrics"}, "parameters": {"anyOf": [{"items": {"type": "object"}, "type": "array"}, {"type": "null"}], "title": "Parameters"}, "metric_url": {"type": "string", "title": "Metric Url"}, "artifact_url": {"type": "string", "title": "Artifact Url"}}, "type": "object", "required": ["id", "metric_url", "artifact_url"], "title": "JobResults"}, "JobStatus": {"type": "string", "enum": ["created", "pending", "running", "failed", "succeeded", "stopped"], "title": "JobStatus"}, "JobType": {"type": "string", "enum": ["inference", "evaluator", "annotate"], "title": "JobType"}, "ListingResponse_DatasetResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/DatasetResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[DatasetResponse]"}, "ListingResponse_GetExperimentResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/GetExperimentResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[GetExperimentResponse]"}, "ListingResponse_Job_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/Job"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[Job]"}, "ListingResponse_ModelsResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/ModelsResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[ModelsResponse]"}, "ModelInfo": {"properties": {"parameter_count": {"type": "string", "title": "Parameter Count"}, "tensor_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tensor Type"}, "model_size": {"type": "string", "title": "Model Size"}}, "type": "object", "required": ["parameter_count", "model_size"], "title": "ModelInfo"}, "ModelRequirement": {"type": "string", "enum": ["api_key", "llamafile"], "title": "ModelRequirement", "description": "Represents a type of requirement for a model"}, "ModelsResponse": {"properties": {"display_name": {"type": "string", "title": "Model name", "description": "Name of the model used in the task. It's just a display name"}, "model": {"type": "string", "title": "Model ID", "description": "Model ID used in the task"}, "provider": {"type": "string", "title": "Model Provider", "description": "LiteLLM key for where the model is hosted (e.g. `openai`, `deepseek`, `gpt3`, etc). If using a HF model that is hosted in the inference job, use `hf`"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base URL", "description": "Base URL for the model API (if applicable, e.g. for Llamafile, vLLM, etc)"}, "website_url": {"type": "string", "title": "Information page URL", "description": "URI containing detailed information about the model"}, "description": {"type": "string", "title": "Model description", "description": "Detailed model description"}, "requirements": {"items": {"$ref": "#/components/schemas/ModelRequirement"}, "type": "array", "title": "Model requirements", "description": "Additional requirements that need to be fulfilled before using the model (e.g. `{ModelRequirement.LLAMAFILE}` to indicate that a llamafile needs to be running or `{ModelRequirement.API_KEY}` to indicate that an API key is necessary)"}, "info": {"anyOf": [{"$ref": "#/components/schemas/ModelInfo"}, {"type": "null"}], "title": "Model info", "description": "Detailed model capabilities"}, "tasks": {"items": {"additionalProperties": {"type": "object"}, "type": "object"}, "type": "array", "title": "Applicable tasks", "description": "List of tasks to which the model can be applied"}}, "type": "object", "required": ["display_name", "model", "provider", "website_url", "description", "tasks"], "title": "ModelsResponse", "description": "Contains detailed model information"}, "SecretGetRequest": {"properties": {"name": {"type": "string", "maxLength": 255, "minLength": 1, "title": "Name"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["name", "description"], "title": "SecretGetRequest", "description": "Represents the result of a get secret request.\n\nNOTE: The secret value should never be exposed to the end user."}, "SecretUploadRequest": {"properties": {"value": {"type": "string", "maxLength": 1024, "minLength": 1, "title": "Value"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["value", "description"], "title": "SecretUploadRequest", "description": "Represents a secret upload request."}, "SummarizationTaskDefinition": {"properties": {"task": {"type": "string", "const": "summarization", "title": "Task", "default": "summarization"}}, "additionalProperties": false, "type": "object", "title": "SummarizationTaskDefinition"}, "TextGenerationTaskDefinition": {"properties": {"task": {"type": "string", "const": "text-generation", "title": "Task", "default": "text-generation"}}, "additionalProperties": false, "type": "object", "title": "TextGenerationTaskDefinition"}, "TranslationTaskDefinition": {"properties": {"task": {"type": "string", "const": "translation", "title": "Task", "default": "translation"}, "source_language": {"type": "string", "title": "Source Language", "examples": ["en", "English"]}, "target_language": {"type": "string", "title": "Target Language", "examples": ["de", "German"]}}, "additionalProperties": false, "type": "object", "required": ["source_language", "target_language"], "title": "TranslationTaskDefinition"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "WorkflowCreateRequest": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "experiment_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "provider": {"type": "string", "title": "Provider"}, "secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. Identifies an existing secret stored in Lumigator that should be used to access the provider."}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "system_prompt": {"type": "string", "title": "System Prompt", "default": ""}, "inference_output_field": {"type": "string", "title": "Inference Output Field", "default": "predictions"}, "config_template": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Config Template"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "job_timeout_sec": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Job Timeout Sec", "default": 3600}, "metrics": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Metrics"}}, "type": "object", "required": ["name", "model", "provider"], "title": "WorkflowCreateRequest"}, "WorkflowDetailsResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "experiment_id": {"type": "string", "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "system_prompt": {"type": "string", "title": "System Prompt"}, "status": {"$ref": "#/components/schemas/WorkflowStatus"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "jobs": {"anyOf": [{"items": {"$ref": "#/components/schemas/JobResults"}, "type": "array"}, {"type": "null"}], "title": "Jobs"}, "metrics": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Metrics"}, "parameters": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Parameters"}, "artifacts_download_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Artifacts Download Url"}}, "type": "object", "required": ["id", "experiment_id", "model", "name", "description", "system_prompt", "status", "created_at"], "title": "WorkflowDetailsResponse"}, "WorkflowResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "experiment_id": {"type": "string", "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "system_prompt": {"type": "string", "title": "System Prompt"}, "status": {"$ref": "#/components/schemas/WorkflowStatus"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["id", "experiment_id", "model", "name", "description", "system_prompt", "status", "created_at"], "title": "WorkflowResponse"}, "WorkflowStatus": {"type": "string", "enum": ["created", "running", "failed", "succeeded"], "title": "WorkflowStatus"}}}} \ No newline at end of file +{"openapi": "3.1.0", "info": {"title": "Lumigator Backend", "description": "Backend server", "version": "0.0.1"}, "paths": {"/api/v1/health/": {"get": {"tags": ["health"], "summary": "Get Health", "operationId": "get_health_api_v1_health__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthResponse"}}}}}}}, "/api/v1/datasets/": {"post": {"tags": ["datasets"], "summary": "Upload Dataset", "description": "Uploads the dataset for use in Lumigator.\n\nAn uploaded dataset is parsed into HuggingFace format files and stored alongside a\nrecreated version of the input dataset.\n\nNOTE: The recreated version of the CSV file may not have identical delimiters as it will follow\nthe format that HuggingFace uses when it generates the CSV.", "operationId": "upload_dataset_api_v1_datasets__post", "requestBody": {"required": true, "content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_dataset_api_v1_datasets__post"}}}}, "responses": {"201": {"description": "Dataset successfully uploaded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetResponse"}}}}, "413": {"description": "Max dataset size (50MB)"}, "422": {"description": "Invalid CSV file"}}}, "get": {"tags": ["datasets"], "summary": "List Datasets", "operationId": "list_datasets_api_v1_datasets__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_DatasetResponse_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/datasets/{dataset_id}": {"get": {"tags": ["datasets"], "summary": "Get Dataset", "operationId": "get_dataset_api_v1_datasets__dataset_id__get", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["datasets"], "summary": "Delete Dataset", "operationId": "delete_dataset_api_v1_datasets__dataset_id__delete", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/datasets/{dataset_id}/download": {"get": {"tags": ["datasets"], "summary": "Get Dataset Download", "description": "Returns a collection of pre-signed URLs which can be used to download the dataset.", "operationId": "get_dataset_download_api_v1_datasets__dataset_id__download_get", "parameters": [{"name": "dataset_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Dataset Id"}}, {"name": "extension", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "description": "When specified, will be used to return only URLs for files which have a matching file extension. Wildcards are not accepted. By default all files are returned. e.g. csv", "title": "Extension"}, "description": "When specified, will be used to return only URLs for files which have a matching file extension. Wildcards are not accepted. By default all files are returned. e.g. csv"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DatasetDownloadResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/inference/": {"post": {"tags": ["jobs"], "summary": "Create Inference Job", "operationId": "create_inference_job_api_v1_jobs_inference__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobInferenceCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/annotate/": {"post": {"tags": ["jobs"], "summary": "Create Annotation Job", "description": "This uses a hardcoded model, that is, Lumigator's opinion on what\nreference model should be used to generate annotations.\nSee more: https://blog.mozilla.ai/lets-build-an-app-for-evaluating-llms/", "operationId": "create_annotation_job_api_v1_jobs_annotate__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobAnnotateCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/evaluator/": {"post": {"tags": ["jobs"], "summary": "Create Evaluation Job", "operationId": "create_evaluation_job_api_v1_jobs_evaluator__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobEvalCreate"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/": {"get": {"tags": ["jobs"], "summary": "List Jobs", "description": "Retrieves job data from the Lumigator repository where Ray\nmetadata is also available.\n\nResults are a merged representation which form an augmented view of a 'job'.\n\nNOTE: Lumigator repository data takes precedence over Ray metadata.", "operationId": "list_jobs_api_v1_jobs__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}, {"name": "job_types", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}, "default": [], "title": "Job Types"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_Job_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}": {"get": {"tags": ["jobs"], "summary": "Get Job", "description": "Retrieves merged job data from the Lumigator repository and Ray\nfor a valid UUID.\n\nThe result is a merged representation which forms an augmented view of a 'job'.\n\nNOTE: Lumigator repository data takes precedence over Ray metadata.", "operationId": "get_job_api_v1_jobs__job_id__get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Job"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/logs": {"get": {"tags": ["jobs"], "summary": "Get Job Logs", "operationId": "get_job_logs_api_v1_jobs__job_id__logs_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobLogsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/result": {"get": {"tags": ["jobs"], "summary": "Get Job Result", "description": "Return job results metadata if available in the DB.", "operationId": "get_job_result_api_v1_jobs__job_id__result_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResultResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/dataset": {"get": {"tags": ["jobs"], "summary": "Get Job Dataset", "description": "Return the job-associated dataset if available in the DB.", "operationId": "get_job_dataset_api_v1_jobs__job_id__dataset_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/DatasetResponse"}, {"type": "null"}], "title": "Response Get Job Dataset Api V1 Jobs Job Id Dataset Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/jobs/{job_id}/result/download": {"get": {"tags": ["jobs"], "summary": "Get Job Result Download", "description": "Return job results file URL for downloading.", "operationId": "get_job_result_download_api_v1_jobs__job_id__result_download_get", "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Job Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobResultDownloadResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/experiments/": {"post": {"tags": ["experiments"], "summary": "Create Experiment Id", "description": "Create an experiment ID.", "operationId": "create_experiment_id_api_v1_experiments__post", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExperimentCreate"}}}}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GetExperimentResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "get": {"tags": ["experiments"], "summary": "List Experiments", "description": "List all experiments.", "operationId": "list_experiments_api_v1_experiments__get", "parameters": [{"name": "skip", "in": "query", "required": false, "schema": {"type": "integer", "default": 0, "title": "Skip"}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "default": 100, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_GetExperimentResponse_"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/experiments/{experiment_id}": {"get": {"tags": ["experiments"], "summary": "Get Experiment", "description": "Get an experiment by ID.", "operationId": "get_experiment_api_v1_experiments__experiment_id__get", "parameters": [{"name": "experiment_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Experiment Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GetExperimentResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["experiments"], "summary": "Delete Experiment", "description": "Delete an experiment by ID.", "operationId": "delete_experiment_api_v1_experiments__experiment_id__delete", "parameters": [{"name": "experiment_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Experiment Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/models/": {"get": {"tags": ["models"], "summary": "Get Suggested Models", "description": "Get a list of suggested models for the given tasks.\n\nUsage: GET api/v1/models/?tasks=summarization&tasks=translation\n\nArgs:\n tasks (List[str], optional): The task names to filter by.\n\nReturns:\n ListingResponse[ModelsResponse]: A list of suggested models.", "operationId": "get_suggested_models_api_v1_models__get", "parameters": [{"name": "tasks", "in": "query", "required": false, "schema": {"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Filter models by task types", "title": "Tasks"}, "description": "Filter models by task types"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListingResponse_ModelsResponse_"}}}}, "400": {"description": "Bad Request"}, "500": {"description": "Internal Server Error"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/": {"post": {"tags": ["workflows"], "summary": "Create Workflow", "description": "A workflow is a single execution for an experiment.\nA workflow is a collection of 1 or more jobs.\nIt must be associated with an experiment id,\nwhich means you must already have created an experiment and have that ID in the request.", "operationId": "create_workflow_api_v1_workflows__post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowCreateRequest"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}": {"get": {"tags": ["workflows"], "summary": "Get Workflow", "description": "Get a workflow by ID.", "operationId": "get_workflow_api_v1_workflows__workflow_id__get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["workflows"], "summary": "Delete Workflow", "description": "Delete a workflow by ID.\n\nArgs:\n service: Workflow service dependency\n workflow_id: ID of the workflow to delete\n force: If True, force deletion even if the workflow is active or has dependencies", "operationId": "delete_workflow_api_v1_workflows__workflow_id__delete", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}, {"name": "force", "in": "query", "required": false, "schema": {"type": "boolean", "default": false, "title": "Force"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}/logs": {"get": {"tags": ["workflows"], "summary": "Get Workflow Logs", "description": "Get the logs for a workflow.", "operationId": "get_workflow_logs_api_v1_workflows__workflow_id__logs_get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JobLogsResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/workflows/{workflow_id}/result/download": {"get": {"tags": ["workflows"], "summary": "Get Workflow Result Download", "description": "Return workflow results file URL for downloading.\n\nArgs:\n service: Workflow service dependency\n workflow_id: ID of the workflow whose results will be returned", "operationId": "get_workflow_result_download_api_v1_workflows__workflow_id__result_download_get", "parameters": [{"name": "workflow_id", "in": "path", "required": true, "schema": {"type": "string", "title": "Workflow Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "string", "title": "Response Get Workflow Result Download Api V1 Workflows Workflow Id Result Download Get"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/v1/settings/secrets/": {"get": {"tags": ["settings"], "summary": "List Secrets", "description": "Lists all API configured secret names (and descriptions) stored in Lumigator.", "operationId": "list_secrets_api_v1_settings_secrets__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/SecretGetRequest"}, "type": "array", "title": "Response List Secrets Api V1 Settings Secrets Get"}}}}}}}, "/api/v1/settings/secrets/{secret_name}": {"delete": {"tags": ["settings"], "summary": "Delete Secret", "description": "Deletes a secret identified by its name.", "operationId": "delete_secret_api_v1_settings_secrets__secret_name__delete", "parameters": [{"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "responses": {"204": {"description": "Successful Response"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["settings"], "summary": "Upload Secret", "description": "Uploads a secret for use in Lumigator.\n\nLumigator uses different secrets for purposes such as external API calls.\nThe user can upload new values for these secrets, but they cannot retrieve\nthose values.", "operationId": "upload_secret_api_v1_settings_secrets__secret_name__put", "parameters": [{"name": "secret_name", "in": "path", "required": true, "schema": {"type": "string", "title": "Secret Name"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SecretUploadRequest"}}}}, "responses": {"201": {"description": "Secret successfully created", "content": {"application/json": {"schema": {}}}}, "204": {"description": "Secret successfully updated"}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/": {"get": {"summary": "Get Root", "operationId": "get_root__get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}}, "components": {"schemas": {"Body_upload_dataset_api_v1_datasets__post": {"properties": {"dataset": {"type": "string", "format": "binary", "title": "Dataset"}, "format": {"$ref": "#/components/schemas/DatasetFormat"}}, "type": "object", "required": ["dataset", "format"], "title": "Body_upload_dataset_api_v1_datasets__post"}, "DatasetDownloadResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "download_urls": {"items": {"type": "string"}, "type": "array", "title": "Download Urls"}}, "type": "object", "required": ["id", "download_urls"], "title": "DatasetDownloadResponse"}, "DatasetFormat": {"type": "string", "enum": ["job"], "title": "DatasetFormat"}, "DatasetResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "filename": {"type": "string", "title": "Filename"}, "format": {"$ref": "#/components/schemas/DatasetFormat"}, "size": {"type": "integer", "title": "Size"}, "ground_truth": {"type": "boolean", "title": "Ground Truth"}, "run_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Run Id"}, "generated": {"anyOf": [{"type": "boolean"}, {"type": "null"}], "title": "Generated"}, "generated_by": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Generated By"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}}, "type": "object", "required": ["id", "filename", "format", "size", "ground_truth", "run_id", "generated", "generated_by", "created_at"], "title": "DatasetResponse"}, "DeepEvalLocalModelConfig": {"properties": {"model_name": {"type": "string", "title": "Model Name"}, "model_base_url": {"type": "string", "title": "Model Base Url"}, "model_api_key": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Model Api Key", "default": "ollama"}}, "type": "object", "required": ["model_name", "model_base_url"], "title": "DeepEvalLocalModelConfig"}, "DeploymentType": {"type": "string", "enum": ["local", "development", "staging", "production"], "title": "DeploymentType"}, "ExperimentCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}}, "type": "object", "required": ["name", "dataset"], "title": "ExperimentCreate"}, "GenerationConfig": {"properties": {"max_new_tokens": {"type": "integer", "title": "Max New Tokens", "default": 1024}, "frequency_penalty": {"type": "number", "title": "Frequency Penalty", "default": 0.0}, "temperature": {"type": "number", "title": "Temperature", "default": 0.5}, "top_p": {"type": "number", "title": "Top P", "default": 0.5}}, "additionalProperties": false, "type": "object", "title": "GenerationConfig", "description": "Custom and limited configuration for generation.\nSort of a subset of HF GenerationConfig\nhttps://huggingface.co/docs/transformers/en/main_classes/text_generation#transformers.GenerationConfig"}, "GetExperimentResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "workflows": {"anyOf": [{"items": {"$ref": "#/components/schemas/WorkflowDetailsResponse"}, "type": "array"}, {"type": "null"}], "title": "Workflows"}}, "type": "object", "required": ["id", "name", "description", "created_at", "task_definition", "dataset"], "title": "GetExperimentResponse"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "HealthResponse": {"properties": {"status": {"type": "string", "title": "Status"}, "deployment_type": {"$ref": "#/components/schemas/DeploymentType"}}, "type": "object", "required": ["status", "deployment_type"], "title": "HealthResponse"}, "Job": {"properties": {"type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Type"}, "submission_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Submission Id"}, "driver_info": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Info"}, "status": {"$ref": "#/components/schemas/JobStatus"}, "config": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Config"}, "message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Message"}, "error_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Error Type"}, "start_time": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Start Time"}, "end_time": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "End Time"}, "metadata": {"type": "object", "title": "Metadata"}, "runtime_env": {"type": "object", "title": "Runtime Env"}, "driver_agent_http_address": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Agent Http Address"}, "driver_node_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Driver Node Id"}, "driver_exit_code": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Driver Exit Code"}, "id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "job_type": {"$ref": "#/components/schemas/JobType"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "experiment_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Experiment Id"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["status", "id", "name", "description", "job_type", "created_at"], "title": "Job", "description": "Job represents the composition of JobResponse and JobSubmissionResponse.\n\nJobSubmissionResponse was formerly returned from some /health/jobs related\nendpoints, while JobResponse was used by /jobs related endpoints.\n\nThe only conflicting field in the two schemas is 'status' which is consistent\nin what it intends to represent, but uses different types (JobStatus/str).\n\nThe Job type has both id and submission_id which will contain the same data.\n\nNOTE: Job is intended to reduce breaking changes experienced by the UI and other\nconsumers. Tt was not conceived as a type that will be around for long, as\nthe API needs to be refactored to better support experiments."}, "JobAnnotateConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "model": {"type": "string", "title": "Model", "default": "facebook/bart-large-cnn"}, "provider": {"type": "string", "title": "Provider", "default": "hf"}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "accelerator": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accelerator", "default": "auto"}, "revision": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Revision", "default": "main"}, "use_fast": {"type": "boolean", "title": "Use Fast", "default": true}, "trust_remote_code": {"type": "boolean", "title": "Trust Remote Code", "default": false}, "torch_dtype": {"type": "string", "title": "Torch Dtype", "default": "auto"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "store_to_dataset": {"type": "boolean", "title": "Store To Dataset", "default": true}, "system_prompt": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "System Prompt", "description": "System prompt to use for the model inference.If not provided, a task-specific default prompt will be used.", "examples": ["You are an advanced AI trained to summarize documents accurately and concisely. Your goal is to extract key information while maintaining clarity and coherence."]}}, "type": "object", "title": "JobAnnotateConfig", "description": "Job configuration for the annotation job type\n\nAn annotation job is a special type of inference job that is used to\nannotate a dataset with predictions from a model. The predictions are\nstored in the dataset as a new field called `ground_truth`.\n\nJobAnnotateConfig inherits from JobInferenceConfig but fixes the following\nfields, using the `SkipJsonSchema` type to prevent them from being included\nin the JSON schema:\n- job_type: Literal[JobType.ANNOTATION]\n- output_field: \"ground_truth\"\n\nIt also sets sensible defaults for the following fields:\n- store_to_dataset: True\n- model: \"facebook/bart-large-cnn\"\n- provider: \"hf\"\n\nUsers can change the model and provider fields but cannot change the\njob_type or output_field fields.\n\nNote that, currently, ground truth generation is limited to summarization\ntasks from the UI. Users can run any ground truth generation task from the\nAPI."}, "JobAnnotateCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobAnnotateConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobAnnotateCreate"}, "JobEvalConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "job_type": {"type": "string", "const": "evaluator", "title": "Job Type", "default": "evaluator"}, "metrics": {"items": {"type": "string"}, "type": "array", "title": "Metrics", "default": ["rouge", "meteor", "bertscore", "bleu"]}, "llm_as_judge": {"anyOf": [{"$ref": "#/components/schemas/DeepEvalLocalModelConfig"}, {"type": "null"}]}}, "type": "object", "title": "JobEvalConfig"}, "JobEvalCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobEvalConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobEvalCreate"}, "JobInferenceConfig": {"properties": {"secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. When creating a job, the secret key name identifies an existing secret stored in Lumigator that should be used to access the provider."}, "job_type": {"type": "string", "const": "inference", "title": "Job Type", "default": "inference"}, "model": {"type": "string", "title": "Model"}, "provider": {"type": "string", "title": "Provider"}, "task_definition": {"oneOf": [{"$ref": "#/components/schemas/SummarizationTaskDefinition"}, {"$ref": "#/components/schemas/TranslationTaskDefinition"}, {"$ref": "#/components/schemas/TextGenerationTaskDefinition"}], "title": "Task Definition", "discriminator": {"propertyName": "task", "mapping": {"summarization": "#/components/schemas/SummarizationTaskDefinition", "text-generation": "#/components/schemas/TextGenerationTaskDefinition", "translation": "#/components/schemas/TranslationTaskDefinition"}}}, "accelerator": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Accelerator", "default": "auto"}, "revision": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Revision", "default": "main"}, "use_fast": {"type": "boolean", "title": "Use Fast", "default": true}, "trust_remote_code": {"type": "boolean", "title": "Trust Remote Code", "default": false}, "torch_dtype": {"type": "string", "title": "Torch Dtype", "default": "auto"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "output_field": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Output Field", "default": "predictions"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "store_to_dataset": {"type": "boolean", "title": "Store To Dataset", "default": false}, "system_prompt": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "System Prompt", "description": "System prompt to use for the model inference.If not provided, a task-specific default prompt will be used.", "examples": ["You are an advanced AI trained to summarize documents accurately and concisely. Your goal is to extract key information while maintaining clarity and coherence."]}}, "type": "object", "required": ["model", "provider"], "title": "JobInferenceConfig"}, "JobInferenceCreate": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "dataset": {"type": "string", "format": "uuid", "title": "Dataset"}, "max_samples": {"type": "integer", "title": "Max Samples", "default": -1}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "job_config": {"$ref": "#/components/schemas/JobInferenceConfig"}}, "type": "object", "required": ["name", "dataset", "job_config"], "title": "JobInferenceCreate"}, "JobLogsResponse": {"properties": {"logs": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Logs"}}, "type": "object", "title": "JobLogsResponse"}, "JobResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "status": {"$ref": "#/components/schemas/JobStatus"}, "job_type": {"$ref": "#/components/schemas/JobType"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "experiment_id": {"anyOf": [{"type": "string", "format": "uuid"}, {"type": "null"}], "title": "Experiment Id"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["id", "name", "description", "status", "job_type", "created_at"], "title": "JobResponse"}, "JobResultDownloadResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "download_url": {"type": "string", "title": "Download Url"}}, "type": "object", "required": ["id", "download_url"], "title": "JobResultDownloadResponse"}, "JobResultResponse": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "job_id": {"type": "string", "format": "uuid", "title": "Job Id"}}, "type": "object", "required": ["id", "job_id"], "title": "JobResultResponse"}, "JobResults": {"properties": {"id": {"type": "string", "format": "uuid", "title": "Id"}, "metrics": {"anyOf": [{"items": {"type": "object"}, "type": "array"}, {"type": "null"}], "title": "Metrics"}, "parameters": {"anyOf": [{"items": {"type": "object"}, "type": "array"}, {"type": "null"}], "title": "Parameters"}, "metric_url": {"type": "string", "title": "Metric Url"}, "artifact_url": {"type": "string", "title": "Artifact Url"}}, "type": "object", "required": ["id", "metric_url", "artifact_url"], "title": "JobResults"}, "JobStatus": {"type": "string", "enum": ["created", "pending", "running", "failed", "succeeded", "stopped", "unrecoverable"], "title": "JobStatus"}, "JobType": {"type": "string", "enum": ["inference", "evaluator", "annotate"], "title": "JobType"}, "ListingResponse_DatasetResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/DatasetResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[DatasetResponse]"}, "ListingResponse_GetExperimentResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/GetExperimentResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[GetExperimentResponse]"}, "ListingResponse_Job_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/Job"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[Job]"}, "ListingResponse_ModelsResponse_": {"properties": {"total": {"type": "integer", "title": "Total"}, "items": {"items": {"$ref": "#/components/schemas/ModelsResponse"}, "type": "array", "title": "Items"}}, "type": "object", "required": ["total", "items"], "title": "ListingResponse[ModelsResponse]"}, "ModelInfo": {"properties": {"parameter_count": {"type": "string", "title": "Parameter Count"}, "tensor_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tensor Type"}, "model_size": {"type": "string", "title": "Model Size"}}, "type": "object", "required": ["parameter_count", "model_size"], "title": "ModelInfo"}, "ModelRequirement": {"type": "string", "enum": ["api_key", "llamafile"], "title": "ModelRequirement", "description": "Represents a type of requirement for a model"}, "ModelsResponse": {"properties": {"display_name": {"type": "string", "title": "Model name", "description": "Name of the model used in the task. It's just a display name"}, "model": {"type": "string", "title": "Model ID", "description": "Model ID used in the task"}, "provider": {"type": "string", "title": "Model Provider", "description": "LiteLLM key for where the model is hosted (e.g. `openai`, `deepseek`, `gpt3`, etc). If using a HF model that is hosted in the inference job, use `hf`"}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base URL", "description": "Base URL for the model API (if applicable, e.g. for Llamafile, vLLM, etc)"}, "website_url": {"type": "string", "title": "Information page URL", "description": "URI containing detailed information about the model"}, "description": {"type": "string", "title": "Model description", "description": "Detailed model description"}, "requirements": {"items": {"$ref": "#/components/schemas/ModelRequirement"}, "type": "array", "title": "Model requirements", "description": "Additional requirements that need to be fulfilled before using the model (e.g. `{ModelRequirement.LLAMAFILE}` to indicate that a llamafile needs to be running or `{ModelRequirement.API_KEY}` to indicate that an API key is necessary)"}, "info": {"anyOf": [{"$ref": "#/components/schemas/ModelInfo"}, {"type": "null"}], "title": "Model info", "description": "Detailed model capabilities"}, "tasks": {"items": {"additionalProperties": {"type": "object"}, "type": "object"}, "type": "array", "title": "Applicable tasks", "description": "List of tasks to which the model can be applied"}}, "type": "object", "required": ["display_name", "model", "provider", "website_url", "description", "tasks"], "title": "ModelsResponse", "description": "Contains detailed model information"}, "SecretGetRequest": {"properties": {"name": {"type": "string", "maxLength": 255, "minLength": 1, "title": "Name"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["name", "description"], "title": "SecretGetRequest", "description": "Represents the result of a get secret request.\n\nNOTE: The secret value should never be exposed to the end user."}, "SecretUploadRequest": {"properties": {"value": {"type": "string", "maxLength": 1024, "minLength": 1, "title": "Value"}, "description": {"type": "string", "title": "Description"}}, "type": "object", "required": ["value", "description"], "title": "SecretUploadRequest", "description": "Represents a secret upload request."}, "SummarizationTaskDefinition": {"properties": {"task": {"type": "string", "const": "summarization", "title": "Task", "default": "summarization"}}, "additionalProperties": false, "type": "object", "title": "SummarizationTaskDefinition"}, "TextGenerationTaskDefinition": {"properties": {"task": {"type": "string", "const": "text-generation", "title": "Task", "default": "text-generation"}}, "additionalProperties": false, "type": "object", "title": "TextGenerationTaskDefinition"}, "TranslationTaskDefinition": {"properties": {"task": {"type": "string", "const": "translation", "title": "Task", "default": "translation"}, "source_language": {"type": "string", "title": "Source Language", "examples": ["en", "English"]}, "target_language": {"type": "string", "title": "Target Language", "examples": ["de", "German"]}}, "additionalProperties": false, "type": "object", "required": ["source_language", "target_language"], "title": "TranslationTaskDefinition"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "WorkflowCreateRequest": {"properties": {"name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description", "default": ""}, "experiment_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "provider": {"type": "string", "title": "Provider"}, "secret_key_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Secret Key Name", "description": "An optional secret key name. Identifies an existing secret stored in Lumigator that should be used to access the provider."}, "batch_size": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Batch Size", "default": 1}, "base_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Base Url"}, "system_prompt": {"type": "string", "title": "System Prompt", "default": ""}, "inference_output_field": {"type": "string", "title": "Inference Output Field", "default": "predictions"}, "config_template": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Config Template"}, "generation_config": {"$ref": "#/components/schemas/GenerationConfig"}, "job_timeout_sec": {"type": "integer", "exclusiveMinimum": 0.0, "title": "Job Timeout Sec", "default": 3600}, "metrics": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Metrics"}}, "type": "object", "required": ["name", "model", "provider"], "title": "WorkflowCreateRequest"}, "WorkflowDetailsResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "experiment_id": {"type": "string", "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "system_prompt": {"type": "string", "title": "System Prompt"}, "status": {"$ref": "#/components/schemas/WorkflowStatus"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}, "jobs": {"anyOf": [{"items": {"$ref": "#/components/schemas/JobResults"}, "type": "array"}, {"type": "null"}], "title": "Jobs"}, "metrics": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Metrics"}, "parameters": {"anyOf": [{"type": "object"}, {"type": "null"}], "title": "Parameters"}, "artifacts_download_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Artifacts Download Url"}}, "type": "object", "required": ["id", "experiment_id", "model", "name", "description", "system_prompt", "status", "created_at"], "title": "WorkflowDetailsResponse"}, "WorkflowResponse": {"properties": {"id": {"type": "string", "title": "Id"}, "experiment_id": {"type": "string", "title": "Experiment Id"}, "model": {"type": "string", "title": "Model"}, "name": {"type": "string", "title": "Name"}, "description": {"type": "string", "title": "Description"}, "system_prompt": {"type": "string", "title": "System Prompt"}, "status": {"$ref": "#/components/schemas/WorkflowStatus"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "updated_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Updated At"}}, "type": "object", "required": ["id", "experiment_id", "model", "name", "description", "system_prompt", "status", "created_at"], "title": "WorkflowResponse"}, "WorkflowStatus": {"type": "string", "enum": ["created", "running", "failed", "succeeded"], "title": "WorkflowStatus"}}}} \ No newline at end of file diff --git a/lumigator/backend/backend/services/jobs.py b/lumigator/backend/backend/services/jobs.py index 64f5e4ed5..8792c3d8c 100644 --- a/lumigator/backend/backend/services/jobs.py +++ b/lumigator/backend/backend/services/jobs.py @@ -92,7 +92,12 @@ class JobService: """list: A list of non-terminal job statuses.""" # TODO: rely on https://github.com/ray-project/ray/blob/7c2a200ef84f17418666dad43017a82f782596a3/python/ray/dashboard/modules/job/common.py#L53 - TERMINAL_STATUS = [JobStatus.FAILED.value, JobStatus.SUCCEEDED.value, JobStatus.STOPPED.value] + TERMINAL_STATUS = [ + JobStatus.FAILED.value, + JobStatus.SUCCEEDED.value, + JobStatus.STOPPED.value, + JobStatus.UNRECOVERABLE.value, + ] """list: A list of terminal job statuses.""" SAFE_JOB_NAME_REGEX = re.compile(r"[^\w\-_.]") @@ -110,15 +115,15 @@ def __init__( secret_service: SecretService, background_tasks: BackgroundTasks, ): - self.job_repo = job_repo - self.result_repo = result_repo - self.ray_client = ray_client + self._job_repo = job_repo + self._result_repo = result_repo + self._ray_client = ray_client self._dataset_service = dataset_service self._secret_service = secret_service self._background_tasks = background_tasks def _get_job_record_per_type(self, job_type: str) -> list[JobRecord]: - records = self.job_repo.get_by_job_type(job_type) + records = self._job_repo.get_by_job_type(job_type) if records is None: return [] return records @@ -131,7 +136,7 @@ def _get_job_record(self, job_id: UUID) -> JobRecord: :rtype: JobRecord :raises JobNotFoundError: If the job does not exist """ - record = self.job_repo.get(job_id) + record = self._job_repo.get(job_id) if record is None: raise JobNotFoundError(job_id) from None @@ -182,7 +187,7 @@ def _update_job_record(self, job_id: UUID, **updates) -> JobRecord: :rtype: JobRecord :raises JobNotFoundError: If the job does not exist in the database """ - record = self.job_repo.update(job_id, **updates) + record = self._job_repo.update(job_id, **updates) if record is None: raise JobNotFoundError(job_id) from None @@ -312,18 +317,20 @@ def _validate_results(self, job_id: UUID, s3_file_system: S3FileSystem) -> JobRe def get_upstream_job_status(self, job_id: UUID) -> str: """Returns the (lowercase) status of the upstream job. - Example: PENDING, RUNNING, STOPPED, SUCCEEDED, FAILED. + Example: pending, running, stopped, succeeded, failed. :param job_id: The ID of the job to retrieve the status for. :return: The status of the upstream job. - :rtype: str - :raises JobUpstreamError: If there is an error with the upstream service returning the - job status + :raises JobNotFoundError: If the job cannot be found in the upstream service. + :raises JobUpstreamError: If there is an error with the upstream service returning the job status """ try: - status_response = self.ray_client.get_job_status(str(job_id)) + status_response = self._ray_client.get_job_status(str(job_id)) return str(status_response.value.lower()) except RuntimeError as e: + # See: https://github.com/ray-project/ray/blob/24ad12d81f8201859f2f00919929e00a750fa4d2/python/ray/dashboard/modules/dashboard_sdk.py#L282-L285 + if "status code 404" in str(e): + raise JobNotFoundError(job_id, "Job not found in upstream Ray service") from e raise JobUpstreamError("ray", "error getting Ray job status") from e def get_job_logs(self, job_id: UUID) -> JobLogsResponse: @@ -335,7 +342,7 @@ def get_job_logs(self, job_id: UUID) -> JobLogsResponse: :raises JobUpstreamError: If there is an error with the upstream service returning the job logs, and there are no logs currently persisted in Lumigator's storage. """ - job = self.job_repo.get(job_id) + job = self._job_repo.get(job_id) if not job: raise JobNotFoundError(job_id) from None @@ -456,7 +463,7 @@ def create_job( # Create a db record for the job # To find the experiment that a job belongs to, # we'd use https://mlflow.org/docs/latest/python_api/mlflow.client.html#mlflow.client.MlflowClient.search_runs - record = self.job_repo.create(name=request.name, description=request.description, job_type=job_type) + record = self._job_repo.create(name=request.name, description=request.description, job_type=job_type) job_result_storage_path = self._get_s3_uri(record.id) dataset_s3_path = self._dataset_service.get_dataset_s3_path(request.dataset) job_config = job_settings.generate_config(request, record.id, dataset_s3_path, job_result_storage_path) @@ -506,7 +513,7 @@ def create_job( num_gpus=settings.RAY_WORKER_GPUS, ) loguru.logger.info(f"Submitting {job_type} Ray job...") - submit_ray_job(self.ray_client, entrypoint) + submit_ray_job(self._ray_client, entrypoint) # NOTE: Only inference jobs can store results in a dataset atm. Among them: # - prediction jobs are run in a workflow before evaluations => they trigger dataset saving @@ -531,21 +538,26 @@ def get_job(self, job_id: UUID) -> JobResponse: :param job_id: the ID of the job to retrieve :return: the job record which includes information on whether a job belongs to an experiment :rtype: JobRecord - :raises JobNotFoundError: If the job does not exist + :raises JobNotFoundError: If the job does not exist in Lumigator. + :raises JobUpstreamError: If there is an error with the upstream service returning the latest job status. """ record = self._get_job_record(job_id) - loguru.logger.info(f"Obtaining info for job {job_id}: {record.name}") + loguru.logger.info(f"Obtained info for job ID: {job_id} name: {record.name}") + # If the job is finished (successfully or not), return the record. if record.status.value in self.TERMINAL_STATUS: return JobResponse.model_validate(record) - # get job status from ray - job_status = self.ray_client.get_job_status(job_id) - loguru.logger.info(f"Obtaining info from ray for job {job_id}: {job_status}") + # Attempt to get the latest job status from the upstream service. + try: + job_status = self.get_upstream_job_status(job_id) + except JobNotFoundError as e: + job_status = JobStatus.UNRECOVERABLE.value.lower() + loguru.logger.error(f"Job ID: {job_id} cannot be found in Ray, Using status: {job_status}", f"error: {e}") - # update job status in the DB if it differs from the current status - if job_status.lower() != record.status.value.lower(): - record = self._update_job_record(job_id, status=job_status.lower()) + # Update job status in the DB if it differs from the current status + if job_status != record.status.value.lower(): + record = self._update_job_record(job_id, status=job_status) return JobResponse.model_validate(record) @@ -558,7 +570,7 @@ def list_jobs( # It would be better if we could just feed an empty dict, # but this complicates things at the ORM level, # see https://docs.sqlalchemy.org/en/20/core/sqlelement.html#sqlalchemy.sql.expression.or_ - records = self.job_repo.list( + records = self._job_repo.list( skip, limit, criteria=[or_(*[JobRecord.job_type == job_type for job_type in job_types])], @@ -593,7 +605,7 @@ def get_job_result(self, job_id: UUID) -> JobResultResponse: :rtype: JobResultResponse :raises JobNotFoundError: if the job does not exist """ - result_record = self.result_repo.get_by_job_id(job_id) + result_record = self._result_repo.get_by_job_id(job_id) if result_record is None: raise JobNotFoundError(job_id) from None diff --git a/lumigator/backend/backend/tests/conftest.py b/lumigator/backend/backend/tests/conftest.py index 99973e376..12f500bab 100644 --- a/lumigator/backend/backend/tests/conftest.py +++ b/lumigator/backend/backend/tests/conftest.py @@ -1,9 +1,7 @@ import csv import io import json -import logging import os -import sys import time import uuid from collections.abc import Generator @@ -31,6 +29,7 @@ ) from lumigator_schemas.models import ModelsResponse from mlflow.entities import Metric, Param, Run, RunData, RunInfo, RunTag +from ray.dashboard.modules.job.sdk import JobSubmissionClient from s3fs import S3FileSystem from sqlalchemy import Engine, create_engine from sqlalchemy.orm import Session @@ -451,8 +450,18 @@ def job_record(db_session): @pytest.fixture(scope="function") -def job_service(db_session, job_repository, result_repository, dataset_service, secret_service, background_tasks): - return JobService(job_repository, result_repository, None, dataset_service, secret_service, background_tasks) +def fake_ray_client() -> JobSubmissionClient: + """Mocked Ray client for testing.""" + return MagicMock(spec=JobSubmissionClient) + + +@pytest.fixture(scope="function") +def job_service( + db_session, job_repository, result_repository, fake_ray_client, dataset_service, secret_service, background_tasks +): + return JobService( + job_repository, result_repository, fake_ray_client, dataset_service, secret_service, background_tasks + ) @pytest.fixture(scope="function") @@ -613,3 +622,9 @@ def fake_mlflow_run_deleted(): run_data = RunData(metrics={}, params={}, tags={}) return Run(run_info=run_info, run_data=run_data) + + +@pytest.fixture(scope="function") +def valid_job_id() -> UUID: + """Fixture that returns a random UUID.""" + return UUID("d34dbeef-4bea-4d19-ad06-214202165812") diff --git a/lumigator/backend/backend/tests/unit/services/test_job_service.py b/lumigator/backend/backend/tests/unit/services/test_job_service.py index 20d49a1c0..ae552763a 100644 --- a/lumigator/backend/backend/tests/unit/services/test_job_service.py +++ b/lumigator/backend/backend/tests/unit/services/test_job_service.py @@ -1,8 +1,10 @@ import json -from unittest.mock import patch +from unittest.mock import MagicMock, patch +from uuid import UUID import loguru import pytest +import requests_mock from lumigator_schemas.datasets import DatasetFormat from lumigator_schemas.jobs import ( JobCreate, @@ -10,12 +12,13 @@ JobType, ) from lumigator_schemas.secrets import SecretUploadRequest +from ray.dashboard.modules.job.common import JobStatus from ray.job_submission import JobSubmissionClient from backend.ray_submit.submission import RayJobEntrypoint -from backend.services.exceptions.job_exceptions import JobValidationError +from backend.services.exceptions.job_exceptions import JobNotFoundError, JobUpstreamError, JobValidationError from backend.services.exceptions.secret_exceptions import SecretNotFoundError -from backend.services.jobs import job_settings_map +from backend.services.jobs import JobService, job_settings_map from backend.settings import settings from backend.tests.conftest import TEST_SEQ2SEQ_MODEL @@ -152,3 +155,31 @@ def test_missing_api_key_in_job_creation( ): with pytest.raises(JobValidationError): job_service.create_job(request) + + +def test_get_upstream_job_status_success(job_service: JobService, valid_job_id: UUID): + # Mock the Ray client's get_job_status method to return a mock response + mock_job_status = MagicMock() + mock_job_status.value = "SUCCEEDED" + job_service._ray_client.get_job_status = MagicMock(return_value=mock_job_status) + status = job_service.get_upstream_job_status(valid_job_id) + assert status == "succeeded" + + +def test_get_upstream_job_status_job_not_found(job_service: JobService, valid_job_id: UUID): + """Test for job not found error (404).""" + # This is the current response from the Ray client when a job is not found. + job_service._ray_client.get_job_status.side_effect = RuntimeError( + "Request failed with status code 404: Job not found." + ) + + with pytest.raises(JobNotFoundError): + job_service.get_upstream_job_status(valid_job_id) + + +def test_get_upstream_job_status_other_error(job_service: JobService, valid_job_id: UUID): + """Test for any other error.""" + job_service._ray_client.get_job_status.side_effect = RuntimeError("Some other error occurred") + + with pytest.raises(JobUpstreamError): + job_service.get_upstream_job_status(valid_job_id) diff --git a/lumigator/frontend/src/components/datasets/LInferenceJobsTable.vue b/lumigator/frontend/src/components/datasets/LInferenceJobsTable.vue index 7f43aa3cc..22bdc5e21 100644 --- a/lumigator/frontend/src/components/datasets/LInferenceJobsTable.vue +++ b/lumigator/frontend/src/components/datasets/LInferenceJobsTable.vue @@ -26,14 +26,14 @@