alem-chto-ty-umeesh-2/index.html

385 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Агент по охране труда</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 50%, #0f172a 100%);
min-height: 100vh;
color: #e2e8f0;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 40px 20px;
}
header {
text-align: center;
margin-bottom: 40px;
}
.logo {
font-size: 64px;
margin-bottom: 16px;
}
h1 {
font-size: clamp(28px, 5vw, 42px);
font-weight: 700;
color: #ffffff;
margin-bottom: 12px;
}
.subtitle {
font-size: 18px;
color: #94a3b8;
max-width: 600px;
margin: 0 auto;
}
.card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 32px;
margin-bottom: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}
.input-section {
margin-bottom: 24px;
}
label {
display: block;
font-size: 14px;
font-weight: 600;
color: #cbd5e1;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
textarea {
width: 100%;
min-height: 140px;
padding: 16px;
font-size: 16px;
font-family: inherit;
background: rgba(15, 23, 42, 0.6);
border: 2px solid rgba(148, 163, 184, 0.2);
border-radius: 12px;
color: #ffffff;
resize: vertical;
transition: border-color 0.3s, box-shadow 0.3s;
}
textarea:focus {
outline: none;
border-color: #38bdf8;
box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.2);
}
textarea::placeholder {
color: #64748b;
}
.btn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 16px 32px;
font-size: 16px;
font-weight: 600;
border: none;
border-radius: 12px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.btn-primary {
background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: #ffffff;
box-shadow: 0 4px 14px rgba(14, 165, 233, 0.4);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(14, 165, 233, 0.5);
}
.btn-primary:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.btn-icon {
font-size: 20px;
}
.quick-questions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}
.quick-btn {
padding: 10px 18px;
font-size: 14px;
background: rgba(56, 189, 248, 0.15);
border: 1px solid rgba(56, 189, 248, 0.3);
border-radius: 20px;
color: #7dd3fc;
cursor: pointer;
transition: all 0.2s;
}
.quick-btn:hover {
background: rgba(56, 189, 248, 0.25);
border-color: #38bdf8;
}
.response-section {
display: none;
}
.response-section.active {
display: block;
}
.response-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid rgba(148, 163, 184, 0.2);
}
.response-icon {
font-size: 28px;
}
.response-title {
font-size: 18px;
font-weight: 600;
color: #ffffff;
}
.response-content {
font-size: 16px;
line-height: 1.7;
color: #cbd5e1;
white-space: pre-wrap;
}
.response-content h1,
.response-content h2,
.response-content h3 {
color: #ffffff;
margin: 24px 0 12px;
font-weight: 600;
}
.response-content h1 { font-size: 24px; }
.response-content h2 { font-size: 20px; }
.response-content h3 { font-size: 18px; }
.response-content ul,
.response-content ol {
margin: 12px 0;
padding-left: 24px;
}
.response-content li {
margin-bottom: 8px;
}
.response-content strong {
color: #ffffff;
font-weight: 600;
}
.response-content code {
background: rgba(255, 255, 255, 0.1);
padding: 2px 6px;
border-radius: 4px;
font-family: "Consolas", "Monaco", monospace;
font-size: 14px;
}
.response-content pre {
background: rgba(15, 23, 42, 0.6);
padding: 16px;
border-radius: 8px;
overflow-x: auto;
margin: 16px 0;
}
.response-content pre code {
background: none;
padding: 0;
}
.loading {
display: none;
text-align: center;
padding: 40px;
}
.loading.active {
display: block;
}
.spinner {
width: 48px;
height: 48px;
border: 4px solid rgba(56, 189, 248, 0.2);
border-top-color: #38bdf8;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 16px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-text {
color: #94a3b8;
font-size: 14px;
}
.error-message {
background: rgba(239, 68, 68, 0.15);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 12px;
padding: 16px 20px;
color: #fca5a5;
margin-top: 16px;
display: none;
}
.error-message.active {
display: block;
}
footer {
text-align: center;
padding: 32px 20px;
color: #64748b;
font-size: 14px;
}
@media (max-width: 640px) {
.container { padding: 20px 16px; }
.card { padding: 24px 20px; }
.btn { width: 100%; justify-content: center; }
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="logo">🛡️</div>
<h1>Агент по охране труда</h1>
<p class="subtitle">Эксперт по технике безопасности и охране труда. Задайте вопрос — получите профессиональный ответ.</p>
</header>
<div class="card">
<div class="input-section">
<label for="question">Ваш вопрос</label>
<textarea
id="question"
placeholder="Например: Какие требования охраны труда предъявляются к работе на высоте?&#10;&#10;Или: Составьте инструкцию по технике безопасности для офиса..."
></textarea>
<div class="quick-questions">
<button class="quick-btn" onclick="setQuestion('Составь инструкцию по охране труда для офиса')">📋 Инструкция для офиса</button>
<button class="quick-btn" onclick="setQuestion('Какие виды инструктажей по охране труда существуют?')">📚 Виды инструктажей</button>
<button class="quick-btn" onclick="setQuestion('Как провести оценку профессиональных рисков?')">⚠️ Оценка рисков</button>
<button class="quick-btn" onclick="setQuestion('Требования к работе на высоте')">🏗️ Работа на высоте</button>
<button class="quick-btn" onclick="setQuestion('Как оформить журнал инструктажей?')">📖 Журнал инструктажей</button>
</div>
</div>
<button class="btn btn-primary" id="askBtn" onclick="askAgent()">
<span class="btn-icon">💬</span>
<span>Задать вопрос агенту</span>
</button>
<div class="error-message" id="errorMessage"></div>
</div>
<div class="loading" id="loading">
<div class="spinner"></div>
<p class="loading-text">Агент анализирует ваш вопрос и готовит ответ...</p>
</div>
<div class="card response-section" id="responseSection">
<div class="response-header">
<span class="response-icon"></span>
<span class="response-title">Ответ агента</span>
</div>
<div class="response-content" id="responseContent"></div>
</div>
<footer>
<p>Приоритет в работе — безопасность людей</p>
</footer>
</div>
<script>
let sessionId = null;
function setQuestion(text) {
document.getElementById('question').value = text;
}
async function createSession() {
const resp = await fetch('/api/session', { method: 'POST' });
const data = await resp.json();
if (!data.ok) throw new Error('Не удалось создать сессию');
sessionId = data.sessionId;
return sessionId;
}
async function askAgent() {
const question = document.getElementById('question').value.trim();
if (!question) {
showError('Введите вопрос');
return;
}
const btn = document.getElementById('askBtn');
const loading = document.getElementById('loading');
const responseSection = document.getElementById('responseSection');
const errorMessage = document.getElementById('errorMessage');
btn.disabled = true;
loading.classList.add('active');
responseSection.classList.remove('active');
errorMessage.classList.remove('active');
try {
if (!sessionId) {
await createSession();
}
const resp = await fetch('/api/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question, sessionId })
});
const data = await resp.json();
if (!data.ok) {
throw new Error(data.error || 'Ошибка при получении ответа');
}
document.getElementById('responseContent').innerHTML = formatResponse(data.answer);
responseSection.classList.add('active');
} catch (err) {
showError(err.message);
} finally {
btn.disabled = false;
loading.classList.remove('active');
}
}
function formatResponse(text) {
if (!text) return '';
let html = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
.replace(/^- (.+)$/gm, '<li>$1</li>')
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
.replace(/`(.+?)`/g, '<code>$1</code>')
.replace(/\n/g, '<br>');
return '<ul>' + html.replace(/<li>/g, '</li><li>').replace(/^<\/li>/, '') + '</ul>';
}
function showError(message) {
const el = document.getElementById('errorMessage');
el.textContent = message;
el.classList.add('active');
}
document.getElementById('question').addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.ctrlKey) {
askAgent();
}
});
</script>
</body>
</html>