File size: 3,544 Bytes
49655be
cc39e44
626c449
1ee80e7
4d9a2f5
cc39e44
 
 
 
4d9a2f5
1ee80e7
 
 
 
 
e55813a
626c449
e55813a
1ee80e7
 
e55813a
1ee80e7
 
4d9a2f5
1ee80e7
626c449
 
4d9a2f5
626c449
 
e55813a
4d9a2f5
1ee80e7
 
 
 
 
 
 
 
 
 
 
626c449
 
 
 
4d9a2f5
626c449
 
e55813a
626c449
 
4d9a2f5
e55813a
 
 
 
626c449
1ee80e7
e55813a
1ee80e7
e55813a
1ee80e7
e55813a
 
 
 
 
 
 
 
4d9a2f5
e55813a
 
1ee80e7
e55813a
 
 
 
 
 
 
 
4d9a2f5
1ee80e7
e55813a
1ee80e7
 
e55813a
1ee80e7
e55813a
 
1ee80e7
 
e55813a
 
 
1ee80e7
 
 
 
 
 
4d9a2f5
1ee80e7
626c449
e55813a
cc39e44
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import gradio as gr
import pandas as pd
import asyncio
from functools import partial

from src.production.flow import generate_data
from src.production.metrics.tools import tools_metrics
from src.production.metrics.machine import machine_metrics, fetch_issues
from src.ui.graphs.tools_graphs import ToolMetricsDisplay

MAX_ROWS = 1000

def hash_dataframe(df):
    """Computes a simple hash to detect changes in the DataFrame."""
    return pd.util.hash_pandas_object(df).sum()

async def dataflow(state):
    """
    Main function that updates data if necessary.
    Avoids processing if the raw data hasn't changed.
    """
    state.setdefault('data', {}).setdefault('tools', {})
    state['data'].setdefault('issues', {})

    if state.get('running'):
        if 'gen_task' not in state or state['gen_task'] is None or state['gen_task'].done():
            state['gen_task'] = asyncio.create_task(generate_data(state))

    raw_data = state['data'].get('raw_df', pd.DataFrame())
    if raw_data.empty:
        return [pd.DataFrame()] * 4

    if len(raw_data) > MAX_ROWS:
        raw_data = raw_data.tail(MAX_ROWS)

    current_hash = hash_dataframe(raw_data)
    if state.get('last_hash') == current_hash:
        return [
            pd.DataFrame(state['data']['tools'].get(f'tool_{i}', pd.DataFrame()))
            for i in range(1, 5)
        ]
    state['last_hash'] = current_hash

    tools_data = await tools_metrics(raw_data)
    tools_data = {tool: df for tool, df in tools_data.items() if not df.empty}
    for tool, df in tools_data.items():
        state['data']['tools'][tool] = df

    machine_data = await machine_metrics(raw_data)
    state['efficiency'] = machine_data

    issues = await fetch_issues(raw_data)
    state['data']['issues'] = issues

    return [
        pd.DataFrame(state['data']['tools'].get(f'tool_{i}', pd.DataFrame()))
        for i in range(1, 5)
    ]

def update_display_and_plots(df, display):
    """
    Uses an existing instance of ToolMetricsDisplay to generate plots.
    """
    return [
        display.normal_curve(df, cote='pos'),
        display.gauge(df, type='cp', cote='pos'),
        display.gauge(df, type='cpk', cote='pos'),
        display.normal_curve(df, cote='ori'),
        display.gauge(df, type='cp', cote='ori'),
        display.gauge(df, type='cpk', cote='ori'),
        display.control_graph(df),
    ]

def init_displays_and_blocks(n=4):
    """
    Initializes the graphical objects (ToolMetricsDisplay) and their associated blocks.
    """
    displays = []
    blocks = []
    for i in range(1, n + 1):
        display = ToolMetricsDisplay()
        displays.append(display)
        blocks.extend(display.tool_block(df=pd.DataFrame(), id=i))
    return displays, blocks

async def on_tick(state, displays):
    """
    Tick function called periodically: updates plots only if data has changed.
    Uses a lock to prevent concurrent execution.
    """
    async with state.setdefault('lock', asyncio.Lock()):
        dfs = await dataflow(state)
        all_plots = []
        for df, display in zip(dfs, displays):
            plots = update_display_and_plots(df, display)
            all_plots.extend(plots)
        return all_plots + [state]

def dashboard_ui(state):
    """
    Creates the Gradio interface and sets a refresh every second.
    """
    displays, initial_plots = init_displays_and_blocks()
    timer = gr.Timer(1.0)
    timer.tick(
        fn=partial(on_tick, displays=displays),
        inputs=[state],
        outputs=initial_plots + [state]
    )