File size: 6,713 Bytes
98a7a72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import logging

# Ленивая загрузка LLM
_generator = None

def load_model():
    """Ленивая загрузка модели"""
    global _generator
    if _generator is None:
        try:
            from transformers import pipeline
            print('Загрузка LLM модели...')
            _generator = pipeline('text2text-generation', model='cointegrated/rut5-base-multitask')
            print('LLM модель загружена')
        except Exception as e:
            print(f'Ошибка загрузки LLM: {e}')
            _generator = None
    return _generator

def answer(question, context, system_prompt=None):
    """Генерирует ответ с помощью LLM"""
    generator = load_model()
    
    if not generator or not context:
        return fallback_answer(context)
    
    try:
        # Формируем контекст
        context_text = 'Доступные курсы:\n'
        for i, course in enumerate(context[:6], 1):
            context_text += f'{i}. {course["name"]} ({course["semester"]} семестр, {course["credits"]} кредитов)\n'
            context_text += f'   Описание: {course["short_desc"]}\n'
            context_text += f'   Теги: {", ".join(course["tags"])}\n\n'
        
        # Системные инструкции
        if system_prompt is None:
            system_prompt = '''Ты помощник для абитуриентов магистратуры ITMO. Отвечай только по предоставленному контексту.
Если в контексте нет нужной информации — ответь: "в предоставленных данных об этом не сказано."
Отвечай кратко и по делу.
Не выдумывай факты и не давай общих ответов без ссылок на элементы контекста.'''
        
        # Формируем промпт
        prompt = f'''{system_prompt}

{context_text}

Вопрос: {question}'''
        
        # Генерируем ответ
        response = generator(
            prompt,
            max_new_tokens=180,
            temperature=0.3,
            do_sample=True
        )[0]['generated_text']
        
        return response.strip()
        
    except Exception as e:
        print(f'Ошибка генерации LLM: {e}')
        return fallback_answer(context)

def fallback_answer(context):
    """Fallback ответ без LLM"""
    if not context:
        return 'В предоставленных данных об этом не сказано.'
    
    courses = []
    for item in context[:3]:
        courses.append(f'{item["name"]} ({item["semester"]} семестр, {item["credits"]} кредитов)')
    
    return f'Найденные курсы: {", ".join(courses)}.'

def generate_recommendations(courses, profile):
    """Генерирует рекомендации с помощью LLM"""
    generator = load_model()
    
    if not generator or not courses:
        return fallback_recommendations(courses, profile)
    
    try:
        # Формируем контекст курсов
        courses_text = 'Доступные курсы:\n'
        for i, course in enumerate(courses[:7], 1):
            courses_text += f'{i}. {course["name"]} ({course["credits"]} кредитов)\n'
            courses_text += f'   Сложность: {course.get("difficulty", "не указана")}, Теги: {", ".join(course["tags"])}\n'
            courses_text += f'   Описание: {course["short_desc"]}\n\n'
        
        # Профиль студента
        programming_exp = profile.get('programming_experience', 2)
        math_level = profile.get('math_level', 2)
        interests = profile.get('interests', [])
        semester = profile.get('semester', 'не указан')
        
        prompt = f'''Ты эксперт по выбору курсов. Дай персонализированные рекомендации студенту.

Профиль студента:
- Опыт программирования: {programming_exp}/5
- Уровень математики: {math_level}/4  
- Интересы: {", ".join(interests)}
- Целевой семестр: {semester}

{courses_text}

Дай 5-7 лучших рекомендаций с объяснением почему они подходят. Учитывай уровень сложности и интересы. Отвечай кратко, по делу.'''
        
        response = generator(
            prompt,
            max_new_tokens=300,
            temperature=0.4,
            do_sample=True
        )[0]['generated_text']
        
        return response.strip()
        
    except Exception as e:
        print(f'Ошибка генерации рекомендаций: {e}')
        return fallback_recommendations(courses, profile)

def fallback_recommendations(courses, profile):
    """Fallback рекомендации без LLM"""
    if not courses:
        semester = profile.get('semester', 'не указан')
        return f'Нет курсов для {semester} семестра.'
    
    programming_exp = profile.get('programming_experience', 2)
    math_level = profile.get('math_level', 2)
    interests = profile.get('interests', [])
    semester = profile.get('semester', 'не указан')
    
    result = f'🎯 Рекомендации для {semester} семестра:\n\n'
    
    for i, course in enumerate(courses[:7], 1):
        result += f'{i}. {course["name"]} ({course["credits"]} кредитов)\n'
        
        # Объяснение почему подходит
        reasons = []
        matching_tags = [tag for tag in interests if tag in course.get('tags', [])]
        if matching_tags:
            reasons.append(f'подходит по интересам: {", ".join(matching_tags)}')
        
        if programming_exp <= 2 and 'python' in course.get('tags', []):
            reasons.append('подходит для начинающих программистов')
        elif programming_exp >= 4 and 'dl' in course.get('tags', []):
            reasons.append('подходит для опытных программистов')
        
        if math_level >= 2 and 'math' in course.get('tags', []):
            reasons.append('требует хорошую математическую подготовку')
        
        if reasons:
            result += f'   Почему подходит: {"; ".join(reasons)}\n'
        
        result += '\n'
    
    return result