diff --git a/optuna_dashboard/ts/components/PreferentialTrials.tsx b/optuna_dashboard/ts/components/PreferentialTrials.tsx
index 5c141403..1129d2a0 100644
--- a/optuna_dashboard/ts/components/PreferentialTrials.tsx
+++ b/optuna_dashboard/ts/components/PreferentialTrials.tsx
@@ -7,17 +7,59 @@ import {
CardContent,
CardActions,
CardActionArea,
+ CardMedia,
+ MenuItem,
+ Select,
+ FormControl,
+ FormLabel,
+ TextField,
+ Modal,
} from "@mui/material"
-import ClearIcon from "@mui/icons-material/Clear"
-import IconButton from "@mui/material/IconButton"
import OpenInFullIcon from "@mui/icons-material/OpenInFull"
import ReplayIcon from "@mui/icons-material/Replay"
-import Modal from "@mui/material/Modal"
-import { red } from "@mui/material/colors"
-
+import ClearIcon from "@mui/icons-material/Clear"
+import IconButton from "@mui/material/IconButton"
+import SettingsIcon from "@mui/icons-material/Settings"
+import red from "@mui/material/colors/red"
+import { useRecoilValue, useSetRecoilState } from "recoil"
import { actionCreator } from "../action"
-import { TrialListDetail } from "./TrialList"
import { MarkdownRenderer } from "./Note"
+import {
+ feedbackComponent,
+ FeedbackComponentType,
+ feedbackArtifactKey,
+} from "../state"
+import {
+ TrialArtifactActions,
+ TrialArtifactContent,
+ TrialListDetail,
+} from "./TrialList"
+
+const FeedbackContent: FC<{
+ trial: Trial
+ artifact?: Artifact
+}> = ({ trial, artifact }) => {
+ const componentId = useRecoilValue(feedbackComponent)
+
+ if (componentId === "note") {
+ return
+ }
+ if (componentId === "artifact") {
+ if (artifact === undefined) {
+ return null
+ }
+ return (
+
+ )
+ }
+
+ return null
+}
const PreferentialTrial: FC<{
trial?: Trial
@@ -29,6 +71,9 @@ const PreferentialTrial: FC<{
const trialWidth = 500
const trialHeight = 300
const [detailShown, setDetailShown] = useState(false)
+ const componentId = useRecoilValue(feedbackComponent)
+ const artifactKey = useRecoilValue(feedbackArtifactKey)
+ const artifact = trial?.artifacts.find((a) => a.filename === artifactKey)
if (trial == undefined) {
return (
@@ -52,7 +97,19 @@ const PreferentialTrial: FC<{
}}
>
- Trial {trial.number}
+
+ Trial {trial.number}
+ {componentId === "artifact" && artifact !== undefined
+ ? ` (${artifact.filename})`
+ : ""}
+
+ {componentId === "artifact" && artifact !== undefined ? (
+
+ ) : null}
-
+
= ({
numbers: studyDetail.best_trials.map((t) => t.number),
last_number: Math.max(...studyDetail.best_trials.map((t) => t.number), -1),
})
+ const [settingShown, setSettingShown] = useState(false)
+ const outputComponent = useRecoilValue(feedbackComponent)
+ const setOutputComponent = useSetRecoilState(feedbackComponent)
+ const outputartifactKey = useRecoilValue(feedbackArtifactKey)
+ const setOutputartifactKey = useSetRecoilState(feedbackArtifactKey)
const new_trails = studyDetail.best_trials.filter(
(t) =>
displayTrials.last_number < t.number &&
@@ -228,7 +290,23 @@ export const PreferentialTrials: FC<{ studyDetail: StudyDetail | null }> = ({
}
return (
-
+
+ setSettingShown(true)}
+ >
+
+
= ({
/>
))}
+
+
+ Settings
+
+
+ Output Component:
+
+
+ {outputComponent === "artifact" ? (
+
+ Output File:
+ {
+ setOutputartifactKey(e.target.value)
+ }}
+ />
+
+ ) : null}
+
+
+
)
}
diff --git a/optuna_dashboard/ts/components/TrialList.tsx b/optuna_dashboard/ts/components/TrialList.tsx
index 4aceb619..25ec9fab 100644
--- a/optuna_dashboard/ts/components/TrialList.tsx
+++ b/optuna_dashboard/ts/components/TrialList.tsx
@@ -22,6 +22,7 @@ import {
CardActionArea,
Modal,
} from "@mui/material"
+import { SxProps } from "@mui/system"
import Chip from "@mui/material/Chip"
import Divider from "@mui/material/Divider"
import List from "@mui/material/List"
@@ -319,16 +320,397 @@ export const TrialListDetail: FC<{
value !== null ? renderInfo(key, value) : null
)}
- {artifactEnabled && }
+ {artifactEnabled && }
)
}
-const TrialArtifact: FC<{ trial: Trial }> = ({ trial }) => {
+export const TrialArtifactContent: FC<{
+ trial: Trial
+ artifact: Artifact
+ width: string
+ height: string
+}> = ({ trial, artifact, width, height }) => {
+ if (artifact.mimetype.startsWith("image")) {
+ return (
+
+ )
+ } else if (
+ artifact.filename.endsWith(".stl") ||
+ artifact.filename.endsWith(".3dm")
+ ) {
+ return (
+
+
+
+ )
+ } else if (artifact.mimetype.startsWith("audio")) {
+ return (
+
+
+
+ )
+ } else {
+ return (
+
+
+
+ )
+ }
+}
+
+export const TrialArtifactActions: FC<{
+ trial: Trial
+ artifact: Artifact
+ sx: SxProps
+}> = ({ trial, artifact, sx }) => {
+ const [open3dModelViewer, setOpen3dModelViewer] = useState(false)
+
+ if (artifact.mimetype.startsWith("image")) {
+ return null
+ } else if (
+ artifact.filename.endsWith(".stl") ||
+ artifact.filename.endsWith(".3dm")
+ ) {
+ return (
+ <>
+ {
+ setOpen3dModelViewer(true)
+ }}
+ >
+
+
+ {
+ setOpen3dModelViewer(false)
+ }}
+ >
+
+
+
+
+ >
+ )
+ }
+ return null
+}
+
+const TrialArtifact: FC<{
+ trial: Trial
+ artifact: Artifact
+ width: string
+ height: string
+}> = ({ trial, artifact, width, height }) => {
+ const [openDeleteArtifactDialog, _] = useDeleteArtifactDialog()
+ const theme = useTheme()
+ if (artifact.mimetype.startsWith("image")) {
+ return (
+
+
+
+
+ {artifact.filename}
+
+ {
+ openDeleteArtifactDialog(trial.study_id, trial.trial_id, artifact)
+ }}
+ >
+
+
+
+
+
+
+
+ )
+ } else if (
+ artifact.filename.endsWith(".stl") ||
+ artifact.filename.endsWith(".3dm")
+ ) {
+ return (
+
+
+
+
+ {artifact.filename}
+
+
+ {
+ openDeleteArtifactDialog(trial.study_id, trial.trial_id, artifact)
+ }}
+ >
+
+
+
+
+
+
+
+ )
+ } else if (artifact.mimetype.startsWith("audio")) {
+ return (
+
+
+
+
+ {artifact.filename}
+
+ {
+ openDeleteArtifactDialog(trial.study_id, trial.trial_id, artifact)
+ }}
+ >
+
+
+
+
+
+
+
+ )
+ } else {
+ return (
+
+
+
+
+ {artifact.filename}
+
+ {
+ openDeleteArtifactDialog(trial.study_id, trial.trial_id, artifact)
+ }}
+ >
+
+
+
+
+
+
+
+ )
+ }
+}
+
+const TrialArtifacts: FC<{ trial: Trial }> = ({ trial }) => {
const theme = useTheme()
const action = actionCreator()
- const [openDeleteArtifactDialog, renderDeleteArtifactDialog] =
- useDeleteArtifactDialog()
+ const [_, renderDeleteArtifactDialog] = useDeleteArtifactDialog()
const [dragOver, setDragOver] = useState(false)
const [open3dModelViewer, setOpen3dModelViewer] = useState<{
[key: string]: boolean
@@ -382,334 +764,15 @@ const TrialArtifact: FC<{ trial: Trial }> = ({ trial }) => {
Artifacts
- {trial.artifacts.map((a) => {
- if (a.mimetype.startsWith("image")) {
- return (
-
-
-
-
- {a.filename}
-
- {
- openDeleteArtifactDialog(
- trial.study_id,
- trial.trial_id,
- a
- )
- }}
- >
-
-
-
-
-
-
-
- )
- } else if (
- a.filename.endsWith(".stl") ||
- a.filename.endsWith(".3dm")
- ) {
- return (
-
-
-
-
-
-
- {a.filename}
-
- {
- setOpen3dModelViewer(() => {
- const obj = { ...open3dModelViewer }
- obj[a.artifact_id] = true
- return obj
- })
- }}
- >
-
-
- {
- setOpen3dModelViewer(() => {
- const obj = { ...open3dModelViewer }
- obj[a.artifact_id] = false
- return obj
- })
- }}
- >
-
-
-
-
- {
- openDeleteArtifactDialog(
- trial.study_id,
- trial.trial_id,
- a
- )
- }}
- >
-
-
-
-
-
-
-
- )
- } else if (a.mimetype.startsWith("audio")) {
- return (
-
-
-
-
-
-
- {a.filename}
-
- {
- openDeleteArtifactDialog(
- trial.study_id,
- trial.trial_id,
- a
- )
- }}
- >
-
-
-
-
-
-
-
- )
- } else {
- return (
-
-
-
-
-
-
- {a.filename}
-
- {
- openDeleteArtifactDialog(
- trial.study_id,
- trial.trial_id,
- a
- )
- }}
- >
-
-
-
-
-
-
-
- )
- }
- })}
+ {trial.artifacts.map((a) => (
+
+ ))}
{trial.state === "Running" || trial.state === "Waiting" ? (
({
default: false,
})
+export type FeedbackComponentType = "note" | "artifact"
+export const feedbackComponent = atom({
+ key: "feedbackComponent",
+ default: "note",
+})
+
+export const feedbackArtifactKey = atom({
+ key: "feedbackArtifactKey",
+ default: "",
+})
+
export const useStudyDetailValue = (studyId: number): StudyDetail | null => {
const studyDetails = useRecoilValue(studyDetailsState)
return studyDetails[studyId] || null