diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -125,62 +125,62 @@ REPO_ID = "arabovs-ai-lab/PectinProductionModels"
AVAILABLE_MODELS = {
"best_model": {
"subfolder": "best_model",
- "description": "🎯 Best overall model (Gradient Boosting) - optimal performance",
+ "description": "🎯 Best overall model (Gradient Boosting) - оптимальная производительность",
"color": "#FF6B6B"
},
"gradient_boosting": {
"subfolder": "gradient_boosting",
- "description": "📈 Gradient Boosting - best for multi-task regression",
+ "description": "📈 Gradient Boosting - лучшая для многозадачной регрессии",
"color": "#4ECDC4"
},
"random_forest": {
"subfolder": "random_forest",
- "description": "🌲 Random Forest - reliable and stable",
+ "description": "🌲 Random Forest - надежная и стабильная",
"color": "#45B7D1"
},
"xgboost": {
"subfolder": "xgboost",
- "description": "⚡ XGBoost - high performance on tabular data",
+ "description": "⚡ XGBoost - высокая производительность на табличных данных",
"color": "#96CEB4"
},
"linear_regression": {
"subfolder": "linear_regression",
- "description": "📊 Linear Regression - basic linear model",
+ "description": "📊 Linear Regression - базовая линейная модель",
"color": "#FECA57"
},
"extra_trees": {
"subfolder": "extra_trees",
- "description": "🌳 Extra Trees - extreme random forests",
+ "description": "🌳 Extra Trees - экстремальные случайные леса",
"color": "#FF9FF3"
},
"k_neighbors": {
"subfolder": "k-neighbors",
- "description": "📏 K-Neighbors - nearest neighbors method",
+ "description": "📏 K-Neighbors - метод ближайших соседей",
"color": "#54A0FF"
},
"lasso_regression": {
"subfolder": "lasso_regression",
- "description": "🎯 Lasso Regression - L1 regularization",
+ "description": "🎯 Lasso Regression - L1-регуляризация",
"color": "#5F27CD"
},
"multilayer_perceptron": {
"subfolder": "multilayer_perceptron",
- "description": "🧠 Neural Network MLP - multilayer perceptron",
+ "description": "🧠 Neural Network MLP - многослойный перцептрон",
"color": "#00D2D3"
},
"ridge_regression": {
"subfolder": "ridge_regression",
- "description": "🏔️ Ridge Regression - L2 regularization",
+ "description": "🏔️ Ridge Regression - L2-регуляризация",
"color": "#FF9F43"
},
"support_vector_regression": {
"subfolder": "support_vector_regression",
- "description": "🔗 Support Vector Regression - support vector method",
+ "description": "🔗 Support Vector Regression - метод опорных векторов",
"color": "#A3CB38"
}
}
# Sample types available
-SAMPLE_TYPES = ["AP(M)", "Abr.", "KrP", "Aiv.", "Tkv", "Rv.", "AP(F)"]
+SAMPLE_TYPES = ["ЯП(М)", "Абр.", "КрП", "Айв.", "Ткв", "Рв.", "ЯП(Ф)"]
# Column mapping for Russian to English
COLUMN_MAPPING = {
@@ -199,26 +199,26 @@ COLUMN_MAPPING = {
# Target descriptions
TARGET_DESCRIPTIONS = {
'pectin_yield': {
- 'name': 'Pectin yield',
- 'description': 'Percentage of pectin yield from raw material',
+ 'name': 'Выход пектина',
+ 'description': 'Процент выхода пектина из сырья',
'unit': '%',
'range': (0, 100)
},
'galacturonic_acid': {
- 'name': 'Galacturonic acid',
- 'description': 'Galacturonic acid content in pectin',
+ 'name': 'Галактуроновая кислота',
+ 'description': 'Содержание галактуроновой кислоты в пектине',
'unit': '%',
'range': (0, 100)
},
'molecular_weight': {
- 'name': 'Molecular weight',
- 'description': 'Pectin molecular weight',
+ 'name': 'Молекулярная масса',
+ 'description': 'Молекулярная масса пектина',
'unit': 'Da',
'range': (0, 500000)
},
'esterification_degree': {
- 'name': 'Esterification degree',
- 'description': 'Pectin esterification degree',
+ 'name': 'Степень этерификации',
+ 'description': 'Степень этерификации пектина',
'unit': '%',
'range': (0, 100)
}
@@ -227,52 +227,52 @@ TARGET_DESCRIPTIONS = {
# Metric descriptions
METRIC_DESCRIPTIONS = {
'mae': {
- 'name': 'MAE (Mean Absolute Error)',
- 'description': 'Mean absolute difference between prediction and true value',
+ 'name': 'MAE (Средняя абсолютная ошибка)',
+ 'description': 'Среднее абсолютное значение разницы между предсказанием и истинным значением',
'better_lower': True,
'perfect_value': 0
},
'mse': {
- 'name': 'MSE (Mean Squared Error)',
- 'description': 'Mean of squared differences between prediction and true value',
+ 'name': 'MSE (Средняя квадратичная ошибка)',
+ 'description': 'Среднее квадратов разниц между предсказанием и истинным значением',
'better_lower': True,
'perfect_value': 0
},
'rmse': {
- 'name': 'RMSE (Root Mean Squared Error)',
- 'description': 'Square root of mean squared error, same dimension as target variable',
+ 'name': 'RMSE (Среднеквадратичная ошибка)',
+ 'description': 'Корень из средней квадратичной ошибки, имеет ту же размерность что и целевая переменная',
'better_lower': True,
'perfect_value': 0
},
'r2': {
- 'name': 'R² (Coefficient of Determination)',
- 'description': 'Proportion of variance in dependent variable explained by the model',
+ 'name': 'R² (Коэффициент детерминации)',
+ 'description': 'Доля дисперсии зависимой переменной, объясняемая моделью',
'better_lower': False,
'perfect_value': 1
},
'mape': {
- 'name': 'MAPE (Mean Absolute Percentage Error)',
- 'description': 'Mean absolute error as percentage of true values',
+ 'name': 'MAPE (Средняя абсолютная процентная ошибка)',
+ 'description': 'Средняя абсолютная ошибка в процентах от истинных значений',
'better_lower': True,
'perfect_value': 0
},
'correlation': {
- 'name': 'Pearson Correlation',
- 'description': 'Measure of linear dependence between predictions and true values',
+ 'name': 'Корреляция Пирсона',
+ 'description': 'Мера линейной зависимости между предсказаниями и истинными значениями',
'better_lower': False,
'perfect_value': 1
}
}
# Helper function to download and cache model files
-@st.cache_resource(show_spinner="🔄 Loading model and support files...")
+@st.cache_resource(show_spinner="🔄 Загрузка модели и вспомогательных файлов...")
def load_pectin_model(model_name: str):
"""Load pectin model and supporting files from Hugging Face Hub"""
try:
model_info = AVAILABLE_MODELS[model_name]
subfolder = model_info["subfolder"]
- st.info(f"🔄 Attempting to load model {model_name} from repository {REPO_ID}")
+ st.info(f"🔄 Попытка загрузки модели {model_name} из репозитория {REPO_ID}")
# Download model file
try:
@@ -281,15 +281,15 @@ def load_pectin_model(model_name: str):
filename=f"{subfolder}/model.pkl",
repo_type="model"
)
- st.success(f"✅ Model {model_name} loaded successfully")
+ st.success(f"✅ Модель {model_name} загружена успешно")
except Exception as e:
- st.error(f"❌ Error loading model {model_name}: {str(e)}")
+ st.error(f"❌ Ошибка загрузки модели {model_name}: {str(e)}")
st.markdown('
', unsafe_allow_html=True)
- st.error("**Possible causes of 403 error:**")
- st.error("1. Repository doesn't exist or is private")
- st.error("2. No internet access")
- st.error("3. Hugging Face authorization issues")
- st.error("4. Model files missing in repository")
+ st.error("**Возможные причины ошибки 403:**")
+ st.error("1. Репозиторий не существует или приватный")
+ st.error("2. Нет доступа к интернету")
+ st.error("3. Проблемы с авторизацией Hugging Face")
+ st.error("4. Файлы модели отсутствуют в репозитории")
st.markdown('
', unsafe_allow_html=True)
return {"status": "error", "error": str(e)}
@@ -300,9 +300,9 @@ def load_pectin_model(model_name: str):
filename="scaler.pkl",
repo_type="model"
)
- st.success("✅ Scaler loaded successfully")
+ st.success("✅ Scaler загружен успешно")
except Exception as e:
- st.error(f"❌ Error loading scaler: {str(e)}")
+ st.error(f"❌ Ошибка загрузки scaler: {str(e)}")
return {"status": "error", "error": f"Scaler error: {str(e)}"}
try:
@@ -311,9 +311,9 @@ def load_pectin_model(model_name: str):
filename="label_encoder.pkl",
repo_type="model"
)
- st.success("✅ Label encoder loaded successfully")
+ st.success("✅ Label encoder загружен успешно")
except Exception as e:
- st.error(f"❌ Error loading label encoder: {str(e)}")
+ st.error(f"❌ Ошибка загрузки label encoder: {str(e)}")
return {"status": "error", "error": f"Encoder error: {str(e)}"}
try:
@@ -322,9 +322,9 @@ def load_pectin_model(model_name: str):
filename="model_metadata.json",
repo_type="model"
)
- st.success("✅ Metadata loaded successfully")
+ st.success("✅ Метаданные загружены успешно")
except Exception as e:
- st.error(f"❌ Error loading metadata: {str(e)}")
+ st.error(f"❌ Ошибка загрузки метаданных: {str(e)}")
return {"status": "error", "error": f"Metadata error: {str(e)}"}
# Load all artifacts
@@ -338,7 +338,7 @@ def load_pectin_model(model_name: str):
with open(metadata_path, 'r', encoding='utf-8') as f:
metadata = json.load(f)
- st.success(f"✅ All model {model_name} artifacts loaded and ready to use")
+ st.success(f"✅ Все артефакты модели {model_name} загружены и готовы к использованию")
return {
"model": model,
@@ -349,13 +349,13 @@ def load_pectin_model(model_name: str):
}
except Exception as e:
- st.error(f"❌ Error loading model artifacts: {str(e)}")
+ st.error(f"❌ Ошибка загрузки артефактов модели: {str(e)}")
return {"status": "error", "error": f"Loading error: {str(e)}"}
except Exception as e:
- st.error(f"❌ Critical error loading model {model_name}: {str(e)}")
+ st.error(f"❌ Критическая ошибка загрузки модели {model_name}: {str(e)}")
st.markdown('', unsafe_allow_html=True)
- st.error("**Error details:**")
+ st.error("**Детали ошибки:**")
st.code(traceback.format_exc())
st.markdown('
', unsafe_allow_html=True)
return {"status": "error", "error": str(e)}
@@ -363,7 +363,7 @@ def load_pectin_model(model_name: str):
# Fallback to demo mode if models cannot be loaded
def create_demo_model():
"""Create demo model for testing when real models are unavailable"""
- st.warning("🎭 Using demo mode with test data")
+ st.warning("🎭 Используется демо-режим с тестовыми данными")
class DemoModel:
def predict(self, X):
@@ -417,7 +417,7 @@ def preprocess_single_input(input_data: Dict, model_artifacts: Dict) -> Optional
if sample_value in label_encoder.classes_:
df['sample_encoded'] = label_encoder.transform([sample_value])[0]
else:
- st.warning(f"⚠️ Raw material type '{sample_value}' not found in encoder. Using default value.")
+ st.warning(f"⚠️ Тип сырья '{sample_value}' не найден в энкодере. Используется значение по умолчанию.")
default_class = label_encoder.classes_[0]
df['sample_encoded'] = label_encoder.transform([default_class])[0]
@@ -442,7 +442,7 @@ def preprocess_single_input(input_data: Dict, model_artifacts: Dict) -> Optional
return X_scaled
except Exception as e:
- st.error(f"❌ Data preprocessing error: {e}")
+ st.error(f"❌ Ошибка предобработки данных: {e}")
st.code(traceback.format_exc())
return None
@@ -469,28 +469,28 @@ def predict_single(input_data: Dict, model_artifacts: Dict) -> Optional[Dict]:
return results
except Exception as e:
- st.error(f"❌ Prediction error: {e}")
+ st.error(f"❌ Ошибка предсказания: {e}")
st.code(traceback.format_exc())
return None
def detect_file_encoding(uploaded_file):
- """Detects file encoding"""
+ """Определяет кодировку файла"""
try:
- # Try different encodings
+ # Пробуем разные кодировки
for encoding in ['utf-8', 'cp1251', 'iso-8859-1', 'windows-1251']:
try:
content = uploaded_file.getvalue().decode(encoding)
- uploaded_file.seek(0) # Reset position
+ uploaded_file.seek(0) # Сбрасываем позицию
return encoding, content
except UnicodeDecodeError:
continue
return 'utf-8', uploaded_file.getvalue().decode('utf-8', errors='ignore')
except Exception as e:
- st.error(f"❌ Encoding detection error: {e}")
+ st.error(f"❌ Ошибка определения кодировки: {e}")
return 'utf-8', uploaded_file.getvalue().decode('utf-8', errors='ignore')
def parse_russian_number(value):
- """Parses Russian numbers with commas as decimal separators"""
+ """Парсит русские числа с запятыми как десятичными разделителями"""
if pd.isna(value) or value == '':
return 0.0
@@ -498,46 +498,46 @@ def parse_russian_number(value):
return float(value)
if isinstance(value, str):
- # Replace commas with dots and remove spaces
+ # Заменяем запятые на точки и убираем пробелы
cleaned = value.replace(',', '.').replace(' ', '')
try:
return float(cleaned)
except ValueError:
- # If conversion fails, return 0
+ # Если не получается, возвращаем 0
return 0.0
return 0.0
def read_flexible_pectin_file(uploaded_file, skiprows=None):
- """Universal function for reading pectin files with different formats"""
+ """Универсальная функция для чтения файлов пектина с разными форматами"""
try:
file_extension = uploaded_file.name.lower()
- st.info(f"📂 Reading file: {uploaded_file.name}, extension: {file_extension}")
+ st.info(f"📂 Чтение файла: {uploaded_file.name}, расширение: {file_extension}")
if file_extension.endswith('.xlsx'):
- # For Excel files
+ # Для Excel файлов
if skiprows is None:
- # Try different skip row options
+ # Пробуем разные варианты пропуска строк
for skip in [0, 1, 2, 3]:
try:
df = pd.read_excel(uploaded_file, skiprows=skip, engine='openpyxl')
- if len(df.columns) > 3: # If enough columns
- st.info(f"✅ Found data structure with {skip} rows skipped")
+ if len(df.columns) > 3: # Если есть достаточно колонок
+ st.info(f"✅ Найдена структура данных с пропуском {skip} строк")
return df
except Exception as e:
- st.warning(f"⚠️ Failed to read with {skip} rows skipped: {e}")
+ st.warning(f"⚠️ Не удалось прочитать с пропуском {skip} строк: {e}")
continue
- # If nothing works, read without skipping
+ # Если ничего не сработало, читаем без пропуска
return pd.read_excel(uploaded_file, engine='openpyxl')
else:
return pd.read_excel(uploaded_file, skiprows=skiprows, engine='openpyxl')
elif file_extension.endswith('.csv') or file_extension.endswith('.txt'):
- # For CSV/TXT files
+ # Для CSV/TXT файлов
encoding, content = detect_file_encoding(uploaded_file)
- st.info(f"📖 Detected encoding: {encoding}")
+ st.info(f"📖 Определена кодировка: {encoding}")
- # Try different separators
+ # Пробуем разные разделители
separators = ['\t', ',', ';', '|']
for sep in separators:
@@ -547,45 +547,45 @@ def read_flexible_pectin_file(uploaded_file, skiprows=None):
else:
df = pd.read_csv(io.StringIO(content), sep=sep, encoding=encoding)
- if len(df.columns) > 3: # If enough columns
- st.info(f"✅ Found separator: '{sep}' with {skiprows or 0} rows skipped")
+ if len(df.columns) > 3: # Если есть достаточно колонок
+ st.info(f"✅ Найден разделитель: '{sep}' с пропуском {skiprows or 0} строк")
return df
except Exception as e:
- st.warning(f"⚠️ Failed to read with separator '{sep}': {e}")
+ st.warning(f"⚠️ Не удалось прочитать с разделителем '{sep}': {e}")
continue
- # If nothing works, try without specifying separator
+ # Если ничего не сработало, пробуем без указания разделителя
try:
return pd.read_csv(io.StringIO(content), encoding=encoding)
except Exception as e:
- st.error(f"❌ Failed to read file: {e}")
+ st.error(f"❌ Не удалось прочитать файл: {e}")
return None
else:
- st.error("❌ Unsupported file format")
+ st.error("❌ Неподдерживаемый формат файла")
return None
except Exception as e:
- st.error(f"❌ File reading error: {e}")
+ st.error(f"❌ Ошибка чтения файла: {e}")
st.code(traceback.format_exc())
return None
def validate_file_structure(uploaded_file, skiprows=None):
- """Validates file structure before processing"""
+ """Проверяет структуру файла перед обработкой"""
try:
- st.info("🔍 Starting file structure validation...")
+ st.info("🔍 Начинаем проверку структуры файла...")
df = read_flexible_pectin_file(uploaded_file, skiprows)
if df is None or df.empty:
- st.error("❌ File is empty or contains no data")
+ st.error("❌ Файл пустой или не содержит данных")
return False, None
- st.success(f"✅ File successfully read! Size: {df.shape}")
- st.info("📋 File structure (first 5 rows):")
+ st.success(f"✅ Файл успешно прочитан! Размер: {df.shape}")
+ st.info("📋 Структура файла (первые 5 строк):")
st.dataframe(df.head(), width='stretch')
- st.info(f"📊 File columns: {list(df.columns)}")
+ st.info(f"📊 Колонки файла: {list(df.columns)}")
- # Check for required columns (Russian or English)
+ # Проверяем наличие необходимых колонок (русских или английских)
required_russian = ['Образец \nпектина', 't, мин', 'T, °C', 'P, атм', 'pH']
required_english = ['sample', 'time_min', 'temperature_c', 'pressure_atm', 'ph']
@@ -593,21 +593,21 @@ def validate_file_structure(uploaded_file, skiprows=None):
has_english = any(col in df.columns for col in required_english)
if not has_russian and not has_english:
- st.error(f"❌ Missing required columns. Need either Russian: {required_russian}, or English: {required_english}")
+ st.error(f"❌ Отсутствуют обязательные колонки. Нужны либо русские: {required_russian}, либо английские: {required_english}")
return False, df
- st.success("✅ All required columns present")
+ st.success("✅ Все необходимые колонки присутствуют")
return True, df
except Exception as e:
- st.error(f"❌ Failed to read file: {e}")
+ st.error(f"❌ Не удалось прочитать файл: {e}")
st.code(traceback.format_exc())
return False, None
def calculate_regression_metrics(y_true, y_pred, target_name):
- """Calculates regression metrics"""
+ """Вычисляет метрики регрессии"""
try:
- # Remove NaN values
+ # Удаляем NaN значения
mask = ~(np.isnan(y_true) | np.isnan(y_pred))
y_true_clean = y_true[mask]
y_pred_clean = y_pred[mask]
@@ -617,7 +617,7 @@ def calculate_regression_metrics(y_true, y_pred, target_name):
metrics = {}
- # Basic metrics
+ # Базовые метрики
metrics['mae'] = mean_absolute_error(y_true_clean, y_pred_clean)
metrics['mse'] = mean_squared_error(y_true_clean, y_pred_clean)
metrics['rmse'] = np.sqrt(metrics['mse'])
@@ -634,7 +634,7 @@ def calculate_regression_metrics(y_true, y_pred, target_name):
else:
metrics['mape'] = np.nan
- # Correlation
+ # Корреляция
if len(y_true_clean) > 1:
correlation, p_value = stats.pearsonr(y_true_clean, y_pred_clean)
metrics['correlation'] = correlation
@@ -643,10 +643,10 @@ def calculate_regression_metrics(y_true, y_pred, target_name):
metrics['correlation'] = np.nan
metrics['correlation_p_value'] = np.nan
- # Number of samples
+ # Количество образцов
metrics['n_samples'] = len(y_true_clean)
- # True value range
+ # Диапазон истинных значений
metrics['true_min'] = np.min(y_true_clean)
metrics['true_max'] = np.max(y_true_clean)
metrics['true_mean'] = np.mean(y_true_clean)
@@ -655,11 +655,11 @@ def calculate_regression_metrics(y_true, y_pred, target_name):
return metrics
except Exception as e:
- st.error(f"❌ Error calculating metrics for {target_name}: {e}")
+ st.error(f"❌ Ошибка вычисления метрик для {target_name}: {e}")
return None
def get_metric_quality(metric_name, value, target_name):
- """Determines metric quality"""
+ """Определяет качество метрики"""
if np.isnan(value):
return "unknown"
@@ -689,7 +689,7 @@ def get_metric_quality(metric_name, value, target_name):
else:
return "poor"
elif metric_name in ['mae', 'mse', 'rmse']:
- # Evaluate relative to target variable range
+ # Оцениваем относительно диапазона целевой переменной
target_range = TARGET_DESCRIPTIONS[target_name]['range'][1] - TARGET_DESCRIPTIONS[target_name]['range'][0]
relative_error = value / target_range * 100
@@ -703,7 +703,7 @@ def get_metric_quality(metric_name, value, target_name):
return "unknown"
def create_metric_card(metric_name, value, target_name, width=200):
- """Creates metric card"""
+ """Создает карточку с метрикой"""
quality = get_metric_quality(metric_name, value, target_name)
metric_info = METRIC_DESCRIPTIONS.get(metric_name, {})
@@ -733,19 +733,19 @@ def create_metric_card(metric_name, value, target_name, width=200):
return card_html
def process_batch_file_single_model(uploaded_file, model_artifacts, model_name, skiprows=None):
- """Process file with single model"""
+ """Обработка файла с одной моделью"""
try:
- st.info(f"🔄 Starting file processing with model {model_name}...")
- # Read file
+ st.info(f"🔄 Начинаем обработку файла с моделью {model_name}...")
+ # Читаем файл
df = read_flexible_pectin_file(uploaded_file, skiprows)
if df is None or df.empty:
- st.error("❌ File is empty or contains no data")
+ st.error("❌ Файл пустой или не содержит данных")
return None
- st.success(f"✅ File loaded: {len(df)} records")
+ st.success(f"✅ Файл загружен: {len(df)} записей")
- # Apply Russian to English column mapping
+ # Применяем маппинг русских названий на английские
columns_renamed = []
for rus_name, eng_name in COLUMN_MAPPING.items():
if rus_name in df.columns:
@@ -753,28 +753,28 @@ def process_batch_file_single_model(uploaded_file, model_artifacts, model_name,
columns_renamed.append(f"{rus_name} -> {eng_name}")
if columns_renamed:
- st.info(f"✅ Renamed columns: {columns_renamed}")
+ st.info(f"✅ Переименованы колонки: {columns_renamed}")
- # Convert numeric columns with Russian formats
+ # Преобразуем числовые колонки с русскими форматами
numeric_columns = ['time_min', 'temperature_c', 'pressure_atm', 'ph',
'pectin_yield', 'galacturonic_acid', 'molecular_weight', 'esterification_degree']
for col in numeric_columns:
if col in df.columns:
df[col] = df[col].apply(parse_russian_number)
- st.info(f"✅ Converted numeric data in column: {col}")
+ st.info(f"✅ Преобразованы числовые данные в колонке: {col}")
- # Check required columns
+ # Проверяем необходимые колонки
required_columns = ['sample', 'time_min', 'temperature_c', 'pressure_atm', 'ph']
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
- st.error(f"❌ Missing required columns: {missing_columns}")
- st.info("📋 Available columns in file:")
+ st.error(f"❌ Отсутствуют обязательные колонки: {missing_columns}")
+ st.info("📋 Доступные колонки в файле:")
st.write(list(df.columns))
return None
- # Process data
+ # Обрабатываем данные
predictions = []
processed_data = []
@@ -785,26 +785,26 @@ def process_batch_file_single_model(uploaded_file, model_artifacts, model_name,
for idx, row in df.iterrows():
try:
- status_text.text(f"Processing record {idx+1} of {len(df)}...")
+ status_text.text(f"Обработка записи {idx+1} из {len(df)}...")
progress_bar.progress((idx + 1) / len(df))
- # Convert row to dictionary
+ # Преобразуем строку в словарь
input_data = row.to_dict()
- # Remove unnecessary columns
+ # Убираем ненужные колонки
for col in list(input_data.keys()):
if col not in required_columns and not col.startswith('predicted_'):
- if col != 'solid_liquid_ratio': # Keep solid_liquid_ratio if present
+ if col != 'solid_liquid_ratio': # Сохраняем Т:Ж если есть
del input_data[col]
- # Check and clean data
+ # Проверяем и очищаем данные
for key in list(input_data.keys()):
if pd.isna(input_data[key]) or input_data[key] == '':
if key in required_columns:
- st.warning(f"⚠️ Row {idx+1}: missing value in column '{key}'")
+ st.warning(f"⚠️ Строка {idx+1}: пропущено значение в колонке '{key}'")
del input_data[key]
- # Check for required fields
+ # Проверяем наличие обязательных полей
if all(field in input_data for field in required_columns):
prediction = predict_single(input_data, model_artifacts)
if prediction:
@@ -816,29 +816,29 @@ def process_batch_file_single_model(uploaded_file, model_artifacts, model_name,
processed_data.append(input_data)
else:
missing = [field for field in required_columns if field not in input_data]
- st.warning(f"⚠️ Row {idx+1}: missing fields {missing}")
+ st.warning(f"⚠️ Строка {idx+1}: отсутствуют поля {missing}")
predictions.append({})
processed_data.append(input_data)
except Exception as e:
- st.error(f"❌ Error processing row {idx+1}: {e}")
+ st.error(f"❌ Ошибка обработки строки {idx+1}: {e}")
predictions.append({})
processed_data.append(row.to_dict() if 'row' in locals() else {})
- status_text.text("✅ Processing completed!")
+ status_text.text("✅ Обработка завершена!")
progress_bar.empty()
- st.info(f"📊 Successfully processed: {successful_predictions} of {len(df)} records")
+ st.info(f"📊 Успешно обработано: {successful_predictions} из {len(df)} записей")
- # Create results DataFrame
+ # Создаем DataFrame с результатами
result_df = pd.DataFrame(processed_data)
- # Add predictions with model prefix
+ # Добавляем предсказания с префиксом модели
target_columns = model_artifacts["metadata"].get('target_columns', [])
for i, target in enumerate(target_columns):
result_df[f'{model_name}_{target}'] = [pred.get(target, None) for pred in predictions]
- # Save original data if present
+ # Сохраняем оригинальные данные если они есть
original_columns = ['pectin_yield', 'galacturonic_acid', 'molecular_weight', 'esterification_degree']
for col in original_columns:
if col in df.columns:
@@ -847,33 +847,33 @@ def process_batch_file_single_model(uploaded_file, model_artifacts, model_name,
return result_df
except Exception as e:
- st.error(f"❌ Critical file processing error: {e}")
+ st.error(f"❌ Критическая ошибка обработки файла: {e}")
st.markdown('', unsafe_allow_html=True)
- st.error("**Error details:**")
+ st.error("**Детали ошибки:**")
st.code(traceback.format_exc())
st.markdown('
', unsafe_allow_html=True)
return None
def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=None):
- """Process file with multiple models and compare results"""
+ """Обработка файла с несколькими моделями и сравнение результатов"""
try:
- st.info("🔄 Starting file processing with multiple models...")
+ st.info("🔄 Начинаем обработку файла с несколькими моделями...")
- # First read and preprocess file once
+ # Сначала читаем и предобрабатываем файл один раз
df = read_flexible_pectin_file(uploaded_file, skiprows)
if df is None or df.empty:
- st.error("❌ File is empty or contains no data")
+ st.error("❌ Файл пустой или не содержит данных")
return None, {}, {}, {}
- st.success(f"✅ File loaded: {len(df)} records")
+ st.success(f"✅ Файл загружен: {len(df)} записей")
- # Apply Russian to English column mapping
+ # Применяем маппинг русских названий на английские
for rus_name, eng_name in COLUMN_MAPPING.items():
if rus_name in df.columns:
df = df.rename(columns={rus_name: eng_name})
- # Convert numeric columns with Russian formats
+ # Преобразуем числовые колонки с русскими форматами
numeric_columns = ['time_min', 'temperature_c', 'pressure_atm', 'ph',
'pectin_yield', 'galacturonic_acid', 'molecular_weight', 'esterification_degree']
@@ -881,22 +881,22 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
if col in df.columns:
df[col] = df[col].apply(parse_russian_number)
- # Check required columns
+ # Проверяем необходимые колонки
required_columns = ['sample', 'time_min', 'temperature_c', 'pressure_atm', 'ph']
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
- st.error(f"❌ Missing required columns: {missing_columns}")
+ st.error(f"❌ Отсутствуют обязательные колонки: {missing_columns}")
return None, {}, {}, {}
- # Create base DataFrame with source data
+ # Создаем базовый DataFrame с исходными данными
base_columns = required_columns.copy()
if 'solid_liquid_ratio' in df.columns:
base_columns.append('solid_liquid_ratio')
result_df = df[base_columns].copy()
- # Add original target variables if present
+ # Добавляем оригинальные целевые переменные если есть
original_columns = ['pectin_yield', 'galacturonic_acid', 'molecular_weight', 'esterification_degree']
has_ground_truth = False
for col in original_columns:
@@ -904,7 +904,7 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
result_df[f'original_{col}'] = df[col]
has_ground_truth = True
- # Process data for each model
+ # Обрабатываем данные для каждой модели
all_predictions = {}
model_results = {}
all_metrics = {}
@@ -914,17 +914,17 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
for model_idx, model_name in enumerate(selected_models):
try:
- status_text.text(f"🔄 Processing with model {model_name} ({model_idx+1}/{len(selected_models)})...")
+ status_text.text(f"🔄 Обработка моделью {model_name} ({model_idx+1}/{len(selected_models)})...")
progress_bar.progress(model_idx / len(selected_models))
- # Load model
+ # Загружаем модель
model_artifacts = load_pectin_model(model_name)
if model_artifacts["status"] not in ["success", "demo"]:
- st.error(f"❌ Failed to load model {model_name}")
+ st.error(f"❌ Не удалось загрузить модель {model_name}")
continue
- # Get predictions for all rows
+ # Получаем предсказания для всех строк
model_predictions = []
successful_predictions = 0
@@ -940,10 +940,10 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
model_predictions.append({})
except Exception as e:
- st.error(f"❌ Prediction error with model {model_name} for row {idx+1}: {e}")
+ st.error(f"❌ Ошибка предсказания моделью {model_name} для строки {idx+1}: {e}")
model_predictions.append({})
- # Save predictions
+ # Сохраняем предсказания
all_predictions[model_name] = model_predictions
model_results[model_name] = {
'successful': successful_predictions,
@@ -951,12 +951,12 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
'artifacts': model_artifacts
}
- # Add predictions to result
+ # Добавляем предсказания в результат
target_columns = model_artifacts["metadata"].get('target_columns', [])
for target in target_columns:
result_df[f'{model_name}_{target}'] = [pred.get(target, None) for pred in model_predictions]
- # Calculate metrics if ground truth exists
+ # Вычисляем метрики если есть ground truth
model_metrics = {}
if has_ground_truth:
for target in target_columns:
@@ -973,44 +973,44 @@ def process_batch_file_multiple_models(uploaded_file, selected_models, skiprows=
all_metrics[model_name] = model_metrics
- st.success(f"✅ Model {model_name}: {successful_predictions}/{len(df)} successful predictions")
+ st.success(f"✅ Модель {model_name}: {successful_predictions}/{len(df)} успешных предсказаний")
except Exception as e:
- st.error(f"❌ Error processing with model {model_name}: {e}")
+ st.error(f"❌ Ошибка обработки моделью {model_name}: {e}")
continue
progress_bar.progress(1.0)
- status_text.text("✅ All models processed!")
+ status_text.text("✅ Все модели обработаны!")
return result_df, all_predictions, model_results, all_metrics
except Exception as e:
- st.error(f"❌ Critical file processing error: {e}")
+ st.error(f"❌ Критическая ошибка обработки файла: {e}")
st.markdown('', unsafe_allow_html=True)
- st.error("**Error details:**")
+ st.error("**Детали ошибки:**")
st.code(traceback.format_exc())
st.markdown('
', unsafe_allow_html=True)
return None, {}, {}, {}
def create_comparison_visualizations(result_df, selected_models, target_columns, all_metrics):
- """Creates visualizations for model comparison"""
+ """Создает визуализации для сравнения моделей"""
try:
- st.markdown("### 📊 Visual Model Comparison")
+ st.markdown("### 📊 Визуальное сравнение моделей")
- # Create tabs for different visualization types
+ # Создаем вкладки для разных типов визуализаций
viz_tab1, viz_tab2, viz_tab3, viz_tab4 = st.tabs([
- "📈 Target Variable Comparison",
- "📋 Summary Statistics",
- "🔍 Detailed Analysis",
- "📉 Quality Metrics"
+ "📈 Сравнение по целевым переменным",
+ "📋 Сводная статистика",
+ "🔍 Детальный анализ",
+ "📉 Метрики качества"
])
with viz_tab1:
- # Graphs for each target variable
+ # Графики для каждой целевой переменной
for target in target_columns:
st.markdown(f"#### {TARGET_DESCRIPTIONS[target]['name']}")
- # Collect data for graph
+ # Собираем данные для графика
plot_data = []
for model in selected_models:
col_name = f'{model}_{target}'
@@ -1025,10 +1025,10 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
})
if len(plot_data) > 0:
- # Create subplot for different graph types
+ # Создаем subplot для разных типов графиков
fig = make_subplots(
rows=1, cols=2,
- subplot_titles=('Prediction Distribution', 'Mean Value Comparison'),
+ subplot_titles=('Распределение предсказаний', 'Сравнение средних значений'),
specs=[[{"type": "box"}, {"type": "bar"}]]
)
@@ -1044,7 +1044,7 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
row=1, col=1
)
- # Bar plot with mean values
+ # Bar plot со средними значениями
models = [data['model'] for data in plot_data]
means = [data['mean'] for data in plot_data]
stds = [data['std'] for data in plot_data]
@@ -1062,17 +1062,17 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
fig.update_layout(
height=400,
- title_text=f"Model Comparison: {TARGET_DESCRIPTIONS[target]['name']}",
+ title_text=f"Сравнение моделей: {TARGET_DESCRIPTIONS[target]['name']}",
showlegend=False
)
st.plotly_chart(fig)
else:
- st.info(f"ℹ️ No data to display for target variable {target}")
+ st.info(f"ℹ️ Нет данных для отображения по целевой переменной {target}")
with viz_tab2:
- # Model summary statistics
- st.markdown("#### 📋 Model Summary Statistics")
+ # Сводная статистика по моделям
+ st.markdown("#### 📋 Сводная статистика по моделям")
stats_data = []
for target in target_columns:
@@ -1082,73 +1082,73 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
values = result_df[col_name].dropna()
if len(values) > 0:
stats_data.append({
- 'Model': model,
- 'Target Variable': TARGET_DESCRIPTIONS[target]['name'],
- 'Mean': float(values.mean()),
- 'Standard Deviation': float(values.std()),
- 'Minimum': float(values.min()),
- 'Maximum': float(values.max()),
- 'Prediction Count': int(len(values))
+ 'Модель': model,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target]['name'],
+ 'Среднее': float(values.mean()),
+ 'Стандартное отклонение': float(values.std()),
+ 'Минимум': float(values.min()),
+ 'Максимум': float(values.max()),
+ 'Количество предсказаний': int(len(values))
})
if stats_data:
stats_df = pd.DataFrame(stats_data)
- # Format numeric columns
+ # Форматируем числовые колонки
formatted_stats = stats_df.copy()
- numeric_columns = ['Mean', 'Standard Deviation', 'Minimum', 'Maximum']
+ numeric_columns = ['Среднее', 'Стандартное отклонение', 'Минимум', 'Максимум']
for col in numeric_columns:
if col in formatted_stats.columns:
- if col == 'Standard Deviation':
+ if col == 'Стандартное отклонение':
formatted_stats[col] = formatted_stats[col].apply(lambda x: f"{x:.4f}")
else:
formatted_stats[col] = formatted_stats[col].apply(lambda x: f"{x:.2f}")
st.dataframe(formatted_stats)
- # Pivot table for easy comparison
+ # Pivot таблица для удобного сравнения
try:
pivot_mean = stats_df.pivot_table(
- index='Model',
- columns='Target Variable',
- values='Mean',
+ index='Модель',
+ columns='Целевая переменная',
+ values='Среднее',
aggfunc='first'
)
- # Format pivot table
+ # Форматируем pivot таблицу
formatted_pivot = pivot_mean.copy()
for col in formatted_pivot.columns:
formatted_pivot[col] = formatted_pivot[col].apply(lambda x: f"{float(x):.2f}" if pd.notna(x) else "N/A")
- st.markdown("#### 📊 Mean Value Comparison")
+ st.markdown("#### 📊 Сравнение средних значений")
st.dataframe(formatted_pivot)
except Exception as e:
- st.warning(f"Failed to create pivot table: {e}")
+ st.warning(f"Не удалось создать сводную таблицу: {e}")
else:
- st.info("ℹ️ No data for statistical analysis")
+ st.info("ℹ️ Нет данных для статистического анализа")
with viz_tab3:
- # Detailed analysis - FIXED VERSION
- st.markdown("#### 🔍 Detailed Prediction Analysis")
+ # Детальный анализ - ИСПРАВЛЕННАЯ ВЕРСИЯ
+ st.markdown("#### 🔍 Детальный анализ предсказаний")
- # Check that result_df is not empty and has data for analysis
+ # Проверяем, что result_df не пустой и есть данные для анализа
if len(result_df) == 0:
- st.info("ℹ️ No data for detailed analysis")
+ st.info("ℹ️ Нет данных для детального анализа")
return
try:
- # Create safe descriptions for dropdown
+ # Создаем безопасные описания для выпадающего списка
options = []
for i in range(len(result_df)):
try:
- # Safe data extraction with column presence check
- sample = "Unknown"
+ # Безопасное извлечение данных с проверкой наличия колонок
+ sample = "Неизвестно"
time_min = "N/A"
temperature_c = "N/A"
if 'sample' in result_df.columns:
sample_val = result_df.iloc[i]['sample']
- sample = str(sample_val) if pd.notna(sample_val) else "Unknown"
+ sample = str(sample_val) if pd.notna(sample_val) else "Неизвестно"
if 'time_min' in result_df.columns:
time_val = result_df.iloc[i]['time_min']
@@ -1158,23 +1158,23 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
temp_val = result_df.iloc[i]['temperature_c']
temperature_c = f"{float(temp_val):.1f}" if pd.notna(temp_val) else "N/A"
- description = f"Record {i+1}: {sample} - t={time_min}min, T={temperature_c}°C"
+ description = f"Запись {i+1}: {sample} - t={time_min}мин, T={temperature_c}°C"
options.append((i, description))
except Exception as e:
- # If error occurs, create basic description
- options.append((i, f"Record {i+1} (format error)"))
+ # Если произошла ошибка, создаем базовое описание
+ options.append((i, f"Запись {i+1} (ошибка формата)"))
- # Create dropdown
+ # Создаем выпадающий список
selected_row_idx = st.selectbox(
- "Select record for detailed analysis:",
+ "Выберите запись для детального анализа:",
options=[opt[0] for opt in options],
- format_func=lambda x: next((opt[1] for opt in options if opt[0] == x), f"Record {x+1}")
+ format_func=lambda x: next((opt[1] for opt in options if opt[0] == x), f"Запись {x+1}")
)
if selected_row_idx is not None and 0 <= selected_row_idx < len(result_df):
row_data = result_df.iloc[selected_row_idx]
- # Create prediction comparison graph for selected row
+ # Создаем график сравнения предсказаний для выбранной строки
comparison_data = []
for target in target_columns:
for model in selected_models:
@@ -1184,13 +1184,13 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
if pd.notna(value):
try:
comparison_data.append({
- 'Model': model,
- 'Target Variable': TARGET_DESCRIPTIONS[target]['name'],
- 'Value': float(value),
- 'Color': AVAILABLE_MODELS[model]['color']
+ 'Модель': model,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target]['name'],
+ 'Значение': float(value),
+ 'Цвет': AVAILABLE_MODELS[model]['color']
})
except (TypeError, ValueError) as e:
- st.warning(f"Failed to convert value for {model}_{target}: {value}")
+ st.warning(f"Не удалось преобразовать значение для {model}_{target}: {value}")
continue
if comparison_data:
@@ -1198,27 +1198,27 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
fig = px.bar(
comp_df,
- x='Target Variable',
- y='Value',
- color='Model',
+ x='Целевая переменная',
+ y='Значение',
+ color='Модель',
barmode='group',
- title=f"Prediction Comparison for Record {selected_row_idx+1}",
+ title=f"Сравнение предсказаний для записи {selected_row_idx+1}",
color_discrete_map={model: AVAILABLE_MODELS[model]['color'] for model in selected_models}
)
st.plotly_chart(fig)
else:
- st.info("ℹ️ No prediction data for selected record")
+ st.info("ℹ️ Нет данных предсказаний для выбранной записи")
- # Show detailed values in table
- st.markdown("#### 📋 Numerical Prediction Values")
+ # Показываем детальные значения в таблице
+ st.markdown("#### 📋 Численные значения предсказаний")
detail_data = []
for target in target_columns:
try:
- row_detail = {'Target Variable': TARGET_DESCRIPTIONS[target]['name']}
+ row_detail = {'Целевая переменная': TARGET_DESCRIPTIONS[target]['name']}
- # Add each model's predictions
+ # Добавляем предсказания каждой модели
for model in selected_models:
col_name = f'{model}_{target}'
if col_name in result_df.columns:
@@ -1227,69 +1227,69 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
try:
row_detail[model] = f"{float(value):.2f}"
except (TypeError, ValueError):
- row_detail[model] = 'Error'
+ row_detail[model] = 'Ошибка'
else:
row_detail[model] = 'N/A'
- # Add original value if present
+ # Добавляем оригинальное значение если есть
orig_col = f'original_{target}'
if orig_col in result_df.columns and pd.notna(row_data[orig_col]):
try:
- row_detail['Original Value'] = f"{float(row_data[orig_col]):.2f}"
+ row_detail['Оригинальное значение'] = f"{float(row_data[orig_col]):.2f}"
except (TypeError, ValueError):
- row_detail['Original Value'] = 'Error'
+ row_detail['Оригинальное значение'] = 'Ошибка'
detail_data.append(row_detail)
except Exception as e:
- st.warning(f"Error processing target variable {target}: {e}")
+ st.warning(f"Ошибка обработки целевой переменной {target}: {e}")
continue
if detail_data:
detail_df = pd.DataFrame(detail_data)
st.dataframe(detail_df)
else:
- st.info("ℹ️ No detailed data to display")
+ st.info("ℹ️ Нет детальных данных для отображения")
else:
- st.error("❌ Invalid record selected for analysis")
+ st.error("❌ Выбрана некорректная запись для анализа")
except Exception as e:
- st.error(f"❌ Error in detailed analysis: {str(e)}")
+ st.error(f"❌ Ошибка в детальном анализе: {str(e)}")
st.markdown('', unsafe_allow_html=True)
- st.error("**Error details:**")
+ st.error("**Детали ошибки:**")
st.code(traceback.format_exc())
st.markdown('
', unsafe_allow_html=True)
with viz_tab4:
- # Quality metrics tab
- st.markdown("#### 📉 Model Quality Metrics")
+ # Вкладка с метриками качества
+ st.markdown("#### 📉 Метрики качества моделей")
if not all_metrics or not any(all_metrics.values()):
st.info("""
- ℹ️ **Original values (ground truth) in uploaded file required for metric calculation**
+ ℹ️ **Для вычисления метрик необходимы оригинальные значения (ground truth) в загруженном файле**
- Ensure your file contains columns with actual values:
- - `pectin_yield` (PV, %)
- - `galacturonic_acid` (GK, %)
- - `molecular_weight` (Mw, D)
- - `esterification_degree` (SE, %)
+ Убедитесь, что ваш файл содержит колонки с настоящими значениями:
+ - `pectin_yield` (ПВ, %)
+ - `galacturonic_acid` (ГК, %)
+ - `molecular_weight` (Mw, Д)
+ - `esterification_degree` (СЭ, %)
""")
return
- # Create metrics table for each model and target variable
+ # Создаем таблицу с метриками для каждой модели и целевой переменной
metrics_data = []
for model_name, model_metrics in all_metrics.items():
for target_name, metrics in model_metrics.items():
for metric_name, metric_value in metrics.items():
if metric_name in ['mae', 'mse', 'rmse', 'r2', 'mape', 'correlation']:
try:
- # Convert value to float for safe formatting
+ # Преобразуем значение в float для безопасного форматирования
float_value = float(metric_value) if metric_value is not None else float('nan')
metrics_data.append({
- 'Model': model_name,
- 'Target Variable': TARGET_DESCRIPTIONS[target_name]['name'],
- 'Metric': METRIC_DESCRIPTIONS[metric_name]['name'],
- 'Value': float_value,
+ 'Модель': model_name,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target_name]['name'],
+ 'Метрика': METRIC_DESCRIPTIONS[metric_name]['name'],
+ 'Значение': float_value,
'metric_type': metric_name,
'target_type': target_name
})
@@ -1299,121 +1299,285 @@ def create_comparison_visualizations(result_df, selected_models, target_columns,
if metrics_data:
metrics_df = pd.DataFrame(metrics_data)
- # Pivot table for easy comparison
+ # Pivot таблица для удобного сравнения
try:
pivot_metrics = metrics_df.pivot_table(
- index=['Model', 'Target Variable'],
- columns='Metric',
- values='Value',
+ index=['Модель', 'Целевая переменная'],
+ columns='Метрика',
+ values='Значение',
aggfunc='first'
).reset_index()
- # Format numeric columns
+ # Форматируем числовые колонки
formatted_pivot = pivot_metrics.copy()
for col in formatted_pivot.columns:
- if col not in ['Model', 'Target Variable']:
+ if col not in ['Модель', 'Целевая переменная']:
formatted_pivot[col] = formatted_pivot[col].apply(
lambda x: f"{float(x):.4f}" if pd.notna(x) else "N/A"
)
st.dataframe(formatted_pivot)
except Exception as e:
- st.warning(f"Failed to create metrics pivot table: {e}")
+ st.warning(f"Не удалось создать сводную таблицу метрик: {e}")
st.dataframe(metrics_df)
- # Metrics visualization
- st.markdown("#### 📊 Quality Metrics Visualization")
+ # Визуализация метрик
+ st.markdown("#### 📊 Визуализация метрик качества")
- # Select metric for visualization
+ # Выбор метрики для визуализации
available_metrics = [m for m in metrics_df['metric_type'].unique() if m in METRIC_DESCRIPTIONS]
if available_metrics:
selected_metric = st.selectbox(
- "Select metric for visualization:",
+ "Выберите метрику для визуализации:",
options=available_metrics,
format_func=lambda x: METRIC_DESCRIPTIONS.get(x, {}).get('name', x)
)
if selected_metric:
- # Filter data for selected metric
+ # Фильтруем данные для выбранной метрики
metric_data = metrics_df[metrics_df['metric_type'] == selected_metric]
if len(metric_data) > 0:
- # Convert values to float for plotting
+ # Преобразуем значения в float для построения графика
metric_data = metric_data.copy()
- metric_data['Numeric Value'] = metric_data['Value'].apply(
+ metric_data['Числовое значение'] = metric_data['Значение'].apply(
lambda x: float(x) if pd.notna(x) else float('nan')
)
fig = px.bar(
metric_data,
- x='Model',
- y='Numeric Value',
- color='Target Variable',
+ x='Модель',
+ y='Числовое значение',
+ color='Целевая переменная',
barmode='group',
- title=f"{METRIC_DESCRIPTIONS[selected_metric]['name']} by Models",
- labels={'Numeric Value': METRIC_DESCRIPTIONS[selected_metric]['name']}
+ title=f"{METRIC_DESCRIPTIONS[selected_metric]['name']} по моделям",
+ labels={'Числовое значение': METRIC_DESCRIPTIONS[selected_metric]['name']}
)
- # Add ideal value line
+ # Добавляем линию идеального значения
perfect_value = METRIC_DESCRIPTIONS[selected_metric].get('perfect_value', 0)
better_lower = METRIC_DESCRIPTIONS[selected_metric].get('better_lower', True)
if not better_lower:
- # For metrics where higher is better (R², correlation)
+ # Для метрик где лучше большее значение (R², корреляция)
fig.add_hline(
y=perfect_value,
line_dash="dash",
line_color="green",
- annotation_text="Ideal Value"
+ annotation_text="Идеальное значение"
)
st.plotly_chart(fig)
else:
- st.info("ℹ️ No metrics available for visualization")
+ st.info("ℹ️ Нет доступных метрик для визуализации")
else:
- st.info("ℹ️ No metrics data to display")
+ st.info("ℹ️ Нет данных метрик для отображения")
except Exception as e:
- st.error(f"❌ Error creating visualizations: {str(e)}")
+ st.error(f"❌ Ошибка создания визуализаций: {str(e)}")
st.markdown('', unsafe_allow_html=True)
- st.error("**Error details:**")
+ st.error("**Детали ошибки:**")
st.code(traceback.format_exc())
st.markdown('
', unsafe_allow_html=True)
def display_metrics_dashboard(all_metrics, selected_models):
- """Creates metrics quality dashboard"""
+ """Создает дашборд с метриками качества"""
try:
- st.markdown("### 📊 Quality Metrics Dashboard")
+ st.markdown("### 📊 Дашборд метрик качества")
if not all_metrics or not any(all_metrics.values()):
st.info("""
- ℹ️ **Original values in uploaded file required for quality metrics display**
+ ℹ️ **Для отображения метрик качества необходимы оригинальные значения в загруженном файле**
- Ensure your file contains columns with actual values:
- - `pectin_yield` (PV, %)
- - `galacturonic_acid` (GK, %)
- - `molecular_weight` (Mw, D)
- - `esterification_degree` (SE, %)
+ Убедитесь, что ваш файл содержит колонки с настоящими значениями:
+ - `pectin_yield` (ПВ, %)
+ - `galacturonic_acid` (ГК, %)
+ - `molecular_weight` (Mw, Д)
+ - `esterification_degree` (СЭ, %)
""")
return
- # Create tabs for different metric views
- metric_tab1, metric_tab2, metric_tab3 = st.tabs(["🎯 Metric Cards", "📈 Comparative Graphs", "📋 Detailed Table"])
+ # Создаем вкладки для разных представлений метрик
+ metric_tab1, metric_tab2, metric_tab3 = st.tabs(["🎯 Карточки метрик", "📈 Сравнительные графики", "📋 Детальная таблица"])
with metric_tab1:
- st.markdown("#### 🎯 Main Quality Metrics")
+ st.markdown("#### 🎯 Основные метрики качества")
- # Show metric cards for each model and target variable
+ # Показываем карточки с метриками для каждой модели и целевой переменной
for model_name in selected_models:
if model_name in all_metrics and all_metrics[model_name]:
- st.markdown(f"##### 🧮 Model: {model_name}")
+ st.markdown(f"##### 🧮 Модель: {model_name}")
model_metrics = all_metrics[model_name]
cols = st.columns(4)
for idx, (target_name, metrics) in enumerate(model_metrics.items()):
with cols[idx % 4]:
- # Show main metrics in cards
+ # Показываем основные метрики в карточках
+ for metric_name in ['r2', 'mae', 'rmse', 'mape']:
+ if metric_name in metrics and metrics[metric_name] is not None:
+ try:
+ value = float(metrics[metric_name])
+ card_html = create_metric_card(
+ metric_name,
+ value,
+ target_name
+ )
+ st.markdown(card_html, unsafe_allow_html=True)
+ except (TypeError, ValueError):
+ continue
+
+ with metric_tab2:
+ st.markdown("#### 📈 Сравнение метрик между моделями")
+
+ # Создаем сравнительные графики для основных метрик
+ comparison_metrics = ['r2', 'mae', 'rmse', 'mape']
+
+ for metric in comparison_metrics:
+ st.markdown(f"##### {METRIC_DESCRIPTIONS[metric]['name']}")
+
+ # Собираем данные для графика
+ plot_data = []
+ for model_name in selected_models:
+ if model_name in all_metrics:
+ for target_name, metrics in all_metrics[model_name].items():
+ if metric in metrics and metrics[metric] is not None:
+ try:
+ value = float(metrics[metric])
+ plot_data.append({
+ 'Модель': model_name,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target_name]['name'],
+ 'Значение': value,
+ 'Метрика': METRIC_DESCRIPTIONS[metric]['name']
+ })
+ except (TypeError, ValueError):
+ continue
+
+ if plot_data:
+ plot_df = pd.DataFrame(plot_data)
+
+ fig = px.bar(
+ plot_df,
+ x='Модель',
+ y='Значение',
+ color='Целевая переменная',
+ barmode='group',
+ title=f"Сравнение {METRIC_DESCRIPTIONS[metric]['name']}",
+ labels={'Значение': METRIC_DESCRIPTIONS[metric]['name']}
+ )
+
+ # Добавляем линию идеального значения если применимо
+ perfect_value = METRIC_DESCRIPTIONS[metric].get('perfect_value', 0)
+ if METRIC_DESCRIPTIONS[metric].get('better_lower', True):
+ # Для метрик где лучше меньшее значение
+ fig.add_hline(y=perfect_value, line_dash="dash", line_color="red")
+ else:
+ # Для метрик где лучше большее значение
+ fig.add_hline(y=perfect_value, line_dash="dash", line_color="green")
+
+ st.plotly_chart(fig, use_container_width=True)
+ else:
+ st.info(f"ℹ️ Нет данных для метрики {METRIC_DESCRIPTIONS[metric]['name']}")
+
+ with metric_tab3:
+ st.markdown("#### 📋 Детальная таблица метрик")
+
+ # Создаем подробную таблицу со всеми метриками
+ detailed_data = []
+ for model_name in selected_models:
+ if model_name in all_metrics:
+ for target_name, metrics in all_metrics[model_name].items():
+ row = {
+ 'Модель': model_name,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target_name]['name'],
+ 'Количество образцов': int(metrics.get('n_samples', 0))
+ }
+
+ # Добавляем все вычисленные метрики
+ for metric_name in ['mae', 'mse', 'rmse', 'r2', 'mape', 'correlation']:
+ if metric_name in metrics and metrics[metric_name] is not None:
+ try:
+ value = float(metrics[metric_name])
+ row[METRIC_DESCRIPTIONS[metric_name]['name']] = value
+ except (TypeError, ValueError):
+ row[METRIC_DESCRIPTIONS[metric_name]['name']] = 'N/A'
+
+ detailed_data.append(row)
+
+ if detailed_data:
+ detailed_df = pd.DataFrame(detailed_data)
+
+ # Форматируем числовые колонки
+ format_dict = {}
+ for metric_name in ['mae', 'mse', 'rmse', 'mape']:
+ display_name = METRIC_DESCRIPTIONS[metric_name]['name']
+ if display_name in detailed_df.columns:
+ # Создаем форматированную версию
+ detailed_df[display_name] = detailed_df[display_name].apply(
+ lambda x: f"{float(x):.4f}" if x != 'N/A' and pd.notna(x) else 'N/A'
+ )
+
+ for metric_name in ['r2', 'correlation']:
+ display_name = METRIC_DESCRIPTIONS[metric_name]['name']
+ if display_name in detailed_df.columns:
+ detailed_df[display_name] = detailed_df[display_name].apply(
+ lambda x: f"{float(x):.3f}" if x != 'N/A' and pd.notna(x) else 'N/A'
+ )
+
+ st.dataframe(detailed_df, width='stretch')
+
+ # Скачивание таблицы метрик
+ csv_metrics = detailed_df.to_csv(index=False, encoding='utf-8-sig')
+ st.download_button(
+ label="📥 Скачать таблицу метрик (CSV)",
+ data=csv_metrics,
+ file_name=f"pectin_metrics_comparison_{pd.Timestamp.now().strftime('%Y%m%d_%H%M')}.csv",
+ mime="text/csv"
+ )
+ else:
+ st.info("ℹ️ Нет данных для создания детальной таблицы метрик")
+
+ except Exception as e:
+ st.error(f"❌ Ошибка создания дашборда метрик: {str(e)}")
+ st.markdown('', unsafe_allow_html=True)
+ st.error("**Детали ошибки:**")
+ st.code(traceback.format_exc())
+ st.markdown('
', unsafe_allow_html=True)
+
+def display_metrics_dashboard(all_metrics, selected_models):
+ """Создает дашборд с метриками качества"""
+ try:
+ st.markdown("### 📊 Дашборд метрик качества")
+
+ if not all_metrics or not any(all_metrics.values()):
+ st.info("""
+ ℹ️ **Для отображения метрик качества необходимы оригинальные значения в загруженном файле**
+
+ Убедитесь, что ваш файл содержит колонки с настоящими значениями:
+ - `pectin_yield` (ПВ, %)
+ - `galacturonic_acid` (ГК, %)
+ - `molecular_weight` (Mw, Д)
+ - `esterification_degree` (СЭ, %)
+ """)
+ return
+
+ # Создаем вкладки для разных представлений метрик
+ metric_tab1, metric_tab2, metric_tab3 = st.tabs(["🎯 Карточки метрик", "📈 Сравнительные графики", "📋 Детальная таблица"])
+
+ with metric_tab1:
+ st.markdown("#### 🎯 Основные метрики качества")
+
+ # Показываем карточки с метриками для каждой модели и целевой переменной
+ for model_name in selected_models:
+ if model_name in all_metrics and all_metrics[model_name]:
+ st.markdown(f"##### 🧮 Модель: {model_name}")
+
+ model_metrics = all_metrics[model_name]
+ cols = st.columns(4)
+
+ for idx, (target_name, metrics) in enumerate(model_metrics.items()):
+ with cols[idx % 4]:
+ # Показываем основные метрики в карточках
for metric_name in ['r2', 'mae', 'rmse', 'mape']:
if metric_name in metrics and not np.isnan(metrics[metric_name]):
card_html = create_metric_card(
@@ -1424,25 +1588,25 @@ def display_metrics_dashboard(all_metrics, selected_models):
st.markdown(card_html, unsafe_allow_html=True)
with metric_tab2:
- st.markdown("#### 📈 Metric Comparison Between Models")
+ st.markdown("#### 📈 Сравнение метрик между моделями")
- # Create comparative graphs for main metrics
+ # Создаем сравнительные графики для основных метрик
comparison_metrics = ['r2', 'mae', 'rmse', 'mape']
for metric in comparison_metrics:
st.markdown(f"##### {METRIC_DESCRIPTIONS[metric]['name']}")
- # Collect data for graph
+ # Собираем данные для графика
plot_data = []
for model_name in selected_models:
if model_name in all_metrics:
for target_name, metrics in all_metrics[model_name].items():
if metric in metrics and not np.isnan(metrics[metric]):
plot_data.append({
- 'Model': model_name,
- 'Target Variable': TARGET_DESCRIPTIONS[target_name]['name'],
- 'Value': metrics[metric],
- 'Metric': METRIC_DESCRIPTIONS[metric]['name']
+ 'Модель': model_name,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target_name]['name'],
+ 'Значение': metrics[metric],
+ 'Метрика': METRIC_DESCRIPTIONS[metric]['name']
})
if plot_data:
@@ -1450,40 +1614,40 @@ def display_metrics_dashboard(all_metrics, selected_models):
fig = px.bar(
plot_df,
- x='Model',
- y='Value',
- color='Target Variable',
+ x='Модель',
+ y='Значение',
+ color='Целевая переменная',
barmode='group',
- title=f"Comparison of {METRIC_DESCRIPTIONS[metric]['name']}",
- labels={'Value': METRIC_DESCRIPTIONS[metric]['name']}
+ title=f"Сравнение {METRIC_DESCRIPTIONS[metric]['name']}",
+ labels={'Значение': METRIC_DESCRIPTIONS[metric]['name']}
)
- # Add ideal value line if applicable
+ # Добавляем линию идеального значения если применимо
perfect_value = METRIC_DESCRIPTIONS[metric].get('perfect_value', 0)
if METRIC_DESCRIPTIONS[metric].get('better_lower', True):
- # For metrics where lower is better
+ # Для метрик где лучше меньшее значение
fig.add_hline(y=perfect_value, line_dash="dash", line_color="red")
else:
- # For metrics where higher is better
+ # Для метрик где лучше большее значение
fig.add_hline(y=perfect_value, line_dash="dash", line_color="green")
st.plotly_chart(fig, use_container_width=True)
with metric_tab3:
- st.markdown("#### 📋 Detailed Metrics Table")
+ st.markdown("#### 📋 Детальная таблица метрик")
- # Create detailed table with all metrics
+ # Создаем подробную таблицу со всеми метриками
detailed_data = []
for model_name in selected_models:
if model_name in all_metrics:
for target_name, metrics in all_metrics[model_name].items():
row = {
- 'Model': model_name,
- 'Target Variable': TARGET_DESCRIPTIONS[target_name]['name'],
- 'Sample Count': metrics.get('n_samples', 0)
+ 'Модель': model_name,
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target_name]['name'],
+ 'Количество образцов': metrics.get('n_samples', 0)
}
- # Add all calculated metrics
+ # Добавляем все вычисленные метрики
for metric_name in ['mae', 'mse', 'rmse', 'r2', 'mape', 'correlation']:
if metric_name in metrics:
row[METRIC_DESCRIPTIONS[metric_name]['name']] = metrics[metric_name]
@@ -1493,7 +1657,7 @@ def display_metrics_dashboard(all_metrics, selected_models):
if detailed_data:
detailed_df = pd.DataFrame(detailed_data)
- # Format numeric columns
+ # Форматируем числовые колонки
format_dict = {}
for metric_name in ['mae', 'mse', 'rmse', 'mape']:
display_name = METRIC_DESCRIPTIONS[metric_name]['name']
@@ -1507,90 +1671,90 @@ def display_metrics_dashboard(all_metrics, selected_models):
st.dataframe(detailed_df.style.format(format_dict), width='stretch')
- # Download metrics table
+ # Скачивание таблицы метрик
csv_metrics = detailed_df.to_csv(index=False, encoding='utf-8-sig')
st.download_button(
- label="📥 Download Metrics Table (CSV)",
+ label="📥 Скачать таблицу метрик (CSV)",
data=csv_metrics,
file_name=f"pectin_metrics_comparison_{pd.Timestamp.now().strftime('%Y%m%d_%H%M')}.csv",
mime="text/csv"
)
except Exception as e:
- st.error(f"❌ Error creating metrics dashboard: {e}")
+ st.error(f"❌ Ошибка создания дашборда метрик: {e}")
# Main app layout
st.markdown('🧪 Pectin Production Predictor
', unsafe_allow_html=True)
# Sidebar
with st.sidebar:
- st.markdown("### ⚙️ Model Settings")
+ st.markdown("### ⚙️ Настройки модели")
selected_model = st.selectbox(
- "Select model:",
+ "Выберите модель:",
options=list(AVAILABLE_MODELS.keys()),
format_func=lambda x: f"{x} - {AVAILABLE_MODELS[x]['description'].split(' - ')[0]}"
)
model_info = AVAILABLE_MODELS[selected_model]
- st.info(f"**Description:** {model_info['description']}")
+ st.info(f"**Описание:** {model_info['description']}")
# Load model
- with st.spinner(f"Loading {selected_model}..."):
+ with st.spinner(f"Загружаем {selected_model}..."):
model_artifacts = load_pectin_model(selected_model)
if model_artifacts["status"] == "success":
- st.success("✅ Model ready to use")
+ st.success("✅ Модель готова к использованию")
# Display model info
metadata = model_artifacts["metadata"]
- st.markdown("### 📊 Model Information")
- st.write(f"**Features:** {len(metadata.get('feature_columns', []))}")
- st.write(f"**Target Variables:** {len(metadata.get('target_columns', []))}")
- st.write(f"**Vocabulary Size:** {len(model_artifacts['label_encoder'].classes_)}")
+ st.markdown("### 📊 Информация о модели")
+ st.write(f"**Признаки:** {len(metadata.get('feature_columns', []))}")
+ st.write(f"**Целевые переменные:** {len(metadata.get('target_columns', []))}")
+ st.write(f"**Размер словаря:** {len(model_artifacts['label_encoder'].classes_)}")
elif model_artifacts["status"] == "demo":
- st.warning("🎭 Working in demo mode")
- st.info("To use real models check:")
- st.info("1. Internet access")
- st.info("2. Hugging Face repository availability")
- st.info("3. Correct REPO_ID in settings")
+ st.warning("🎭 Работаем в демо-режиме")
+ st.info("Для использования реальных моделей проверьте:")
+ st.info("1. Доступ к интернету")
+ st.info("2. Наличие репозитория на Hugging Face")
+ st.info("3. Правильность REPO_ID в настройках")
else:
- st.error("❌ Failed to load model")
- st.markdown("### 🔧 Troubleshooting")
+ st.error("❌ Не удалось загрузить модель")
+ st.markdown("### 🔧 Решение проблем")
st.info("""
- 1. **Check internet connection**
- 2. **Ensure repository exists**: https://huggingface.co/arabovs-ai-lab/PectinProductionModels
- 3. **Use local models** - place files in models/ folder
- 4. **Change REPO_ID** to your repository
+ 1. **Проверьте интернет-соединение**
+ 2. **Убедитесь что репозиторий существует**: https://huggingface.co/arabovs-ai-lab/PectinProductionModels
+ 3. **Используйте локальные модели** - поместите файлы в папку models/
+ 4. **Измените REPO_ID** на ваш репозиторий
""")
- if st.button("🔄 Try Again"):
+ if st.button("🔄 Попробовать снова"):
st.cache_resource.clear()
st.rerun()
# Main content tabs
-tab1, tab2, tab3, tab4 = st.tabs(["🎯 Single Prediction", "📁 Batch Processing", "📊 Model Comparison", "🔄 Multi-Model Processing"])
+tab1, tab2, tab3, tab4 = st.tabs(["🎯 Одиночное предсказание", "📁 Пакетная обработка", "📊 Сравнение моделей", "🔄 Мультимодельная обработка"])
with tab1:
- st.markdown('', unsafe_allow_html=True)
+ st.markdown('', unsafe_allow_html=True)
col1, col2 = st.columns([1, 1])
with col1:
- st.markdown("### 📝 Process Parameters")
+ st.markdown("### 📝 Параметры процесса")
with st.form("single_prediction_form"):
- sample = st.selectbox("Raw Material Type:", options=SAMPLE_TYPES, help="Select type of raw material")
- time_min = st.number_input("Extraction Time (min):", min_value=0.0, max_value=300.0, value=5.0, step=1.0)
- temperature_c = st.number_input("Temperature (°C):", min_value=0.0, max_value=200.0, value=120.0, step=1.0)
- pressure_atm = st.number_input("Pressure (atm):", min_value=0.0, max_value=10.0, value=1.0, step=0.1)
+ sample = st.selectbox("Тип сырья:", options=SAMPLE_TYPES, help="Выберите тип исходного сырья")
+ time_min = st.number_input("Время экстракции (мин):", min_value=0.0, max_value=300.0, value=5.0, step=1.0)
+ temperature_c = st.number_input("Температура (°C):", min_value=0.0, max_value=200.0, value=120.0, step=1.0)
+ pressure_atm = st.number_input("Давление (атм):", min_value=0.0, max_value=10.0, value=1.0, step=0.1)
ph = st.number_input("pH:", min_value=0.0, max_value=14.0, value=2.5, step=0.1)
- submitted = st.form_submit_button("🎯 Make Prediction")
+ submitted = st.form_submit_button("🎯 Выполнить предсказание")
with col2:
- st.markdown("### 📊 Prediction Results")
+ st.markdown("### 📊 Результаты предсказания")
if submitted:
input_data = {
@@ -1601,22 +1765,22 @@ with tab1:
'ph': ph
}
- with st.spinner("🔮 Making prediction..."):
+ with st.spinner("🔮 Выполняем предсказание..."):
prediction = predict_single(input_data, model_artifacts)
if prediction:
st.markdown('', unsafe_allow_html=True)
if model_artifacts.get("status") == "demo":
- st.warning("🎭 Demo mode: using test data")
+ st.warning("🎭 Демо-режим: используются тестовые данные")
else:
- st.success("✅ Prediction successful!")
+ st.success("✅ Предсказание успешно выполнено!")
# Display predictions as metrics
target_descriptions = {
- 'pectin_yield': 'Pectin Yield (%)',
- 'galacturonic_acid': 'GA (%)',
- 'molecular_weight': 'Mol. Weight (Da)',
- 'esterification_degree': 'ED (%)'
+ 'pectin_yield': 'Выход пектина (%)',
+ 'galacturonic_acid': 'ГК (%)',
+ 'molecular_weight': 'Мол. масса (Da)',
+ 'esterification_degree': 'СЭ (%)'
}
cols = st.columns(2)
@@ -1631,118 +1795,118 @@ with tab1:
st.markdown('
', unsafe_allow_html=True)
# Show input parameters
- with st.expander("📋 Input Parameters"):
+ with st.expander("📋 Параметры ввода"):
st.json(input_data)
with tab2:
- st.markdown('', unsafe_allow_html=True)
+ st.markdown('', unsafe_allow_html=True)
st.markdown("""
-
🎯 Supported Formats
+
🎯 Поддерживаемые форматы
- - Excel (.xlsx) - automatic structure detection
- - CSV/TXT - with different separators and encodings
+ - Excel (.xlsx) - автоматическое определение структуры
+ - CSV/TXT - с разными разделителями и кодировками
-
📊 Required Fields
+
📊 Обязательные поля
- - sample (Pectin Sample) - raw material type
- - time_min (t, min) - extraction time
- - temperature_c (T, °C) - temperature
- - pressure_atm (P, atm) - pressure
- - ph (pH) - acidity level
+ - sample (Образец пектина) - тип сырья
+ - time_min (t, мин) - время экстракции
+ - temperature_c (T, °C) - температура
+ - pressure_atm (P, атм) - давление
+ - ph (pH) - уровень кислотности
-
🔧 Processing Features
+
🔧 Особенности обработки
- - Automatic encoding and separator detection
- - Support for Russian numbers with commas (2,08 → 2.08)
- - Flexible row skipping settings
+ - Автоматическое определение кодировки и разделителей
+ - Поддержка русских чисел с запятыми (2,08 → 2.08)
+ - Гибкая настройка пропуска строк
""", unsafe_allow_html=True)
uploaded_file = st.file_uploader(
- "Upload data file",
+ "Загрузите файл с данными",
type=['xlsx', 'csv', 'txt'],
- help="Excel, CSV and text files with experimental data supported"
+ help="Поддерживаются Excel, CSV и текстовые файлы с данными экспериментов"
)
if uploaded_file is not None:
- st.markdown("### ⚙️ Processing Settings")
+ st.markdown("### ⚙️ Настройки обработки")
col_set1, col_set2 = st.columns(2)
with col_set1:
skip_rows = st.number_input(
- "Skip rows at file beginning:",
+ "Пропустить строк в начале файла:",
min_value=0,
max_value=10,
value=0,
- help="Use if file has headers or empty rows at beginning"
+ help="Используйте если в файле есть заголовки или пустые строки в начале"
)
with col_set2:
- file_preview = st.checkbox("Show file preview", value=True)
+ file_preview = st.checkbox("Показать предпросмотр файла", value=True)
- # Button for file structure validation
- if st.button("🔍 Validate File Structure", type="secondary"):
+ # Кнопка для проверки структуры файла
+ if st.button("🔍 Проверить структуру файла", type="secondary"):
is_valid, preview_df = validate_file_structure(uploaded_file, skip_rows)
if is_valid:
- st.success("✅ File ready for processing!")
+ st.success("✅ Файл готов к обработке!")
if file_preview and preview_df is not None:
- st.markdown("### 👀 Data Preview")
+ st.markdown("### 👀 Предпросмотр данных")
st.dataframe(preview_df.head(10), width='stretch')
- if st.button("🚀 Process File", type="primary"):
- with st.spinner("🔄 Processing file..."):
+ if st.button("🚀 Обработать файл", type="primary"):
+ with st.spinner("🔄 Обрабатываем файл..."):
result_df = process_batch_file_single_model(uploaded_file, model_artifacts, selected_model, skip_rows)
if result_df is not None:
- st.success(f"✅ Successfully processed {len(result_df)} records")
+ st.success(f"✅ Успешно обработано {len(result_df)} записей")
if model_artifacts.get("status") == "demo":
- st.warning("🎭 Demo mode: using test data")
+ st.warning("🎭 Демо-режим: используются тестовые данные")
- # Show results
- st.markdown("### 📈 Batch Processing Results")
+ # Показываем результаты
+ st.markdown("### 📈 Результаты пакетной обработки")
- # Create nice DataFrame for display
+ # Создаем красивый DataFrame для отображения
display_columns = ['sample', 'time_min', 'temperature_c', 'pressure_atm', 'ph']
prediction_columns = [col for col in result_df.columns if col.startswith(f'{selected_model}_')]
display_columns.extend(prediction_columns)
- # Select only existing columns
+ # Выбираем только существующие колонки
existing_columns = [col for col in display_columns if col in result_df.columns]
display_df = result_df[existing_columns]
st.dataframe(display_df, width='stretch')
- # Download results
+ # Скачивание результатов
csv = result_df.to_csv(index=False, encoding='utf-8-sig')
st.download_button(
- label="📥 Download Full Results (CSV)",
+ label="📥 Скачать полные результаты (CSV)",
data=csv,
file_name=f"pectin_predictions_{selected_model}_{pd.Timestamp.now().strftime('%Y%m%d_%H%M')}.csv",
mime="text/csv",
- help="Download all data with predictions in CSV format"
+ help="Скачать все данные с предсказаниями в CSV формате"
)
- # Show statistics
- st.markdown("### 📊 Prediction Statistics")
+ # Показываем статистику
+ st.markdown("### 📊 Статистика предсказаний")
if prediction_columns:
stats_data = []
for col in prediction_columns:
pred_values = result_df[col].dropna()
if len(pred_values) > 0:
stats_data.append({
- 'Parameter': col.replace(f'{selected_model}_', ''),
- 'Mean': pred_values.mean(),
- 'Standard Deviation': pred_values.std(),
- 'Minimum': pred_values.min(),
- 'Maximum': pred_values.max(),
- 'Successful Predictions': len(pred_values)
+ 'Параметр': col.replace(f'{selected_model}_', ''),
+ 'Среднее': pred_values.mean(),
+ 'Стандартное отклонение': pred_values.std(),
+ 'Минимум': pred_values.min(),
+ 'Максимум': pred_values.max(),
+ 'Успешных предсказаний': len(pred_values)
})
if stats_data:
@@ -1750,31 +1914,31 @@ with tab2:
st.dataframe(stats_df, width='stretch')
with tab3:
- st.markdown('', unsafe_allow_html=True)
+ st.markdown('', unsafe_allow_html=True)
- st.info("Compare predictions of different models on the same data")
+ st.info("Сравните предсказания разных моделей на одних и тех же данных")
col1, col2 = st.columns([1, 1])
with col1:
- st.markdown("### 📝 Test Parameters")
- compare_sample = st.selectbox("Raw Material Type for Comparison:", options=SAMPLE_TYPES, key="compare_sample")
- compare_time = st.slider("Extraction Time (min):", 0.0, 300.0, 5.0, key="compare_time")
- compare_temp = st.slider("Temperature (°C):", 0.0, 200.0, 120.0, key="compare_temp")
- compare_pressure = st.slider("Pressure (atm):", 0.0, 10.0, 1.0, key="compare_pressure")
+ st.markdown("### 📝 Тестовые параметры")
+ compare_sample = st.selectbox("Тип сырья для сравнения:", options=SAMPLE_TYPES, key="compare_sample")
+ compare_time = st.slider("Время экстракции (мин):", 0.0, 300.0, 5.0, key="compare_time")
+ compare_temp = st.slider("Температура (°C):", 0.0, 200.0, 120.0, key="compare_temp")
+ compare_pressure = st.slider("Давление (атм):", 0.0, 10.0, 1.0, key="compare_pressure")
compare_ph = st.slider("pH:", 0.0, 14.0, 2.5, key="compare_ph")
with col2:
- st.markdown("### 🎯 Model Selection")
+ st.markdown("### 🎯 Выбор моделей")
models_to_compare = st.multiselect(
- "Select models for comparison:",
+ "Выберите моделей для сравнения:",
options=list(AVAILABLE_MODELS.keys()),
default=["best_model", "gradient_boosting", "random_forest"]
)
- if st.button("🔍 Compare Models", type="primary"):
+ if st.button("🔍 Сравнить модели", type="primary"):
if not models_to_compare:
- st.warning("⚠️ Select at least one model for comparison")
+ st.warning("⚠️ Выберите хотя бы одну модель для сравнения")
else:
input_data = {
'sample': compare_sample,
@@ -1786,9 +1950,9 @@ with tab3:
comparison_results = []
- with st.spinner("🔍 Comparing models..."):
+ with st.spinner("🔍 Выполняем сравнение моделей..."):
for model_name in models_to_compare:
- with st.spinner(f"Loading {model_name}..."):
+ with st.spinner(f"Загружаем {model_name}..."):
model_artifacts_compare = load_pectin_model(model_name)
if model_artifacts_compare["status"] in ["success", "demo"]:
@@ -1800,19 +1964,19 @@ with tab3:
})
if comparison_results:
- st.success("✅ Comparison completed!")
+ st.success("✅ Сравнение завершено!")
if any("demo" in str(r) for r in comparison_results):
- st.warning("🎭 Some models working in demo mode")
+ st.warning("🎭 Некоторые модели работают в демо-режиме")
# Create comparison dataframe
compare_df = pd.DataFrame(comparison_results)
# Display comparison table
- st.markdown("### 📋 Prediction Comparison")
+ st.markdown("### 📋 Сравнение предсказаний")
st.dataframe(compare_df.set_index('model'), width='stretch')
# Visualization
- st.markdown("### 📊 Visual Comparison")
+ st.markdown("### 📊 Визуальное сравнение")
# Melt dataframe for plotting
plot_df = compare_df.melt(id_vars=['model'], var_name='parameter', value_name='value')
@@ -1824,176 +1988,176 @@ with tab3:
y='value',
color='parameter',
barmode='group',
- title="Prediction Comparison by Models",
- labels={'value': 'Value', 'model': 'Model', 'parameter': 'Parameter'}
+ title="Сравнение предсказаний по моделям",
+ labels={'value': 'Значение', 'model': 'Модель', 'parameter': 'Параметр'}
)
st.plotly_chart(fig, use_container_width=True)
# Show input parameters
- with st.expander("📋 Comparison Parameters"):
+ with st.expander("📋 Параметры сравнения"):
st.json(input_data)
with tab4:
- st.markdown('', unsafe_allow_html=True)
+ st.markdown('', unsafe_allow_html=True)
st.markdown("""
-
🎯 Multi-Model Processing Capabilities
+
🎯 Возможности мультимодельной обработки
- - Apply multiple models to one data file
- - Compare results of different algorithms
- - Visual analysis of prediction distributions
- - Statistical comparison of model performance
- - Quality metrics if actual values available
+ - Применение нескольких моделей к одному файлу данных
+ - Сравнение результатов разных алгоритмов
+ - Визуальный анализ распределений предсказаний
+ - Статистическое сравнение производительности моделей
+ - Метрики качества если есть настоящие значения
-
📊 Output Data
+
📊 Выходные данные
- - Combined table with predictions from all models
- - Comparison graphs by target variables
- - Statistical summaries for each model
- - Detailed analysis of individual records
- - Quality metrics for accuracy assessment
+ - Объединенная таблица с предсказаниями всех моделей
+ - Графики сравнения по целевым переменным
+ - Статистические сводки по каждой модели
+ - Детальный анализ отдельных записей
+ - Метрики качества для оценки точности
""", unsafe_allow_html=True)
- # Model selection for multi-model processing
- st.markdown("### 🎯 Model Selection for Processing")
+ # Выбор моделей для мультимодельной обработки
+ st.markdown("### 🎯 Выбор моделей для обработки")
multi_models = st.multiselect(
- "Select models to apply:",
+ "Выберите модели для применения:",
options=list(AVAILABLE_MODELS.keys()),
default=["best_model", "gradient_boosting", "random_forest"],
- help="Select one or more models for file processing"
+ help="Выберите одну или несколько моделей для обработки файла"
)
uploaded_file_multi = st.file_uploader(
- "Upload data file for multi-model processing",
+ "Загрузите файл с данными для мультимодельной обработки",
type=['xlsx', 'csv', 'txt'],
key="multi_uploader"
)
if uploaded_file_multi is not None and multi_models:
- st.markdown("### ⚙️ Processing Settings")
+ st.markdown("### ⚙️ Настройки обработки")
col_set1, col_set2 = st.columns(2)
with col_set1:
skip_rows_multi = st.number_input(
- "Skip rows at file beginning:",
+ "Пропустить строк в начале файла:",
min_value=0,
max_value=10,
value=0,
key="multi_skip",
- help="Use if file has headers or empty rows at beginning"
+ help="Используйте если в файле есть заголовки или пустые строки в начале"
)
with col_set2:
- enable_viz = st.checkbox("Enable advanced visualization", value=True)
- enable_metrics = st.checkbox("Enable metric calculation", value=True)
+ enable_viz = st.checkbox("Включить расширенную визуализацию", value=True)
+ enable_metrics = st.checkbox("Включить расчет метрик", value=True)
- if st.button("🚀 Run Multi-Model Processing", type="primary"):
+ if st.button("🚀 Запустить мультимодельную обработку", type="primary"):
if not multi_models:
- st.warning("⚠️ Select at least one model for processing")
+ st.warning("⚠️ Выберите хотя бы одну модель для обработки")
else:
- with st.spinner("🔄 Processing file with multiple models..."):
+ with st.spinner("🔄 Обрабатываем файл несколькими моделями..."):
result_df, all_predictions, model_results, all_metrics = process_batch_file_multiple_models(
uploaded_file_multi, multi_models, skip_rows_multi
)
if result_df is not None:
- st.success(f"✅ Multi-model processing completed! Processed {len(result_df)} records")
+ st.success(f"✅ Мультимодельная обработка завершена! Обработано {len(result_df)} записей")
- # Show model summary
- st.markdown("### 📊 Model Summary")
+ # Показываем сводку по моделям
+ st.markdown("### 📊 Сводка по моделям")
summary_data = []
for model_name in multi_models:
if model_name in model_results:
summary_data.append({
- 'Model': model_name,
- 'Successful Predictions': model_results[model_name]['successful'],
- 'Total Records': model_results[model_name]['total'],
- 'Success Rate': f"{(model_results[model_name]['successful'] / model_results[model_name]['total'] * 100):.1f}%",
- 'Mode': 'Demo' if model_results[model_name]['artifacts'].get('status') == 'demo' else 'Real'
+ 'Модель': model_name,
+ 'Успешных предсказаний': model_results[model_name]['successful'],
+ 'Всего записей': model_results[model_name]['total'],
+ 'Процент успеха': f"{(model_results[model_name]['successful'] / model_results[model_name]['total'] * 100):.1f}%",
+ 'Режим': 'Демо' if model_results[model_name]['artifacts'].get('status') == 'demo' else 'Реальный'
})
if summary_data:
summary_df = pd.DataFrame(summary_data)
st.dataframe(summary_df, width='stretch')
- # Show results
- st.markdown("### 📈 Processing Results")
+ # Показываем результаты
+ st.markdown("### 📈 Результаты обработки")
- # Create simplified DataFrame for display
+ # Создаем упрощенный DataFrame для отображения
display_columns = ['sample', 'time_min', 'temperature_c', 'pressure_atm', 'ph']
- # Add one prediction from each model for compactness
+ # Добавляем по одному предсказанию от каждой модели для компактности
for model_name in multi_models:
if f'{model_name}_pectin_yield' in result_df.columns:
display_columns.append(f'{model_name}_pectin_yield')
- display_df = result_df[display_columns].head(10) # Show only first 10 rows
+ display_df = result_df[display_columns].head(10) # Показываем только первые 10 строк
st.dataframe(display_df, width='stretch')
- # Download full results
+ # Скачивание полных результатов
csv = result_df.to_csv(index=False, encoding='utf-8-sig')
st.download_button(
- label="📥 Download Full Results (CSV)",
+ label="📥 Скачать полные результаты (CSV)",
data=csv,
file_name=f"pectin_predictions_multimodel_{pd.Timestamp.now().strftime('%Y%m%d_%H%M')}.csv",
mime="text/csv",
- help="Download all data with predictions from all models in CSV format"
+ help="Скачать все данные с предсказаниями всех моделей в CSV формате"
)
- # Display quality metrics if enabled and ground truth exists
+ # Отображаем метрики качества если включено и есть ground truth
if enable_metrics:
display_metrics_dashboard(all_metrics, multi_models)
- # Model comparison visualization
+ # Визуализация сравнения моделей
if enable_viz and len(multi_models) > 1:
target_columns = ['pectin_yield', 'galacturonic_acid', 'molecular_weight', 'esterification_degree']
create_comparison_visualizations(result_df, multi_models, target_columns, all_metrics)
- # Detailed divergence analysis
+ # Детальный анализ расхождений
if len(multi_models) > 1:
- st.markdown("### 🔍 Model Divergence Analysis")
+ st.markdown("### 🔍 Анализ расхождений между моделями")
- # Calculate standard deviations for each record across all models
+ # Вычисляем стандартные отклонения для каждой записи по всем моделям
divergence_data = []
for target in target_columns:
model_cols = [f'{model}_{target}' for model in multi_models if f'{model}_{target}' in result_df.columns]
if len(model_cols) > 1:
- # Calculate standard deviation by rows
+ # Вычисляем стандартное отклонение по строкам
result_df[f'std_{target}'] = result_df[model_cols].std(axis=1)
- # Find records with largest divergences
+ # Находим записи с наибольшими расхождениями
max_std_idx = result_df[f'std_{target}'].idxmax()
max_std = result_df.loc[max_std_idx, f'std_{target}']
if not pd.isna(max_std) and max_std > 0:
divergence_data.append({
- 'Target Variable': TARGET_DESCRIPTIONS[target]['name'],
- 'Maximum std': max_std,
- 'Record': max_std_idx + 1,
- 'Parameters': f"{result_df.loc[max_std_idx, 'sample']}, t={result_df.loc[max_std_idx, 'time_min']}min"
+ 'Целевая переменная': TARGET_DESCRIPTIONS[target]['name'],
+ 'Максимальное std': max_std,
+ 'Запись': max_std_idx + 1,
+ 'Параметры': f"{result_df.loc[max_std_idx, 'sample']}, t={result_df.loc[max_std_idx, 'time_min']}мин"
})
if divergence_data:
- st.info("📊 Records with largest model divergences:")
+ st.info("📊 Записи с наибольшими расхождениями между моделями:")
divergence_df = pd.DataFrame(divergence_data)
st.dataframe(divergence_df, width='stretch')
else:
- st.info("ℹ️ No significant model divergences detected")
+ st.info("ℹ️ Значительных расхождений между моделями не обнаружено")
# Footer
st.markdown("---")
st.markdown(
"""
-
🧪 Pectin Production Predictor | Machine learning models for pectin production parameter prediction
-
📚 Model repository: Hugging Face Hub
+
🧪 Pectin Production Predictor | Модели машинного обучения для прогнозирования параметров производства пектина
+
📚 Репозиторий моделей: Hugging Face Hub
""",
unsafe_allow_html=True