# Гайд по интеграции рефакторинга ## 🚀 Быстрый старт После рефакторинга были созданы новые модули в папке `common/`. Ниже показано, как их использовать. ## 📋 Содержание 1. [Константы вместо магических чисел](#константы) 2. [Логирование](#логирование) 3. [Валидация данных](#валидация) 4. [Типизированные структуры](#структуры) 5. [Обработка ошибок](#ошибки) --- ## Константы ### Прежде всего обновите импорты ```python # app/gui_app.py from common import ( UIColors, UIDimensions, Messages, FontConfig, AudioFormats, get_logger ) logger = get_logger(__name__) ``` ### UI размеры ```python # ДО self.setGeometry(100, 100, 1200, 800) # ПОСЛЕ self.setGeometry( 100, 100, UIDimensions.MAIN_WINDOW_WIDTH, UIDimensions.MAIN_WINDOW_HEIGHT ) ``` ### UI цвета ```python # ДО 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}; }} """) ``` ### Текстовые сообщения ```python # ДО 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 ``` ### Диалоги выбора файлов ```python # ДО 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) ```python 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()) ``` ### Использование в модулях ```python # В каждом файле 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) ``` ### Удалите старый код логирования ```python # ДО (удалить) 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__) ``` --- ## Валидация ### Валидация аудиофайлов ```python 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) ``` ### Валидация пациента ```python 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 ) ``` ### Валидация текста ```python 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}") ``` --- ## Структуры данных ### Использование типизированных результатов ```python 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) ``` ### Создание метаданных пациента ```python 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() ``` --- ## Обработка ошибок ### Специфичные исключения ```python 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("Неверная конфигурация") ``` ### Информативные ошибки с контекстом ```python # ДО 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}" ) # Точно известно, что произошло, где и почему ``` --- ## Шаблон для новых модулей При создании нового модуля используйте этот шаблон: ```python """ Описание модуля. 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` - использовать новые структуры --- ## Полезные ссылки в коде ```python # Все константы 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. ) ``` --- ## Итого 1. **Константы** - используйте вместо магических чисел 2. **Логирование** - вызовите `configure_logging()` в main, затем `get_logger()` 3. **Валидация** - используйте `Validator.validate_*()` 4. **Структуры** - создавайте с типизацией вместо dict 5. **Ошибки** - ловите специфичные исключения Это сделает код более читаемым, надёжным и поддерживаемым! 🎉