import json import os import sys from typing import List, Dict from scraper.html_scraper import HTMLScraper from scraper.pdf_parser import PDFParser from scraper.normalize import DataNormalizer from knowledge_base import KnowledgeBase from retriever import Retriever def update_data_async(): try: print('Начинаем обновление данных с сайтов ITMO...') # 1. Скрапинг страниц программ scraper = HTMLScraper() programs = scraper.scrape_programs() scraper.save_programs(programs) if not programs: print('Не удалось получить данные программ, используем тестовые данные') knowledge_base = KnowledgeBase() retriever = Retriever() retriever.build_or_load_index(knowledge_base.courses) return # 2. Скачивание и парсинг PDF pdf_parser = PDFParser() all_courses = [] for program_id, program in programs.items(): print(f'\nОбработка программы: {program["title"]}') if not program.get('pdf_links'): print(f'PDF ссылки не найдены для программы {program_id}') continue for pdf_link in program['pdf_links']: try: filename = pdf_link['filename'] url = pdf_link['url'] print(f'Скачивание PDF: {filename}') local_path = pdf_parser.download_pdf(url, filename) if local_path: print(f'Парсинг PDF: {filename}') courses = pdf_parser.parse_pdf(local_path, program_id) all_courses.extend(courses) print(f'Извлечено курсов из {filename}: {len(courses)}') else: print(f'Не удалось скачать PDF: {filename}') except Exception as e: print(f'Ошибка обработки PDF {pdf_link["filename"]}: {e}') # 3. Нормализация данных if all_courses: print(f'\nНормализация {len(all_courses)} курсов...') normalizer = DataNormalizer() normalized_courses = normalizer.normalize_courses(all_courses) enriched_courses = normalizer.enrich_courses(normalized_courses) # Сохранение курсов save_courses(enriched_courses) # 4. Создание индекса print('Создание индекса...') retriever = Retriever() retriever.build_or_load_index(enriched_courses) # Статистика stats = normalizer.get_statistics(enriched_courses) print(f'Статистика: {stats}') print('Обновление данных завершено успешно!') else: print('Не удалось извлечь курсы из PDF, используем тестовые данные') knowledge_base = KnowledgeBase() retriever = Retriever() retriever.build_or_load_index(knowledge_base.courses) except Exception as e: print(f'Ошибка обновления данных: {e}') print('Используем тестовые данные...') knowledge_base = KnowledgeBase() retriever = Retriever() retriever.build_or_load_index(knowledge_base.courses) def save_courses(courses: List[Dict], output_path: str = 'data/processed/courses.json'): os.makedirs(os.path.dirname(output_path), exist_ok=True) with open(output_path, 'w', encoding='utf-8') as f: json.dump(courses, f, ensure_ascii=False, indent=2) print(f'Курсы сохранены в {output_path}') def check_data_exists() -> bool: programs_path = 'data/processed/programs.json' courses_path = 'data/processed/courses.json' index_path = 'data/index/index.faiss' return all(os.path.exists(path) for path in [programs_path, courses_path, index_path]) def load_existing_data() -> tuple[Dict, List[Dict]]: programs = {} courses = [] try: with open('data/processed/programs.json', 'r', encoding='utf-8') as f: programs = json.load(f) except FileNotFoundError: print('Файл programs.json не найден') try: with open('data/processed/courses.json', 'r', encoding='utf-8') as f: courses = json.load(f) except FileNotFoundError: print('Файл courses.json не найден') return programs, courses def check_for_updates() -> bool: """Проверяет наличие обновлений на сайтах ITMO""" try: scraper = HTMLScraper() programs, _ = load_existing_data() if not programs: return True # Нет данных, нужно обновление updates = scraper.check_updates(programs) return len(updates) > 0 except Exception as e: print(f'Ошибка проверки обновлений: {e}') return False def initialize_data(): if check_data_exists(): print('Данные уже существуют, проверяем обновления...') if check_for_updates(): print('Обнаружены обновления, запускаем обновление данных...') update_data_async() else: print('Обновлений не найдено, загружаем существующие данные...') programs, courses = load_existing_data() if courses: retriever = Retriever() retriever.build_or_load_index(courses) print(f'Загружено {len(courses)} курсов') else: print('Курсы не найдены, запускаем обновление...') update_data_async() else: print('Данные не найдены, запускаем первичное обновление...') update_data_async() def main(): if len(sys.argv) > 1: if sys.argv[1] == '--force': print('Принудительное обновление данных...') update_data_async() elif sys.argv[1] == '--check': print('Проверка обновлений...') if check_for_updates(): print('Обнаружены обновления') else: print('Обновлений не найдено') else: print('Использование: python update_data.py [--force|--check]') else: initialize_data() if __name__ == '__main__': main()