Bikyla commited on
Commit
21233df
·
verified ·
1 Parent(s): 7a2b466

Upload 9 files

Browse files
Files changed (10) hide show
  1. .gitattributes +3 -0
  2. Dockerfile +21 -20
  3. Frez.jpg +3 -0
  4. Main.jpg +3 -0
  5. Toch.jpg +3 -0
  6. df.csv +0 -0
  7. main.py +388 -0
  8. model.pkl +3 -0
  9. requirements.txt +7 -3
  10. scaler.pkl +3 -0
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ Frez.jpg filter=lfs diff=lfs merge=lfs -text
37
+ Main.jpg filter=lfs diff=lfs merge=lfs -text
38
+ Toch.jpg filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,20 +1,21 @@
1
- FROM python:3.13.5-slim
2
-
3
- WORKDIR /app
4
-
5
- RUN apt-get update && apt-get install -y \
6
- build-essential \
7
- curl \
8
- git \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- COPY requirements.txt ./
12
- COPY src/ ./src/
13
-
14
- RUN pip3 install -r requirements.txt
15
-
16
- EXPOSE 8501
17
-
18
- HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
19
-
20
- ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /LastProject
4
+
5
+ COPY requirements.txt .
6
+
7
+ RUN apt-get update && apt-get install -y libgomp1
8
+
9
+ RUN pip install -r requirements.txt
10
+
11
+ COPY Frez.jpg .
12
+ COPY Main.jpg .
13
+ COPY Toch.jpg .
14
+ COPY model.pkl .
15
+ COPY scaler.pkl .
16
+ COPY df.csv .
17
+ COPY ReadMe.md .
18
+
19
+ COPY main.py .
20
+
21
+ CMD ["streamlit","run","main.py"]
Frez.jpg ADDED

Git LFS Details

  • SHA256: 476b50f29f35e196a2a11e06b5d4f2097533033be12cff1e0748c9f629a6914e
  • Pointer size: 131 Bytes
  • Size of remote file: 120 kB
Main.jpg ADDED

Git LFS Details

  • SHA256: 752462baac5c7040721040ed0cb2bba9b948cda8fbf0a1a703c9e8d4e468f822
  • Pointer size: 131 Bytes
  • Size of remote file: 107 kB
Toch.jpg ADDED

Git LFS Details

  • SHA256: 5abb5f5386f519545a0ddb86c5e29027df2139707603c6b3e0d0a1e919851700
  • Pointer size: 131 Bytes
  • Size of remote file: 104 kB
df.csv ADDED
The diff for this file is too large to render. See raw diff
 
main.py ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Информация о модели и метриках
2
+ MODEL_INFO = {
3
+ 'type': 'Регрессионная модель',
4
+ 'algorithm': 'LGBMRegressor',
5
+ 'features': [
6
+ 'Скорость_шпинделя',
7
+ 'Подача',
8
+ 'Глубина_резания',
9
+ 'Длина_обработки',
10
+ 'Операция',
11
+ 'Материал',
12
+ 'Тип_инструмента'
13
+ ],
14
+ 'target': 'Время обработки (секунды)'
15
+ }
16
+
17
+ METRICS = {
18
+ 'MSE': 379.5,
19
+ 'RMSE': 19.4,
20
+ 'MAE': 10.6,
21
+ 'MAPE': 1.08,
22
+ 'R2': 0.85
23
+ }
24
+
25
+ import streamlit as st
26
+ import pandas as pd
27
+ import matplotlib.pyplot as plt
28
+ import pickle
29
+ import os
30
+ import seaborn as sns
31
+
32
+ from matplotlib import gridspec
33
+ from datetime import datetime
34
+
35
+
36
+ # Инициализация session_state для хранения результатов
37
+ if 'results' not in st.session_state:
38
+ st.session_state.results = []
39
+
40
+ # Создаем структуру папок
41
+ if not os.path.exists('pages'):
42
+ os.makedirs('pages')
43
+
44
+ # Функция загрузки модели
45
+ @st.cache_data
46
+ def load_model(model_path):
47
+ if os.path.exists(model_path):
48
+ with open(model_path, 'rb') as f:
49
+ return pickle.load(f)
50
+ else:
51
+ st.error(f"Файл модели {model_path} не найден!")
52
+ return None
53
+
54
+ # Функция загрузки скалера
55
+ @st.cache_data
56
+ def load_scaler(scaler_path):
57
+ if os.path.exists(scaler_path):
58
+ with open(scaler_path, 'rb') as f:
59
+ return pickle.load(f)
60
+ else:
61
+ st.error(f"Файл скалера {scaler_path} не найден!")
62
+ return None
63
+
64
+ # Функция сохранения результатов
65
+ def save_result(result):
66
+ st.session_state.results.append(result) # Добавляем результат без сброса истории
67
+
68
+ # Функция очистки истории
69
+ def clear_results():
70
+ st.session_state.results = []
71
+
72
+ # Функция визуализации зависимостей
73
+ def plot_dependencies(df):
74
+ fig = plt.figure(figsize=(15, 12))
75
+ gs = gridspec.GridSpec(2, 2)
76
+
77
+ # График зависимости от скорости шпинделя
78
+ ax1 = fig.add_subplot(gs[0, 0])
79
+ sns.scatterplot(data=df, x='Скорость_шпинделя', y='Время_обработки', ax=ax1, alpha=0.6)
80
+ ax1.legend()
81
+ ax1.set_title('Зависимость от скорости шпинделя')
82
+
83
+ # График зависимости от подачи
84
+ ax2 = fig.add_subplot(gs[0, 1])
85
+ sns.scatterplot(data=df, x='Подача', y='Время_обработки', ax=ax2, alpha=0.6)
86
+ ax2.set_title('Зависимость от подачи')
87
+
88
+ # График зависимости от глубины резания
89
+ ax3 = fig.add_subplot(gs[1, 0])
90
+ sns.scatterplot(data=df, x='Глубина_резания', y='Время_обработки', ax=ax3, alpha=0.6)
91
+ ax3.set_title('Зависимость от глубины резания')
92
+
93
+ # График зависимости от длины обработки
94
+ ax4 = fig.add_subplot(gs[1, 1])
95
+ sns.scatterplot(data=df, x='Длина_обработки', y='Время_обработки', ax=ax4, alpha=0.6)
96
+ ax4.set_title('Зависимость от длины обработки')
97
+
98
+ plt.tight_layout()
99
+ st.pyplot(fig)
100
+
101
+ df = pd.read_csv('df.csv')
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+ # Общие настройки приложения
112
+ st.set_page_config(
113
+ page_title='Прогноз времени обработки',
114
+ layout='wide',
115
+ initial_sidebar_state='auto',
116
+ page_icon='⚙️'
117
+ )
118
+
119
+ # Создание навигационного меню
120
+ st.sidebar.title('Навигация')
121
+ page = st.sidebar.radio(
122
+ "Выберите страницу",
123
+ ('Главная', 'Расчет', 'История', 'О модели','Инструкция')
124
+ )
125
+
126
+ # Страница 1: Главная
127
+ if page == 'Главная':
128
+ st.title('Добро пожаловать в приложение - "Прогноз времени обработки"')
129
+ st.markdown('''
130
+ Это веб-приложение поможет вам рассчитать время обработки деталей на станках при различных входных параметрах.
131
+ ''')
132
+ try:
133
+ st.image('Main.jpg', width=1000)
134
+ except Exception:
135
+ st.warning("Изображение Main.jpg не найдено")
136
+
137
+ # Страница 2: Расчет
138
+ elif page == 'Расчет':
139
+ st.title('Расчет времени обработки')
140
+
141
+ # Загрузка модели и скалера
142
+ model = load_model('model.pkl')
143
+ scaler = load_scaler('scaler.pkl')
144
+
145
+ if model is None or scaler is None:
146
+ st.stop()
147
+
148
+ # Словарь признаков
149
+ features = dict(
150
+ speed='Скорость_шпинделя',
151
+ feed='Подача',
152
+ depth='Глубина_резания',
153
+ length='Длина_обработки',
154
+ operation='Тип_операции',
155
+ material='Тип_материала',
156
+ tool='Тип_инструмента'
157
+ )
158
+
159
+ # Слайдеры и радиокнопки
160
+ speed = st.sidebar.number_input(
161
+ label=f"{features['speed']} (об/мин)",
162
+ min_value=245,
163
+ max_value=3270,
164
+ value=245,
165
+ step=1,
166
+ format='%d'
167
+ )
168
+
169
+ feed = st.sidebar.number_input(
170
+ label=f"{features['feed']} (мм/об)",
171
+ min_value=0.007,
172
+ max_value=0.538,
173
+ value=0.007,
174
+ step=0.001,
175
+ format='%.3f'
176
+ )
177
+
178
+ depth = st.sidebar.number_input(
179
+ label=f"{features['depth']} (мм)",
180
+ min_value=0.001,
181
+ max_value=3.217,
182
+ value=0.001,
183
+ step=0.001,
184
+ format='%.3f'
185
+ )
186
+
187
+ length = st.sidebar.number_input(
188
+ label=f"{features['length']} (мм)",
189
+ min_value=1.0,
190
+ max_value=324.0,
191
+ value=1.0,
192
+ step=1.0,
193
+ format='%.0f'
194
+ )
195
+
196
+ operations = st.sidebar.radio(features['operation'], ['Фрезерование', 'Точение'], horizontal=True)
197
+ materials = st.sidebar.radio(features['material'], ['Латунь', 'Чугун', 'Низкоуглеродистая_сталь'], horizontal=True)
198
+ tools = st.sidebar.radio(features['tool'], ['Твердосплавный', 'Твердосплавный_с_покрытием', 'Быстрорежущий'], horizontal=True)
199
+
200
+ # Подготовка данных
201
+ operation_to_index = {'Фрезерование': 0, 'Точение': 1}
202
+ material_to_index = {'Латунь': 0, 'Чугун': 1, 'Низкоуглеродистая_сталь': 2}
203
+ tool_to_index = {'Твердосплавный': 0, 'Твердосплавный_с_покрытием': 1, 'Быстрорежущий': 2}
204
+
205
+ if operations == 'Фрезерование':
206
+ try:
207
+ st.image('Frez.jpg', width=600)
208
+ except Exception:
209
+ st.warning("Изображение Frez.jpg не найдено")
210
+ elif operations == 'Точение':
211
+ try:
212
+ st.image('Toch.jpg', width=600)
213
+ except Exception:
214
+ st.warning("Изображение Toch.jpg не найдено")
215
+
216
+ data_df = pd.DataFrame([dict(
217
+ Скорость_шпинделя=speed,
218
+ Подача=feed,
219
+ Глубина_резания=depth,
220
+ Длина_обработки=length,
221
+ Операция=operation_to_index[operations],
222
+ Материал=material_to_index[materials],
223
+ Тип_инструмента=tool_to_index[tools]
224
+ )])
225
+
226
+ # Вывод входных данных
227
+ st.write("##### Ваши данные")
228
+ st.write(data_df)
229
+
230
+ # Расчет
231
+ if st.button("Рассчитать"):
232
+ try:
233
+ s_data_df = scaler.transform(data_df)
234
+ time_prob = model.predict(s_data_df)
235
+
236
+ st.write("## Результаты расчета")
237
+ st.write(f"Время обработки: {time_prob[0]:.2f} секунд")
238
+
239
+ # Сохранение результата сразу после расчёта
240
+ save_result({
241
+ 'timestamp': datetime.now(),
242
+ 'data': data_df.to_dict(),
243
+ 'time': time_prob[0]
244
+ })
245
+ st.success('Результат успешно сохранен!')
246
+
247
+ except Exception as e:
248
+ st.error(f"Ошибка при расчёте: {str(e)}")
249
+
250
+ # Страница 3: История
251
+ elif page == 'История':
252
+ st.title('История расчетов')
253
+
254
+ if not st.session_state.results:
255
+ st.info('История расчетов пуста')
256
+ else:
257
+ # Создаем DataFrame из сохраненных результатов
258
+ results_df = pd.DataFrame([
259
+ {
260
+ 'Номер': idx + 1,
261
+ 'Дата': result['timestamp'].strftime('%d.%m.%Y %H:%M'),
262
+ 'Скорость шпинделя, (об/мин)': result['data']['Скорость_шпинделя'][0],
263
+ 'Подача, (мм/об)': result['data']['Подача'][0],
264
+ 'Глубина резания, (мм)': result['data']['Глубина_резания'][0],
265
+ 'Длина обработки, (мм)': result['data']['Длина_обработки'][0],
266
+ 'Тип операции': ['Фрезерование', 'Точение'][result['data']['Операция'][0]],
267
+ 'Материал': ['Латунь', 'Чугун', 'Низкоугле��одистая_сталь'][result['data']['Материал'][0]],
268
+ 'Инструмент': ['Твердосплавный', 'Твердосплавный_с_покрытием', 'Быстрорежущий'][result['data']['Тип_инструмента'][0]],
269
+ 'Время обработки, (сек)': result['time']
270
+ }
271
+ for idx,result in enumerate(st.session_state.results)
272
+ ])
273
+
274
+ # Отображаем таблицу
275
+ st.dataframe(results_df)
276
+
277
+ # Кнопка для построения графика
278
+ if st.button('Построить график истории'):
279
+ try:
280
+ # Создаем график
281
+ fig, ax = plt.subplots(figsize=(12, 6))
282
+ plt.plot(
283
+ results_df['Номер'],
284
+ results_df['Время обработки, (сек)'],
285
+ marker='o',
286
+ linestyle='-',
287
+ color='blue'
288
+ )
289
+
290
+ # Находим минимальное значение
291
+ min_time = results_df['Время обработки, (сек)'].min()
292
+ min_index = results_df[results_df['Время обработки, (сек)'] == min_time]['Номер'].values[0]
293
+
294
+ # Отмечаем минимальное значение
295
+ plt.plot(
296
+ min_index,
297
+ min_time,
298
+ marker='o',
299
+ color='red',
300
+ markersize=10
301
+ )
302
+ plt.text(
303
+ min_index,
304
+ min_time,
305
+ f'Минимум: {min_time:.2f} сек',
306
+ verticalalignment='bottom',
307
+ horizontalalignment='center'
308
+ )
309
+
310
+ # Форматируем оси
311
+ plt.title('Динамика времени обработки по истории расчетов')
312
+ plt.xlabel('Номер расчета')
313
+ plt.ylabel('Время обработки (сек)')
314
+ plt.grid(True)
315
+ plt.xticks(results_df['Номер']) # Показываем все номера
316
+ plt.tight_layout()
317
+
318
+ st.pyplot(fig)
319
+
320
+ except Exception as e:
321
+ st.error(f"Ошибка при построении графика: {str(e)}")
322
+
323
+ # Добавляем кнопку очистки истории
324
+ if st.button('Очистить историю'):
325
+ clear_results()
326
+ st.success('История успешно очищена')
327
+
328
+ # Страница 4: Информация о модели
329
+ elif page == 'О модели':
330
+ st.title('О модели прогнозирования')
331
+
332
+ st.subheader('Информация о модели')
333
+ st.write(f"Тип модели: {MODEL_INFO['type']}")
334
+ st.write(f"Используемый алгоритм: {MODEL_INFO['algorithm']}")
335
+
336
+ st.subheader('Входные параметры')
337
+ st.write(MODEL_INFO['features'])
338
+
339
+ st.subheader('Целевая переменная')
340
+ st.write(MODEL_INFO['target'])
341
+
342
+ st.subheader('Метрики качества на тестовой выборке')
343
+ metrics_df = pd.DataFrame(METRICS.items(), columns=['Метрика', 'Значение'])
344
+ st.dataframe(metrics_df)
345
+
346
+ st.subheader('Важные характеристики')
347
+ st.markdown('''
348
+ * Модель обучена на наборе данных с 47553 наблюдений
349
+ * Данные прошли предварительную обработку (EDA)
350
+ * Использовано масштабирование признаков
351
+ * Модель показывает точность прогнозирования на тестовых данных ~85%
352
+
353
+ # Далее представлены графики зависимости времени обработки от некоторых признаков, а также карта корреляций
354
+ ''')
355
+
356
+ plot_dependencies(df)
357
+
358
+ st.subheader('Корреляция параметров')
359
+ fig_corr = plt.figure(figsize=(5, 4))
360
+ sns.heatmap(df.corr(), annot=True, cmap='coolwarm', fmt=".2f")
361
+ st.pyplot(fig_corr)
362
+
363
+ # Страница 5: Инструкция
364
+ elif page == 'Инструкция':
365
+ st.title('Инструкция по работе с приложением')
366
+ st.markdown('''
367
+ * Страница "Расчёт". На данной странице требуется ввести в ручном режиме:
368
+ * Скорость шпинделя (об/мин)
369
+ * Подача (мм/об)
370
+ * Глубина резания (мм)
371
+ * Длина обработки (мм)
372
+ * Тип операции (категориальный)
373
+ * Материал (категориальный)
374
+ * Тип инструмента (категориальный)
375
+
376
+ Далее требуется нажать кнопку "Рассчитать" -> Данный предикт модели будет рассчитан и автоматически сохранён (Его можно увидеть на странице "История").
377
+
378
+
379
+
380
+ * Страница "История". На данной странице можно просматривать результаты расчётов модели.
381
+
382
+ Также имеется возможность построить график с целью определения параметров обработки деталей с минимальным временем обработки.
383
+
384
+ При необходимости нажав на кнопку "Очистить историю" можно удалить все результаты (на данный момент отсутствует возможность фильтрации и соответственно удалении только определенных результатов)
385
+
386
+
387
+ * Страница "О модели". Данная страница хранит информацию об используемой в приложении модели, параметрах обучения, графиков и т.д.
388
+ ''')
model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fd0ca3cf60c79adb7e7cdbfa2660430f8533e11fbd4e8877ab8046c20317c8a2
3
+ size 280843
requirements.txt CHANGED
@@ -1,3 +1,7 @@
1
- altair
2
- pandas
3
- streamlit
 
 
 
 
 
1
+ pandas
2
+ streamlit
3
+ lightgbm
4
+ matplotlib
5
+ seaborn
6
+ numpy
7
+ scikit-learn
scaler.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5a37b5df3041e5cc112d61de60b03177321a2ff19d56f14377b47a3a7b1911ed
3
+ size 890