Гайд по интеграции рефакторинга
🚀 Быстрый старт
После рефакторинга были созданы новые модули в папке common/. Ниже показано, как их использовать.
📋 Содержание
- Константы вместо магических чисел
- Логирование
- Валидация данных
- Типизированные структуры
- Обработка ошибок
Константы
Прежде всего обновите импорты
# app/gui_app.py
from common import (
UIColors,
UIDimensions,
Messages,
FontConfig,
AudioFormats,
get_logger
)
logger = get_logger(__name__)
UI размеры
# ДО
self.setGeometry(100, 100, 1200, 800)
# ПОСЛЕ
self.setGeometry(
100, 100,
UIDimensions.MAIN_WINDOW_WIDTH,
UIDimensions.MAIN_WINDOW_HEIGHT
)
UI цвета
# ДО
self.start_btn.setStyleSheet("""
QPushButton {
background-color: #4CAF50;
color: white;
}
QPushButton:hover {
background-color: #45a049;
}
""")
# ПОСЛЕ
self.start_btn.setStyleSheet(f"""
QPushButton {{
background-color: {UIColors.PRIMARY_GREEN};
color: white;
}}
QPushButton:hover {{
background-color: {UIColors.HOVER_GREEN};
}}
""")
Текстовые сообщения
# ДО
if not self.audio_path:
QMessageBox.warning(
self,
"Ошибка",
"Пожалуйста, выберите аудиофайл!"
)
return
# ПОСЛЕ
if not self.audio_path:
QMessageBox.warning(
self,
Messages.WARNING_TITLE,
Messages.ERROR_NO_AUDIO_FILE
)
return
Диалоги выбора файлов
# ДО
file_path, _ = QFileDialog.getOpenFileName(
self,
"Выберите аудиофайл",
"",
"Audio Files (*.wav *.mp3 *.m4a);;All Files (*)"
)
# ПОСЛЕ
file_path, _ = QFileDialog.getOpenFileName(
self,
"Выберите аудиофайл",
"",
AudioFormats.FILE_DIALOG_FILTER
)
Логирование
Инициализация (в main.py или run_gui.py)
from common import configure_logging, get_logger
if __name__ == "__main__":
# Один раз в начале программы
configure_logging() # Создаст папку logs/ и файл логов
app = QApplication(sys.argv)
window = MedicalTranscriptionApp()
window.show()
sys.exit(app.exec())
Использование в модулях
# В каждом файле
from common import get_logger
logger = get_logger(__name__)
def my_function():
logger.info("Starting operation")
try:
# ...
logger.debug("Processing step 1")
except Exception as e:
logger.error(f"Error occurred: {e}", exc_info=True)
Удалите старый код логирования
# ДО (удалить)
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# ПОСЛЕ (достаточно)
from common import get_logger
logger = get_logger(__name__)
Валидация
Валидация аудиофайлов
from common import Validator, AudioFileException
from pathlib import Path
def start_transcription(self):
try:
# Валидирует файл, проверяет существование, формат и размер
audio_file = Validator.validate_audio_file(self.audio_path)
# audio_file является объектом Path
except AudioFileException as e:
QMessageBox.critical(self, "Ошибка аудиофайла", e.message)
Валидация пациента
from common import Validator, ValidationException
def open_patient_dialog(self):
dialog = PatientDataDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
try:
data = dialog.get_data()
# Валидация каждого поля
patient_name = Validator.validate_patient_name(data["patient_name"])
patient_dob = Validator.validate_date(data["patient_dob"])
self.patient_data = data
except ValidationException as e:
QMessageBox.warning(
self,
f"Ошибка в поле {e.field}",
e.message
)
Валидация текста
from common import Validator, ValidationException
def correct_text(text):
try:
validated_text = Validator.validate_text(text, "transcription")
# Дальше работаем с проверенным текстом
except ValidationException as e:
logger.error(f"Validation error: {e.message}")
Структуры данных
Использование типизированных результатов
from common import PipelineResult, TranscriptionResult, PatientMetadata
from datetime import datetime
from pathlib import Path
def process_pipeline():
# Создание структурированного результата
result = PipelineResult(
timestamp=datetime.now(),
audio_file=Path("audio.wav"),
patient_data=PatientMetadata(
name="Иванов Иван Иванович",
date_of_birth="01.01.1980",
study_area="МРТ головы"
),
transcription=TranscriptionResult(
timestamp=datetime.now(),
audio_file=Path("audio.wav"),
original_text="исходный текст",
corrected_text="исправленный текст",
corrections_count=5
),
status="success"
)
# IDE будет подсказывать все доступные поля!
print(result.status)
print(result.transcription.corrections_count)
print(result.is_successful()) # Вспомогательный метод
# Сериализация в JSON
result_dict = result.to_dict()
json.dump(result_dict, f)
Создание метаданных пациента
from common import PatientMetadata
patient_data = PatientMetadata(
name="Петров Петр Петрович",
date_of_birth="15.03.1975",
study_area="КТ грудной клетки",
study_number="12345",
study_date="16.01.2026",
doctor_name="Сидоров С.С."
)
# Проверка полноты данных
if patient_data.is_complete():
print("Все необходимые данные заполнены")
# Преобразование в словарь
patient_dict = patient_data.to_dict()
Обработка ошибок
Специфичные исключения
from common import (
AudioFileException,
TranscriptionException,
APIException,
ValidationException,
ConfigurationException
)
def pipeline_process():
try:
# ...
pass
except AudioFileException as e:
# Обработка ошибок с аудио файлом
logger.error(f"Audio file error: {e.message}")
show_error_dialog(f"Ошибка аудиофайла: {e.file_path}")
except APIException as e:
# Обработка ошибок API
logger.error(f"API error: {e.message} (code: {e.status_code})")
show_error_dialog(f"Ошибка API: {e.status_code}")
except ValidationException as e:
# Обработка ошибок валидации
logger.warning(f"Validation error in {e.field}: {e.message}")
show_warning_dialog(f"Проверьте поле '{e.field}'")
except ConfigurationException as e:
# Обработка ошибок конфигурации
logger.error(f"Config error: {e}")
show_error_dialog("Неверная конфигурация")
Информативные ошибки с контекстом
# ДО
except Exception as e:
logger.error(f"Error: {e}")
# Непонятно, что произошло
# ПОСЛЕ
except APIException as e:
logger.error(
f"API request failed for {e.endpoint} "
f"with status {e.status_code}: {e.message}"
)
# Точно известно, что произошло, где и почему
Шаблон для новых модулей
При создании нового модуля используйте этот шаблон:
"""
Описание модуля.
Example:
>>> from my_module import MyClass
>>> obj = MyClass()
>>> result = obj.my_method()
"""
from pathlib import Path
from typing import Optional, Dict, Any
from common import get_logger, Validator, ValidationException
logger = get_logger(__name__)
class MyClass:
"""Описание класса."""
def __init__(self, param: str) -> None:
"""
Initialize.
Args:
param: Parameter description
Raises:
ValueError: If param is invalid
"""
self.param = param
logger.info(f"Initialized MyClass with param: {param}")
def my_method(self, data: str) -> Dict[str, Any]:
"""
Do something.
Args:
data: Input data
Returns:
Result dictionary
Raises:
ValidationException: If data is invalid
"""
try:
validated_data = Validator.validate_text(data)
logger.debug(f"Processing {len(validated_data)} characters")
result = {"status": "success", "data": validated_data}
logger.info("Processing completed successfully")
return result
except ValidationException as e:
logger.error(f"Validation failed: {e.message}")
raise
Чек-лист для интеграции
Phase 1: Основные импорты
-
common/exceptions.pyсоздан ✅ -
common/constants.pyсоздан ✅ -
common/logger.pyсоздан ✅ -
common/validators.pyсоздан ✅ -
common/models.pyсоздан ✅ -
common/__init__.pyсоздан ✅
Phase 2: Обновление импортов в app/
-
app/gui_app.py- добавить импорты common -
app/main.py- вызватьconfigure_logging() - Заменить все магические числа на константы
- Заменить все
Exceptionна специфичные типы
Phase 3: Обновление импортов в pipeline/
-
pipeline/medical_pipeline.py- использовать новые структуры -
pipeline/pipeline_config.py- использовать константы
Phase 4: Обновление импортов в corrector/
-
corrector/llm_corrector.py- улучшить типизацию ✅ -
corrector/openrouter_client.py- использовать APISettings ✅ -
corrector/report_generator.py- использовать ReportDefaults
Phase 5: Обновление импортов в stt/
-
stt/whisper_transcriber.py- использовать ModelDefaults -
stt/audio_processor.py- использовать AudioFormats
Phase 6: Обновление импортов в knowledge_base/
-
knowledge_base/term_manager.py- использовать новые структуры
Полезные ссылки в коде
# Все константы
from common import UIColors, UIDimensions, Messages, etc.
# Логирование
from common import get_logger, configure_logging
# Валидация
from common import Validator
# Структуры данных
from common import PatientMetadata, PipelineResult, etc.
# Исключения
from common import (
AudioFileException,
ValidationException,
APIException,
etc.
)
Итого
- Константы - используйте вместо магических чисел
- Логирование - вызовите
configure_logging()в main, затемget_logger() - Валидация - используйте
Validator.validate_*() - Структуры - создавайте с типизацией вместо dict
- Ошибки - ловите специфичные исключения
Это сделает код более читаемым, надёжным и поддерживаемым! 🎉