alchemist-nrel 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. alchemist_core/__init__.py +14 -7
  2. alchemist_core/acquisition/botorch_acquisition.py +14 -6
  3. alchemist_core/audit_log.py +594 -0
  4. alchemist_core/data/experiment_manager.py +69 -5
  5. alchemist_core/models/botorch_model.py +6 -4
  6. alchemist_core/models/sklearn_model.py +44 -6
  7. alchemist_core/session.py +600 -8
  8. alchemist_core/utils/doe.py +200 -0
  9. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/METADATA +57 -40
  10. alchemist_nrel-0.3.0.dist-info/RECORD +66 -0
  11. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/entry_points.txt +1 -0
  12. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/top_level.txt +1 -0
  13. api/main.py +19 -3
  14. api/models/requests.py +71 -0
  15. api/models/responses.py +144 -0
  16. api/routers/experiments.py +117 -5
  17. api/routers/sessions.py +329 -10
  18. api/routers/visualizations.py +10 -5
  19. api/services/session_store.py +210 -54
  20. api/static/NEW_ICON.ico +0 -0
  21. api/static/NEW_ICON.png +0 -0
  22. api/static/NEW_LOGO_DARK.png +0 -0
  23. api/static/NEW_LOGO_LIGHT.png +0 -0
  24. api/static/assets/api-vcoXEqyq.js +1 -0
  25. api/static/assets/index-C0_glioA.js +4084 -0
  26. api/static/assets/index-CB4V1LI5.css +1 -0
  27. api/static/index.html +14 -0
  28. api/static/vite.svg +1 -0
  29. run_api.py +55 -0
  30. ui/gpr_panel.py +7 -2
  31. ui/notifications.py +197 -10
  32. ui/ui.py +1117 -68
  33. ui/variables_setup.py +47 -2
  34. ui/visualizations.py +60 -3
  35. alchemist_nrel-0.2.1.dist-info/RECORD +0 -54
  36. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/WHEEL +0 -0
  37. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 98%;--foreground: 222.2 84% 4.9%;--card: 0 0% 100%;--card-foreground: 222.2 84% 4.9%;--popover: 0 0% 100%;--popover-foreground: 222.2 84% 4.9%;--primary: 217 91% 50%;--primary-foreground: 0 0% 100%;--secondary: 214 32% 88%;--secondary-foreground: 222.2 47.4% 11.2%;--muted: 210 40% 93%;--muted-foreground: 215.4 16.3% 40%;--accent: 210 40% 93%;--accent-foreground: 222.2 47.4% 11.2%;--destructive: 0 84.2% 50%;--destructive-foreground: 0 0% 100%;--border: 214.3 31.8% 85%;--input: 214.3 31.8% 85%;--ring: 217 91% 50%;--radius: .5rem}.dark{--background: 220 13% 13%;--foreground: 210 40% 98%;--card: 220 13% 16%;--card-foreground: 210 40% 98%;--popover: 220 13% 16%;--popover-foreground: 210 40% 98%;--primary: 211 100% 65%;--primary-foreground: 220 13% 13%;--secondary: 217.2 32.6% 20%;--secondary-foreground: 210 40% 98%;--muted: 220 13% 20%;--muted-foreground: 215 15% 65%;--accent: 220 13% 20%;--accent-foreground: 210 40% 98%;--destructive: 0 70% 55%;--destructive-foreground: 210 40% 98%;--border: 220 13% 24%;--input: 220 13% 24%;--ring: 211 100% 65%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));margin:0;min-height:100vh;font-feature-settings:"kern" 1,"liga" 1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code,.tabular-nums{font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.z-50{z-index:50}.col-span-1{grid-column:span 1 / span 1}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-12{height:3rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-96{height:24rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-\[120px\]{max-height:120px}.max-h-\[450px\]{max-height:450px}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:0px}.min-h-\[550px\]{min-height:550px}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[320px\]{width:320px}.w-\[580px\]{width:580px}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1\.5{row-gap:.375rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-500\/20{border-color:#f59e0b33}.border-blue-500\/30{border-color:#3b82f64d}.border-border{border-color:hsl(var(--border))}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-destructive\/30{border-color:hsl(var(--destructive) / .3)}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-green-500\/20{border-color:#22c55e33}.border-input{border-color:hsl(var(--input))}.border-muted{border-color:hsl(var(--muted))}.border-muted-foreground\/20{border-color:hsl(var(--muted-foreground) / .2)}.border-primary{border-color:hsl(var(--primary))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-background{background-color:hsl(var(--background))}.bg-black\/50{background-color:#00000080}.bg-blue-500\/5{background-color:#3b82f60d}.bg-card{background-color:hsl(var(--card))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-secondary{background-color:hsl(var(--secondary))}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pr-2{padding-right:.5rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-6xl{font-size:3.75rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-destructive{color:hsl(var(--destructive))}.text-foreground{color:hsl(var(--foreground))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-600{--tw-text-opacity: 1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--muted-foreground) / .3);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:hsl(var(--muted-foreground) / .5)}*{scrollbar-width:thin;scrollbar-color:hsl(var(--muted-foreground) / .3) transparent}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/10:hover{background-color:hsl(var(--destructive) / .1)}.hover\:bg-green-700:hover{--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:bg-muted\/5:hover{background-color:hsl(var(--muted) / .05)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-muted\/80:hover{background-color:hsl(var(--muted) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-secondary\/90:hover{background-color:hsl(var(--secondary) / .9)}.hover\:text-destructive\/80:hover{color:hsl(var(--destructive) / .8)}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary\/80:hover{color:hsl(var(--primary) / .8)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-primary\/50:focus{--tw-ring-color: hsl(var(--primary) / .5)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.dark\:text-amber-500:is(.dark *){--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.dark\:text-green-500:is(.dark *){--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
api/static/index.html ADDED
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/NEW_ICON.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>ALchemist - Active Learning Toolkit</title>
8
+ <script type="module" crossorigin src="/assets/index-C0_glioA.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-CB4V1LI5.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
api/static/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
run_api.py ADDED
@@ -0,0 +1,55 @@
1
+ """
2
+ Startup script for ALchemist FastAPI server.
3
+
4
+ Usage:
5
+ python run_api.py # Development mode with auto-reload
6
+ python run_api.py --production # Production mode (no reload)
7
+ python run_api.py --dev # Explicitly start in development mode
8
+ alchemist-web # Entry point (production mode by default)
9
+ """
10
+
11
+ def main():
12
+ """Entry point for alchemist-web command."""
13
+ import uvicorn
14
+ import sys
15
+
16
+ # For the alchemist-web entry point, default to production mode
17
+ # Only use dev mode if explicitly requested
18
+ is_script_call = any(arg.endswith('run_api.py') for arg in sys.argv)
19
+
20
+ if is_script_call:
21
+ # Called as: python run_api.py
22
+ # Default to dev mode unless --production flag is present
23
+ production = "--production" in sys.argv or "--prod" in sys.argv
24
+ else:
25
+ # Called as: alchemist-web
26
+ # Default to production mode unless --dev flag is present
27
+ production = "--dev" not in sys.argv and "--development" not in sys.argv
28
+
29
+ if production:
30
+ print("Starting ALchemist API in PRODUCTION mode...")
31
+ print("Access the web UI at: http://localhost:8000")
32
+ # Run the API server in production mode
33
+ uvicorn.run(
34
+ "api.main:app",
35
+ host="0.0.0.0",
36
+ port=8000,
37
+ reload=False,
38
+ log_level="warning",
39
+ workers=1 # Increase to 4 for multi-core production
40
+ )
41
+ else:
42
+ print("Starting ALchemist API in DEVELOPMENT mode...")
43
+ print("API docs: http://localhost:8000/api/docs")
44
+ # Run the API server in development mode
45
+ uvicorn.run(
46
+ "api.main:app",
47
+ host="0.0.0.0",
48
+ port=8000,
49
+ reload=True,
50
+ log_level="info"
51
+ )
52
+
53
+
54
+ if __name__ == "__main__":
55
+ main()
ui/gpr_panel.py CHANGED
@@ -444,10 +444,15 @@ class GaussianProcessPanel(ctk.CTkFrame):
444
444
 
445
445
  # Get categorical dimensions
446
446
  categorical_variables = self.main_app.search_space_manager.get_categorical_variables()
447
+
448
+ # Get feature columns (excluding metadata)
449
+ metadata_cols = {'Output', 'Noise', 'Iteration', 'Reason'}
450
+ feature_cols = [col for col in self.main_app.exp_df.columns if col not in metadata_cols]
451
+
447
452
  cat_dims = [
448
- list(self.main_app.exp_df.columns).index(var)
453
+ feature_cols.index(var)
449
454
  for var in categorical_variables
450
- if var in self.main_app.exp_df.columns
455
+ if var in feature_cols
451
456
  ]
452
457
 
453
458
  # Train using session API
ui/notifications.py CHANGED
@@ -16,7 +16,16 @@ class ResultNotificationWindow:
16
16
  """
17
17
  self.window = ctk.CTkToplevel(parent)
18
18
  self.window.title("Suggested Next Experiment")
19
- self.window.geometry("600x500")
19
+ # Increase height to avoid bottom content being cut off on smaller displays
20
+ # Use a taller default and enforce a reasonable minimum size
21
+ screen_h = self.window.winfo_screenheight()
22
+ default_h = min(750, int(screen_h * 0.65))
23
+ self.window.geometry(f"600x{default_h}")
24
+ # Ensure window cannot be resized smaller than a usable size
25
+ try:
26
+ self.window.minsize(560, 600)
27
+ except Exception:
28
+ pass
20
29
  self.window.lift()
21
30
  self.window.focus_force()
22
31
  self.window.grab_set()
@@ -39,16 +48,23 @@ class ResultNotificationWindow:
39
48
  # Fill strategy info tab
40
49
  self._create_strategy_info_tab(result_data)
41
50
 
42
- # Add export and close buttons
51
+ # Add action buttons
43
52
  button_frame = ctk.CTkFrame(self.window)
44
53
  button_frame.pack(fill="x", padx=10, pady=10)
45
54
 
46
- export_button = ctk.CTkButton(
55
+ # Store references for logging
56
+ self.result_data = result_data
57
+ self.model_data = model_data
58
+ self.parent = parent
59
+
60
+ log_button = ctk.CTkButton(
47
61
  button_frame,
48
- text="Export to CSV",
49
- command=lambda: self._export_to_csv(result_data, model_data)
62
+ text="📝 Log to Audit Trail",
63
+ command=self._log_to_audit_trail,
64
+ fg_color="green",
65
+ hover_color="darkgreen"
50
66
  )
51
- export_button.pack(side="left", padx=10, pady=5)
67
+ log_button.pack(side="left", padx=10, pady=5)
52
68
 
53
69
  close_button = ctk.CTkButton(
54
70
  button_frame,
@@ -146,7 +162,7 @@ class ResultNotificationWindow:
146
162
  ).pack(pady=5)
147
163
 
148
164
  # Create scrollable frame for coordinates
149
- coords_scroll = ctk.CTkScrollableFrame(coords_frame, height=150)
165
+ coords_scroll = ctk.CTkScrollableFrame(coords_frame, height=220)
150
166
  coords_scroll.pack(fill="x", padx=10, pady=5)
151
167
 
152
168
  # Add each coordinate
@@ -232,7 +248,7 @@ class ResultNotificationWindow:
232
248
  ).pack(pady=5)
233
249
 
234
250
  # Create scrollable frame for model details
235
- model_scroll = ctk.CTkScrollableFrame(model_frame, height=350)
251
+ model_scroll = ctk.CTkScrollableFrame(model_frame, height=520)
236
252
  model_scroll.pack(fill="both", expand=True, padx=10, pady=5)
237
253
 
238
254
  # Basic model info
@@ -342,7 +358,7 @@ class ResultNotificationWindow:
342
358
  ).pack(pady=5)
343
359
 
344
360
  # Create scrollable frame for strategy details
345
- strategy_scroll = ctk.CTkScrollableFrame(strategy_frame, height=350)
361
+ strategy_scroll = ctk.CTkScrollableFrame(strategy_frame, height=520)
346
362
  strategy_scroll.pack(fill="both", expand=True, padx=10, pady=5)
347
363
 
348
364
  # Strategy type
@@ -479,6 +495,112 @@ class ResultNotificationWindow:
479
495
 
480
496
  except Exception as e:
481
497
  print(f"Error exporting results: {e}")
498
+
499
+ def _log_to_audit_trail(self):
500
+ """Log the complete optimization decision (data + model + acquisition) to audit trail."""
501
+ # Show notes dialog
502
+ notes_dialog = AuditNotesDialog(self.window)
503
+ self.window.wait_window(notes_dialog)
504
+
505
+ # Check if user cancelled
506
+ if notes_dialog.result is None:
507
+ print("Audit logging cancelled by user")
508
+ return
509
+
510
+ notes = notes_dialog.result
511
+
512
+ # Get the main app from parent chain
513
+ main_app = self._get_main_app()
514
+ if main_app is None:
515
+ print("Error: Could not find main app to log audit trail")
516
+ return
517
+
518
+ # Get next point(s) from result data
519
+ next_point_df = self.result_data.get('point_df')
520
+
521
+ # Create strategy info dict
522
+ strategy_type = self.result_data.get('strategy_type', 'Unknown')
523
+ strategy_info = {
524
+ 'type': strategy_type,
525
+ 'params': self.result_data.get('strategy_params'),
526
+ 'maximize': self.result_data.get('maximize'),
527
+ 'description': self.result_data.get('strategy_description'),
528
+ 'notes': notes # Add user notes
529
+ }
530
+
531
+ # Store pending suggestions in main app for use with Add Point dialog
532
+ if next_point_df is not None and len(next_point_df) > 0:
533
+ # Convert DataFrame to list of dicts and add metadata
534
+ pending = next_point_df.to_dict('records')
535
+ # Attach authoritative Iteration from the session so the Add Point
536
+ # dialog displays the correct iteration (session.lock_acquisition
537
+ # may have already incremented it).
538
+ sess_iter = int(getattr(main_app.session.experiment_manager, '_current_iteration',
539
+ getattr(main_app.experiment_manager, '_current_iteration', 0)))
540
+ for suggestion in pending:
541
+ suggestion['_reason'] = strategy_type # Tag with acquisition strategy name
542
+ suggestion['Iteration'] = int(suggestion.get('Iteration', sess_iter))
543
+
544
+ # Sync UI experiment manager iteration to session so iteration
545
+ # shown in other UI places is consistent.
546
+ try:
547
+ main_app.experiment_manager._current_iteration = sess_iter
548
+ except Exception:
549
+ pass
550
+
551
+ main_app.pending_suggestions = pending
552
+ main_app.current_suggestion_index = 0
553
+
554
+ batch_size = len(pending)
555
+ if batch_size > 1:
556
+ print(f"✓ Stored {batch_size} pending suggestions from {strategy_type}")
557
+ else:
558
+ print(f"✓ Stored 1 pending suggestion from {strategy_type}")
559
+
560
+ # Call the main app's logging function
561
+ success = main_app.log_optimization_to_audit(next_point_df, strategy_info)
562
+
563
+ if success:
564
+ print("✓ Complete optimization decision logged to audit trail")
565
+ # Show brief success message and close window
566
+ import tkinter as tk
567
+ msg = "Optimization decision logged successfully!\n\n" \
568
+ "• Data snapshot recorded\n" \
569
+ "• Model parameters recorded\n" \
570
+ "• Acquisition strategy recorded\n"
571
+
572
+ if next_point_df is not None and len(next_point_df) > 0:
573
+ batch_size = len(next_point_df)
574
+ if batch_size > 1:
575
+ msg += f"\n{batch_size} suggestions are now pending.\n" \
576
+ f"Use 'Add Point' to enter results for each suggestion."
577
+ else:
578
+ msg += f"\n1 suggestion is now pending.\n" \
579
+ f"Use 'Add Point' to enter the result."
580
+
581
+ tk.messagebox.showinfo("Logged to Audit Trail", msg, parent=self.window)
582
+ self.window.destroy()
583
+ else:
584
+ import tkinter as tk
585
+ tk.messagebox.showerror("Logging Failed",
586
+ "Failed to log optimization decision to audit trail.\n"
587
+ "Check the console for details.",
588
+ parent=self.window)
589
+
590
+ def _get_main_app(self):
591
+ """Walk up the widget tree to find the main app."""
592
+ widget = self.parent
593
+ while widget is not None:
594
+ if hasattr(widget, 'log_optimization_to_audit'):
595
+ return widget
596
+ # Try to get parent for CustomTkinter widgets
597
+ if hasattr(widget, 'master'):
598
+ widget = widget.master
599
+ elif hasattr(widget, 'main_app'):
600
+ widget = widget.main_app
601
+ else:
602
+ break
603
+ return None
482
604
 
483
605
 
484
606
  class CalibrationWarningDialog:
@@ -495,7 +617,8 @@ class CalibrationWarningDialog:
495
617
  """
496
618
  self.window = ctk.CTkToplevel(parent)
497
619
  self.window.title("⚠ Model Calibration Warning")
498
- self.window.geometry("550x400")
620
+ # Slightly taller to ensure recommendations aren't clipped
621
+ self.window.geometry("600x480")
499
622
  self.window.lift()
500
623
  self.window.focus_force()
501
624
  self.window.grab_set()
@@ -652,3 +775,67 @@ def show_calibration_warning(parent, calibration_factor, backend="scikit-learn")
652
775
  CalibrationWarningDialog(parent, calibration_factor, backend)
653
776
  return True
654
777
  return False
778
+
779
+
780
+ # ============================================================
781
+ # Audit Notes Dialog
782
+ # ============================================================
783
+
784
+ class AuditNotesDialog(ctk.CTkToplevel):
785
+ """Simple dialog for entering optional notes when logging to audit trail."""
786
+
787
+ def __init__(self, parent):
788
+ super().__init__(parent)
789
+ self.result = None # Will be None (cancelled) or notes string (confirmed)
790
+
791
+ self.title("Add Notes to Audit Log")
792
+ self.geometry("450x250")
793
+
794
+ # Message
795
+ msg_label = ctk.CTkLabel(
796
+ self,
797
+ text="Add optional notes to this audit log entry:",
798
+ font=('Arial', 12)
799
+ )
800
+ msg_label.pack(pady=(20, 10))
801
+
802
+ # Notes field
803
+ self.notes_text = ctk.CTkTextbox(self, width=400, height=100)
804
+ self.notes_text.pack(pady=5, padx=20)
805
+ self.notes_text.focus()
806
+
807
+ # Buttons
808
+ button_frame = ctk.CTkFrame(self, fg_color="transparent")
809
+ button_frame.pack(pady=20)
810
+
811
+ confirm_btn = ctk.CTkButton(
812
+ button_frame,
813
+ text="Log to Audit Trail",
814
+ command=self.confirm,
815
+ fg_color="green",
816
+ hover_color="darkgreen",
817
+ width=150
818
+ )
819
+ confirm_btn.pack(side='left', padx=5)
820
+
821
+ cancel_btn = ctk.CTkButton(
822
+ button_frame,
823
+ text="Cancel",
824
+ command=self.cancel,
825
+ width=100
826
+ )
827
+ cancel_btn.pack(side='left', padx=5)
828
+
829
+ # Make modal
830
+ self.transient(parent)
831
+ self.grab_set()
832
+
833
+ def confirm(self):
834
+ """Confirm and return notes."""
835
+ self.result = self.notes_text.get("1.0", "end-1c").strip()
836
+ self.destroy()
837
+
838
+ def cancel(self):
839
+ """Cancel."""
840
+ self.result = None
841
+ self.destroy()