| 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...') |
| |
| |
| 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 |
| |
| |
| 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}') |
| |
| |
| 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) |
| |
| |
| 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() |
|
|