From ddeea56675f642fc11fb1547803cdd3f57d63390 Mon Sep 17 00:00:00 2001 From: porink0424 Date: Wed, 24 Apr 2024 16:54:36 +0900 Subject: [PATCH] Impl abstract class APIClient --- optuna_dashboard/ts/apiClient.ts | 493 ++++++++----------------------- 1 file changed, 126 insertions(+), 367 deletions(-) diff --git a/optuna_dashboard/ts/apiClient.ts b/optuna_dashboard/ts/apiClient.ts index 982d1553..038ea9f7 100644 --- a/optuna_dashboard/ts/apiClient.ts +++ b/optuna_dashboard/ts/apiClient.ts @@ -1,5 +1,4 @@ import * as Optuna from "@optuna/types" -import axios from "axios" import * as plotly from "plotly.js-dist-min" import { Artifact, @@ -17,19 +16,11 @@ import { TrialParam, } from "./types/optuna" -const axiosInstance = axios.create({ baseURL: API_ENDPOINT }) - -type APIMeta = { +export type APIMeta = { artifact_is_available: boolean plotlypy_is_available: boolean } -export const getMetaInfoAPI = (): Promise => { - return axiosInstance - .get(`/api/meta`) - .then((res) => res.data) -} - interface TrialResponse { trial_id: number study_id: number @@ -50,29 +41,6 @@ interface TrialResponse { constraints: number[] } -const convertTrialResponse = (res: TrialResponse): Trial => { - return { - trial_id: res.trial_id, - study_id: res.study_id, - number: res.number, - state: res.state, - values: res.values, - intermediate_values: res.intermediate_values, - datetime_start: res.datetime_start - ? new Date(res.datetime_start) - : undefined, - datetime_complete: res.datetime_complete - ? new Date(res.datetime_complete) - : undefined, - params: res.params, - fixed_params: res.fixed_params, - user_attrs: res.user_attrs, - note: res.note, - artifacts: res.artifacts, - constraints: res.constraints, - } -} - interface PreferenceHistoryResponse { history: { id: string @@ -85,21 +53,7 @@ interface PreferenceHistoryResponse { is_removed: boolean } -const convertPreferenceHistory = ( - res: PreferenceHistoryResponse -): PreferenceHistory => { - return { - id: res.history.id, - candidates: res.history.candidates, - clicked: res.history.clicked, - feedback_mode: res.history.mode, - timestamp: new Date(res.history.timestamp), - preferences: res.history.preferences, - is_removed: res.is_removed, - } -} - -interface StudyDetailResponse { +export interface StudyDetailResponse { name: string datetime_start: string directions: Optuna.StudyDirection[] @@ -122,52 +76,7 @@ interface StudyDetailResponse { skipped_trial_numbers?: number[] } -export const getStudyDetailAPI = ( - studyId: number, - nLocalTrials: number -): Promise => { - return axiosInstance - .get(`/api/studies/${studyId}`, { - params: { - after: nLocalTrials, - }, - }) - .then((res) => { - const trials = res.data.trials.map((trial): Trial => { - return convertTrialResponse(trial) - }) - const best_trials = res.data.best_trials.map((trial): Trial => { - return convertTrialResponse(trial) - }) - return { - id: studyId, - name: res.data.name, - datetime_start: new Date(res.data.datetime_start), - directions: res.data.directions, - user_attrs: res.data.user_attrs, - trials: trials, - best_trials: best_trials, - union_search_space: res.data.union_search_space, - intersection_search_space: res.data.intersection_search_space, - union_user_attrs: res.data.union_user_attrs, - has_intermediate_values: res.data.has_intermediate_values, - note: res.data.note, - objective_names: res.data.objective_names, - form_widgets: res.data.form_widgets, - is_preferential: res.data.is_preferential, - feedback_component_type: res.data.feedback_component_type, - preferences: res.data.preferences, - preference_history: res.data.preference_history?.map( - convertPreferenceHistory - ), - plotly_graph_objects: res.data.plotly_graph_objects, - artifacts: res.data.artifacts, - skipped_trial_numbers: res.data.skipped_trial_numbers ?? [], - } - }) -} - -interface StudySummariesResponse { +export interface StudySummariesResponse { study_summaries: { study_id: number study_name: string @@ -178,26 +87,7 @@ interface StudySummariesResponse { }[] } -export const getStudySummariesAPI = (): Promise => { - return axiosInstance - .get(`/api/studies`, {}) - .then((res) => { - return res.data.study_summaries.map((study): StudySummary => { - return { - study_id: study.study_id, - study_name: study.study_name, - directions: study.directions, - user_attrs: study.user_attrs, - is_preferential: study.is_preferential, - datetime_start: study.datetime_start - ? new Date(study.datetime_start) - : undefined, - } - }) - }) -} - -interface CreateNewStudyResponse { +export interface CreateNewStudyResponse { study_summary: { study_id: number study_name: string @@ -208,38 +98,7 @@ interface CreateNewStudyResponse { } } -export const createNewStudyAPI = ( - studyName: string, - directions: Optuna.StudyDirection[] -): Promise => { - return axiosInstance - .post(`/api/studies`, { - study_name: studyName, - directions, - }) - .then((res) => { - const study_summary = res.data.study_summary - return { - study_id: study_summary.study_id, - study_name: study_summary.study_name, - directions: study_summary.directions, - // best_trial: undefined, - user_attrs: study_summary.user_attrs, - is_preferential: study_summary.is_preferential, - datetime_start: study_summary.datetime_start - ? new Date(study_summary.datetime_start) - : undefined, - } - }) -} - -export const deleteStudyAPI = (studyId: number): Promise => { - return axiosInstance.delete(`/api/studies/${studyId}`).then(() => { - return - }) -} - -type RenameStudyResponse = { +export type RenameStudyResponse = { study_id: number study_name: string directions: Optuna.StudyDirection[] @@ -248,220 +107,20 @@ type RenameStudyResponse = { datetime_start?: string } -export const renameStudyAPI = ( - studyId: number, - studyName: string -): Promise => { - return axiosInstance - .post(`/api/studies/${studyId}/rename`, { - study_name: studyName, - }) - .then((res) => { - return { - study_id: res.data.study_id, - study_name: res.data.study_name, - directions: res.data.directions, - user_attrs: res.data.user_attrs, - is_preferential: res.data.is_prefential, - datetime_start: res.data.datetime_start - ? new Date(res.data.datetime_start) - : undefined, - } - }) -} - -export const saveStudyNoteAPI = ( - studyId: number, - note: { version: number; body: string } -): Promise => { - return axiosInstance - .put(`/api/studies/${studyId}/note`, note) - .then(() => { - return - }) -} - -export const saveTrialNoteAPI = ( - studyId: number, - trialId: number, - note: { version: number; body: string } -): Promise => { - return axiosInstance - .put(`/api/studies/${studyId}/${trialId}/note`, note) - .then(() => { - return - }) -} - -type UploadArtifactAPIResponse = { +export type UploadArtifactAPIResponse = { artifact_id: string artifacts: Artifact[] } -export const uploadTrialArtifactAPI = ( - studyId: number, - trialId: number, - fileName: string, - dataUrl: string -): Promise => { - return axiosInstance - .post(`/api/artifacts/${studyId}/${trialId}`, { - file: dataUrl, - filename: fileName, - }) - .then((res) => { - return res.data - }) -} - -export const uploadStudyArtifactAPI = ( - studyId: number, - fileName: string, - dataUrl: string -): Promise => { - return axiosInstance - .post(`/api/artifacts/${studyId}`, { - file: dataUrl, - filename: fileName, - }) - .then((res) => { - return res.data - }) -} - -export const deleteTrialArtifactAPI = ( - studyId: number, - trialId: number, - artifactId: string -): Promise => { - return axiosInstance - .delete(`/api/artifacts/${studyId}/${trialId}/${artifactId}`) - .then(() => { - return - }) -} - -export const deleteStudyArtifactAPI = ( - studyId: number, - artifactId: string -): Promise => { - return axiosInstance - .delete(`/api/artifacts/${studyId}/${artifactId}`) - .then(() => { - return - }) -} - -export const tellTrialAPI = ( - trialId: number, - state: Optuna.TrialStateFinished, - values?: number[] -): Promise => { - const req: { state: Optuna.TrialState; values?: number[] } = { - state: state, - values: values, - } - - return axiosInstance - .post(`/api/trials/${trialId}/tell`, req) - .then(() => { - return - }) -} - -export const saveTrialUserAttrsAPI = ( - trialId: number, - user_attrs: { [key: string]: number | string } -): Promise => { - const req = { user_attrs: user_attrs } - - return axiosInstance - .post(`/api/trials/${trialId}/user-attrs`, req) - .then(() => { - return - }) -} - -interface ParamImportancesResponse { +export interface ParamImportancesResponse { param_importances: ParamImportance[][] } -export const getParamImportances = ( - studyId: number -): Promise => { - return axiosInstance - .get(`/api/studies/${studyId}/param_importances`) - .then((res) => { - return res.data.param_importances - }) -} - -export const reportPreferenceAPI = ( - studyId: number, - candidates: number[], - clicked: number -): Promise => { - return axiosInstance - .post(`/api/studies/${studyId}/preference`, { - candidates: candidates, - clicked: clicked, - mode: "ChooseWorst", - }) - .then(() => { - return - }) -} - -export const skipPreferentialTrialAPI = ( - studyId: number, - trialId: number -): Promise => { - return axiosInstance - .post(`/api/studies/${studyId}/${trialId}/skip`) - .then(() => { - return - }) -} - -export const removePreferentialHistoryAPI = ( - studyId: number, - historyUuid: string -): Promise => { - return axiosInstance - .delete(`/api/studies/${studyId}/preference/${historyUuid}`) - .then(() => { - return - }) -} -export const restorePreferentialHistoryAPI = ( - studyId: number, - historyUuid: string -): Promise => { - return axiosInstance - .post(`/api/studies/${studyId}/preference/${historyUuid}`) - .then(() => { - return - }) -} - -export const reportFeedbackComponentAPI = ( - studyId: number, - component_type: FeedbackComponentType -): Promise => { - return axiosInstance - .put( - `/api/studies/${studyId}/preference_feedback_component`, - component_type - ) - .then(() => { - return - }) -} - -type PlotResponse = { +export type PlotResponse = { data: plotly.Data[] layout: plotly.Layout } + export enum PlotType { Contour = "contour", Slice = "slice", @@ -472,25 +131,125 @@ export enum PlotType { ParamImportances = "param_importances", ParetoFront = "pareto_front", } -export const getPlotAPI = ( - studyId: number, - plotType: PlotType -): Promise => { - return axiosInstance - .get(`/api/studies/${studyId}/plot/${plotType}`) - .then((res) => res.data) -} export enum CompareStudiesPlotType { EDF = "edf", } -export const getCompareStudiesPlotAPI = ( - studyIds: number[], - plotType: CompareStudiesPlotType -): Promise => { - return axiosInstance - .get(`/api/compare-studies/plot/${plotType}`, { - params: { study_ids: studyIds }, - }) - .then((res) => res.data) + +export abstract class APIClient { + constructor() {} + + convertTrialResponse(response: TrialResponse): Trial { + return { + trial_id: response.trial_id, + study_id: response.study_id, + number: response.number, + state: response.state, + values: response.values, + intermediate_values: response.intermediate_values, + datetime_start: response.datetime_start + ? new Date(response.datetime_start) + : undefined, + datetime_complete: response.datetime_complete + ? new Date(response.datetime_complete) + : undefined, + params: response.params, + fixed_params: response.fixed_params, + user_attrs: response.user_attrs, + note: response.note, + artifacts: response.artifacts, + constraints: response.constraints, + } + } + convertPreferenceHistory( + response: PreferenceHistoryResponse + ): PreferenceHistory { + return { + id: response.history.id, + candidates: response.history.candidates, + clicked: response.history.clicked, + feedback_mode: response.history.mode, + timestamp: new Date(response.history.timestamp), + preferences: response.history.preferences, + is_removed: response.is_removed, + } + } + + abstract getMetaInfo(): Promise + abstract getStudyDetail( + studyId: number, + nLocalTrials: number + ): Promise + abstract getStudySummaries(): Promise + abstract createNewStudy( + studyName: string, + directions: Optuna.StudyDirection[] + ): Promise + abstract deleteStudy(studyId: number): Promise + abstract renameStudy( + studyId: number, + studyName: string + ): Promise + abstract saveStudyNote(studyId: number, note: Note): Promise + abstract saveTrialNote( + studyId: number, + trialId: number, + note: Note + ): Promise + abstract uploadTrialArtifact( + studyId: number, + trialId: number, + fileName: string, + dataUrl: string + ): Promise + abstract uploadStudyArtifact( + studyId: number, + fileName: string, + dataUrl: string + ): Promise + abstract deleteTrialArtifact( + studyId: number, + trialId: number, + artifactId: string + ): Promise + abstract deleteStudyArtifact( + studyId: number, + artifactId: string + ): Promise + abstract tellTrial( + trialId: number, + state: Optuna.TrialStateFinished, + values?: number[] + ): Promise + abstract saveTrialUserAttrs( + trialId: number, + user_attrs: { [key: string]: number | string } + ): Promise + abstract getParamImportances(studyId: number): Promise + abstract reportPreference( + studyId: number, + candidates: number[], + clicked: number + ): Promise + abstract skipPreferentialTrial( + studyId: number, + trialId: number + ): Promise + abstract removePreferentialHistory( + studyId: number, + historyUuid: string + ): Promise + abstract restorePreferentialHistory( + studyId: number, + historyUuid: string + ): Promise + abstract reportFeedbackComponent( + studyId: number, + component_type: FeedbackComponentType + ): Promise + abstract getPlot(studyId: number, plotType: PlotType): Promise + abstract getCompareStudiesPlot( + studyIds: number[], + plotType: CompareStudiesPlotType + ): Promise }