Skip to content

Commit

Permalink
Merge pull request #3 from crane-cloud/ft-mlops-api
Browse files Browse the repository at this point in the history
feat: Integrate mlops api for experiments and runs
  • Loading branch information
Mubangizi authored Nov 22, 2024
2 parents 255cf38 + 0346e7b commit 15e37df
Show file tree
Hide file tree
Showing 8 changed files with 452 additions and 1 deletion.
239 changes: 239 additions & 0 deletions api_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,242 @@ paths:
description: "Apps not found"
500:
description: "Internal Server Error"

"/experiments":
get:
tags:
- experiments
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: query
name: name
type: string
description: Name of the experiment
responses:
200:
description: "Experiments got successfully"
404:
description: "Experiments not found"
500:
description: "Internal Server Error"

"/experiments/{experiment_id}":
patch:
tags:
- experiments
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: experiment_id
required: true
type: string
description: Experiment id
- in: body
name: user
schema:
properties:
name:
type: string
responses:
200:
description: "Experiment updated successfully"
404:
description: "Experiment not found"
400:
description: "Bad request"
500:
description: "Internal Server Error"

get:
tags:
- experiments
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: experiment_id
required: true
type: string
description: Experiment id
responses:
200:
description: "Experiment fetched successfully"
404:
description: "Experiment not found"
500:
description: "Internal Server Error"

delete:
tags:
- experiments
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: experiment_id
required: true
type: string
description: Experiment id

responses:
200:
description: "Success"
404:
description: "Experiment not found"
400:
description: "Bad request"
500:
description: "Internal Server Error"

"/experiments/{experiment_id}/runs":
get:
tags:
- experiments
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: experiment_id
required: true
type: string
description: Experiment id
- in: query
name: max_results
type: integer
description: Number or runs
responses:
200:
description: "Success"
404:
description: "No runs to retrieve"
400:
description: "Bad request"
500:
description: "Internal Server Error"

"/run/{run_id}":
get:
tags:
- runs
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: run_id
required: true
type: string
description: Run id
responses:
200:
description: "Success"
404:
description: "Run was not found"
400:
description: "Bad request"
500:
description: "Internal Server Error"
patch:
tags:
- runs
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: run_id
required: true
type: string
description: "Run id"
- in: body
name: user
schema:
properties:
run_name:
type: string
status:
type: string

responses:
200:
description: "Success"
404:
description: "Run was not found"
400:
description: "Bad request"
500:
description: "Internal Server Error"

delete:
tags:
- runs
consumes:
- application/json
produces:
- application/json
parameters:
- in: header
name: Authorization
required: true
description: "Bearer [token]"
type: string
- in: path
name: run_id
required: true
type: string
description: "Run id"

responses:
200:
description: "Success"
404:
description: "Run not found"
400:
description: "Bad request"
500:
description: "Internal Server Error"
3 changes: 3 additions & 0 deletions app/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from .index import (IndexView)
from .apps import (AppsView)
from .experiments import (
ExperimentRunsView, ExperimentView, ExperimenDetailView)
from .runs import (RunView)
113 changes: 113 additions & 0 deletions app/controllers/experiments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from app.helpers.authenticate import jwt_required
from mlflow.tracking import MlflowClient
from flask_restful import Resource, request
from app.schemas.experiments import ExperimentsSchema
import marshmallow
from types import SimpleNamespace


class ExperimentView(Resource):
def __init__(self):
self.client = MlflowClient("https://mlflow.renu-01.cranecloud.io")

@jwt_required
def get(self, current_user):
# Retrieve all experiments
name = request.args.get('name', None)
if name:
experiments = self.client.search_experiments(
filter_string=f"name LIKE '%{name}%'")
else:
experiments = self.client.search_experiments()

return {"status": "success", "data": [{"experiment_id": exp.experiment_id, "name": exp.name} for exp in experiments]}


class ExperimenDetailView(Resource):
def __init__(self):
self.client = MlflowClient("https://mlflow.renu-01.cranecloud.io")

@jwt_required
def get(self):
# Retrieve from the user's saved experiment ids
pass

@jwt_required
def get(self, experiment_id, current_user):
# Retrieve a single experiment by ID

try:
experiment = self.client.get_experiment(experiment_id)
return {
"status": "success",
"data": {
"experiment_id": experiment.experiment_id,
"name": experiment.name,
"artifact_location": experiment.artifact_location,
"lifecycle_stage": experiment.lifecycle_stage,
"tags": experiment.tags
}
}
except Exception as e:
return {"status": "error", "message": str(e)}, 404

@jwt_required
def patch(self, experiment_id, current_user):
# Update experiment details
experiments_schema = ExperimentsSchema()
try:
validated_data = experiments_schema.load(request.json)
except marshmallow.exceptions.ValidationError as e:
return dict(status="error", message=e.messages), 400

experiment_data = SimpleNamespace(**validated_data)

try:
if experiment_data.name:
self.client.rename_experiment(
experiment_id, experiment_data.name)
# if experiment_data.tags:
# self.client.set_experiment_tag(experiment_id, experiment_data.tags)

return {"status": "success", "message": "Experiment updated successfully"}
except Exception as e:
return {"status": "error", "message": str(e)}, 400

@jwt_required
def delete(self, experiment_id, current_user):
# Delete an experiment
try:
self.client.delete_experiment(experiment_id)
return {"status": "success", "message": "Experiment deleted successfully"}
except Exception as e:
return {"status": "error", "message": str(e)}, 400


class ExperimentRunsView(Resource):
def __init__(self):
self.client = MlflowClient("https://mlflow.renu-01.cranecloud.io")

@jwt_required
def get(self, experiment_id, current_user):
# Get all runs for an experiment
max_results = request.args.get('max_results', 100, type=int)

try:
runs = self.client.search_runs(
experiment_ids=[experiment_id],
max_results=max_results,
)
return {
"status": "success",
"data": [{
"run_id": run.info.run_id,
"status": run.info.status,
"start_time": run.info.start_time,
"end_time": run.info.end_time,
"metrics": run.data.metrics,
"params": run.data.params,
"tags": run.data.tags
} for run in runs]
}
except Exception as e:
return {"status": "error", "message": str(e)}, 404
Loading

0 comments on commit 15e37df

Please sign in to comment.