mriusero commited on
Commit
626c449
·
1 Parent(s): 5423593

feat: real-time

Browse files
app.py CHANGED
@@ -15,7 +15,7 @@ STATE = {
15
  "current_time": None,
16
  "part_id": None,
17
  "data": {},
18
- "machine": {},
19
  }
20
 
21
  with gr.Blocks(theme=custom_theme) as demo:
 
15
  "current_time": None,
16
  "part_id": None,
17
  "data": {},
18
+ "efficiency": {},
19
  }
20
 
21
  with gr.Blocks(theme=custom_theme) as demo:
src/production/flow.py CHANGED
@@ -1,12 +1,12 @@
1
- import time
2
  import random
3
  import numpy as np
4
  import pandas as pd
 
5
  from datetime import datetime, timedelta
6
 
7
  from .downtime import machine_errors
8
 
9
- def generate_data(state):
10
  """
11
  Generate synthetic production data for a manufacturing process.
12
  """
@@ -83,7 +83,7 @@ def generate_data(state):
83
 
84
  print(f" - part {part_id} data generated")
85
  part_id += 1
86
- time.sleep(0.5)
87
 
88
  current_time += timedelta(seconds=1)
89
 
 
 
1
  import random
2
  import numpy as np
3
  import pandas as pd
4
+ import asyncio
5
  from datetime import datetime, timedelta
6
 
7
  from .downtime import machine_errors
8
 
9
+ async def generate_data(state):
10
  """
11
  Generate synthetic production data for a manufacturing process.
12
  """
 
83
 
84
  print(f" - part {part_id} data generated")
85
  part_id += 1
86
+ await asyncio.sleep(0.5)
87
 
88
  current_time += timedelta(seconds=1)
89
 
src/production/metrics/machine.py CHANGED
@@ -1,8 +1,6 @@
1
  import pandas as pd
2
- import json
3
- import os
4
 
5
- def machine_metrics(raw_data):
6
  """
7
  Calculate machine efficiency metrics from raw production data.
8
  :param raw_data: collection of raw production data containing timestamps, downtime, and compliance information.
@@ -64,7 +62,7 @@ def machine_metrics(raw_data):
64
  "MTTR": str(mttr)
65
  }
66
 
67
- def fetch_issues(raw_data):
68
  df = pd.DataFrame(raw_data)
69
  issues = df[df["Event"] == "Machine Error"]
70
  return issues[["Timestamp", "Event", "Error Code", "Error Description", "Downtime Start", "Downtime End"]]
 
1
  import pandas as pd
 
 
2
 
3
+ async def machine_metrics(raw_data):
4
  """
5
  Calculate machine efficiency metrics from raw production data.
6
  :param raw_data: collection of raw production data containing timestamps, downtime, and compliance information.
 
62
  "MTTR": str(mttr)
63
  }
64
 
65
+ async def fetch_issues(raw_data):
66
  df = pd.DataFrame(raw_data)
67
  issues = df[df["Event"] == "Machine Error"]
68
  return issues[["Timestamp", "Event", "Error Code", "Error Description", "Downtime Start", "Downtime End"]]
src/production/metrics/tools.py CHANGED
@@ -1,5 +1,5 @@
1
  import numpy as np
2
- from concurrent.futures import ThreadPoolExecutor
3
 
4
  def stats_metrics(data, column, usl, lsl):
5
  """
@@ -21,7 +21,7 @@ def stats_metrics(data, column, usl, lsl):
21
  return rolling_mean, rolling_std, cp, cpk
22
 
23
 
24
- def process_unique_tool(tool, raw_data):
25
  """
26
  Process data for a single tool and save the results to a CSV file.
27
  Args:
@@ -35,17 +35,18 @@ def process_unique_tool(tool, raw_data):
35
  return tool, tool_data
36
 
37
 
38
- def tools_metrics(raw_data):
39
  """
40
  Process the raw production data to extract tool metrics in parallel.
41
  """
42
  metrics = {}
43
  tools = raw_data['Tool ID'].unique()
44
 
45
- with ThreadPoolExecutor() as executor:
46
- results = list(executor.map(lambda tool: process_unique_tool(tool, raw_data), tools))
47
- for tool, tool_data in results:
48
- metrics[f"tool_{tool}"] = tool_data
 
49
 
50
  # Calculate metrics for all tools together
51
  all_tools_data = raw_data.copy()
 
1
  import numpy as np
2
+ import asyncio
3
 
4
  def stats_metrics(data, column, usl, lsl):
5
  """
 
21
  return rolling_mean, rolling_std, cp, cpk
22
 
23
 
24
+ async def process_unique_tool(tool, raw_data):
25
  """
26
  Process data for a single tool and save the results to a CSV file.
27
  Args:
 
35
  return tool, tool_data
36
 
37
 
38
+ async def tools_metrics(raw_data):
39
  """
40
  Process the raw production data to extract tool metrics in parallel.
41
  """
42
  metrics = {}
43
  tools = raw_data['Tool ID'].unique()
44
 
45
+ tasks = [process_unique_tool(tool, raw_data) for tool in tools]
46
+ results = await asyncio.gather(*tasks)
47
+
48
+ for tool, tool_data in results:
49
+ metrics[f"tool_{tool}"] = tool_data
50
 
51
  # Calculate metrics for all tools together
52
  all_tools_data = raw_data.copy()
src/ui/dashboard.py CHANGED
@@ -1,54 +1,63 @@
1
- import time
2
- import json
3
  import gradio as gr
4
  import pandas as pd
 
5
 
6
  from src.production.flow import generate_data
7
  from src.production.metrics.tools import tools_metrics
8
  from src.production.metrics.machine import machine_metrics, fetch_issues
9
-
10
  from src.ui.graphs.tools_graphs import ToolMetricsDisplay
11
 
12
- def dashboard_ui(state):
 
 
13
 
14
- display1 = ToolMetricsDisplay()
 
15
 
16
- def dataflow(state):
 
 
 
17
 
18
- # --- INIT ---
19
- if 'tools' not in state['data']:
20
- state['data']['tools'] = {}
21
 
22
- if 'issues' not in state['data']:
23
- state['data']['issues'] = {}
 
 
24
 
25
- # --- DATA FLOW ---
26
- if state['running']:
 
 
27
 
28
- # Generation
29
- generate_data(state)
30
- raw_data = state['data']['raw_df']
 
 
 
31
 
32
- # Process tools metrics
33
- tools_data = tools_metrics(raw_data)
34
- tools_data = {tool: df for tool, df in tools_data.items() if not df.empty}
35
- for tool, df in tools_data.items():
36
- state['data']['tools'][tool] = df
 
37
 
38
- # Process machine metrics
39
- machine_data = machine_metrics(raw_data)
40
- state['machine'] = machine_data
41
- issues = fetch_issues(raw_data)
42
- state['data']['issues'] = issues
43
 
44
- # --- UPDATE UI ---
45
- df1 = pd.DataFrame(state['data']['tools'].get('tool_1', pd.DataFrame()))
46
- return display1.tool_block(df=df1, id=1)
47
 
48
- plots = display1.tool_block(df=pd.DataFrame(), id=1)
49
  timer = gr.Timer(1)
50
  timer.tick(
51
- fn=dataflow,
52
- inputs=state,
53
- outputs=plots
54
  )
 
 
 
1
  import gradio as gr
2
  import pandas as pd
3
+ import asyncio
4
 
5
  from src.production.flow import generate_data
6
  from src.production.metrics.tools import tools_metrics
7
  from src.production.metrics.machine import machine_metrics, fetch_issues
 
8
  from src.ui.graphs.tools_graphs import ToolMetricsDisplay
9
 
10
+ async def dataflow(state):
11
+ if 'tools' not in state['data']:
12
+ state['data']['tools'] = {}
13
 
14
+ if 'issues' not in state['data']:
15
+ state['data']['issues'] = {}
16
 
17
+ if state['running']:
18
+ if 'gen_task' not in state or state['gen_task'] is None or state['gen_task'].done():
19
+ print("Launching generate_data in background")
20
+ state['gen_task'] = asyncio.create_task(generate_data(state))
21
 
22
+ raw_data = state['data'].get('raw_df', pd.DataFrame())
23
+ if raw_data.empty:
24
+ return pd.DataFrame()
25
 
26
+ tools_data = await tools_metrics(raw_data)
27
+ tools_data = {tool: df for tool, df in tools_data.items() if not df.empty}
28
+ for tool, df in tools_data.items():
29
+ state['data']['tools'][tool] = df
30
 
31
+ machine_data = await machine_metrics(raw_data)
32
+ state['efficiency'] = machine_data
33
+ issues = await fetch_issues(raw_data)
34
+ state['data']['issues'] = issues
35
 
36
+ df1 = pd.DataFrame(state['data']['tools'].get('tool_1', pd.DataFrame()))
37
+ return df1
38
+
39
+ def dashboard_ui(state):
40
+ display = ToolMetricsDisplay()
41
+ plots = display.tool_block(df=pd.DataFrame(), id=1)
42
 
43
+ async def on_tick(state):
44
+ df1 = await dataflow(state)
45
+ updated = [
46
+ display.normal_curve(df1, cote='pos'),
47
+ display.gauge(df1, type='cp', cote='pos'),
48
+ display.gauge(df1, type='cpk', cote='pos'),
49
 
50
+ display.normal_curve(df1, cote='ori'),
51
+ display.gauge(df1, type='cp', cote='ori'),
52
+ display.gauge(df1, type='cpk', cote='ori'),
 
 
53
 
54
+ display.control_graph(df1),
55
+ ]
56
+ return updated + [state]
57
 
 
58
  timer = gr.Timer(1)
59
  timer.tick(
60
+ fn=on_tick,
61
+ inputs=[state],
62
+ outputs=plots + [state]
63
  )
src/ui/graphs/tools_graphs.py CHANGED
@@ -1,6 +1,5 @@
1
  import numpy as np
2
  from scipy.stats import norm
3
- import pandas as pd
4
  import plotly.graph_objects as go
5
  import gradio as gr
6
 
@@ -10,6 +9,7 @@ class ToolMetricsDisplay:
10
  self.df = None
11
  self.pos_color = '#2CFCFF'
12
  self.ori_color = '#ff8508'
 
13
 
14
  @staticmethod
15
  def gauge(df, type=None, cote=None):
@@ -120,8 +120,12 @@ class ToolMetricsDisplay:
120
 
121
  if cote == 'pos':
122
  color = self.pos_color
 
 
123
  else:
124
  color = self.ori_color
 
 
125
  mu_column = f"{cote}_rolling_mean"
126
  std_column = f"{cote}_rolling_std"
127
  idx = df['Timestamp'].idxmax()
@@ -130,9 +134,9 @@ class ToolMetricsDisplay:
130
  y = norm.pdf(x, mu, std)
131
  fig = go.Figure()
132
  fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Normal Curve', line=dict(color=color)))
133
- fig.add_shape(type="line", x0=0.6, y0=0, x1=0.6, y1=max(y), line=dict(color="red", width=1, dash="dot"),
134
  name='usl')
135
- fig.add_shape(type="line", x0=0.2, y0=0, x1=0.2, y1=max(y), line=dict(color="red", width=1, dash="dot"),
136
  name='lsl')
137
  fig.update_layout(
138
  template='plotly_dark',
@@ -175,5 +179,9 @@ class ToolMetricsDisplay:
175
  with gr.Row(height=400):
176
  control_plot = gr.Plot(self.control_graph(df=df))
177
 
178
- return [pos_normal_plot, pos_cp_gauge, pos_cpk_gauge, ori_normal_plot, ori_cp_gauge, ori_cpk_gauge,
179
- control_plot]
 
 
 
 
 
1
  import numpy as np
2
  from scipy.stats import norm
 
3
  import plotly.graph_objects as go
4
  import gradio as gr
5
 
 
9
  self.df = None
10
  self.pos_color = '#2CFCFF'
11
  self.ori_color = '#ff8508'
12
+ self.plots = []
13
 
14
  @staticmethod
15
  def gauge(df, type=None, cote=None):
 
120
 
121
  if cote == 'pos':
122
  color = self.pos_color
123
+ lsl = 0.3
124
+ usl = 0.5
125
  else:
126
  color = self.ori_color
127
+ lsl = 0.2
128
+ usl = 0.6
129
  mu_column = f"{cote}_rolling_mean"
130
  std_column = f"{cote}_rolling_std"
131
  idx = df['Timestamp'].idxmax()
 
134
  y = norm.pdf(x, mu, std)
135
  fig = go.Figure()
136
  fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Normal Curve', line=dict(color=color)))
137
+ fig.add_shape(type="line", x0=usl, y0=0, x1=usl, y1=max(y), line=dict(color="red", width=1, dash="dot"),
138
  name='usl')
139
+ fig.add_shape(type="line", x0=lsl, y0=0, x1=lsl, y1=max(y), line=dict(color="red", width=1, dash="dot"),
140
  name='lsl')
141
  fig.update_layout(
142
  template='plotly_dark',
 
179
  with gr.Row(height=400):
180
  control_plot = gr.Plot(self.control_graph(df=df))
181
 
182
+ self.plots = [
183
+ pos_normal_plot, pos_cp_gauge, pos_cpk_gauge,
184
+ ori_normal_plot, ori_cp_gauge, ori_cpk_gauge,
185
+ control_plot
186
+ ]
187
+ return self.plots