mirror of
https://github.com/clearml/clearml-server
synced 2025-06-25 22:05:48 +00:00
Add reports support
Fix schema
This commit is contained in:
parent
1ce4058157
commit
c7cd949fd0
@ -50,6 +50,9 @@
|
|||||||
130: ["task_not_found", "task not found"]
|
130: ["task_not_found", "task not found"]
|
||||||
131: ["events_not_added", "events not added"]
|
131: ["events_not_added", "events not added"]
|
||||||
|
|
||||||
|
# Reports
|
||||||
|
150: ["operation_supported_on_reports_only", "passed task is not report"]
|
||||||
|
|
||||||
# Models
|
# Models
|
||||||
200: ["model_error", "general task error"]
|
200: ["model_error", "general task error"]
|
||||||
201: ["invalid_model_id", "invalid model id"]
|
201: ["invalid_model_id", "invalid model id"]
|
||||||
|
70
apiserver/apimodels/reports.py
Normal file
70
apiserver/apimodels/reports.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from typing import Sequence
|
||||||
|
|
||||||
|
from jsonmodels import validators
|
||||||
|
from jsonmodels.fields import StringField, ListField, BoolField, EmbeddedField, IntField
|
||||||
|
from jsonmodels.models import Base
|
||||||
|
from jsonmodels.validators import Length
|
||||||
|
|
||||||
|
from apiserver.apimodels.events import MetricVariants, HistogramRequestBase
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
name = StringField(nullable=True, validators=Length(minimum_value=3))
|
||||||
|
tags = ListField(items_types=[str])
|
||||||
|
comment = StringField()
|
||||||
|
report = StringField()
|
||||||
|
|
||||||
|
|
||||||
|
class CreateReportRequest(Base):
|
||||||
|
name = StringField(required=True, validators=Length(minimum_value=3))
|
||||||
|
tags = ListField(items_types=[str])
|
||||||
|
comment = StringField()
|
||||||
|
report = StringField()
|
||||||
|
project = StringField()
|
||||||
|
|
||||||
|
|
||||||
|
class PublishReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
message = StringField(default="")
|
||||||
|
|
||||||
|
|
||||||
|
class ArchiveReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
message = StringField(default="")
|
||||||
|
|
||||||
|
|
||||||
|
class ShareReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
share = BoolField(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
force = BoolField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class MoveReportRequest(Base):
|
||||||
|
task = StringField(required=True)
|
||||||
|
project = StringField()
|
||||||
|
project_name = StringField()
|
||||||
|
|
||||||
|
|
||||||
|
class EventsRequest(Base):
|
||||||
|
iters = IntField(default=1, validators=validators.Min(1))
|
||||||
|
metrics: Sequence[MetricVariants] = ListField(items_types=MetricVariants)
|
||||||
|
|
||||||
|
|
||||||
|
class ScalarMetricsIterHistogram(HistogramRequestBase):
|
||||||
|
metrics: Sequence[MetricVariants] = ListField(items_types=MetricVariants)
|
||||||
|
|
||||||
|
|
||||||
|
class GetTasksDataRequest(Base):
|
||||||
|
debug_images: EventsRequest = EmbeddedField(EventsRequest)
|
||||||
|
plots: EventsRequest = EmbeddedField(EventsRequest)
|
||||||
|
scalar_metrics_iter_histogram: ScalarMetricsIterHistogram = EmbeddedField(ScalarMetricsIterHistogram)
|
||||||
|
allow_public = BoolField(default=True)
|
||||||
|
|
||||||
|
|
||||||
|
class GetAllRequest(Base):
|
||||||
|
allow_public = BoolField(default=True)
|
@ -766,10 +766,9 @@ class EventBLL(object):
|
|||||||
def get_task_events(
|
def get_task_events(
|
||||||
self,
|
self,
|
||||||
company_id: str,
|
company_id: str,
|
||||||
task_id: str,
|
task_id: Union[str, Sequence[str]],
|
||||||
event_type: EventType,
|
event_type: EventType,
|
||||||
metric=None,
|
metrics: MetricVariants = None,
|
||||||
variant=None,
|
|
||||||
last_iter_count=None,
|
last_iter_count=None,
|
||||||
sort=None,
|
sort=None,
|
||||||
size=500,
|
size=500,
|
||||||
@ -790,10 +789,8 @@ class EventBLL(object):
|
|||||||
task_ids = [task_id] if isinstance(task_id, str) else task_id
|
task_ids = [task_id] if isinstance(task_id, str) else task_id
|
||||||
|
|
||||||
must = []
|
must = []
|
||||||
if metric:
|
if metrics:
|
||||||
must.append({"term": {"metric": metric}})
|
must.append(get_metric_variants_condition(metrics))
|
||||||
if variant:
|
|
||||||
must.append({"term": {"variant": variant}})
|
|
||||||
|
|
||||||
if last_iter_count is None or model_events:
|
if last_iter_count is None or model_events:
|
||||||
must.append({"terms": {"task": task_ids}})
|
must.append({"terms": {"task": task_ids}})
|
||||||
|
@ -112,6 +112,7 @@ class EventMetrics:
|
|||||||
tasks: Sequence[Task],
|
tasks: Sequence[Task],
|
||||||
samples,
|
samples,
|
||||||
key: ScalarKeyEnum,
|
key: ScalarKeyEnum,
|
||||||
|
metric_variants: MetricVariants = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Compare scalar metrics for different tasks per metric and variant
|
Compare scalar metrics for different tasks per metric and variant
|
||||||
@ -128,6 +129,7 @@ class EventMetrics:
|
|||||||
event_type=event_type,
|
event_type=event_type,
|
||||||
samples=samples,
|
samples=samples,
|
||||||
key=ScalarKey.resolve(key),
|
key=ScalarKey.resolve(key),
|
||||||
|
metric_variants=metric_variants,
|
||||||
run_parallel=False,
|
run_parallel=False,
|
||||||
)
|
)
|
||||||
task_ids = [t.id for t in tasks]
|
task_ids = [t.id for t in tasks]
|
||||||
|
@ -128,13 +128,12 @@ class TaskBLL:
|
|||||||
return list(q)
|
return list(q)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(call: APICall, fields: dict):
|
def create(company: str, user: str, fields: dict):
|
||||||
identity = call.identity
|
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
return Task(
|
return Task(
|
||||||
id=create_id(),
|
id=create_id(),
|
||||||
user=identity.user,
|
user=user,
|
||||||
company=identity.company,
|
company=company,
|
||||||
created=now,
|
created=now,
|
||||||
last_update=now,
|
last_update=now,
|
||||||
last_change=now,
|
last_change=now,
|
||||||
|
@ -149,6 +149,7 @@ class TaskType(object):
|
|||||||
application = "application"
|
application = "application"
|
||||||
monitor = "monitor"
|
monitor = "monitor"
|
||||||
controller = "controller"
|
controller = "controller"
|
||||||
|
report = "report"
|
||||||
optimizer = "optimizer"
|
optimizer = "optimizer"
|
||||||
service = "service"
|
service = "service"
|
||||||
qc = "qc"
|
qc = "qc"
|
||||||
|
@ -15,6 +15,35 @@ metadata_item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
task_status_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
created
|
||||||
|
queued
|
||||||
|
in_progress
|
||||||
|
stopped
|
||||||
|
published
|
||||||
|
publishing
|
||||||
|
closed
|
||||||
|
failed
|
||||||
|
completed
|
||||||
|
unknown
|
||||||
|
]
|
||||||
|
}
|
||||||
|
multi_field_pattern_data {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
pattern {
|
||||||
|
description: "Pattern string (regex)"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
fields {
|
||||||
|
description: "List of field names"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
credentials {
|
credentials {
|
||||||
type: object
|
type: object
|
||||||
properties {
|
properties {
|
||||||
|
106
apiserver/schema/services/_events_common.conf
Normal file
106
apiserver/schema/services/_events_common.conf
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
scalar_key_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
iter
|
||||||
|
timestamp
|
||||||
|
iso_time
|
||||||
|
]
|
||||||
|
}
|
||||||
|
metric_variants {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
metric {
|
||||||
|
description: The metric name
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
variants {
|
||||||
|
type: array
|
||||||
|
description: The names of the metric variants
|
||||||
|
items {type: string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_images_response_task_metrics {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
type: string
|
||||||
|
description: Task ID
|
||||||
|
}
|
||||||
|
iterations {
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
iter {
|
||||||
|
type: integer
|
||||||
|
description: Iteration number
|
||||||
|
}
|
||||||
|
events {
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: object
|
||||||
|
description: Debug image event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_images_response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
scroll_id {
|
||||||
|
type: string
|
||||||
|
description: "Scroll ID for getting more results"
|
||||||
|
}
|
||||||
|
metrics {
|
||||||
|
type: array
|
||||||
|
description: "Debug image events grouped by tasks and iterations"
|
||||||
|
items {"$ref": "#/definitions/debug_images_response_task_metrics"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plots_response_task_metrics {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
type: string
|
||||||
|
description: Task ID
|
||||||
|
}
|
||||||
|
iterations {
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
iter {
|
||||||
|
type: integer
|
||||||
|
description: Iteration number
|
||||||
|
}
|
||||||
|
events {
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: object
|
||||||
|
description: Plot event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plots_response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
scroll_id {
|
||||||
|
type: string
|
||||||
|
description: "Scroll ID for getting more results"
|
||||||
|
}
|
||||||
|
metrics {
|
||||||
|
type: array
|
||||||
|
description: "Plot events grouped by tasks and iterations"
|
||||||
|
items {"$ref": "#/definitions/plots_response_task_metrics"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
498
apiserver/schema/services/_tasks_common.conf
Normal file
498
apiserver/schema/services/_tasks_common.conf
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
include "_common.conf"
|
||||||
|
task_type_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
training
|
||||||
|
testing
|
||||||
|
inference
|
||||||
|
data_processing
|
||||||
|
application
|
||||||
|
monitor
|
||||||
|
controller
|
||||||
|
optimizer
|
||||||
|
service
|
||||||
|
qc
|
||||||
|
custom
|
||||||
|
]
|
||||||
|
}
|
||||||
|
script {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
binary {
|
||||||
|
description: "Binary to use when running the script"
|
||||||
|
type: string
|
||||||
|
default: python
|
||||||
|
}
|
||||||
|
repository {
|
||||||
|
description: "Name of the repository where the script is located"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
tag {
|
||||||
|
description: "Repository tag"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
branch {
|
||||||
|
description: "Repository branch id If not provided and tag not provided, default repository branch is used."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
version_num {
|
||||||
|
description: "Version (changeset) number. Optional (default is head version) Unused if tag is provided."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
entry_point {
|
||||||
|
description: "Path to execute within the repository"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
working_dir {
|
||||||
|
description: "Path to the folder from which to run the script Default - root folder of repository"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
requirements {
|
||||||
|
description: "A JSON object containing requirements strings by key"
|
||||||
|
type: object
|
||||||
|
}
|
||||||
|
diff {
|
||||||
|
description: "Uncommitted changes found in the repository when task was run"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model_type_enum {
|
||||||
|
type: string
|
||||||
|
enum: ["input", "output"]
|
||||||
|
}
|
||||||
|
task_model_item {
|
||||||
|
type: object
|
||||||
|
required: [ name, model]
|
||||||
|
properties {
|
||||||
|
name {
|
||||||
|
description: "The task model name"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
model {
|
||||||
|
description: "The model ID"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
destination {
|
||||||
|
description: "Storage id. This is where output files will be stored."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
model {
|
||||||
|
description: "Model id."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
result {
|
||||||
|
description: "Task result. Values: 'success', 'failure'"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
error {
|
||||||
|
description: "Last error text"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task_execution_progress_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
unknown
|
||||||
|
running
|
||||||
|
stopping
|
||||||
|
stopped
|
||||||
|
]
|
||||||
|
}
|
||||||
|
artifact_type_data {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
preview {
|
||||||
|
description: "Description or textual data"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
content_type {
|
||||||
|
description: "System defined raw data content type"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
data_hash {
|
||||||
|
description: "Hash of raw data, without any headers or descriptive parts"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
artifact_mode_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
input
|
||||||
|
output
|
||||||
|
]
|
||||||
|
default: output
|
||||||
|
}
|
||||||
|
artifact {
|
||||||
|
type: object
|
||||||
|
required: [key, type]
|
||||||
|
properties {
|
||||||
|
key {
|
||||||
|
description: "Entry key"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
type {
|
||||||
|
description: "System defined type"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
mode {
|
||||||
|
description: "System defined input/output indication"
|
||||||
|
"$ref": "#/definitions/artifact_mode_enum"
|
||||||
|
}
|
||||||
|
uri {
|
||||||
|
description: "Raw data location"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
content_size {
|
||||||
|
description: "Raw data length in bytes"
|
||||||
|
type: integer
|
||||||
|
}
|
||||||
|
hash {
|
||||||
|
description: "Hash of entire raw data"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
timestamp {
|
||||||
|
description: "Epoch time when artifact was created"
|
||||||
|
type: integer
|
||||||
|
}
|
||||||
|
type_data {
|
||||||
|
description: "Additional fields defined by the system"
|
||||||
|
"$ref": "#/definitions/artifact_type_data"
|
||||||
|
}
|
||||||
|
display_data {
|
||||||
|
description: "User-defined list of key/value pairs, sorted"
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: string # can also be a number... TODO: upgrade the generator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
artifact_id {
|
||||||
|
type: object
|
||||||
|
required: [key]
|
||||||
|
properties {
|
||||||
|
key {
|
||||||
|
description: "Entry key"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
mode {
|
||||||
|
description: "System defined input/output indication"
|
||||||
|
"$ref": "#/definitions/artifact_mode_enum"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task_models {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
input {
|
||||||
|
description: "The list of task input models"
|
||||||
|
type: array
|
||||||
|
items {"$ref": "#/definitions/task_model_item"}
|
||||||
|
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
description: "The list of task output models"
|
||||||
|
type: array
|
||||||
|
items {"$ref": "#/definitions/task_model_item"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execution {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
queue {
|
||||||
|
description: "Queue ID where task was queued."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
parameters {
|
||||||
|
description: "Json object containing the Task parameters"
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
model {
|
||||||
|
description: "Execution input model ID Not applicable for Register (Import) tasks"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
model_desc {
|
||||||
|
description: "Json object representing the Model descriptors"
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
model_labels {
|
||||||
|
description: """Json object representing the ids of the labels in the model.
|
||||||
|
The keys are the layers' names and the values are the IDs.
|
||||||
|
Not applicable for Register (Import) tasks.
|
||||||
|
Mandatory for Training tasks"""
|
||||||
|
type: object
|
||||||
|
additionalProperties: { type: integer }
|
||||||
|
}
|
||||||
|
framework {
|
||||||
|
description: """Framework related to the task. Case insensitive. Mandatory for Training tasks. """
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
docker_cmd {
|
||||||
|
description: "Command for running docker script for the execution of the task"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
artifacts {
|
||||||
|
description: "Task artifacts"
|
||||||
|
type: array
|
||||||
|
items { "$ref": "#/definitions/artifact" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_metrics_event {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
metric {
|
||||||
|
description: "Metric name"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
variant {
|
||||||
|
description: "Variant name"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
value {
|
||||||
|
description: "Last value reported"
|
||||||
|
type: number
|
||||||
|
}
|
||||||
|
min_value {
|
||||||
|
description: "Minimum value reported"
|
||||||
|
type: number
|
||||||
|
}
|
||||||
|
max_value {
|
||||||
|
description: "Maximum value reported"
|
||||||
|
type: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_metrics_variants {
|
||||||
|
type: object
|
||||||
|
description: "Last metric events, one for each variant hash"
|
||||||
|
additionalProperties {
|
||||||
|
"$ref": "#/definitions/last_metrics_event"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params_item {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
section {
|
||||||
|
description: "Section that the parameter belongs to"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Name of the parameter. The combination of section and name should be unique"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
value {
|
||||||
|
description: "Value of the parameter"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
type {
|
||||||
|
description: "Type of the parameter. Optional"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
description {
|
||||||
|
description: "The parameter description. Optional"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configuration_item {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
name {
|
||||||
|
description: "Name of the parameter. Should be unique"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
value {
|
||||||
|
description: "Value of the parameter"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
type {
|
||||||
|
description: "Type of the parameter. Optional"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
description {
|
||||||
|
description: "The parameter description. Optional"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
section_params {
|
||||||
|
description: "Task section params"
|
||||||
|
type: object
|
||||||
|
additionalProperties {
|
||||||
|
"$ref": "#/definitions/params_item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
id {
|
||||||
|
description: "Task id"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Task Name"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
description: "Associated user id"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
company {
|
||||||
|
description: "Company ID"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
type {
|
||||||
|
description: "Type of task. Values: 'training', 'testing'"
|
||||||
|
"$ref": "#/definitions/task_type_enum"
|
||||||
|
}
|
||||||
|
status {
|
||||||
|
description: ""
|
||||||
|
"$ref": "#/definitions/task_status_enum"
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "Free text comment"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
created {
|
||||||
|
description: "Task creation time (UTC) "
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
started {
|
||||||
|
description: "Task start time (UTC)"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
completed {
|
||||||
|
description: "Task end time (UTC)"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
active_duration {
|
||||||
|
description: "Task duration time (seconds)"
|
||||||
|
type: integer
|
||||||
|
}
|
||||||
|
parent {
|
||||||
|
description: "Parent task id"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "Project ID of the project to which this task is assigned"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
description: "Task output params"
|
||||||
|
"$ref": "#/definitions/output"
|
||||||
|
}
|
||||||
|
execution {
|
||||||
|
description: "Task execution params"
|
||||||
|
"$ref": "#/definitions/execution"
|
||||||
|
}
|
||||||
|
container {
|
||||||
|
description: "Docker container parameters"
|
||||||
|
type: object
|
||||||
|
additionalProperties { type: [string, null] }
|
||||||
|
}
|
||||||
|
models {
|
||||||
|
description: "Task models"
|
||||||
|
"$ref": "#/definitions/task_models"
|
||||||
|
}
|
||||||
|
// TODO: will be removed
|
||||||
|
script {
|
||||||
|
description: "Script info"
|
||||||
|
"$ref": "#/definitions/script"
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "User-defined tags list"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
system_tags {
|
||||||
|
description: "System tags list. This field is reserved for system use, please don't use it."
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
status_changed {
|
||||||
|
description: "Last status change time"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
status_message {
|
||||||
|
description: "free text string representing info about the status"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
status_reason {
|
||||||
|
description: "Reason for last status change"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
published {
|
||||||
|
description: "Task publish time"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
last_worker {
|
||||||
|
description: "ID of last worker that handled the task"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
last_worker_report {
|
||||||
|
description: "Last time a worker reported while working on this task"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
last_update {
|
||||||
|
description: "Last time this task was created, edited, changed or events for this task were reported"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
last_change {
|
||||||
|
description: "Last time any update was done to the task"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
last_iteration {
|
||||||
|
description: "Last iteration reported for this task"
|
||||||
|
type: integer
|
||||||
|
}
|
||||||
|
last_metrics {
|
||||||
|
description: "Last metric variants (hash to events), one for each metric hash"
|
||||||
|
type: object
|
||||||
|
additionalProperties {
|
||||||
|
"$ref": "#/definitions/last_metrics_variants"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hyperparams {
|
||||||
|
description: "Task hyper params per section"
|
||||||
|
type: object
|
||||||
|
additionalProperties {
|
||||||
|
"$ref": "#/definitions/section_params"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configuration {
|
||||||
|
description: "Task configuration params"
|
||||||
|
type: object
|
||||||
|
additionalProperties {
|
||||||
|
"$ref": "#/definitions/configuration_item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtime {
|
||||||
|
description: "Task runtime mapping"
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,6 @@
|
|||||||
_description : "Provides an API for running tasks to report events collected by the system."
|
_description : "Provides an API for running tasks to report events collected by the system."
|
||||||
_definitions {
|
_definitions {
|
||||||
metric_variants {
|
include "_events_common.conf"
|
||||||
type: object
|
|
||||||
metric {
|
|
||||||
description: The metric name
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
variants {
|
|
||||||
type: array
|
|
||||||
description: The names of the metric variants
|
|
||||||
items {type: string}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
metrics_scalar_event {
|
metrics_scalar_event {
|
||||||
description: "Used for reporting scalar metrics during training task"
|
description: "Used for reporting scalar metrics during training task"
|
||||||
type: object
|
type: object
|
||||||
@ -164,14 +153,6 @@ _definitions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scalar_key_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
iter
|
|
||||||
timestamp
|
|
||||||
iso_time
|
|
||||||
]
|
|
||||||
}
|
|
||||||
log_level_enum {
|
log_level_enum {
|
||||||
type: string
|
type: string
|
||||||
enum: [
|
enum: [
|
||||||
@ -260,90 +241,6 @@ _definitions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_images_response_task_metrics {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
task {
|
|
||||||
type: string
|
|
||||||
description: Task ID
|
|
||||||
}
|
|
||||||
iterations {
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
iter {
|
|
||||||
type: integer
|
|
||||||
description: Iteration number
|
|
||||||
}
|
|
||||||
events {
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: object
|
|
||||||
description: Debug image event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_images_response {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
scroll_id {
|
|
||||||
type: string
|
|
||||||
description: "Scroll ID for getting more results"
|
|
||||||
}
|
|
||||||
metrics {
|
|
||||||
type: array
|
|
||||||
description: "Debug image events grouped by tasks and iterations"
|
|
||||||
items {"$ref": "#/definitions/debug_images_response_task_metrics"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
plots_response_task_metrics {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
task {
|
|
||||||
type: string
|
|
||||||
description: Task ID
|
|
||||||
}
|
|
||||||
iterations {
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
iter {
|
|
||||||
type: integer
|
|
||||||
description: Iteration number
|
|
||||||
}
|
|
||||||
events {
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: object
|
|
||||||
description: Plot event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
plots_response {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
scroll_id {
|
|
||||||
type: string
|
|
||||||
description: "Scroll ID for getting more results"
|
|
||||||
}
|
|
||||||
metrics {
|
|
||||||
type: array
|
|
||||||
description: "Plot events grouped by tasks and iterations"
|
|
||||||
items {"$ref": "#/definitions/plots_response_task_metrics"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debug_image_sample_response {
|
debug_image_sample_response {
|
||||||
type: object
|
type: object
|
||||||
properties {
|
properties {
|
||||||
@ -547,7 +444,7 @@ debug_images {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of results available for this query"
|
description: "Total number of results available for this query. In case there are more than 10000 results it is set to 10000"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -601,7 +498,7 @@ debug_images {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${debug_images."2.14"} {
|
"2.22": ${debug_images."2.14"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -624,7 +521,7 @@ plots {
|
|||||||
}
|
}
|
||||||
iters {
|
iters {
|
||||||
type: integer
|
type: integer
|
||||||
description: "Max number of latest iterations for which to return debug images"
|
description: "Max number of latest iterations for which to return plots"
|
||||||
}
|
}
|
||||||
navigate_earlier {
|
navigate_earlier {
|
||||||
type: boolean
|
type: boolean
|
||||||
@ -643,7 +540,7 @@ plots {
|
|||||||
response {"$ref": "#/definitions/plots_response"}
|
response {"$ref": "#/definitions/plots_response"}
|
||||||
}
|
}
|
||||||
"2.22": ${plots."2.20"} {
|
"2.22": ${plots."2.20"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model plots. Otherwise task plots
|
description: If set then the retrieving model plots. Otherwise task plots
|
||||||
default: false
|
default: false
|
||||||
@ -693,7 +590,7 @@ get_debug_image_sample {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_debug_image_sample."2.20"} {
|
"2.22": ${get_debug_image_sample."2.20"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model debug images. Otherwise task debug images
|
description: If set then the retrieving model debug images. Otherwise task debug images
|
||||||
default: false
|
default: false
|
||||||
@ -730,7 +627,7 @@ next_debug_image_sample {
|
|||||||
default: false
|
default: false
|
||||||
description: If set then navigate to the next/previous iteration
|
description: If set then navigate to the next/previous iteration
|
||||||
}
|
}
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model debug images. Otherwise task debug images
|
description: If set then the retrieving model debug images. Otherwise task debug images
|
||||||
default: false
|
default: false
|
||||||
@ -774,7 +671,7 @@ get_plot_sample {
|
|||||||
response {"$ref": "#/definitions/plot_sample_response"}
|
response {"$ref": "#/definitions/plot_sample_response"}
|
||||||
}
|
}
|
||||||
"2.22": ${get_plot_sample."2.20"} {
|
"2.22": ${get_plot_sample."2.20"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model plots. Otherwise task plots
|
description: If set then the retrieving model plots. Otherwise task plots
|
||||||
default: false
|
default: false
|
||||||
@ -811,7 +708,7 @@ next_plot_sample {
|
|||||||
default: false
|
default: false
|
||||||
description: If set then navigate to the next/previous iteration
|
description: If set then navigate to the next/previous iteration
|
||||||
}
|
}
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model plots. Otherwise task plots
|
description: If set then the retrieving model plots. Otherwise task plots
|
||||||
default: false
|
default: false
|
||||||
@ -850,7 +747,7 @@ get_task_metrics{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_task_metrics."2.7"} {
|
"2.22": ${get_task_metrics."2.7"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then get metrics from model events. Otherwise from task events
|
description: If set then get metrics from model events. Otherwise from task events
|
||||||
default: false
|
default: false
|
||||||
@ -955,7 +852,7 @@ get_task_log {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of results available for this query"
|
description: "Total number of results available for this query. In case there are more than 10000 results it is set to 10000"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -1009,7 +906,7 @@ get_task_log {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of log events available for this query"
|
description: "Total number of log events available for this query. In case there are more than 10000 events it is set to 10000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1064,7 +961,7 @@ get_task_events {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of results available for this query"
|
description: "Total number of results available for this query. In case there are more than 10000 results it is set to 10000"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -1074,7 +971,7 @@ get_task_events {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_task_events."2.1"} {
|
"2.22": ${get_task_events."2.1"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then get retrieving model events. Otherwise task events
|
description: If set then get retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1154,7 +1051,7 @@ get_task_plots {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of results available for this query"
|
description: "Total number of results available for this query. In case there are more than 10000 results it is set to 10000"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -1182,7 +1079,7 @@ get_task_plots {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_task_plots."2.16"} {
|
"2.22": ${get_task_plots."2.16"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1208,7 +1105,7 @@ get_multi_task_plots {
|
|||||||
}
|
}
|
||||||
iters {
|
iters {
|
||||||
type: integer
|
type: integer
|
||||||
description: "Max number of latest iterations for which to return debug images"
|
description: "Max number of latest iterations for which to return plots"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -1229,7 +1126,7 @@ get_multi_task_plots {
|
|||||||
}
|
}
|
||||||
total {
|
total {
|
||||||
type: number
|
type: number
|
||||||
description: "Total number of results available for this query"
|
description: "Total number of results available for this query. In case there are more than 10000 results it is set to 10000"
|
||||||
}
|
}
|
||||||
scroll_id {
|
scroll_id {
|
||||||
type: string
|
type: string
|
||||||
@ -1246,7 +1143,7 @@ get_multi_task_plots {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_multi_task_plots."2.16"} {
|
"2.22": ${get_multi_task_plots."2.16"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1281,7 +1178,7 @@ get_vector_metrics_and_variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_vector_metrics_and_variants."2.1"} {
|
"2.22": ${get_vector_metrics_and_variants."2.1"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1326,7 +1223,7 @@ vector_metrics_iter_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${vector_metrics_iter_histogram."2.1"} {
|
"2.22": ${vector_metrics_iter_histogram."2.1"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1386,7 +1283,7 @@ scalar_metrics_iter_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${scalar_metrics_iter_histogram."2.14"} {
|
"2.22": ${scalar_metrics_iter_histogram."2.14"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1403,7 +1300,7 @@ multi_task_scalar_metrics_iter_histogram {
|
|||||||
]
|
]
|
||||||
properties {
|
properties {
|
||||||
tasks {
|
tasks {
|
||||||
description: "List of task Task IDs. Maximum amount of tasks is 10"
|
description: "List of task Task IDs. Maximum amount of tasks is 100"
|
||||||
type: array
|
type: array
|
||||||
items {
|
items {
|
||||||
type: string
|
type: string
|
||||||
@ -1432,7 +1329,7 @@ multi_task_scalar_metrics_iter_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${multi_task_scalar_metrics_iter_histogram."2.1"} {
|
"2.22": ${multi_task_scalar_metrics_iter_histogram."2.1"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1488,7 +1385,7 @@ get_task_single_value_metrics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_task_single_value_metrics."2.20"} {
|
"2.22": ${get_task_single_value_metrics."2.20"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1574,7 +1471,7 @@ get_scalar_metrics_and_variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_scalar_metrics_and_variants."2.1"} {
|
"2.22": ${get_scalar_metrics_and_variants."2.1"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1630,7 +1527,7 @@ get_scalar_metric_data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${get_scalar_metric_data."2.16"} {
|
"2.22": ${get_scalar_metric_data."2.16"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1701,7 +1598,7 @@ scalar_metrics_iter_raw {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"2.22": ${scalar_metrics_iter_raw."2.16"} {
|
"2.22": ${scalar_metrics_iter_raw."2.16"} {
|
||||||
model_events {
|
request.properties.model_events {
|
||||||
type: boolean
|
type: boolean
|
||||||
description: If set then the retrieving model events. Otherwise task events
|
description: If set then the retrieving model events. Otherwise task events
|
||||||
default: false
|
default: false
|
||||||
@ -1762,4 +1659,4 @@ clear_task_log {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
686
apiserver/schema/services/reports.conf
Normal file
686
apiserver/schema/services/reports.conf
Normal file
@ -0,0 +1,686 @@
|
|||||||
|
_description: "Provides a management API for reports in the system."
|
||||||
|
_definitions {
|
||||||
|
include "_tasks_common.conf"
|
||||||
|
include "_events_common.conf"
|
||||||
|
update_response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
updated {
|
||||||
|
description: "Number of reports updated (0 or 1)"
|
||||||
|
type: integer
|
||||||
|
enum: [ 0, 1 ]
|
||||||
|
}
|
||||||
|
fields {
|
||||||
|
description: "Updated fields names and values"
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
report_status_enum {
|
||||||
|
type: string
|
||||||
|
enum: [
|
||||||
|
created
|
||||||
|
published
|
||||||
|
]
|
||||||
|
}
|
||||||
|
report {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
id {
|
||||||
|
description: "Report id"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Report Name"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
description: "Associated user id"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
company {
|
||||||
|
description: "Company ID"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
status {
|
||||||
|
description: ""
|
||||||
|
"$ref": "#/definitions/report_status_enum"
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "Free text comment"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
report {
|
||||||
|
description: "Report template"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
created {
|
||||||
|
description: "Report creation time (UTC) "
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "Project ID of the project to which this report is assigned"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "User-defined tags list"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
system_tags {
|
||||||
|
description: "System tags list. This field is reserved for system use, please don't use it."
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
status_changed {
|
||||||
|
description: "Last status change time"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
status_message {
|
||||||
|
description: "free text string representing info about the status"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
status_reason {
|
||||||
|
description: "Reason for last status change"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
published {
|
||||||
|
description: "Report publish time"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
last_update {
|
||||||
|
description: "Last time this report was created, edited, changed"
|
||||||
|
type: string
|
||||||
|
format: "date-time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create {
|
||||||
|
"999.0" {
|
||||||
|
description: "Create a new report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
name
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
name {
|
||||||
|
description: "Report name. Unique within the company."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "User-defined tags list"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "Free text comment "
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
report {
|
||||||
|
description: "Report template"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "Project ID of the project to which this report is assigned Must exist[ab]"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
id {
|
||||||
|
description: "ID of the report"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update {
|
||||||
|
"999.0" {
|
||||||
|
description: "Create a new report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
task
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "The ID of the report task to update"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Report name. Unique within the company."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "User-defined tags list"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "Free text comment "
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
report {
|
||||||
|
description: "Report template"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response: ${_definitions.update_response}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
move {
|
||||||
|
"999.0" {
|
||||||
|
description: "Move reports to a project"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [task]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "ID of the report to move"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "Target project ID. If not provided, `project_name` must be provided."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
project_name {
|
||||||
|
description: "Target project name. If provided and a project with this name does not exist, a new project will be created. If not provided, `project` must be provided."
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
project_id: {
|
||||||
|
description: The ID of the target project
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publish {
|
||||||
|
"999.0" {
|
||||||
|
description: "Publish report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
task
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "The ID of the report task to publish"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "The client message"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response: ${_definitions.update_response}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
archive {
|
||||||
|
"999.0" {
|
||||||
|
description: "Archive report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
task
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "The ID of the report task to archive"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "The client message"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
archived {
|
||||||
|
description: "Number of reports archived (0 or 1)"
|
||||||
|
type: integer
|
||||||
|
enum: [0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unarchive {
|
||||||
|
"999.0" {
|
||||||
|
description: "Unarchive report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
task
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "The ID of the report task to unarchive"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
description: "The client message"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
unarchived {
|
||||||
|
description: "Number of reports unarchived (0 or 1)"
|
||||||
|
type: integer
|
||||||
|
enum: [0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//share {
|
||||||
|
// "999.0" {
|
||||||
|
// description: "Share or unshare report"
|
||||||
|
// request {
|
||||||
|
// type: object
|
||||||
|
// required: [
|
||||||
|
// task
|
||||||
|
// ]
|
||||||
|
// properties {
|
||||||
|
// task {
|
||||||
|
// description: "The ID of the report task to share/unshare"
|
||||||
|
// type: string
|
||||||
|
// }
|
||||||
|
// share {
|
||||||
|
// description: "If set to 'true' then the report will be shared. Otherwise unshared."
|
||||||
|
// type: boolean
|
||||||
|
// default: true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// response {
|
||||||
|
// type: object
|
||||||
|
// properties {
|
||||||
|
// changed {
|
||||||
|
// description: "Number of changed reports (0 or 1)"
|
||||||
|
// type: integer
|
||||||
|
// enum: [0, 1]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
delete {
|
||||||
|
"999.0" {
|
||||||
|
description: "Delete report"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
required: [
|
||||||
|
task
|
||||||
|
]
|
||||||
|
properties {
|
||||||
|
task {
|
||||||
|
description: "The ID of the report task to delete"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
force {
|
||||||
|
description: "If not set then published or unarchived reports cannot be deleted"
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
deleted {
|
||||||
|
description: "Number of deleted reports (0 or 1)"
|
||||||
|
type: integer
|
||||||
|
enum: [0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_task_data {
|
||||||
|
"999.0" {
|
||||||
|
description: "Get the tasks data according the passed search criteria + requested events"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
id {
|
||||||
|
description: "List of IDs to filter by"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Get only tasks whose name matches this pattern (python regular expression syntax)"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
description: "List of user IDs used to filter results by the task's creating user"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
description: "The number of tasks to retrieve"
|
||||||
|
}
|
||||||
|
order_by {
|
||||||
|
description: "List of field names to order by. When search_text is used, '@text_score' can be used as a field representing the text score of returned documents. Use '-' prefix to specify descending order. Optional, recommended when using page"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
type {
|
||||||
|
description: "List of task types. One or more of: 'import', 'annotation', 'training' or 'testing' (case insensitive)"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "List of task user-defined tags. Use '-' prefix to exclude tags"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
system_tags {
|
||||||
|
description: "List of task system tags. Use '-' prefix to exclude system tags"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
status {
|
||||||
|
description: "List of task status."
|
||||||
|
type: array
|
||||||
|
items { "$ref": "#/definitions/task_status_enum" }
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "List of project IDs"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
only_fields {
|
||||||
|
description: "List of task field names (nesting is supported using '.', e.g. execution.model_labels). If provided, this list defines the query's projection (only these fields will be returned for each result entry)"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
parent {
|
||||||
|
description: "Parent ID"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
status_changed {
|
||||||
|
description: "List of status changed constraint strings (utcformat, epoch) with an optional prefix modifier (>, >=, <, <=)"
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: string
|
||||||
|
pattern: "^(>=|>|<=|<)?.*$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
search_text {
|
||||||
|
description: "Free text search query"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
allow_public {
|
||||||
|
description: "Allow public tasks to be returned in the results"
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
_all_ {
|
||||||
|
description: "Multi-field pattern condition (all fields match pattern)"
|
||||||
|
"$ref": "#/definitions/multi_field_pattern_data"
|
||||||
|
}
|
||||||
|
_any_ {
|
||||||
|
description: "Multi-field pattern condition (any field matches pattern)"
|
||||||
|
"$ref": "#/definitions/multi_field_pattern_data"
|
||||||
|
}
|
||||||
|
"input.view.entries.dataset" {
|
||||||
|
description: "List of input dataset IDs"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
"input.view.entries.version" {
|
||||||
|
description: "List of input dataset version IDs"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
search_hidden {
|
||||||
|
description: "If set to 'true' then hidden tasks are included in the search results"
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
include_subprojects {
|
||||||
|
description: "If set to 'true' and project field is set then tasks from the subprojects are searched too"
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
plots {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
iters {
|
||||||
|
type: integer
|
||||||
|
description: "Max number of latest iterations for which to return plots"
|
||||||
|
}
|
||||||
|
metrics {
|
||||||
|
type: array
|
||||||
|
description: List of metrics and variants
|
||||||
|
items { "$ref": "#/definitions/metric_variants" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_images {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
iters {
|
||||||
|
type: integer
|
||||||
|
description: "Max number of latest iterations for which to return debug images"
|
||||||
|
}
|
||||||
|
metrics {
|
||||||
|
type: array
|
||||||
|
description: List of metrics and variants
|
||||||
|
items { "$ref": "#/definitions/metric_variants" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scalar_metrics_iter_histogram {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
samples {
|
||||||
|
description: "The amount of histogram points to return (0 to return all the points). Optional, the default value is 6000."
|
||||||
|
type: integer
|
||||||
|
}
|
||||||
|
key {
|
||||||
|
description: """
|
||||||
|
Histogram x axis to use:
|
||||||
|
iter - iteration number
|
||||||
|
iso_time - event time as ISO formatted string
|
||||||
|
timestamp - event timestamp as milliseconds since epoch
|
||||||
|
"""
|
||||||
|
"$ref": "#/definitions/scalar_key_enum"
|
||||||
|
}
|
||||||
|
metrics {
|
||||||
|
type: array
|
||||||
|
description: List of metrics and variants
|
||||||
|
items { "$ref": "#/definitions/metric_variants" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
tasks {
|
||||||
|
description: "List of tasks"
|
||||||
|
type: array
|
||||||
|
items { "$ref": "#/definitions/task" }
|
||||||
|
}
|
||||||
|
plots {
|
||||||
|
type: object
|
||||||
|
description: "Plots mapped by metric, variant, task and iteration"
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
debug_images {
|
||||||
|
type: array
|
||||||
|
description: "Debug image events grouped by tasks and iterations"
|
||||||
|
items {"$ref": "#/definitions/debug_images_response_task_metrics"}
|
||||||
|
}
|
||||||
|
scalar_metrics_iter_histogram {
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_all_ex {
|
||||||
|
"999.0" {
|
||||||
|
description: "Get all the company's and public report tasks"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
id {
|
||||||
|
description: "List of IDs to filter by"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
name {
|
||||||
|
description: "Get only reports whose name matches this pattern (python regular expression syntax)"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
user {
|
||||||
|
description: "List of user IDs used to filter results by the reports's creating user"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
page {
|
||||||
|
description: "Page number, returns a specific page out of the resulting list of reports"
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
}
|
||||||
|
page_size {
|
||||||
|
description: "Page size, specifies the number of results returned in each page (last page may contain fewer results)"
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
}
|
||||||
|
order_by {
|
||||||
|
description: "List of field names to order by. When search_text is used, '@text_score' can be used as a field representing the text score of returned documents. Use '-' prefix to specify descending order. Optional, recommended when using page"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
description: "List of report user-defined tags. Use '-' prefix to exclude tags"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
system_tags {
|
||||||
|
description: "List of report system tags. Use '-' prefix to exclude system tags"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
status {
|
||||||
|
description: "List of report status."
|
||||||
|
type: array
|
||||||
|
items { "$ref": "#/definitions/report_status_enum" }
|
||||||
|
}
|
||||||
|
project {
|
||||||
|
description: "List of project IDs"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
only_fields {
|
||||||
|
description: "List of report field names (nesting is supported using '.'). If provided, this list defines the query's projection (only these fields will be returned for each result entry)"
|
||||||
|
type: array
|
||||||
|
items { type: string }
|
||||||
|
}
|
||||||
|
status_changed {
|
||||||
|
description: "List of status changed constraint strings (utcformat, epoch) with an optional prefix modifier (>, >=, <, <=)"
|
||||||
|
type: array
|
||||||
|
items {
|
||||||
|
type: string
|
||||||
|
pattern: "^(>=|>|<=|<)?.*$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
search_text {
|
||||||
|
description: "Free text search query"
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
scroll_id {
|
||||||
|
type: string
|
||||||
|
description: "Scroll ID returned from the previos calls to get_all"
|
||||||
|
}
|
||||||
|
refresh_scroll {
|
||||||
|
type: boolean
|
||||||
|
description: "If set then all the data received with this scroll will be requeried"
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
description: "The number of tasks to retrieve"
|
||||||
|
}
|
||||||
|
allow_public {
|
||||||
|
description: "Allow public reports to be returned in the results"
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
_all_ {
|
||||||
|
description: "Multi-field pattern condition (all fields match pattern)"
|
||||||
|
"$ref": "#/definitions/multi_field_pattern_data"
|
||||||
|
}
|
||||||
|
_any_ {
|
||||||
|
description: "Multi-field pattern condition (any field matches pattern)"
|
||||||
|
"$ref": "#/definitions/multi_field_pattern_data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
page: [ page_size ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
tasks {
|
||||||
|
description: "List of report tasks"
|
||||||
|
type: array
|
||||||
|
items { "$ref": "#/definitions/report" }
|
||||||
|
}
|
||||||
|
scroll_id {
|
||||||
|
type: string
|
||||||
|
description: "Scroll ID that can be used with the next calls to get_all to retrieve more data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_tags {
|
||||||
|
"999.0" {
|
||||||
|
description: "Get all the user tags used for the company reports"
|
||||||
|
request {
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
}
|
||||||
|
response {
|
||||||
|
type: object
|
||||||
|
properties {
|
||||||
|
tags {
|
||||||
|
description: "The list of unique tag values"
|
||||||
|
type: array
|
||||||
|
items {type: string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ _references {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_definitions {
|
_definitions {
|
||||||
include "_common.conf"
|
include "_tasks_common.conf"
|
||||||
change_many_request: ${_definitions.batch_operation} {
|
change_many_request: ${_definitions.batch_operation} {
|
||||||
request {
|
request {
|
||||||
properties {
|
properties {
|
||||||
@ -69,374 +69,6 @@ _definitions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
multi_field_pattern_data {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
pattern {
|
|
||||||
description: "Pattern string (regex)"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
fields {
|
|
||||||
description: "List of field names"
|
|
||||||
type: array
|
|
||||||
items { type: string }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model_type_enum {
|
|
||||||
type: string
|
|
||||||
enum: ["input", "output"]
|
|
||||||
}
|
|
||||||
task_model_item {
|
|
||||||
type: object
|
|
||||||
required: [ name, model]
|
|
||||||
properties {
|
|
||||||
name {
|
|
||||||
description: "The task model name"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
model {
|
|
||||||
description: "The model ID"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
script {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
binary {
|
|
||||||
description: "Binary to use when running the script"
|
|
||||||
type: string
|
|
||||||
default: python
|
|
||||||
}
|
|
||||||
repository {
|
|
||||||
description: "Name of the repository where the script is located"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
tag {
|
|
||||||
description: "Repository tag"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
branch {
|
|
||||||
description: "Repository branch id If not provided and tag not provided, default repository branch is used."
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
version_num {
|
|
||||||
description: "Version (changeset) number. Optional (default is head version) Unused if tag is provided."
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
entry_point {
|
|
||||||
description: "Path to execute within the repository"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
working_dir {
|
|
||||||
description: "Path to the folder from which to run the script Default - root folder of repository"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
requirements {
|
|
||||||
description: "A JSON object containing requirements strings by key"
|
|
||||||
type: object
|
|
||||||
}
|
|
||||||
diff {
|
|
||||||
description: "Uncommitted changes found in the repository when task was run"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
destination {
|
|
||||||
description: "Storage id. This is where output files will be stored."
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
model {
|
|
||||||
description: "Model id."
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
result {
|
|
||||||
description: "Task result. Values: 'success', 'failure'"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
error {
|
|
||||||
description: "Last error text"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task_execution_progress_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
unknown
|
|
||||||
running
|
|
||||||
stopping
|
|
||||||
stopped
|
|
||||||
]
|
|
||||||
}
|
|
||||||
output_rois_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
all_in_frame
|
|
||||||
only_filtered
|
|
||||||
frame_per_roi
|
|
||||||
]
|
|
||||||
}
|
|
||||||
artifact_type_data {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
preview {
|
|
||||||
description: "Description or textual data"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
content_type {
|
|
||||||
description: "System defined raw data content type"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
data_hash {
|
|
||||||
description: "Hash of raw data, without any headers or descriptive parts"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
artifact_mode_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
input
|
|
||||||
output
|
|
||||||
]
|
|
||||||
default: output
|
|
||||||
}
|
|
||||||
artifact {
|
|
||||||
type: object
|
|
||||||
required: [key, type]
|
|
||||||
properties {
|
|
||||||
key {
|
|
||||||
description: "Entry key"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
type {
|
|
||||||
description: "System defined type"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
mode {
|
|
||||||
description: "System defined input/output indication"
|
|
||||||
"$ref": "#/definitions/artifact_mode_enum"
|
|
||||||
}
|
|
||||||
uri {
|
|
||||||
description: "Raw data location"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
content_size {
|
|
||||||
description: "Raw data length in bytes"
|
|
||||||
type: integer
|
|
||||||
}
|
|
||||||
hash {
|
|
||||||
description: "Hash of entire raw data"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
timestamp {
|
|
||||||
description: "Epoch time when artifact was created"
|
|
||||||
type: integer
|
|
||||||
}
|
|
||||||
type_data {
|
|
||||||
description: "Additional fields defined by the system"
|
|
||||||
"$ref": "#/definitions/artifact_type_data"
|
|
||||||
}
|
|
||||||
display_data {
|
|
||||||
description: "User-defined list of key/value pairs, sorted"
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: array
|
|
||||||
items {
|
|
||||||
type: string # can also be a number... TODO: upgrade the generator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
artifact_id {
|
|
||||||
type: object
|
|
||||||
required: [key]
|
|
||||||
properties {
|
|
||||||
key {
|
|
||||||
description: "Entry key"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
mode {
|
|
||||||
description: "System defined input/output indication"
|
|
||||||
"$ref": "#/definitions/artifact_mode_enum"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task_models {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
input {
|
|
||||||
description: "The list of task input models"
|
|
||||||
type: array
|
|
||||||
items {"$ref": "#/definitions/task_model_item"}
|
|
||||||
|
|
||||||
}
|
|
||||||
output {
|
|
||||||
description: "The list of task output models"
|
|
||||||
type: array
|
|
||||||
items {"$ref": "#/definitions/task_model_item"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
execution {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
queue {
|
|
||||||
description: "Queue ID where task was queued."
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
parameters {
|
|
||||||
description: "Json object containing the Task parameters"
|
|
||||||
type: object
|
|
||||||
additionalProperties: true
|
|
||||||
}
|
|
||||||
model {
|
|
||||||
description: "Execution input model ID Not applicable for Register (Import) tasks"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
model_desc {
|
|
||||||
description: "Json object representing the Model descriptors"
|
|
||||||
type: object
|
|
||||||
additionalProperties: true
|
|
||||||
}
|
|
||||||
model_labels {
|
|
||||||
description: """Json object representing the ids of the labels in the model.
|
|
||||||
The keys are the layers' names and the values are the IDs.
|
|
||||||
Not applicable for Register (Import) tasks.
|
|
||||||
Mandatory for Training tasks"""
|
|
||||||
type: object
|
|
||||||
additionalProperties: { type: integer }
|
|
||||||
}
|
|
||||||
framework {
|
|
||||||
description: """Framework related to the task. Case insensitive. Mandatory for Training tasks. """
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
docker_cmd {
|
|
||||||
description: "Command for running docker script for the execution of the task"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
artifacts {
|
|
||||||
description: "Task artifacts"
|
|
||||||
type: array
|
|
||||||
items { "$ref": "#/definitions/artifact" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task_status_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
created
|
|
||||||
queued
|
|
||||||
in_progress
|
|
||||||
stopped
|
|
||||||
published
|
|
||||||
publishing
|
|
||||||
closed
|
|
||||||
failed
|
|
||||||
completed
|
|
||||||
unknown
|
|
||||||
]
|
|
||||||
}
|
|
||||||
task_type_enum {
|
|
||||||
type: string
|
|
||||||
enum: [
|
|
||||||
training
|
|
||||||
testing
|
|
||||||
inference
|
|
||||||
data_processing
|
|
||||||
application
|
|
||||||
monitor
|
|
||||||
controller
|
|
||||||
optimizer
|
|
||||||
service
|
|
||||||
qc
|
|
||||||
custom
|
|
||||||
]
|
|
||||||
}
|
|
||||||
last_metrics_event {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
metric {
|
|
||||||
description: "Metric name"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
variant {
|
|
||||||
description: "Variant name"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
value {
|
|
||||||
description: "Last value reported"
|
|
||||||
type: number
|
|
||||||
}
|
|
||||||
min_value {
|
|
||||||
description: "Minimum value reported"
|
|
||||||
type: number
|
|
||||||
}
|
|
||||||
max_value {
|
|
||||||
description: "Maximum value reported"
|
|
||||||
type: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_metrics_variants {
|
|
||||||
type: object
|
|
||||||
description: "Last metric events, one for each variant hash"
|
|
||||||
additionalProperties {
|
|
||||||
"$ref": "#/definitions/last_metrics_event"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params_item {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
section {
|
|
||||||
description: "Section that the parameter belongs to"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
name {
|
|
||||||
description: "Name of the parameter. The combination of section and name should be unique"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
value {
|
|
||||||
description: "Value of the parameter"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
type {
|
|
||||||
description: "Type of the parameter. Optional"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
description {
|
|
||||||
description: "The parameter description. Optional"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configuration_item {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
name {
|
|
||||||
description: "Name of the parameter. Should be unique"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
value {
|
|
||||||
description: "Value of the parameter"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
type {
|
|
||||||
description: "Type of the parameter. Optional"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
description {
|
|
||||||
description: "The parameter description. Optional"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
param_key {
|
param_key {
|
||||||
type: object
|
type: object
|
||||||
properties {
|
properties {
|
||||||
@ -450,13 +82,6 @@ _definitions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
section_params {
|
|
||||||
description: "Task section params"
|
|
||||||
type: object
|
|
||||||
additionalProperties {
|
|
||||||
"$ref": "#/definitions/params_item"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
replace_hyperparams_enum {
|
replace_hyperparams_enum {
|
||||||
type: string
|
type: string
|
||||||
enum: [
|
enum: [
|
||||||
@ -465,165 +90,6 @@ _definitions {
|
|||||||
all
|
all
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
task {
|
|
||||||
type: object
|
|
||||||
properties {
|
|
||||||
id {
|
|
||||||
description: "Task id"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
name {
|
|
||||||
description: "Task Name"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
user {
|
|
||||||
description: "Associated user id"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
company {
|
|
||||||
description: "Company ID"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
type {
|
|
||||||
description: "Type of task. Values: 'training', 'testing'"
|
|
||||||
"$ref": "#/definitions/task_type_enum"
|
|
||||||
}
|
|
||||||
status {
|
|
||||||
description: ""
|
|
||||||
"$ref": "#/definitions/task_status_enum"
|
|
||||||
}
|
|
||||||
comment {
|
|
||||||
description: "Free text comment"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
created {
|
|
||||||
description: "Task creation time (UTC) "
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
started {
|
|
||||||
description: "Task start time (UTC)"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
completed {
|
|
||||||
description: "Task end time (UTC)"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
active_duration {
|
|
||||||
description: "Task duration time (seconds)"
|
|
||||||
type: integer
|
|
||||||
}
|
|
||||||
parent {
|
|
||||||
description: "Parent task id"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
project {
|
|
||||||
description: "Project ID of the project to which this task is assigned"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
output {
|
|
||||||
description: "Task output params"
|
|
||||||
"$ref": "#/definitions/output"
|
|
||||||
}
|
|
||||||
execution {
|
|
||||||
description: "Task execution params"
|
|
||||||
"$ref": "#/definitions/execution"
|
|
||||||
}
|
|
||||||
container {
|
|
||||||
description: "Docker container parameters"
|
|
||||||
type: object
|
|
||||||
additionalProperties { type: [string, null] }
|
|
||||||
}
|
|
||||||
models {
|
|
||||||
description: "Task models"
|
|
||||||
"$ref": "#/definitions/task_models"
|
|
||||||
}
|
|
||||||
// TODO: will be removed
|
|
||||||
script {
|
|
||||||
description: "Script info"
|
|
||||||
"$ref": "#/definitions/script"
|
|
||||||
}
|
|
||||||
tags {
|
|
||||||
description: "User-defined tags list"
|
|
||||||
type: array
|
|
||||||
items { type: string }
|
|
||||||
}
|
|
||||||
system_tags {
|
|
||||||
description: "System tags list. This field is reserved for system use, please don't use it."
|
|
||||||
type: array
|
|
||||||
items { type: string }
|
|
||||||
}
|
|
||||||
status_changed {
|
|
||||||
description: "Last status change time"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
status_message {
|
|
||||||
description: "free text string representing info about the status"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
status_reason {
|
|
||||||
description: "Reason for last status change"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
published {
|
|
||||||
description: "Last status change time"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
last_worker {
|
|
||||||
description: "ID of last worker that handled the task"
|
|
||||||
type: string
|
|
||||||
}
|
|
||||||
last_worker_report {
|
|
||||||
description: "Last time a worker reported while working on this task"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
last_update {
|
|
||||||
description: "Last time this task was created, updated, changed or events for this task were reported"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
last_change {
|
|
||||||
description: "Last time any update was done to the task"
|
|
||||||
type: string
|
|
||||||
format: "date-time"
|
|
||||||
}
|
|
||||||
last_iteration {
|
|
||||||
description: "Last iteration reported for this task"
|
|
||||||
type: integer
|
|
||||||
}
|
|
||||||
last_metrics {
|
|
||||||
description: "Last metric variants (hash to events), one for each metric hash"
|
|
||||||
type: object
|
|
||||||
additionalProperties {
|
|
||||||
"$ref": "#/definitions/last_metrics_variants"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hyperparams {
|
|
||||||
description: "Task hyper params per section"
|
|
||||||
type: object
|
|
||||||
additionalProperties {
|
|
||||||
"$ref": "#/definitions/section_params"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
configuration {
|
|
||||||
description: "Task configuration params"
|
|
||||||
type: object
|
|
||||||
additionalProperties {
|
|
||||||
"$ref": "#/definitions/configuration_item"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runtime {
|
|
||||||
description: "Task runtime mapping"
|
|
||||||
type: object
|
|
||||||
additionalProperties: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task_urls {
|
task_urls {
|
||||||
type: object
|
type: object
|
||||||
properties {
|
properties {
|
||||||
@ -1227,6 +693,10 @@ validate {
|
|||||||
description: "Task execution params"
|
description: "Task execution params"
|
||||||
"$ref": "#/definitions/execution"
|
"$ref": "#/definitions/execution"
|
||||||
}
|
}
|
||||||
|
script {
|
||||||
|
description: "Script info"
|
||||||
|
"$ref": "#/definitions/script"
|
||||||
|
}
|
||||||
hyperparams {
|
hyperparams {
|
||||||
description: "Task hyper params per section"
|
description: "Task hyper params per section"
|
||||||
type: object
|
type: object
|
||||||
@ -1241,10 +711,6 @@ validate {
|
|||||||
"$ref": "#/definitions/configuration_item"
|
"$ref": "#/definitions/configuration_item"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
script {
|
|
||||||
description: "Script info"
|
|
||||||
"$ref": "#/definitions/script"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response {
|
response {
|
||||||
@ -1392,6 +858,10 @@ edit {
|
|||||||
description: "Task execution params"
|
description: "Task execution params"
|
||||||
"$ref": "#/definitions/execution"
|
"$ref": "#/definitions/execution"
|
||||||
}
|
}
|
||||||
|
script {
|
||||||
|
description: "Script info"
|
||||||
|
"$ref": "#/definitions/script"
|
||||||
|
}
|
||||||
hyperparams {
|
hyperparams {
|
||||||
description: "Task hyper params per section"
|
description: "Task hyper params per section"
|
||||||
type: object
|
type: object
|
||||||
@ -1406,10 +876,6 @@ edit {
|
|||||||
"$ref": "#/definitions/configuration_item"
|
"$ref": "#/definitions/configuration_item"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
script {
|
|
||||||
description: "Script info"
|
|
||||||
"$ref": "#/definitions/script"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response: ${_definitions.update_response}
|
response: ${_definitions.update_response}
|
||||||
@ -1478,6 +944,10 @@ reset {
|
|||||||
description: "If set to 'true' then return the urls of the files that were uploaded by this task. Default value is 'false'"
|
description: "If set to 'true' then return the urls of the files that were uploaded by this task. Default value is 'false'"
|
||||||
type: boolean
|
type: boolean
|
||||||
}
|
}
|
||||||
|
delete_output_models {
|
||||||
|
description: "If set to 'true' then delete output models of this task that are not referenced by other tasks. Default value is 'true'"
|
||||||
|
type: boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response {
|
response {
|
||||||
@ -1665,6 +1135,10 @@ delete {
|
|||||||
description: "If set to 'true' then return the urls of the files that were uploaded by this task. Default value is 'false'"
|
description: "If set to 'true' then return the urls of the files that were uploaded by this task. Default value is 'false'"
|
||||||
type: boolean
|
type: boolean
|
||||||
}
|
}
|
||||||
|
delete_output_models {
|
||||||
|
description: "If set to 'true' then delete output models of this task that are not referenced by other tasks. Default value is 'true'"
|
||||||
|
type: boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response {
|
response {
|
||||||
@ -1736,12 +1210,12 @@ archive_many {
|
|||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response {
|
}
|
||||||
properties {
|
response {
|
||||||
succeeded.items.properties.archived {
|
properties {
|
||||||
description: "Indicates whether the task was archived"
|
succeeded.items.properties.archived {
|
||||||
type: boolean
|
description: "Indicates whether the task was archived"
|
||||||
}
|
type: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import itertools
|
|||||||
import math
|
import math
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import Sequence, Optional, Union, Tuple
|
from typing import Sequence, Optional, Union, Tuple, Mapping
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import jsonmodels.fields
|
import jsonmodels.fields
|
||||||
@ -27,7 +27,9 @@ from apiserver.apimodels.events import (
|
|||||||
ClearScrollRequest,
|
ClearScrollRequest,
|
||||||
ClearTaskLogRequest,
|
ClearTaskLogRequest,
|
||||||
SingleValueMetricsRequest,
|
SingleValueMetricsRequest,
|
||||||
GetVariantSampleRequest, GetMetricSamplesRequest,
|
GetVariantSampleRequest,
|
||||||
|
GetMetricSamplesRequest,
|
||||||
|
TaskMetric,
|
||||||
)
|
)
|
||||||
from apiserver.bll.event import EventBLL
|
from apiserver.bll.event import EventBLL
|
||||||
from apiserver.bll.event.event_common import EventType, MetricVariants
|
from apiserver.bll.event.event_common import EventType, MetricVariants
|
||||||
@ -405,7 +407,7 @@ def get_scalar_metric_data(call, company_id, _):
|
|||||||
task_id,
|
task_id,
|
||||||
event_type=EventType.metrics_scalar,
|
event_type=EventType.metrics_scalar,
|
||||||
sort=[{"iter": {"order": "desc"}}],
|
sort=[{"iter": {"order": "desc"}}],
|
||||||
metric=metric,
|
metrics={metric: []},
|
||||||
scroll_id=scroll_id,
|
scroll_id=scroll_id,
|
||||||
no_scroll=no_scroll,
|
no_scroll=no_scroll,
|
||||||
model_events=model_events,
|
model_events=model_events,
|
||||||
@ -457,6 +459,7 @@ def scalar_metrics_iter_histogram(
|
|||||||
task_id=request.task,
|
task_id=request.task,
|
||||||
samples=request.samples,
|
samples=request.samples,
|
||||||
key=request.key,
|
key=request.key,
|
||||||
|
metric_variants=_get_metric_variants_from_request(request.metrics),
|
||||||
)
|
)
|
||||||
call.result.data = metrics
|
call.result.data = metrics
|
||||||
|
|
||||||
@ -546,10 +549,10 @@ def get_multi_task_plots_v1_7(call, company_id, _):
|
|||||||
scroll_id=scroll_id,
|
scroll_id=scroll_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
tasks = {t.id: t.name for t in tasks_or_models}
|
task_names = {t.id: t.name for t in tasks_or_models}
|
||||||
|
|
||||||
return_events = _get_top_iter_unique_events_per_task(
|
return_events = _get_top_iter_unique_events_per_task(
|
||||||
result.events, max_iters=iters, tasks=tasks
|
result.events, max_iters=iters, task_names=task_names
|
||||||
)
|
)
|
||||||
|
|
||||||
call.result.data = dict(
|
call.result.data = dict(
|
||||||
@ -560,6 +563,34 @@ def get_multi_task_plots_v1_7(call, company_id, _):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_multitask_plots(
|
||||||
|
company: str,
|
||||||
|
tasks_or_models: Sequence[Task],
|
||||||
|
last_iters: int,
|
||||||
|
metrics: MetricVariants = None,
|
||||||
|
scroll_id=None,
|
||||||
|
no_scroll=True,
|
||||||
|
model_events=False,
|
||||||
|
) -> Tuple[dict, int, str]:
|
||||||
|
task_names = {t.id: t.name for t in tasks_or_models}
|
||||||
|
|
||||||
|
result = event_bll.get_task_events(
|
||||||
|
company_id=company,
|
||||||
|
task_id=list(task_names),
|
||||||
|
event_type=EventType.metrics_plot,
|
||||||
|
metrics=metrics,
|
||||||
|
last_iter_count=last_iters,
|
||||||
|
sort=[{"iter": {"order": "desc"}}],
|
||||||
|
scroll_id=scroll_id,
|
||||||
|
no_scroll=no_scroll,
|
||||||
|
model_events=model_events,
|
||||||
|
)
|
||||||
|
return_events = _get_top_iter_unique_events_per_task(
|
||||||
|
result.events, max_iters=last_iters, task_names=task_names
|
||||||
|
)
|
||||||
|
return return_events, result.total_events, result.next_scroll_id
|
||||||
|
|
||||||
|
|
||||||
@endpoint("events.get_multi_task_plots", min_version="1.8", required_fields=["tasks"])
|
@endpoint("events.get_multi_task_plots", min_version="1.8", required_fields=["tasks"])
|
||||||
def get_multi_task_plots(call, company_id, _):
|
def get_multi_task_plots(call, company_id, _):
|
||||||
task_ids = call.data["tasks"]
|
task_ids = call.data["tasks"]
|
||||||
@ -572,28 +603,19 @@ def get_multi_task_plots(call, company_id, _):
|
|||||||
company_id, task_ids, model_events
|
company_id, task_ids, model_events
|
||||||
)
|
)
|
||||||
|
|
||||||
result = event_bll.get_task_events(
|
return_events, total_events, next_scroll_id = _get_multitask_plots(
|
||||||
company,
|
company=company,
|
||||||
task_ids,
|
tasks_or_models=tasks_or_models,
|
||||||
event_type=EventType.metrics_plot,
|
last_iters=iters,
|
||||||
sort=[{"iter": {"order": "desc"}}],
|
|
||||||
last_iter_count=iters,
|
|
||||||
scroll_id=scroll_id,
|
scroll_id=scroll_id,
|
||||||
no_scroll=no_scroll,
|
no_scroll=no_scroll,
|
||||||
model_events=model_events,
|
model_events=model_events,
|
||||||
)
|
)
|
||||||
|
|
||||||
tasks = {t.id: t.name for t in tasks_or_models}
|
|
||||||
|
|
||||||
return_events = _get_top_iter_unique_events_per_task(
|
|
||||||
result.events, max_iters=iters, tasks=tasks
|
|
||||||
)
|
|
||||||
|
|
||||||
call.result.data = dict(
|
call.result.data = dict(
|
||||||
plots=return_events,
|
plots=return_events,
|
||||||
returned=len(return_events),
|
returned=len(return_events),
|
||||||
total=result.total_events,
|
total=total_events,
|
||||||
scroll_id=result.next_scroll_id,
|
scroll_id=next_scroll_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -674,22 +696,42 @@ def get_task_plots(call, company_id, request: TaskPlotsRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _task_metrics_dict_from_request(req_metrics: Sequence[TaskMetric]) -> dict:
|
||||||
|
task_metrics = defaultdict(dict)
|
||||||
|
for tm in req_metrics:
|
||||||
|
task_metrics[tm.task][tm.metric] = tm.variants
|
||||||
|
for metrics in task_metrics.values():
|
||||||
|
if None in metrics:
|
||||||
|
metrics.clear()
|
||||||
|
|
||||||
|
return task_metrics
|
||||||
|
|
||||||
|
|
||||||
|
def _get_metrics_response(metric_events: Sequence[tuple]) -> Sequence[MetricEvents]:
|
||||||
|
return [
|
||||||
|
MetricEvents(
|
||||||
|
task=task,
|
||||||
|
iterations=[
|
||||||
|
IterationEvents(iter=iteration["iter"], events=iteration["events"])
|
||||||
|
for iteration in iterations
|
||||||
|
],
|
||||||
|
)
|
||||||
|
for (task, iterations) in metric_events
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@endpoint(
|
@endpoint(
|
||||||
"events.plots",
|
"events.plots",
|
||||||
request_data_model=MetricEventsRequest,
|
request_data_model=MetricEventsRequest,
|
||||||
response_data_model=MetricEventsResponse,
|
response_data_model=MetricEventsResponse,
|
||||||
)
|
)
|
||||||
def task_plots(call, company_id, request: MetricEventsRequest):
|
def task_plots(call, company_id, request: MetricEventsRequest):
|
||||||
task_metrics = defaultdict(dict)
|
task_metrics = _task_metrics_dict_from_request(request.metrics)
|
||||||
for tm in request.metrics:
|
task_ids = list(task_metrics)
|
||||||
task_metrics[tm.task][tm.metric] = tm.variants
|
|
||||||
for metrics in task_metrics.values():
|
|
||||||
if None in metrics:
|
|
||||||
metrics.clear()
|
|
||||||
|
|
||||||
company, _ = _get_task_or_model_index_company(
|
company, _ = _get_task_or_model_index_company(
|
||||||
company_id, task_ids=list(task_metrics), model_events=request.model_events
|
company_id, task_ids=task_ids, model_events=request.model_events
|
||||||
)
|
)
|
||||||
|
|
||||||
result = event_bll.plots_iterator.get_task_events(
|
result = event_bll.plots_iterator.get_task_events(
|
||||||
company_id=company,
|
company_id=company,
|
||||||
task_metrics=task_metrics,
|
task_metrics=task_metrics,
|
||||||
@ -701,16 +743,7 @@ def task_plots(call, company_id, request: MetricEventsRequest):
|
|||||||
|
|
||||||
call.result.data_model = MetricEventsResponse(
|
call.result.data_model = MetricEventsResponse(
|
||||||
scroll_id=result.next_scroll_id,
|
scroll_id=result.next_scroll_id,
|
||||||
metrics=[
|
metrics=_get_metrics_response(result.metric_events),
|
||||||
MetricEvents(
|
|
||||||
task=task,
|
|
||||||
iterations=[
|
|
||||||
IterationEvents(iter=iteration["iter"], events=iteration["events"])
|
|
||||||
for iteration in iterations
|
|
||||||
],
|
|
||||||
)
|
|
||||||
for (task, iterations) in result.metric_events
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -789,15 +822,10 @@ def get_debug_images_v1_8(call, company_id, _):
|
|||||||
response_data_model=MetricEventsResponse,
|
response_data_model=MetricEventsResponse,
|
||||||
)
|
)
|
||||||
def get_debug_images(call, company_id, request: MetricEventsRequest):
|
def get_debug_images(call, company_id, request: MetricEventsRequest):
|
||||||
task_metrics = defaultdict(dict)
|
task_metrics = _task_metrics_dict_from_request(request.metrics)
|
||||||
for tm in request.metrics:
|
task_ids = list(task_metrics)
|
||||||
task_metrics[tm.task][tm.metric] = tm.variants
|
|
||||||
for metrics in task_metrics.values():
|
|
||||||
if None in metrics:
|
|
||||||
metrics.clear()
|
|
||||||
|
|
||||||
company, _ = _get_task_or_model_index_company(
|
company, _ = _get_task_or_model_index_company(
|
||||||
company_id, task_ids=list(task_metrics), model_events=request.model_events
|
company_id, task_ids=task_ids, model_events=request.model_events
|
||||||
)
|
)
|
||||||
|
|
||||||
result = event_bll.debug_images_iterator.get_task_events(
|
result = event_bll.debug_images_iterator.get_task_events(
|
||||||
@ -811,16 +839,7 @@ def get_debug_images(call, company_id, request: MetricEventsRequest):
|
|||||||
|
|
||||||
call.result.data_model = MetricEventsResponse(
|
call.result.data_model = MetricEventsResponse(
|
||||||
scroll_id=result.next_scroll_id,
|
scroll_id=result.next_scroll_id,
|
||||||
metrics=[
|
metrics=_get_metrics_response(result.metric_events),
|
||||||
MetricEvents(
|
|
||||||
task=task,
|
|
||||||
iterations=[
|
|
||||||
IterationEvents(iter=iteration["iter"], events=iteration["events"])
|
|
||||||
for iteration in iterations
|
|
||||||
],
|
|
||||||
)
|
|
||||||
for (task, iterations) in result.metric_events
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -955,7 +974,9 @@ def clear_task_log(call: APICall, company_id: str, request: ClearTaskLogRequest)
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_top_iter_unique_events_per_task(events, max_iters, tasks):
|
def _get_top_iter_unique_events_per_task(
|
||||||
|
events, max_iters: int, task_names: Mapping[str, str]
|
||||||
|
):
|
||||||
key = itemgetter("metric", "variant", "task", "iter")
|
key = itemgetter("metric", "variant", "task", "iter")
|
||||||
|
|
||||||
unique_events = itertools.chain.from_iterable(
|
unique_events = itertools.chain.from_iterable(
|
||||||
@ -968,7 +989,7 @@ def _get_top_iter_unique_events_per_task(events, max_iters, tasks):
|
|||||||
def collect(evs, fields):
|
def collect(evs, fields):
|
||||||
if not fields:
|
if not fields:
|
||||||
evs = list(evs)
|
evs = list(evs)
|
||||||
return {"name": tasks.get(evs[0].get("task")), "plots": evs}
|
return {"name": task_names.get(evs[0].get("task")), "plots": evs}
|
||||||
return {
|
return {
|
||||||
str(k): collect(group, fields[1:])
|
str(k): collect(group, fields[1:])
|
||||||
for k, group in itertools.groupby(evs, key=itemgetter(fields[0]))
|
for k, group in itertools.groupby(evs, key=itemgetter(fields[0]))
|
||||||
@ -1034,7 +1055,9 @@ def scalar_metrics_iter_raw(
|
|||||||
request.batch_size = request.batch_size or scroll.request.batch_size
|
request.batch_size = request.batch_size or scroll.request.batch_size
|
||||||
|
|
||||||
task_id = request.task
|
task_id = request.task
|
||||||
task_or_model = _assert_task_or_model_exists(company_id, task_id, model_events=request.model_events)[0]
|
task_or_model = _assert_task_or_model_exists(
|
||||||
|
company_id, task_id, model_events=request.model_events
|
||||||
|
)[0]
|
||||||
metric_variants = _get_metric_variants_from_request([request.metric])
|
metric_variants = _get_metric_variants_from_request([request.metric])
|
||||||
|
|
||||||
if request.count_total and total is None:
|
if request.count_total and total is None:
|
||||||
|
387
apiserver/services/reports.py
Normal file
387
apiserver/services/reports.py
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
import textwrap
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
|
from apiserver.apimodels.reports import (
|
||||||
|
CreateReportRequest,
|
||||||
|
UpdateReportRequest,
|
||||||
|
PublishReportRequest,
|
||||||
|
ArchiveReportRequest,
|
||||||
|
DeleteReportRequest,
|
||||||
|
MoveReportRequest,
|
||||||
|
GetTasksDataRequest,
|
||||||
|
EventsRequest,
|
||||||
|
GetAllRequest,
|
||||||
|
)
|
||||||
|
from apiserver.apierrors import errors
|
||||||
|
from apiserver.apimodels.base import IdResponse, UpdateResponse
|
||||||
|
from apiserver.services.utils import process_include_subprojects, sort_tags_response
|
||||||
|
from apiserver.bll.organization import OrgBLL
|
||||||
|
from apiserver.bll.project import ProjectBLL
|
||||||
|
from apiserver.bll.task import TaskBLL, ChangeStatusRequest
|
||||||
|
from apiserver.database.model import EntityVisibility
|
||||||
|
from apiserver.database.model.project import Project
|
||||||
|
from apiserver.database.model.task.task import Task, TaskType, TaskStatus
|
||||||
|
from apiserver.service_repo import APICall, endpoint
|
||||||
|
from apiserver.services.events import (
|
||||||
|
_get_task_or_model_index_company,
|
||||||
|
event_bll,
|
||||||
|
_get_metrics_response,
|
||||||
|
_get_metric_variants_from_request,
|
||||||
|
_get_multitask_plots,
|
||||||
|
)
|
||||||
|
from apiserver.services.tasks import (
|
||||||
|
escape_execution_parameters,
|
||||||
|
_hidden_query,
|
||||||
|
unprepare_from_saved,
|
||||||
|
)
|
||||||
|
|
||||||
|
org_bll = OrgBLL()
|
||||||
|
project_bll = ProjectBLL()
|
||||||
|
task_bll = TaskBLL()
|
||||||
|
|
||||||
|
|
||||||
|
reports_project_name = ".reports"
|
||||||
|
reports_tag = "reports"
|
||||||
|
update_fields = {
|
||||||
|
"name",
|
||||||
|
"tags",
|
||||||
|
"comment",
|
||||||
|
"report",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _assert_report(
|
||||||
|
company_id, task_id, only_fields=None, requires_write_access=True
|
||||||
|
):
|
||||||
|
if only_fields and "type" not in only_fields:
|
||||||
|
only_fields += ("type",)
|
||||||
|
|
||||||
|
task = TaskBLL.get_task_with_access(
|
||||||
|
task_id=task_id,
|
||||||
|
company_id=company_id,
|
||||||
|
only=only_fields,
|
||||||
|
requires_write_access=requires_write_access,
|
||||||
|
)
|
||||||
|
if task.type != TaskType.report:
|
||||||
|
raise errors.bad_request.OperationSupportedOnReportsOnly(id=task_id)
|
||||||
|
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.update", response_data_model=UpdateResponse)
|
||||||
|
def update_report(call: APICall, company_id: str, request: UpdateReportRequest):
|
||||||
|
task = _assert_report(
|
||||||
|
task_id=request.task,
|
||||||
|
company_id=company_id,
|
||||||
|
only_fields=("status",),
|
||||||
|
)
|
||||||
|
if task.status != TaskStatus.created:
|
||||||
|
raise errors.bad_request.InvalidTaskStatus(
|
||||||
|
expected=TaskStatus.created, status=task.status
|
||||||
|
)
|
||||||
|
|
||||||
|
partial_update_dict = {
|
||||||
|
field: value for field, value in call.data.items() if field in update_fields
|
||||||
|
}
|
||||||
|
if not partial_update_dict:
|
||||||
|
return UpdateResponse(updated=0)
|
||||||
|
|
||||||
|
now = datetime.utcnow()
|
||||||
|
updated = task.update(
|
||||||
|
upsert=False,
|
||||||
|
**partial_update_dict,
|
||||||
|
last_change=now,
|
||||||
|
last_update=now,
|
||||||
|
last_changed_by=call.identity.user,
|
||||||
|
)
|
||||||
|
if not updated:
|
||||||
|
return UpdateResponse(updated=0)
|
||||||
|
|
||||||
|
updated_tags = partial_update_dict.get("tags")
|
||||||
|
if updated_tags:
|
||||||
|
partial_update_dict["tags"] = sorted(updated_tags)
|
||||||
|
updated_report = partial_update_dict.get("report")
|
||||||
|
if updated_report:
|
||||||
|
partial_update_dict["report"] = textwrap.shorten(updated_report, width=100)
|
||||||
|
|
||||||
|
return UpdateResponse(updated=updated, fields=partial_update_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_reports_project(company: str, user: str, name: str):
|
||||||
|
name = name.strip("/")
|
||||||
|
_, _, basename = name.rpartition("/")
|
||||||
|
if basename != reports_project_name:
|
||||||
|
name = f"{name}/{reports_project_name}"
|
||||||
|
|
||||||
|
return project_bll.find_or_create(
|
||||||
|
user=user,
|
||||||
|
company=company,
|
||||||
|
project_name=name,
|
||||||
|
description="Reports project",
|
||||||
|
system_tags=[reports_tag, EntityVisibility.hidden.value],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.create", response_data_model=IdResponse)
|
||||||
|
def create_report(call: APICall, company_id: str, request: CreateReportRequest):
|
||||||
|
user_id = call.identity.user
|
||||||
|
project_id = request.project
|
||||||
|
if request.project:
|
||||||
|
project = Project.get_for_writing(
|
||||||
|
company=company_id, id=project_id, _only=("name",)
|
||||||
|
)
|
||||||
|
project_name = project.name
|
||||||
|
else:
|
||||||
|
project_name = ""
|
||||||
|
|
||||||
|
project_id = _ensure_reports_project(
|
||||||
|
company=company_id, user=user_id, name=project_name
|
||||||
|
)
|
||||||
|
task = task_bll.create(
|
||||||
|
company=company_id,
|
||||||
|
user=user_id,
|
||||||
|
fields=dict(
|
||||||
|
project=project_id,
|
||||||
|
name=request.name,
|
||||||
|
tags=request.tags,
|
||||||
|
comment=request.comment,
|
||||||
|
type=TaskType.report,
|
||||||
|
system_tags=[reports_tag, EntityVisibility.hidden.value],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
task.save()
|
||||||
|
return IdResponse(id=task.id)
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_reports_project_if_empty(project_id):
|
||||||
|
project = Project.objects(id=project_id).only("basename").first()
|
||||||
|
if (
|
||||||
|
project
|
||||||
|
and project.basename == reports_project_name
|
||||||
|
and Task.objects(project=project_id).count() == 0
|
||||||
|
):
|
||||||
|
project.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.get_all_ex")
|
||||||
|
def get_all_ex(call: APICall, company_id, request: GetAllRequest):
|
||||||
|
call_data = call.data
|
||||||
|
call_data["type"] = TaskType.report
|
||||||
|
call_data["include_subprojects"] = True
|
||||||
|
|
||||||
|
process_include_subprojects(call_data)
|
||||||
|
ret_params = {}
|
||||||
|
tasks = Task.get_many_with_join(
|
||||||
|
company=company_id,
|
||||||
|
query_dict=call_data,
|
||||||
|
allow_public=request.allow_public,
|
||||||
|
ret_params=ret_params,
|
||||||
|
)
|
||||||
|
unprepare_from_saved(call, tasks)
|
||||||
|
|
||||||
|
call.result.data = {"tasks": tasks, **ret_params}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_task_metrics_from_request(
|
||||||
|
task_ids: Sequence[str], request: EventsRequest
|
||||||
|
) -> dict:
|
||||||
|
task_metrics = {}
|
||||||
|
for task in task_ids:
|
||||||
|
task_dict = {}
|
||||||
|
for mv in request.metrics:
|
||||||
|
task_dict[mv.metric] = mv.variants
|
||||||
|
task_metrics[task] = task_dict
|
||||||
|
|
||||||
|
return task_metrics
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.get_task_data", required_fields=[])
|
||||||
|
def get_task_data(call: APICall, company_id, request: GetTasksDataRequest):
|
||||||
|
call_data = escape_execution_parameters(call)
|
||||||
|
process_include_subprojects(call_data)
|
||||||
|
|
||||||
|
ret_params = {}
|
||||||
|
tasks = Task.get_many_with_join(
|
||||||
|
company=company_id,
|
||||||
|
query_dict=call_data,
|
||||||
|
query=_hidden_query(call_data),
|
||||||
|
allow_public=request.allow_public,
|
||||||
|
ret_params=ret_params,
|
||||||
|
)
|
||||||
|
unprepare_from_saved(call, tasks)
|
||||||
|
res = {"tasks": tasks, **ret_params}
|
||||||
|
if not (
|
||||||
|
request.debug_images
|
||||||
|
or request.plots
|
||||||
|
or request.scalar_metrics_iter_histogram
|
||||||
|
):
|
||||||
|
return res
|
||||||
|
|
||||||
|
task_ids = [task["id"] for task in tasks]
|
||||||
|
company, tasks_or_models = _get_task_or_model_index_company(
|
||||||
|
company_id, task_ids
|
||||||
|
)
|
||||||
|
if request.debug_images:
|
||||||
|
result = event_bll.debug_images_iterator.get_task_events(
|
||||||
|
company_id=company,
|
||||||
|
task_metrics=_get_task_metrics_from_request(task_ids, request.debug_images),
|
||||||
|
iter_count=request.debug_images.iters,
|
||||||
|
)
|
||||||
|
res["debug_images"] = [
|
||||||
|
r.to_struct() for r in _get_metrics_response(result.metric_events)
|
||||||
|
]
|
||||||
|
|
||||||
|
if request.plots:
|
||||||
|
res["plots"] = _get_multitask_plots(
|
||||||
|
company=company,
|
||||||
|
tasks_or_models=tasks_or_models,
|
||||||
|
last_iters=request.plots.iters,
|
||||||
|
metrics=_get_metric_variants_from_request(request.plots.metrics),
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
if request.scalar_metrics_iter_histogram:
|
||||||
|
res[
|
||||||
|
"scalar_metrics_iter_histogram"
|
||||||
|
] = event_bll.metrics.compare_scalar_metrics_average_per_iter(
|
||||||
|
company_id=company_id,
|
||||||
|
tasks=tasks_or_models,
|
||||||
|
samples=request.scalar_metrics_iter_histogram.samples,
|
||||||
|
key=request.scalar_metrics_iter_histogram.key,
|
||||||
|
metric_variants=_get_metric_variants_from_request(
|
||||||
|
request.scalar_metrics_iter_histogram.metrics
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
call.result.data = res
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.move")
|
||||||
|
def move(call: APICall, company_id: str, request: MoveReportRequest):
|
||||||
|
if not (request.project or request.project_name):
|
||||||
|
raise errors.bad_request.MissingRequiredFields(
|
||||||
|
"project or project_name is required"
|
||||||
|
)
|
||||||
|
|
||||||
|
task = _assert_report(
|
||||||
|
company_id=company_id,
|
||||||
|
task_id=request.task,
|
||||||
|
only_fields=("project",),
|
||||||
|
)
|
||||||
|
user_id = call.identity.user
|
||||||
|
project_name = request.project_name
|
||||||
|
if not project_name:
|
||||||
|
project = Project.get_for_writing(
|
||||||
|
company=company_id, id=request.project, _only=("name",)
|
||||||
|
)
|
||||||
|
project_name = project.name
|
||||||
|
|
||||||
|
project_id = _ensure_reports_project(
|
||||||
|
company=company_id, user=user_id, name=project_name
|
||||||
|
)
|
||||||
|
|
||||||
|
project_bll.move_under_project(
|
||||||
|
entity_cls=Task,
|
||||||
|
user=call.identity.user,
|
||||||
|
company=company_id,
|
||||||
|
ids=[request.task],
|
||||||
|
project=project_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
_delete_reports_project_if_empty(task.project)
|
||||||
|
|
||||||
|
return {"project_id": project_id}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint(
|
||||||
|
"reports.publish", response_data_model=UpdateResponse,
|
||||||
|
)
|
||||||
|
def publish(call: APICall, company_id, request: PublishReportRequest):
|
||||||
|
task = _assert_report(
|
||||||
|
company_id=company_id, task_id=request.task
|
||||||
|
)
|
||||||
|
updates = ChangeStatusRequest(
|
||||||
|
task=task,
|
||||||
|
company=company_id,
|
||||||
|
new_status=TaskStatus.published,
|
||||||
|
force=True,
|
||||||
|
status_reason="",
|
||||||
|
status_message=request.message,
|
||||||
|
user_id=call.identity.user,
|
||||||
|
).execute(published=datetime.utcnow())
|
||||||
|
|
||||||
|
call.result.data_model = UpdateResponse(**updates)
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.archive")
|
||||||
|
def archive(call: APICall, company_id, request: ArchiveReportRequest):
|
||||||
|
task = _assert_report(
|
||||||
|
company_id=company_id, task_id=request.task
|
||||||
|
)
|
||||||
|
archived = task.update(
|
||||||
|
status_message=request.message,
|
||||||
|
status_reason="",
|
||||||
|
add_to_set__system_tags=EntityVisibility.archived.value,
|
||||||
|
last_change=datetime.utcnow(),
|
||||||
|
last_changed_by=call.identity.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"archived": archived}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.unarchive")
|
||||||
|
def unarchive(call: APICall, company_id, request: ArchiveReportRequest):
|
||||||
|
task = _assert_report(
|
||||||
|
company_id=company_id, task_id=request.task
|
||||||
|
)
|
||||||
|
unarchived = task.update(
|
||||||
|
status_message=request.message,
|
||||||
|
status_reason="",
|
||||||
|
pull__system_tags=EntityVisibility.archived.value,
|
||||||
|
last_change=datetime.utcnow(),
|
||||||
|
last_changed_by=call.identity.user,
|
||||||
|
)
|
||||||
|
return {"unarchived": unarchived}
|
||||||
|
|
||||||
|
|
||||||
|
# @endpoint("reports.share")
|
||||||
|
# def share(call: APICall, company_id, request: ShareReportRequest):
|
||||||
|
# _assert_report(
|
||||||
|
# company_id=company_id, user_id=call.identity.user, task_id=request.task
|
||||||
|
# )
|
||||||
|
# call.result.data = {
|
||||||
|
# "changed": task_bll.share_task(
|
||||||
|
# company_id=company_id, task_ids=[request.task], share=request.share
|
||||||
|
# )
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.delete")
|
||||||
|
def delete(call: APICall, company_id, request: DeleteReportRequest):
|
||||||
|
task = _assert_report(
|
||||||
|
company_id=company_id,
|
||||||
|
task_id=request.task,
|
||||||
|
only_fields=("project",),
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
task.status != TaskStatus.created
|
||||||
|
and EntityVisibility.archived.value not in task.system_tags
|
||||||
|
and not request.force
|
||||||
|
):
|
||||||
|
raise errors.bad_request.TaskCannotBeDeleted(
|
||||||
|
"due to status, use force=True",
|
||||||
|
task=task.id,
|
||||||
|
expected=TaskStatus.created,
|
||||||
|
current=task.status,
|
||||||
|
)
|
||||||
|
|
||||||
|
task.delete()
|
||||||
|
_delete_reports_project_if_empty(task.project)
|
||||||
|
|
||||||
|
call.result.data = {"deleted": 1}
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint("reports.get_tags")
|
||||||
|
def get_tags(call: APICall, company_id: str, _):
|
||||||
|
tags = Task.objects(company=company_id, type=TaskType.report).distinct(field="tags")
|
||||||
|
call.result.data = sort_tags_response({"tags": tags})
|
@ -475,7 +475,9 @@ def _validate_and_get_task_from_call(call: APICall, **kwargs) -> Tuple[Task, dic
|
|||||||
field_does_not_exist_cls=errors.bad_request.ValidationError
|
field_does_not_exist_cls=errors.bad_request.ValidationError
|
||||||
):
|
):
|
||||||
fields = prepare_create_fields(call, **kwargs)
|
fields = prepare_create_fields(call, **kwargs)
|
||||||
task = task_bll.create(call, fields)
|
task = task_bll.create(
|
||||||
|
company=call.identity.company, user=call.identity.user, fields=fields
|
||||||
|
)
|
||||||
|
|
||||||
task_bll.validate(task)
|
task_bll.validate(task)
|
||||||
|
|
||||||
@ -710,7 +712,11 @@ def edit(call: APICall, company_id, req_model: UpdateRequest):
|
|||||||
d.update(value)
|
d.update(value)
|
||||||
fields[key] = d
|
fields[key] = d
|
||||||
|
|
||||||
task_bll.validate(task_bll.create(call, fields))
|
task_bll.validate(
|
||||||
|
task_bll.create(
|
||||||
|
company=call.identity.company, user=call.identity.user, fields=fields
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# make sure field names do not end in mongoengine comparison operators
|
# make sure field names do not end in mongoengine comparison operators
|
||||||
fixed_fields = {
|
fixed_fields = {
|
||||||
|
@ -60,12 +60,12 @@ class TestService(TestCase, TestServiceInterface):
|
|||||||
def update_missing(target: dict, **update):
|
def update_missing(target: dict, **update):
|
||||||
target.update({k: v for k, v in update.items() if k not in target})
|
target.update({k: v for k, v in update.items() if k not in target})
|
||||||
|
|
||||||
def create_temp(self, service, *, client=None, delete_params=None, **kwargs) -> str:
|
def create_temp(self, service, *, client=None, delete_params=None, object_name="", **kwargs) -> str:
|
||||||
return self._create_temp_helper(
|
return self._create_temp_helper(
|
||||||
service=service,
|
service=service,
|
||||||
create_endpoint="create",
|
create_endpoint="create",
|
||||||
delete_endpoint="delete",
|
delete_endpoint="delete",
|
||||||
object_name=service.rstrip("s"),
|
object_name=object_name or service.rstrip("s"),
|
||||||
create_params=kwargs,
|
create_params=kwargs,
|
||||||
client=client,
|
client=client,
|
||||||
delete_params=delete_params,
|
delete_params=delete_params,
|
||||||
|
189
apiserver/tests/automated/test_reports.py
Normal file
189
apiserver/tests/automated/test_reports.py
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from boltons.iterutils import first
|
||||||
|
|
||||||
|
from apiserver.apierrors import errors
|
||||||
|
from apiserver.es_factory import es_factory
|
||||||
|
from apiserver.tests.automated import TestService
|
||||||
|
from apiserver.utilities.dicts import nested_get
|
||||||
|
|
||||||
|
|
||||||
|
class TestReports(TestService):
|
||||||
|
def _delete_project(self, name):
|
||||||
|
existing_project = first(
|
||||||
|
self.api.projects.get_all_ex(
|
||||||
|
name=f"^{re.escape(name)}$", search_hidden=True
|
||||||
|
).projects
|
||||||
|
)
|
||||||
|
if existing_project:
|
||||||
|
self.api.projects.delete(
|
||||||
|
project=existing_project.id, force=True, delete_contents=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_update_move(self):
|
||||||
|
task_name = "Rep1"
|
||||||
|
comment = "My report"
|
||||||
|
tags = ["hello"]
|
||||||
|
|
||||||
|
# report creates a hidden task under hidden .reports subproject
|
||||||
|
self._delete_project(".reports")
|
||||||
|
task_id = self._temp_report(name=task_name, comment=comment, tags=tags)
|
||||||
|
task = self.api.tasks.get_all_ex(id=[task_id]).tasks[0]
|
||||||
|
self.assertEqual(task.name, task_name)
|
||||||
|
self.assertEqual(task.comment, comment)
|
||||||
|
self.assertEqual(set(task.tags), set(tags))
|
||||||
|
self.assertEqual(task.type, "report")
|
||||||
|
self.assertEqual(set(task.system_tags), {"hidden", "reports"})
|
||||||
|
projects = self.api.projects.get_all_ex(name=r"^\.reports$").projects
|
||||||
|
self.assertEqual(len(projects), 0)
|
||||||
|
project = self.api.projects.get_all_ex(
|
||||||
|
name=r"^\.reports$", search_hidden=True
|
||||||
|
).projects[0]
|
||||||
|
self.assertEqual(project.id, task.project.id)
|
||||||
|
self.assertEqual(set(project.system_tags), {"hidden", "reports"})
|
||||||
|
ret = self.api.reports.get_tags()
|
||||||
|
self.assertEqual(ret.tags, sorted(tags))
|
||||||
|
|
||||||
|
# update is working on draft reports
|
||||||
|
new_comment = "My new comment"
|
||||||
|
res = self.api.reports.update(task=task_id, comment=new_comment, tags=[])
|
||||||
|
self.assertEqual(res.updated, 1)
|
||||||
|
task = self.api.tasks.get_all_ex(id=[task_id]).tasks[0]
|
||||||
|
self.assertEqual(task.name, task_name)
|
||||||
|
self.assertEqual(task.comment, new_comment)
|
||||||
|
self.assertEqual(task.tags, [])
|
||||||
|
ret = self.api.reports.get_tags()
|
||||||
|
self.assertEqual(ret.tags, [])
|
||||||
|
self.api.reports.publish(task=task_id)
|
||||||
|
with self.api.raises(errors.bad_request.InvalidTaskStatus):
|
||||||
|
self.api.reports.update(task=task_id, comment=comment)
|
||||||
|
|
||||||
|
# move under another project autodeletes the empty project
|
||||||
|
new_project_name = "Reports Test"
|
||||||
|
self._delete_project(new_project_name)
|
||||||
|
task2_id = self._temp_report(name="Rep2")
|
||||||
|
new_project_id = self.api.reports.move(
|
||||||
|
task=task_id, project_name=new_project_name
|
||||||
|
).project_id
|
||||||
|
new_project = self.api.projects.get_all_ex(id=[new_project_id]).projects[0]
|
||||||
|
self.assertEqual(new_project.name, f"{new_project_name}/.reports")
|
||||||
|
self.assertEqual(set(new_project.system_tags), {"hidden", "reports"})
|
||||||
|
self.assertEqual(len(self.api.projects.get_all_ex(id=project.id).projects), 1)
|
||||||
|
self.api.reports.move(task=task2_id, project=new_project_id)
|
||||||
|
self.assertEqual(len(self.api.projects.get_all_ex(id=project.id).projects), 0)
|
||||||
|
tasks = self.api.tasks.get_all_ex(
|
||||||
|
project=new_project_id, search_hidden=True
|
||||||
|
).tasks
|
||||||
|
self.assertTrue({task_id, task2_id}.issubset({t.id for t in tasks}))
|
||||||
|
|
||||||
|
def test_reports_search(self):
|
||||||
|
report_task = self._temp_report(name="Rep1")
|
||||||
|
non_report_task = self._temp_task(name="hello")
|
||||||
|
res = self.api.reports.get_all_ex(
|
||||||
|
_any_={"pattern": "hello", "fields": ["name", "id", "tags", "report"]}
|
||||||
|
).tasks
|
||||||
|
self.assertEqual(len(res), 0)
|
||||||
|
|
||||||
|
self.api.reports.update(task=report_task, report="hello world")
|
||||||
|
res = self.api.reports.get_all_ex(
|
||||||
|
_any_={"pattern": "hello", "fields": ["name", "id", "tags", "report"]}
|
||||||
|
).tasks
|
||||||
|
self.assertEqual(len(res), 1)
|
||||||
|
self.assertEqual(res[0].id, report_task)
|
||||||
|
|
||||||
|
def test_reports_task_data(self):
|
||||||
|
report_task = self._temp_report(name="Rep1")
|
||||||
|
non_report_task = self._temp_task(name="hello")
|
||||||
|
debug_image_events = [
|
||||||
|
self._create_task_event(
|
||||||
|
task=non_report_task,
|
||||||
|
type_="training_debug_image",
|
||||||
|
iteration=1,
|
||||||
|
metric=f"Metric_{m}",
|
||||||
|
variant=f"Variant_{v}",
|
||||||
|
url=f"{m}_{v}",
|
||||||
|
)
|
||||||
|
for m in range(2)
|
||||||
|
for v in range(2)
|
||||||
|
]
|
||||||
|
plot_events = [
|
||||||
|
self._create_task_event(
|
||||||
|
task=non_report_task,
|
||||||
|
type_="plot",
|
||||||
|
iteration=1,
|
||||||
|
metric=f"Metric_{m}",
|
||||||
|
variant=f"Variant_{v}",
|
||||||
|
plot_str=f"Hello plot",
|
||||||
|
)
|
||||||
|
for m in range(2)
|
||||||
|
for v in range(2)
|
||||||
|
]
|
||||||
|
self.send_batch([*debug_image_events, *plot_events])
|
||||||
|
|
||||||
|
res = self.api.reports.get_task_data(
|
||||||
|
id=[non_report_task],
|
||||||
|
only_fields=["name"],
|
||||||
|
)
|
||||||
|
self.assertEqual(len(res.tasks), 1)
|
||||||
|
self.assertEqual(res.tasks[0].id, non_report_task)
|
||||||
|
self.assertFalse(any(field in res for field in ("plots", "debug_images")))
|
||||||
|
|
||||||
|
res = self.api.reports.get_task_data(
|
||||||
|
id=[non_report_task],
|
||||||
|
only_fields=["name"],
|
||||||
|
debug_images={"metrics": []},
|
||||||
|
plots={"metrics": [{"metric": "Metric_1"}]},
|
||||||
|
)
|
||||||
|
self.assertEqual(len(res.debug_images), 1)
|
||||||
|
task_events = res.debug_images[0]
|
||||||
|
self.assertEqual(task_events.task, non_report_task)
|
||||||
|
self.assertEqual(len(task_events.iterations), 1)
|
||||||
|
self.assertEqual(len(task_events.iterations[0].events), 4)
|
||||||
|
|
||||||
|
self.assertEqual(len(res.plots), 1)
|
||||||
|
for m, v in (("Metric_1", "Variant_0"), ("Metric_1", "Variant_1")):
|
||||||
|
tasks = nested_get(res.plots, (m, v))
|
||||||
|
self.assertEqual(len(tasks), 1)
|
||||||
|
task_plots = tasks[non_report_task]
|
||||||
|
self.assertEqual(len(task_plots), 1)
|
||||||
|
iter_plots = task_plots["1"]
|
||||||
|
self.assertEqual(iter_plots.name, "hello")
|
||||||
|
self.assertEqual(len(iter_plots.plots), 1)
|
||||||
|
ev = iter_plots.plots[0]
|
||||||
|
self.assertEqual(ev["metric"], m)
|
||||||
|
self.assertEqual(ev["variant"], v)
|
||||||
|
self.assertEqual(ev["task"], non_report_task)
|
||||||
|
self.assertEqual(ev["iter"], 1)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_task_event(type_, task, iteration, **kwargs):
|
||||||
|
return {
|
||||||
|
"worker": "test",
|
||||||
|
"type": type_,
|
||||||
|
"task": task,
|
||||||
|
"iter": iteration,
|
||||||
|
"timestamp": kwargs.get("timestamp") or es_factory.get_timestamp_millis(),
|
||||||
|
**kwargs,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _temp_report(self, name, **kwargs):
|
||||||
|
return self.create_temp(
|
||||||
|
"reports",
|
||||||
|
name=name,
|
||||||
|
object_name="task",
|
||||||
|
delete_params={"force": True},
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _temp_task(self, name, **kwargs):
|
||||||
|
return self.create_temp(
|
||||||
|
"tasks",
|
||||||
|
name=name,
|
||||||
|
type="training",
|
||||||
|
delete_params={"force": True},
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def send_batch(self, events):
|
||||||
|
_, data = self.api.send_batch("events.add_batch", events)
|
||||||
|
return data
|
Loading…
Reference in New Issue
Block a user