mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-09-23 13:30:25 +08:00
Implement human-in-the-loop via trial.user_attrs
This commit is contained in:
@@ -447,6 +447,23 @@ def create_app(
|
||||
response.status = 204
|
||||
return {}
|
||||
|
||||
@app.post("/api/trials/<trial_id:int>/user-attrs")
|
||||
@json_api_view
|
||||
def save_trial_user_attrs(trial_id: int) -> dict[str, Any]:
|
||||
if "user_attrs" not in request.json:
|
||||
response.status = 400 # Bad request
|
||||
return {"reason": "user_attrs must be specified."}
|
||||
|
||||
try: # TODO(knshnb): Proper error handling.
|
||||
for key, val in request.json.get("user_attrs").items():
|
||||
storage.set_trial_user_attr(trial_id, key, val)
|
||||
except Exception as e:
|
||||
response.status = 500
|
||||
return {"reason": f"Internal server error: {e}"}
|
||||
|
||||
response.status = 204
|
||||
return {}
|
||||
|
||||
@app.put("/api/studies/<study_id:int>/<trial_id:int>/note")
|
||||
@json_api_view
|
||||
def save_trial_note(study_id: int, trial_id: int) -> dict[str, Any]:
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
uploadArtifactAPI,
|
||||
getMetaInfoAPI,
|
||||
deleteArtifactAPI,
|
||||
saveTrialUserAttrsAPI,
|
||||
} from "./apiClient"
|
||||
import {
|
||||
graphVisibilityState,
|
||||
@@ -482,6 +483,32 @@ export const actionCreator = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const saveTrialUserAttrs = (
|
||||
studyId: number,
|
||||
trialId: number,
|
||||
user_attrs: {[key: string]: number},
|
||||
): void => {
|
||||
console.log("user_attrs", user_attrs)
|
||||
// TODO(knshnb): Update rendering of `user_attrs`.
|
||||
const message = `id=${trialId}, user_attrs=${user_attrs}`
|
||||
saveTrialUserAttrsAPI(trialId, user_attrs)
|
||||
.then(() => {
|
||||
// TODO(knshnb): Update states.
|
||||
enqueueSnackbar(`Successfully updated trial (${message})`, {
|
||||
variant: "success",
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
const reason = err.response?.data.reason
|
||||
enqueueSnackbar(
|
||||
`Failed to update trial (${message}). Reason: ${reason}`,
|
||||
{
|
||||
variant: "error",
|
||||
}
|
||||
)
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
return {
|
||||
updateAPIMeta,
|
||||
updateStudyDetail,
|
||||
@@ -499,6 +526,7 @@ export const actionCreator = () => {
|
||||
uploadArtifact,
|
||||
deleteArtifact,
|
||||
tellTrial,
|
||||
saveTrialUserAttrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,19 @@ export const tellTrialAPI = (
|
||||
})
|
||||
}
|
||||
|
||||
export const saveTrialUserAttrsAPI = (
|
||||
trialId: number,
|
||||
user_attrs: { [key: string]: number }
|
||||
): Promise<void> => {
|
||||
const req = { user_attrs: user_attrs }
|
||||
|
||||
return axiosInstance
|
||||
.post<void>(`/api/trials/${trialId}/user-attrs`, req)
|
||||
.then((res) => {
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
interface ParamImportancesResponse {
|
||||
param_importances: ParamImportance[][]
|
||||
}
|
||||
|
||||
@@ -65,11 +65,8 @@ export const ObjectiveForm: FC<{
|
||||
|
||||
const handleSubmit = (e: React.MouseEvent<HTMLButtonElement>): void => {
|
||||
e.preventDefault()
|
||||
const filtered = values.filter<number>((v): v is number => v !== null)
|
||||
if (filtered.length !== directions.length) {
|
||||
return
|
||||
}
|
||||
action.tellTrial(trial.study_id, trial.trial_id, "Complete", filtered)
|
||||
const user_attrs = Object.fromEntries(widgets.map((widget, i) => [widget.description, values[i]]))
|
||||
action.saveTrialUserAttrs(trial.study_id, trial.trial_id, user_attrs)
|
||||
}
|
||||
|
||||
const getObjectiveName = (i: number): string => {
|
||||
|
||||
Reference in New Issue
Block a user