engineerassistant / index.html
AssanaliAidarkhan's picture
Upload index.html
25bc0b5 verified
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mindia AI - Умный помощник инженера</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
.typing {
overflow: hidden;
white-space: nowrap;
border-right: 3px solid #3b82f6;
animation: typing 2s steps(40, end), blink 0.75s step-end infinite;
}
@keyframes blink {
from, to { border-color: transparent; }
50% { border-color: #3b82f6; }
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useRef } = React;
// Icons
const Search = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.35-4.35"/>
</svg>
);
const Brain = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/>
<path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>
</svg>
);
const FileText = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
</svg>
);
const Book = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/>
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>
</svg>
);
const Link = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
</svg>
);
const Zap = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
);
const Clock = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<circle cx="12" cy="12" r="10"/>
<polyline points="12 6 12 12 16 14"/>
</svg>
);
const TrendingUp = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/>
<polyline points="17 6 23 6 23 12"/>
</svg>
);
const Users = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
);
const Image = ({ size = 24, className = "" }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<polyline points="21 15 16 10 5 21"/>
</svg>
);
const MindiaAssistant = () => {
const [query, setQuery] = useState('');
const [isSearching, setIsSearching] = useState(false);
const [searchResult, setSearchResult] = useState(null);
const [searchHistory, setSearchHistory] = useState([
{ query: 'температура эксплуатации двигателя ДП-45', time: '14:23' },
{ query: 'схема подключения датчика вибрации', time: '13:45' },
{ query: 'регламент ТО редуктора', time: '12:10' }
]);
const exampleQueries = [
"момент затяжки болтов для редуктора Р-500",
"температурный режим работы двигателя ДП-45",
"схема подключения датчика давления",
"периодичность замены масла в гидросистеме",
"допустимый уровень вибрации для насоса НШ-100"
];
const knowledgeBase = {
"момент затяжки болтов для редуктора Р-500": {
answer: "Момент затяжки болтов крепления крышки редуктора Р-500 составляет 120 Н·м (класс прочности 8.8).",
source: {
title: "Инструкция по эксплуатации Р-500.pdf",
page: 42,
section: "3.5.1",
excerpt: "...для обеспечения герметичности, момент затяжки болтов (поз. 12 на рис. 4) должен составлять 120 Н·м при использовании болтов класса прочности 8.8. Затяжку производить крест-накрест в два этапа: сначала 60 Н·м, затем 120 Н·м..."
},
relatedDocs: [
{ title: "Сборочный чертеж редуктора Р-500.dwg", type: "DWG" },
{ title: "Регламент ТО-2 для Линии 3.pdf", type: "PDF" },
{ title: "ГОСТ 1759.4-87 Болты класс прочности.pdf", type: "PDF" }
]
},
"температурный режим работы двигателя ДП-45": {
answer: "Номинальная рабочая температура двигателя ДП-45: обмотка 80-105°C, подшипники не более 65°C. Критическая температура обмотки: 130°C.",
source: {
title: "Техническая документация ДП-45.pdf",
page: 18,
section: "2.3",
excerpt: "Температурный режим работы: номинальная температура обмотки статора 80-105°C (класс изоляции F). Температура подшипников не должна превышать 65°C. При достижении температуры обмотки 130°C необходима немедленная остановка..."
},
relatedDocs: [
{ title: "Схема термоконтроля ДП-45.pdf", type: "PDF" },
{ title: "Инструкция по монтажу двигателей.pdf", type: "PDF" }
]
},
"схема подключения датчика давления": {
answer: "Датчик давления подключается по 4-проводной схеме: +24V (красный), GND (черный), Signal+ (белый), Signal- (синий). Диапазон измерения: 0-10 bar, выходной сигнал: 4-20 mA.",
source: {
title: "Руководство по КИПиА.pdf",
page: 67,
section: "5.2.4",
excerpt: "Датчики давления серии ДД-100 подключаются по стандартной 4-проводной схеме. Красный провод - питание +24V DC, черный - общий (GND), белый и синий - дифференциальный токовый выход 4-20 mA..."
},
relatedDocs: [
{ title: "Схема подключения КИП.dwg", type: "DWG" },
{ title: "Паспорт датчика ДД-100.pdf", type: "PDF" }
]
}
};
const handleSearch = () => {
if (!query.trim()) return;
setIsSearching(true);
setTimeout(() => {
const result = knowledgeBase[query.toLowerCase()] || {
answer: `По вашему запросу "${query}" найдено 3 документа. Наиболее релевантная информация находится в техническом регламенте.`,
source: {
title: "Общий технический регламент.pdf",
page: 124,
section: "Раздел 7",
excerpt: "Информация по запросу доступна в разделе технической документации..."
},
relatedDocs: [
{ title: "Техническая документация оборудования.pdf", type: "PDF" },
{ title: "Справочник инженера.pdf", type: "PDF" }
]
};
setSearchResult(result);
setSearchHistory(prev => [
{ query, time: new Date().toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }) },
...prev.slice(0, 9)
]);
setIsSearching(false);
}, 1500);
};
const handleExampleClick = (example) => {
setQuery(example);
};
return (
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-white to-purple-50 p-6">
<div className="max-w-6xl mx-auto">
{/* Header */}
<div className="bg-gradient-to-r from-indigo-600 to-purple-700 rounded-xl shadow-2xl p-8 mb-8 border-2 border-indigo-300">
<div className="flex items-center gap-4 mb-4">
<div className="bg-white p-3 rounded-xl shadow-lg">
<Brain size={40} className="text-indigo-600" />
</div>
<div>
<h1 className="text-4xl font-bold text-white mb-1">MINDIA</h1>
<p className="text-indigo-100 text-lg font-medium">База знаний предприятия • Умный помощник инженера</p>
</div>
</div>
</div>
{/* Search Bar */}
<div className="bg-white rounded-xl shadow-2xl p-6 mb-6 border-2 border-indigo-200">
<div className="flex gap-3">
<div className="flex-1 relative">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 text-gray-400" size={24} />
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
placeholder="Задайте вопрос на естественном языке..."
className="w-full pl-14 pr-4 py-4 text-lg border-2 border-gray-300 rounded-lg focus:border-indigo-500 focus:outline-none"
/>
</div>
<button
onClick={handleSearch}
disabled={isSearching}
className="px-8 py-4 bg-gradient-to-r from-indigo-600 to-purple-600 text-white font-bold rounded-lg hover:from-indigo-700 hover:to-purple-700 transition-all shadow-lg disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSearching ? (
<div className="flex items-center gap-2">
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
Поиск...
</div>
) : (
'Найти'
)}
</button>
</div>
{/* Example Queries */}
<div className="mt-4">
<p className="text-sm text-gray-600 mb-2 font-semibold">Примеры запросов:</p>
<div className="flex flex-wrap gap-2">
{exampleQueries.map((example, index) => (
<button
key={index}
onClick={() => handleExampleClick(example)}
className="text-sm px-3 py-1.5 bg-indigo-50 text-indigo-700 rounded-full hover:bg-indigo-100 transition-colors border border-indigo-200"
>
"{example}"
</button>
))}
</div>
</div>
</div>
<div className="grid grid-cols-3 gap-6">
{/* Left Column - Search Result */}
<div className="col-span-2">
{searchResult ? (
<div className="space-y-6 fade-in">
{/* Direct Answer */}
<div className="bg-white rounded-xl shadow-xl p-6 border-2 border-green-200">
<div className="flex items-center gap-2 mb-4">
<Zap className="text-green-600" size={24} />
<h2 className="text-xl font-bold text-gray-800">Прямой ответ</h2>
</div>
<div className="bg-green-50 rounded-lg p-6 border-2 border-green-200">
<p className="text-lg text-gray-800 leading-relaxed font-medium">
{searchResult.answer}
</p>
</div>
</div>
{/* Source Document */}
<div className="bg-white rounded-xl shadow-xl p-6 border-2 border-blue-200">
<div className="flex items-center gap-2 mb-4">
<FileText className="text-blue-600" size={24} />
<h2 className="text-xl font-bold text-gray-800">Источник</h2>
</div>
<div className="space-y-4">
<div className="flex items-center gap-3 p-4 bg-blue-50 rounded-lg border border-blue-200">
<FileText className="text-blue-600" size={32} />
<div className="flex-1">
<p className="font-bold text-blue-900">{searchResult.source.title}</p>
<p className="text-sm text-blue-700">
Страница {searchResult.source.page}, пункт {searchResult.source.section}
</p>
</div>
</div>
<div className="bg-gray-50 rounded-lg p-4 border-l-4 border-blue-500">
<p className="text-gray-700 leading-relaxed italic">
{searchResult.source.excerpt}
</p>
</div>
<button className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors">
<Image size={18} />
Показать на схеме
</button>
</div>
</div>
{/* Related Documents */}
<div className="bg-white rounded-xl shadow-xl p-6 border-2 border-purple-200">
<div className="flex items-center gap-2 mb-4">
<Book className="text-purple-600" size={24} />
<h2 className="text-xl font-bold text-gray-800">Связанные документы</h2>
</div>
<div className="space-y-3">
{searchResult.relatedDocs.map((doc, index) => (
<div
key={index}
className="flex items-center gap-3 p-4 bg-purple-50 rounded-lg border border-purple-200 hover:bg-purple-100 transition-colors cursor-pointer"
>
<div className={`px-3 py-1 rounded font-bold text-sm ${
doc.type === 'PDF'
? 'bg-red-100 text-red-700'
: 'bg-blue-100 text-blue-700'
}`}>
{doc.type}
</div>
<p className="flex-1 text-gray-800 font-medium">{doc.title}</p>
<Link className="text-purple-600" size={20} />
</div>
))}
</div>
</div>
</div>
) : (
<div className="bg-white rounded-xl shadow-xl p-12 border-2 border-gray-200 text-center">
<Brain size={64} className="mx-auto mb-4 text-gray-300" />
<h3 className="text-2xl font-bold text-gray-800 mb-2">
Задайте вопрос Mindia
</h3>
<p className="text-gray-600">
Я помогу найти нужную информацию в технической документации
</p>
</div>
)}
</div>
{/* Right Column - Info and History */}
<div className="col-span-1 space-y-6">
{/* Statistics */}
<div className="bg-white rounded-xl shadow-xl p-6 border-2 border-indigo-200">
<h2 className="text-lg font-bold text-gray-800 mb-4">Эффективность</h2>
<div className="space-y-4">
<div className="bg-gradient-to-br from-green-500 to-green-600 rounded-lg p-4 text-white">
<div className="flex items-center gap-2 mb-1">
<Zap size={18} />
<p className="text-sm font-semibold">Скорость поиска</p>
</div>
<p className="text-3xl font-bold">×10</p>
<p className="text-xs opacity-90">быстрее</p>
</div>
<div className="bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg p-4 text-white">
<div className="flex items-center gap-2 mb-1">
<Clock size={18} />
<p className="text-sm font-semibold">Экономия времени</p>
</div>
<p className="text-3xl font-bold">30%</p>
<p className="text-xs opacity-90">рабочего времени</p>
</div>
<div className="bg-gradient-to-br from-purple-500 to-purple-600 rounded-lg p-4 text-white">
<div className="flex items-center gap-2 mb-1">
<Users size={18} />
<p className="text-sm font-semibold">Адаптация новичков</p>
</div>
<p className="text-3xl font-bold"></p>
<p className="text-xs opacity-90">быстрее</p>
</div>
</div>
</div>
{/* Search History */}
<div className="bg-white rounded-xl shadow-xl p-6 border-2 border-gray-200">
<h2 className="text-lg font-bold text-gray-800 mb-4 flex items-center gap-2">
<Clock className="text-gray-600" />
История запросов
</h2>
<div className="space-y-2 max-h-96 overflow-y-auto">
{searchHistory.map((item, index) => (
<div
key={index}
onClick={() => setQuery(item.query)}
className="p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer border border-gray-200"
>
<p className="text-sm text-gray-800 font-medium line-clamp-2">
{item.query}
</p>
<p className="text-xs text-gray-500 mt-1">{item.time}</p>
</div>
))}
</div>
</div>
{/* Knowledge Base Stats */}
<div className="bg-gradient-to-br from-indigo-600 to-purple-700 rounded-xl shadow-xl p-6 text-white">
<h2 className="text-lg font-bold mb-4">База знаний</h2>
<div className="space-y-3 text-sm">
<div className="flex justify-between">
<span className="opacity-90">Документов:</span>
<span className="font-bold">2,847</span>
</div>
<div className="flex justify-between">
<span className="opacity-90">ГОСТы:</span>
<span className="font-bold">456</span>
</div>
<div className="flex justify-between">
<span className="opacity-90">Чертежей:</span>
<span className="font-bold">1,203</span>
</div>
<div className="flex justify-between">
<span className="opacity-90">Инструкций:</span>
<span className="font-bold">892</span>
</div>
<div className="pt-3 border-t border-white/20">
<p className="text-xs opacity-75">Последнее обновление: сегодня, 09:15</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MindiaAssistant />);
</script>
</body>
</html>