| <!DOCTYPE html>
|
| <html lang="ru">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>ITMO Магистратура - Чат-бот</title>
|
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
| <style>
|
| body {
|
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| min-height: 100vh;
|
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| }
|
| .main-container {
|
| background: rgba(255, 255, 255, 0.95);
|
| border-radius: 20px;
|
| box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
| margin: 20px auto;
|
| max-width: 1200px;
|
| }
|
| .chat-container {
|
| height: 400px;
|
| overflow-y: auto;
|
| border: 1px solid #dee2e6;
|
| border-radius: 10px;
|
| padding: 15px;
|
| background: #f8f9fa;
|
| }
|
| .message {
|
| margin-bottom: 15px;
|
| padding: 10px 15px;
|
| border-radius: 15px;
|
| max-width: 80%;
|
| }
|
| .user-message {
|
| background: #007bff;
|
| color: white;
|
| margin-left: auto;
|
| }
|
| .bot-message {
|
| background: #e9ecef;
|
| color: #333;
|
| }
|
| .loading {
|
| display: none;
|
| text-align: center;
|
| padding: 20px;
|
| }
|
| .spinner-border-sm {
|
| width: 1rem;
|
| height: 1rem;
|
| }
|
| .card {
|
| border: none;
|
| box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
| border-radius: 15px;
|
| }
|
| .btn-primary {
|
| background: linear-gradient(45deg, #667eea, #764ba2);
|
| border: none;
|
| border-radius: 25px;
|
| padding: 10px 25px;
|
| }
|
| .btn-secondary {
|
| background: linear-gradient(45deg, #6c757d, #495057);
|
| border: none;
|
| border-radius: 25px;
|
| padding: 10px 25px;
|
| }
|
| .form-control, .form-select {
|
| border-radius: 10px;
|
| border: 2px solid #e9ecef;
|
| }
|
| .form-control:focus, .form-select:focus {
|
| border-color: #667eea;
|
| box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
| }
|
| </style>
|
| </head>
|
| <body>
|
| <div class="container-fluid">
|
| <div class="main-container p-4">
|
|
|
| <div class="text-center mb-4">
|
| <h1 class="display-4 text-primary">
|
| <i class="fas fa-robot"></i> ITMO Магистратура - Чат-бот
|
| </h1>
|
| <p class="lead text-muted">Задавайте вопросы о программах ИИ и AI Product, получайте персональные рекомендации по курсам</p>
|
| <div class="row justify-content-center">
|
| <div class="col-md-3">
|
| <div class="card text-center">
|
| <div class="card-body">
|
| <i class="fas fa-graduation-cap fa-2x text-primary"></i>
|
| <h5 class="card-title">{{ courses_count }}</h5>
|
| <p class="card-text">Курсов загружено</p>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <div class="row">
|
|
|
| <div class="col-lg-8">
|
| <div class="card">
|
| <div class="card-header bg-primary text-white">
|
| <h5 class="mb-0"><i class="fas fa-comments"></i> Чат с ботом</h5>
|
| </div>
|
| <div class="card-body">
|
| <div class="chat-container" id="chatContainer">
|
| <div class="message bot-message">
|
| <strong>Бот:</strong> Привет! Я помогу тебе узнать больше о магистерских программах ITMO. Задавай вопросы о курсах, программах и получай персональные рекомендации!
|
| </div>
|
| </div>
|
|
|
| <div class="loading" id="loading">
|
| <div class="spinner-border text-primary" role="status">
|
| <span class="visually-hidden">Загрузка...</span>
|
| </div>
|
| <p class="mt-2">Бот думает...</p>
|
| </div>
|
|
|
| <div class="input-group mt-3">
|
| <input type="text" class="form-control" id="messageInput"
|
| placeholder="Спрашивайте о дисциплинах, программах, учебных планах...">
|
| <button class="btn btn-primary" type="button" id="sendBtn">
|
| <i class="fas fa-paper-plane"></i> Отправить
|
| </button>
|
| <button class="btn btn-outline-secondary" type="button" id="clearBtn">
|
| <i class="fas fa-trash"></i> Очистить
|
| </button>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="col-lg-4">
|
| <div class="card">
|
| <div class="card-header bg-success text-white">
|
| <h5 class="mb-0"><i class="fas fa-user-graduate"></i> Профиль для рекомендаций</h5>
|
| </div>
|
| <div class="card-body">
|
| <form id="recommendationsForm">
|
| <div class="mb-3">
|
| <label class="form-label">Опыт программирования (0-5)</label>
|
| <input type="range" class="form-range" id="programmingExp" min="0" max="5" value="2">
|
| <div class="d-flex justify-content-between">
|
| <small>Нет опыта</small>
|
| <small>Эксперт</small>
|
| </div>
|
| </div>
|
|
|
| <div class="mb-3">
|
| <label class="form-label">Уровень математики (0-4)</label>
|
| <input type="range" class="form-range" id="mathLevel" min="0" max="4" value="2">
|
| <div class="d-flex justify-content-between">
|
| <small>Базовый</small>
|
| <small>Продвинутый</small>
|
| </div>
|
| </div>
|
|
|
| <div class="mb-3">
|
| <label class="form-label">Интересы</label>
|
| <div class="row">
|
| <div class="col-6">
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="ml" id="ml" checked>
|
| <label class="form-check-label" for="ml">ML</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="dl" id="dl">
|
| <label class="form-check-label" for="dl">DL</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="nlp" id="nlp">
|
| <label class="form-check-label" for="nlp">NLP</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="cv" id="cv">
|
| <label class="form-check-label" for="cv">CV</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="product" id="product">
|
| <label class="form-check-label" for="product">Product</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="business" id="business">
|
| <label class="form-check-label" for="business">Business</label>
|
| </div>
|
| </div>
|
| <div class="col-6">
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="research" id="research">
|
| <label class="form-check-label" for="research">Research</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="data" id="data">
|
| <label class="form-check-label" for="data">Data</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="systems" id="systems">
|
| <label class="form-check-label" for="systems">Systems</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="python" id="python">
|
| <label class="form-check-label" for="python">Python</label>
|
| </div>
|
| <div class="form-check">
|
| <input class="form-check-input" type="checkbox" value="math" id="math">
|
| <label class="form-check-label" for="math">Math</label>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <div class="mb-3">
|
| <label class="form-label">Целевой семестр</label>
|
| <select class="form-select" id="semester">
|
| <option value="">Выберите семестр</option>
|
| <option value="1">1 семестр</option>
|
| <option value="2">2 семестр</option>
|
| <option value="3">3 семестр</option>
|
| <option value="4">4 семестр</option>
|
| </select>
|
| </div>
|
|
|
| <button type="submit" class="btn btn-success w-100 mb-2">
|
| <i class="fas fa-lightbulb"></i> Получить рекомендации
|
| </button>
|
|
|
| <button type="button" class="btn btn-secondary w-100" id="updateBtn">
|
| <i class="fas fa-sync-alt"></i> Обновить данные
|
| </button>
|
| </form>
|
|
|
| <div class="mt-3">
|
| <textarea class="form-control" id="recommendationsOutput" rows="8"
|
| placeholder="Здесь появятся рекомендации..." readonly></textarea>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
| <script>
|
|
|
| function addMessage(message, isUser = false) {
|
| const chatContainer = document.getElementById('chatContainer');
|
| const messageDiv = document.createElement('div');
|
| messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;
|
| messageDiv.innerHTML = `<strong>${isUser ? 'Вы:' : 'Бот:'}</strong> ${message}`;
|
| chatContainer.appendChild(messageDiv);
|
| chatContainer.scrollTop = chatContainer.scrollHeight;
|
| }
|
|
|
| function showLoading() {
|
| document.getElementById('loading').style.display = 'block';
|
| }
|
|
|
| function hideLoading() {
|
| document.getElementById('loading').style.display = 'none';
|
| }
|
|
|
|
|
| async function sendMessage() {
|
| const input = document.getElementById('messageInput');
|
| const message = input.value.trim();
|
|
|
| if (!message) return;
|
|
|
| addMessage(message, true);
|
| input.value = '';
|
| showLoading();
|
|
|
| try {
|
| const response = await fetch('/api/chat', {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json',
|
| },
|
| body: JSON.stringify({ message: message })
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (response.ok) {
|
| addMessage(data.response);
|
| } else {
|
| addMessage(`Ошибка: ${data.error}`);
|
| }
|
| } catch (error) {
|
| addMessage(`Ошибка соединения: ${error.message}`);
|
| } finally {
|
| hideLoading();
|
| }
|
| }
|
|
|
|
|
| async function getRecommendations() {
|
| const programmingExp = document.getElementById('programmingExp').value;
|
| const mathLevel = document.getElementById('mathLevel').value;
|
| const semester = document.getElementById('semester').value;
|
|
|
| if (!semester) {
|
| alert('Пожалуйста, выберите семестр');
|
| return;
|
| }
|
|
|
| const interests = [];
|
| document.querySelectorAll('input[type="checkbox"]:checked').forEach(cb => {
|
| interests.push(cb.value);
|
| });
|
|
|
| const output = document.getElementById('recommendationsOutput');
|
| output.value = 'Генерируем рекомендации...';
|
|
|
| try {
|
| const response = await fetch('/api/recommendations', {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json',
|
| },
|
| body: JSON.stringify({
|
| programming_exp: parseInt(programmingExp),
|
| math_level: parseInt(mathLevel),
|
| interests: interests,
|
| semester: semester
|
| })
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (response.ok) {
|
| output.value = data.response;
|
| } else {
|
| output.value = `Ошибка: ${data.error}`;
|
| }
|
| } catch (error) {
|
| output.value = `Ошибка соединения: ${error.message}`;
|
| }
|
| }
|
|
|
|
|
| async function updateData() {
|
| const output = document.getElementById('recommendationsOutput');
|
| output.value = 'Обновляем данные...';
|
|
|
| try {
|
| const response = await fetch('/api/update', {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json',
|
| }
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (response.ok) {
|
| output.value = data.message;
|
| location.reload();
|
| } else {
|
| output.value = `Ошибка: ${data.error}`;
|
| }
|
| } catch (error) {
|
| output.value = `Ошибка соединения: ${error.message}`;
|
| }
|
| }
|
|
|
|
|
| function clearChat() {
|
| const chatContainer = document.getElementById('chatContainer');
|
| chatContainer.innerHTML = `
|
| <div class="message bot-message">
|
| <strong>Бот:</strong> Привет! Я помогу тебе узнать больше о магистерских программах ITMO. Задавай вопросы о курсах, программах и получай персональные рекомендации!
|
| </div>
|
| `;
|
| }
|
|
|
|
|
| document.getElementById('sendBtn').addEventListener('click', sendMessage);
|
| document.getElementById('messageInput').addEventListener('keypress', function(e) {
|
| if (e.key === 'Enter') {
|
| sendMessage();
|
| }
|
| });
|
| document.getElementById('clearBtn').addEventListener('click', clearChat);
|
| document.getElementById('recommendationsForm').addEventListener('submit', function(e) {
|
| e.preventDefault();
|
| getRecommendations();
|
| });
|
| document.getElementById('updateBtn').addEventListener('click', updateData);
|
| </script>
|
| </body>
|
| </html>
|
|
|