flowyml 1.7.2__py3-none-any.whl → 1.8.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 (126) hide show
  1. flowyml/assets/base.py +15 -0
  2. flowyml/assets/metrics.py +5 -0
  3. flowyml/cli/main.py +709 -0
  4. flowyml/cli/stack_cli.py +138 -25
  5. flowyml/core/__init__.py +17 -0
  6. flowyml/core/executor.py +161 -26
  7. flowyml/core/image_builder.py +129 -0
  8. flowyml/core/log_streamer.py +227 -0
  9. flowyml/core/orchestrator.py +22 -2
  10. flowyml/core/pipeline.py +34 -10
  11. flowyml/core/routing.py +558 -0
  12. flowyml/core/step.py +9 -1
  13. flowyml/core/step_grouping.py +49 -35
  14. flowyml/core/types.py +407 -0
  15. flowyml/monitoring/alerts.py +10 -0
  16. flowyml/monitoring/notifications.py +104 -25
  17. flowyml/monitoring/slack_blocks.py +323 -0
  18. flowyml/plugins/__init__.py +251 -0
  19. flowyml/plugins/alerters/__init__.py +1 -0
  20. flowyml/plugins/alerters/slack.py +168 -0
  21. flowyml/plugins/base.py +752 -0
  22. flowyml/plugins/config.py +478 -0
  23. flowyml/plugins/deployers/__init__.py +22 -0
  24. flowyml/plugins/deployers/gcp_cloud_run.py +200 -0
  25. flowyml/plugins/deployers/sagemaker.py +306 -0
  26. flowyml/plugins/deployers/vertex.py +290 -0
  27. flowyml/plugins/integration.py +369 -0
  28. flowyml/plugins/manager.py +510 -0
  29. flowyml/plugins/model_registries/__init__.py +22 -0
  30. flowyml/plugins/model_registries/mlflow.py +159 -0
  31. flowyml/plugins/model_registries/sagemaker.py +489 -0
  32. flowyml/plugins/model_registries/vertex.py +386 -0
  33. flowyml/plugins/orchestrators/__init__.py +13 -0
  34. flowyml/plugins/orchestrators/sagemaker.py +443 -0
  35. flowyml/plugins/orchestrators/vertex_ai.py +461 -0
  36. flowyml/plugins/registries/__init__.py +13 -0
  37. flowyml/plugins/registries/ecr.py +321 -0
  38. flowyml/plugins/registries/gcr.py +313 -0
  39. flowyml/plugins/registry.py +454 -0
  40. flowyml/plugins/stack.py +494 -0
  41. flowyml/plugins/stack_config.py +537 -0
  42. flowyml/plugins/stores/__init__.py +13 -0
  43. flowyml/plugins/stores/gcs.py +460 -0
  44. flowyml/plugins/stores/s3.py +453 -0
  45. flowyml/plugins/trackers/__init__.py +11 -0
  46. flowyml/plugins/trackers/mlflow.py +316 -0
  47. flowyml/plugins/validators/__init__.py +3 -0
  48. flowyml/plugins/validators/deepchecks.py +119 -0
  49. flowyml/registry/__init__.py +2 -1
  50. flowyml/registry/model_environment.py +109 -0
  51. flowyml/registry/model_registry.py +241 -96
  52. flowyml/serving/__init__.py +17 -0
  53. flowyml/serving/model_server.py +628 -0
  54. flowyml/stacks/__init__.py +60 -0
  55. flowyml/stacks/aws.py +93 -0
  56. flowyml/stacks/base.py +62 -0
  57. flowyml/stacks/components.py +12 -0
  58. flowyml/stacks/gcp.py +44 -9
  59. flowyml/stacks/plugins.py +115 -0
  60. flowyml/stacks/registry.py +2 -1
  61. flowyml/storage/sql.py +401 -12
  62. flowyml/tracking/experiment.py +8 -5
  63. flowyml/ui/backend/Dockerfile +87 -16
  64. flowyml/ui/backend/auth.py +12 -2
  65. flowyml/ui/backend/main.py +149 -5
  66. flowyml/ui/backend/routers/ai_context.py +226 -0
  67. flowyml/ui/backend/routers/assets.py +23 -4
  68. flowyml/ui/backend/routers/auth.py +96 -0
  69. flowyml/ui/backend/routers/deployments.py +660 -0
  70. flowyml/ui/backend/routers/model_explorer.py +597 -0
  71. flowyml/ui/backend/routers/plugins.py +103 -51
  72. flowyml/ui/backend/routers/projects.py +91 -8
  73. flowyml/ui/backend/routers/runs.py +20 -1
  74. flowyml/ui/backend/routers/schedules.py +22 -17
  75. flowyml/ui/backend/routers/templates.py +319 -0
  76. flowyml/ui/backend/routers/websocket.py +2 -2
  77. flowyml/ui/frontend/Dockerfile +55 -6
  78. flowyml/ui/frontend/dist/assets/index-B5AsPTSz.css +1 -0
  79. flowyml/ui/frontend/dist/assets/index-dFbZ8wD8.js +753 -0
  80. flowyml/ui/frontend/dist/index.html +2 -2
  81. flowyml/ui/frontend/dist/logo.png +0 -0
  82. flowyml/ui/frontend/nginx.conf +65 -4
  83. flowyml/ui/frontend/package-lock.json +1404 -74
  84. flowyml/ui/frontend/package.json +3 -0
  85. flowyml/ui/frontend/public/logo.png +0 -0
  86. flowyml/ui/frontend/src/App.jsx +10 -7
  87. flowyml/ui/frontend/src/app/auth/Login.jsx +90 -0
  88. flowyml/ui/frontend/src/app/dashboard/page.jsx +8 -8
  89. flowyml/ui/frontend/src/app/deployments/page.jsx +786 -0
  90. flowyml/ui/frontend/src/app/model-explorer/page.jsx +1031 -0
  91. flowyml/ui/frontend/src/app/pipelines/page.jsx +12 -2
  92. flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectExperimentsList.jsx +19 -6
  93. flowyml/ui/frontend/src/app/runs/[runId]/page.jsx +36 -24
  94. flowyml/ui/frontend/src/app/runs/page.jsx +8 -2
  95. flowyml/ui/frontend/src/app/settings/page.jsx +267 -253
  96. flowyml/ui/frontend/src/components/AssetDetailsPanel.jsx +29 -7
  97. flowyml/ui/frontend/src/components/Layout.jsx +6 -0
  98. flowyml/ui/frontend/src/components/PipelineGraph.jsx +79 -29
  99. flowyml/ui/frontend/src/components/RunDetailsPanel.jsx +36 -6
  100. flowyml/ui/frontend/src/components/RunMetaPanel.jsx +113 -0
  101. flowyml/ui/frontend/src/components/ai/AIAssistantButton.jsx +71 -0
  102. flowyml/ui/frontend/src/components/ai/AIAssistantPanel.jsx +420 -0
  103. flowyml/ui/frontend/src/components/header/Header.jsx +22 -0
  104. flowyml/ui/frontend/src/components/plugins/PluginManager.jsx +4 -4
  105. flowyml/ui/frontend/src/components/plugins/{ZenMLIntegration.jsx → StackImport.jsx} +38 -12
  106. flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx +36 -13
  107. flowyml/ui/frontend/src/contexts/AIAssistantContext.jsx +245 -0
  108. flowyml/ui/frontend/src/contexts/AuthContext.jsx +108 -0
  109. flowyml/ui/frontend/src/hooks/useAIContext.js +156 -0
  110. flowyml/ui/frontend/src/hooks/useWebGPU.js +54 -0
  111. flowyml/ui/frontend/src/layouts/MainLayout.jsx +6 -0
  112. flowyml/ui/frontend/src/router/index.jsx +47 -20
  113. flowyml/ui/frontend/src/services/pluginService.js +3 -1
  114. flowyml/ui/server_manager.py +5 -5
  115. flowyml/ui/utils.py +157 -39
  116. flowyml/utils/config.py +37 -15
  117. flowyml/utils/model_introspection.py +123 -0
  118. flowyml/utils/observability.py +30 -0
  119. flowyml-1.8.0.dist-info/METADATA +174 -0
  120. {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/RECORD +123 -65
  121. {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/WHEEL +1 -1
  122. flowyml/ui/frontend/dist/assets/index-B40RsQDq.css +0 -1
  123. flowyml/ui/frontend/dist/assets/index-CjI0zKCn.js +0 -685
  124. flowyml-1.7.2.dist-info/METADATA +0 -477
  125. {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/entry_points.txt +0 -0
  126. {flowyml-1.7.2.dist-info → flowyml-1.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -111,15 +111,25 @@ export function Pipelines() {
111
111
  />
112
112
  ) : (
113
113
  <div className="h-full flex flex-col items-center justify-center text-center p-8 bg-slate-50/50 dark:bg-slate-900/50">
114
- <div className="w-20 h-20 bg-primary-100 dark:bg-primary-900/30 rounded-full flex items-center justify-center mb-6 animate-pulse">
114
+ <div className="w-20 h-20 bg-gradient-to-br from-primary-100 to-primary-200 dark:from-primary-900/30 dark:to-primary-800/30 rounded-full flex items-center justify-center mb-6">
115
115
  <Layers size={40} className="text-primary-500" />
116
116
  </div>
117
117
  <h2 className="text-2xl font-bold text-slate-900 dark:text-white mb-2">
118
118
  Select a Pipeline
119
119
  </h2>
120
- <p className="text-slate-500 max-w-md">
120
+ <p className="text-slate-500 max-w-md mb-6">
121
121
  Choose a pipeline from the sidebar to view execution history and statistics.
122
122
  </p>
123
+ <div className="bg-slate-900 dark:bg-slate-950 rounded-lg p-4 max-w-md mx-auto text-left shadow-lg">
124
+ <p className="text-xs text-slate-400 mb-2">Define a pipeline in Python:</p>
125
+ <pre className="text-sm font-mono text-slate-300 overflow-x-auto">
126
+ <code>{`from flowyml import pipeline, step
127
+
128
+ @pipeline
129
+ def training_pipeline():
130
+ load_data() >> train_model()`}</code>
131
+ </pre>
132
+ </div>
123
133
  </div>
124
134
  )}
125
135
  </div>
@@ -130,13 +130,26 @@ export function ProjectExperimentsList({ projectId }) {
130
130
  </div>
131
131
  )}
132
132
  emptyState={
133
- <div className="text-center py-12">
134
- <div className="inline-flex items-center justify-center w-12 h-12 rounded-full bg-slate-100 dark:bg-slate-800 mb-4">
135
- <FlaskConical className="w-6 h-6 text-slate-400" />
133
+ <div className="text-center py-12 px-6">
134
+ <div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-gradient-to-br from-purple-100 to-purple-200 dark:from-purple-900/30 dark:to-purple-800/30 mb-6">
135
+ <FlaskConical className="w-8 h-8 text-purple-500" />
136
136
  </div>
137
- <h3 className="text-lg font-medium text-slate-900 dark:text-white mb-1">No experiments found</h3>
138
- <p className="text-slate-500">
139
- Create an experiment to track your model development.
137
+ <h3 className="text-xl font-bold text-slate-900 dark:text-white mb-2">No experiments yet</h3>
138
+ <p className="text-slate-500 max-w-md mx-auto mb-6">
139
+ Experiments help you organize and compare multiple pipeline runs. Create one using the SDK:
140
+ </p>
141
+ <div className="bg-slate-900 dark:bg-slate-950 rounded-lg p-4 max-w-md mx-auto text-left mb-6 shadow-lg">
142
+ <pre className="text-sm font-mono text-slate-300 overflow-x-auto">
143
+ <code>{`from flowyml import experiment
144
+
145
+ with experiment("my-experiment"):
146
+ pipeline.run(context={
147
+ "learning_rate": 0.01
148
+ })`}</code>
149
+ </pre>
150
+ </div>
151
+ <p className="text-xs text-slate-400">
152
+ All runs within an experiment block are automatically grouped and tracked together.
140
153
  </p>
141
154
  </div>
142
155
  }
@@ -14,6 +14,8 @@ import { ProjectSelector } from '../../../components/ProjectSelector';
14
14
  import { CodeSnippet } from '../../../components/ui/CodeSnippet';
15
15
  import { TrainingMetricsPanel } from '../../../components/TrainingMetricsPanel';
16
16
  import { TrainingHistoryChart } from '../../../components/TrainingHistoryChart';
17
+ import { RunMetaPanel } from '../../../components/RunMetaPanel';
18
+ import { useAIContext } from '../../../hooks/useAIContext';
17
19
 
18
20
  export function RunDetails() {
19
21
  const { runId } = useParams();
@@ -31,6 +33,15 @@ export function RunDetails() {
31
33
  const [stepPanelExpanded, setStepPanelExpanded] = useState(false);
32
34
  const [hasTrainingHistory, setHasTrainingHistory] = useState(false);
33
35
 
36
+ // Share run context with AI assistant
37
+ useAIContext({
38
+ pageType: 'run',
39
+ resourceId: runId,
40
+ includeLogs: true,
41
+ includeCode: true,
42
+ includeMetrics: true
43
+ });
44
+
34
45
  const handleStopRun = async () => {
35
46
  if (!confirm('Are you sure you want to stop this run?')) return;
36
47
 
@@ -231,12 +242,16 @@ export function RunDetails() {
231
242
  />
232
243
  </div>
233
244
 
245
+ {/* Environment & Metadata Panel */}
246
+ <RunMetaPanel run={run} />
247
+
248
+ {/* Main Content - Dynamic Split View */}
249
+
234
250
  {/* Main Content - Dynamic Split View */}
235
- <div className={`grid gap-6 transition-all duration-300 ${
236
- stepPanelExpanded
237
- ? 'grid-cols-1 lg:grid-cols-2'
238
- : 'grid-cols-1 lg:grid-cols-3'
239
- }`}>
251
+ <div className={`grid gap-6 transition-all duration-300 ${stepPanelExpanded
252
+ ? 'grid-cols-1 lg:grid-cols-2'
253
+ : 'grid-cols-1 lg:grid-cols-3'
254
+ }`}>
240
255
  {/* DAG Visualization */}
241
256
  <div className={stepPanelExpanded ? 'lg:col-span-1' : 'lg:col-span-2'}>
242
257
  <h3 className="text-xl font-bold text-slate-900 dark:text-white mb-4 flex items-center gap-2">
@@ -278,7 +293,7 @@ export function RunDetails() {
278
293
  found = artifacts.find(a =>
279
294
  a.type === expectedType &&
280
295
  (a.name.toLowerCase().includes(suffix.toLowerCase()) ||
281
- suffix.toLowerCase().includes(a.name.toLowerCase().replace(/_/g, '')))
296
+ suffix.toLowerCase().includes(a.name.toLowerCase().replace(/_/g, '')))
282
297
  );
283
298
  }
284
299
 
@@ -322,9 +337,8 @@ export function RunDetails() {
322
337
  </div>
323
338
 
324
339
  {selectedStepData ? (
325
- <Card className={`overflow-hidden transition-all duration-300 ${
326
- stepPanelExpanded ? 'h-auto' : ''
327
- }`}>
340
+ <Card className={`overflow-hidden transition-all duration-300 ${stepPanelExpanded ? 'h-auto' : ''
341
+ }`}>
328
342
  {/* Step Header */}
329
343
  <div className="pb-4 border-b border-slate-100 dark:border-slate-700">
330
344
  <div className="flex items-center justify-between">
@@ -385,9 +399,8 @@ export function RunDetails() {
385
399
  </div>
386
400
 
387
401
  {/* Tab Content - Larger when expanded */}
388
- <div className={`mt-4 overflow-y-auto transition-all duration-300 ${
389
- stepPanelExpanded ? 'max-h-[600px]' : 'max-h-[450px]'
390
- }`}>
402
+ <div className={`mt-4 overflow-y-auto transition-all duration-300 ${stepPanelExpanded ? 'max-h-[600px]' : 'max-h-[450px]'
403
+ }`}>
391
404
  {activeTab === 'overview' && (
392
405
  <OverviewTab
393
406
  stepData={selectedStepData}
@@ -952,8 +965,8 @@ function ArtifactModal({ artifact, onClose }) {
952
965
  <div className="flex gap-1 px-6 py-3 border-b border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50">
953
966
  <TabBtn active={activeTab === 'visualization'} onClick={() => setActiveTab('visualization')}>
954
967
  {isModel ? <><LineChart size={14} /> Visualization</> :
955
- isDataset ? <><BarChart2 size={14} /> Statistics</> :
956
- <><Activity size={14} /> Metrics</>}
968
+ isDataset ? <><BarChart2 size={14} /> Statistics</> :
969
+ <><Activity size={14} /> Metrics</>}
957
970
  </TabBtn>
958
971
  {displayableProps.length > 0 && (
959
972
  <TabBtn active={activeTab === 'properties'} onClick={() => setActiveTab('properties')}>
@@ -1059,8 +1072,8 @@ function ArtifactModal({ artifact, onClose }) {
1059
1072
  </span>
1060
1073
  <span className="text-sm font-mono font-semibold text-slate-900 dark:text-white break-all">
1061
1074
  {typeof value === 'object' ? JSON.stringify(value, null, 2) :
1062
- typeof value === 'number' ? value.toLocaleString() :
1063
- String(value)}
1075
+ typeof value === 'number' ? value.toLocaleString() :
1076
+ String(value)}
1064
1077
  </span>
1065
1078
  </div>
1066
1079
  ))}
@@ -1139,11 +1152,10 @@ function TabBtn({ active, onClick, children }) {
1139
1152
  return (
1140
1153
  <button
1141
1154
  onClick={onClick}
1142
- className={`flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-all ${
1143
- active
1144
- ? 'bg-white dark:bg-slate-700 text-slate-900 dark:text-white shadow-sm'
1145
- : 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-white/50 dark:hover:bg-slate-700/50'
1146
- }`}
1155
+ className={`flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-all ${active
1156
+ ? 'bg-white dark:bg-slate-700 text-slate-900 dark:text-white shadow-sm'
1157
+ : 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-white/50 dark:hover:bg-slate-700/50'
1158
+ }`}
1147
1159
  >
1148
1160
  {children}
1149
1161
  </button>
@@ -1176,9 +1188,9 @@ function MetricDisplayCard({ name, value, index }) {
1176
1188
 
1177
1189
  // Determine if this is a "good" metric (accuracy, score) or "bad" (loss, error)
1178
1190
  const isLossLike = name.toLowerCase().includes('loss') ||
1179
- name.toLowerCase().includes('error') ||
1180
- name.toLowerCase().includes('mse') ||
1181
- name.toLowerCase().includes('mae');
1191
+ name.toLowerCase().includes('error') ||
1192
+ name.toLowerCase().includes('mse') ||
1193
+ name.toLowerCase().includes('mae');
1182
1194
 
1183
1195
  return (
1184
1196
  <motion.div
@@ -169,15 +169,21 @@ export function Runs() {
169
169
  />
170
170
  ) : (
171
171
  <div className="h-full flex flex-col items-center justify-center text-center p-8 bg-slate-50/50 dark:bg-slate-900/50">
172
- <div className="w-20 h-20 bg-blue-100 dark:bg-blue-900/30 rounded-full flex items-center justify-center mb-6 animate-pulse">
172
+ <div className="w-20 h-20 bg-gradient-to-br from-blue-100 to-blue-200 dark:from-blue-900/30 dark:to-blue-800/30 rounded-full flex items-center justify-center mb-6">
173
173
  <PlayCircle size={40} className="text-blue-500" />
174
174
  </div>
175
175
  <h2 className="text-2xl font-bold text-slate-900 dark:text-white mb-2">
176
176
  Select a Run
177
177
  </h2>
178
- <p className="text-slate-500 max-w-md">
178
+ <p className="text-slate-500 max-w-md mb-6">
179
179
  Choose a run from the sidebar to view execution details, logs, and artifacts.
180
180
  </p>
181
+ <div className="bg-slate-900 dark:bg-slate-950 rounded-lg p-4 max-w-md mx-auto text-left shadow-lg">
182
+ <p className="text-xs text-slate-400 mb-2">Run a pipeline from the CLI:</p>
183
+ <pre className="text-sm font-mono text-slate-300 overflow-x-auto">
184
+ <code>{`flowyml run my_pipeline`}</code>
185
+ </pre>
186
+ </div>
181
187
  </div>
182
188
  )}
183
189
  </div>