from dash import html, dcc, callback_context, dash_table
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from utils.file_utils import list_directories_in_directory, list_files_in_directory, get_file_metadata, get_training_time, get_file_size, trainer_classes, get_Size_String
import os
import json
import plotly.graph_objs as go
TRAINING_HOTWORD_DIR = './training/hotword/'
def HotwordsLayout():
hotword_models = list_directories_in_directory(TRAINING_HOTWORD_DIR)
model_table = generate_model_table(hotword_models)
return html.Div([
html.H2("Hotword Models"),
dbc.Button("Add New Hotword", id="add-new-hotword", color="primary", className="mb-3"),
html.Div(id="new-hotword-input"),
model_table,
dcc.Store(id='hidden-model-name'),
html.Div(id="hotword-manage-training-data")
])
def generate_model_table(models):
header = [
html.Thead(html.Tr([html.Th("Model Name"), html.Th("Actions")]))
]
rows = []
for model in models:
rows.append(html.Tr([
html.Td(model),
html.Td([
dbc.Button("Details", href=f"/manage_hotword/{model}", color='primary', className='mr-2'),
dbc.Button("Delete", id={'type': 'delete-hotword', 'index': model}, color='danger')
])
]))
return dbc.Table(header + [html.Tbody(rows)], bordered=True, hover=True)
def ManageHotwordLayout(model_name):
page_size = 10
training_data = list_files_in_directory(f"{TRAINING_HOTWORD_DIR}/{model_name}/", ".wav")
training_data_table, row_count = generate_training_data_table(model_name, training_data, 1, page_size)
trainer_options = [{'label': name, 'value': name} for name in trainer_classes.keys()]
training_time = get_training_time(model_name)
tab_trainer = []
for trainer_info in trainer_options:
infoFile = f"./model/hotword/{model_name}/info_{trainer_info['value']}.json"
if os.path.exists(infoFile):
with open(infoFile, 'r') as file:
info = json.load(file)
epochs = '-'
batch_size = '-'
dropout_rate = '-'
training_method = '-'
duration = '-'
testAccuracy = '-'
accu = []
loss = []
size = '-'
if 'epochs' in info:
epochs = info['epochs']
if 'batch_size' in info:
batch_size = info['batch_size']
if 'dropout_rate' in info:
dropout_rate = info['dropout_rate']
if 'trainer_script' in info:
training_method = info['trainer_script']
if 'accuracy' in info:
accu = info['accuracy']
if 'loss' in info:
loss = info['loss']
if 'training_time' in info:
duration = info['training_time']
if 'test_accuracy' in info:
testAccuracy = info['test_accuracy']
if 'model_size' in info:
size = info['model_size']
chart_fig1 = go.Figure(data=[go.Scatter(y=accu)])
chart_fig2 = go.Figure(data=[go.Scatter(y=loss)])
entries = [
dcc.Graph(figure=chart_fig1),
dcc.Graph(figure=chart_fig2),
html.P("Epochen: "+str(epochs), className="card-text"),
html.P("Batch Size: "+str(batch_size), className="card-text"),
html.P("Dropout Rate: "+str(dropout_rate), className="card-text"),
html.P("Methode: "+str(training_method), className="card-text"),
html.P("Duration: "+str(duration), className="card-text"),
html.P("Test Accuracy: "+str(testAccuracy), className="card-text"),
html.P("Size: "+get_Size_String(size*1024), className="card-text"),
]
tab_trainer.append(
dbc.Tab(entries
, label=trainer_info['label'], tab_id=trainer_info['value'])
)
else:
tab_trainer.append(
dbc.Tab("",label=trainer_info['label'], tab_id=trainer_info['value'], disabled=True)
)
# Pagination logic
num_pages = (row_count // page_size) + (1 if row_count % page_size > 0 else 0)
pagination = dbc.Pagination(id='data-table-pagination', max_value=num_pages, active_page=1)
return html.Div([
html.H2(f"Manage Hotword Model: {model_name}"),
dbc.Card([dbc.CardHeader("Model Infos"),dbc.CardBody(dbc.Tabs(tab_trainer))]),
dbc.Card([
dbc.CardHeader("Training Controls"),
dbc.CardBody([
#dbc.Row([
#dbc.Col(dbc.Button("Start Training", id="start-training-hotword", color="success", className="mb-3")),
#dbc.Col(dbc.Button("Optimize Training", id="optimize-training-hotword", color="primary", className="mb-3 ml-3")),
#dbc.Col(dbc.Button("Stop Training", id="stop-training-hotword", color="danger", className="mb-3 ml-3")),
dbc.ButtonGroup([
dbc.DropdownMenu(
label="Start training",
children=[
dbc.DropdownMenuItem("Item 1"),
dbc.DropdownMenuItem("Item 2"),
dbc.DropdownMenuItem("Item 3"),
],
),
dbc.Button("Start Training", id="start-training-hotword", color="success", className="mb-3"),
dbc.Button("Optimize Training", id="optimize-training-hotword", color="primary", className="mb-3 ml-3"),
dbc.Button("Stop Training", id="stop-training-hotword", color="danger", className="mb-3 ml-3"),
]),
#]),
dbc.Row([
dbc.Col(
dcc.Dropdown(
id="training-method-dropdown",
options=trainer_options,
value=trainer_options[0]["value"], # default value
clearable=False,
className="mb-3",
placeholder="Select Training Method",
)
),
dbc.Col(
dcc.Input(
id="dropout-rate",
type="number",
value=0.5,
step=0.1,
min=0,
max=1,
className="mb-3",
placeholder="Dropout Rate"
)
),
dbc.Col(
dcc.Slider(0, 10000, value=3000, id="num-epochs",tooltip={"placement": "bottom", "always_visible": False})
#dcc.Input(
# id="num-epochs",
# type="number",
# value=10,
# step=1,
# min=1,
# className="mb-3",
# placeholder="Epochs"
#)
),
dbc.Col(
dcc.Slider(0, 256, marks={
8: '8',
16: '16',
32: '32',
64: '64',
128: '128',
256: '256',
}, value=32, id="batch-size", step=None)
#dcc.Input(
# id="batch-size",
# type="number",
# value=32,
# step=1,
# min=1,
# className="mb-3",
# placeholder="Batch Size"
#)
)
]),
html.Div(id="training-status", className='mt-3'),
html.Div(id="training-timer", className='mt-3'),
dbc.Card([
dbc.CardHeader("Training Progress"),
dbc.CardBody([
dcc.Graph(id="training-chart", figure=[]),
dbc.Progress(id="training-progress", striped=True, animated=True, style={"height": "20px"}),
])
]),
])
]),
dbc.Card([
dbc.CardHeader("Upload Training Data"),
dbc.CardBody([
dcc.Upload(
id="upload-training-data",
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
multiple=True
),
html.Div(id="file-preview-list"),
dbc.Button("Upload Files", id="confirm-upload", color='success', className='mt-3'),
html.Div(id="upload-status"),
])
]),
dbc.Card([
dbc.CardHeader("Training Data"),
dbc.CardBody([
training_data_table, pagination
])
])
])
def generate_training_data_table(model_name, files, page=1, page_size=10):
import os
header = [
html.Thead(html.Tr([html.Th("Audio"), html.Th("File Name"), html.Th("Display"), html.Th("Length (s)"), html.Th("Size (KB)"), html.Th("Actions")]))
]
rows = []
for file in files:
filex = os.path.basename(file)
if not os.path.isdir(f"{TRAINING_HOTWORD_DIR}/{model_name}/{filex}"):
file_name = filex.lstrip('_')
file_path = f"{TRAINING_HOTWORD_DIR}/{model_name}/{filex}"
fileImg = filex[0:-3] + "png"
try:
length, size = get_file_metadata(file_path)
rows.append(html.Tr([
html.Td(html.Audio(src=f"/audio/hotword/{model_name}/{filex}", controls=True)),
html.Td(file_name),
html.Td(html.Img(src=f"/audio/hotword/{model_name}/{fileImg}")),
html.Td(length),
html.Td(size),
html.Td([
dbc.Button("Delete", id={'type': 'delete-button', 'index': file}, color='danger', className='mr-2'),
dbc.Button("Deactivate" if not filex.startswith('_') else "Activate", id={'type': 'toggle-button', 'index': filex}, color='warning')
])
]))
except ValueError as e:
rows.append(html.Tr([
html.Td("-"),
html.Td(file_name),
html.Td("-"),
html.Td("-"),
html.Td("-"),
html.Td([
dbc.Button("Delete", id={'type': 'delete-button', 'index': file}, color='danger', className='mr-2')
])
]))
except FileNotFoundError as e:
rows.append(html.Tr([
html.Td("-"),
html.Td(file_name),
html.Td("-"),
html.Td("-"),
html.Td("-"),
html.Td("File not found")
]))
start = (page - 1) * 10
end = start + 10
row_count = len(rows)
table_body = html.Tbody(id='data-table-body', children=rows[start:end])
return html.Div([
dbc.Table(header + [table_body], bordered=True, hover=True)
]), row_count