| | <!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; |
| | |
| | |
| | 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">5×</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> |
| |
|