diff --git a/.gitignore b/.gitignore
index e427ff3..d387093 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules/
*/node_modules/
*/build/
+.env
diff --git a/api.php b/api.php
new file mode 100644
index 0000000..c3823cc
--- /dev/null
+++ b/api.php
@@ -0,0 +1,110 @@
+ 'Ошибка: API-ключ не найден. Пожалуйста, добавьте его в файл .env']);
+ exit;
+}
+
+// 2. Get user message from POST request
+$input = json_decode(file_get_contents('php://input'), true);
+$userMessage = trim($input['message'] ?? '');
+
+if (empty($userMessage)) {
+ echo json_encode(['reply' => 'Пожалуйста, введите сообщение.']);
+ exit;
+}
+
+// 3. Load the knowledge base
+$knowledgeBasePath = __DIR__ . '/db/knowledge_base.txt';
+if (!file_exists($knowledgeBasePath)) {
+ echo json_encode(['reply' => 'Ошибка: База знаний не найдена.']);
+ exit;
+}
+$knowledgeBase = file_get_contents($knowledgeBasePath);
+
+// 4. Prepare the prompt for the AI
+$prompt = "Ты — ИИ-ассистент, специалист по внутренней системе управления складом под названием HUB. Твоя задача — отвечать на вопросы пользователя, основываясь ИСКЛЮЧИТЕЛЬНО на предоставленной базе знаний. Не придумывай ничего от себя. Если ответа в базе знаний нет, вежливо сообщи, что ты можешь отвечать только на вопросы, связанные с системой HUB.\n\nВот база знаний:\n---\n" . $knowledgeBase . "\n---\n\nВопрос пользователя: \"" . $userMessage . "\"";
+
+// 5. Call the Gemini API
+$url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=' . $apiKey;
+
+$data = [
+ 'contents' => [
+ [
+ 'parts' => [
+ ['text' => $prompt]
+ ]
+ ]
+ ]
+];
+
+$options = [
+ 'http' => [
+ 'header' => "Content-type: application/json\r\n",
+ 'method' => 'POST',
+ 'content' => json_encode($data),
+ 'ignore_errors' => true // To see the error message from the API
+ ]
+];
+
+$context = stream_context_create($options);
+$response = file_get_contents($url, false, $context);
+$http_response_header = $http_response_header ?? [];
+
+// 6. Process the response
+if ($response === FALSE) {
+ $error = 'Не удалось связаться с API. ';
+ // Check for more specific errors if possible
+ $last_error = error_get_last();
+ if ($last_error) {
+ $error .= $last_error['message'];
+ }
+ // Try to get the HTTP status and response body
+ $status_line = $http_response_header[0] ?? 'HTTP/1.1 500 Internal Server Error';
+ preg_match('{HTTP/\S+\s(\d+)}', $status_line, $match);
+ $status = $match[1] ?? 500;
+
+ error_log("Gemini API Error: Status $status, Response: $response");
+
+ echo json_encode(['reply' => "Ошибка при обращении к сервису ИИ. Статус: $status. Пожалуйста, проверьте ключ API и настройки сервера."]);
+
+} else {
+ $result = json_decode($response, true);
+
+ if (isset($result['candidates'][0]['content']['parts'][0]['text'])) {
+ $reply = $result['candidates'][0]['content']['parts'][0]['text'];
+ echo json_encode(['reply' => $reply]);
+ } else {
+ // Log the actual error response from the API for debugging
+ error_log("Gemini API - Unexpected response structure: " . $response);
+ echo json_encode(['reply' => 'Получен неожиданный ответ от сервиса ИИ. Возможно, проблема с конфигурацией или ключом API.']);
+ }
+}
\ No newline at end of file
diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..1aa7031
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,163 @@
+
+:root {
+ --bg-color: #121212;
+ --surface-color: #1E1E1E;
+ --primary-color: #00FF9B;
+ --secondary-color: #00C2FF;
+ --text-color: #E0E0E0;
+ --text-muted-color: #888;
+ --border-radius-md: 12px;
+ --border-radius-sm: 8px;
+}
+
+body {
+ background-color: var(--bg-color);
+ color: var(--text-color);
+ font-family: 'Roboto Mono', 'Consolas', 'Monaco', monospace;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ overflow: hidden;
+}
+
+.chat-container {
+ width: 100%;
+ max-width: 800px;
+ height: 100vh;
+ max-height: 100vh; /* For mobile browsers */
+ display: flex;
+ flex-direction: column;
+ background-color: var(--bg-color);
+ border-radius: 0;
+ box-shadow: 0 0 40px rgba(0, 255, 155, 0.1);
+ overflow: hidden;
+}
+
+.chat-header {
+ padding: 16px 24px;
+ background-color: var(--surface-color);
+ border-bottom: 1px solid #333;
+ text-align: center;
+}
+
+.chat-header h1 {
+ font-size: 1.5rem;
+ font-weight: 500;
+ margin: 0;
+ background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-fill-color: transparent;
+}
+
+.chat-header .text-muted {
+ font-size: 0.85rem;
+ color: var(--text-muted-color);
+ margin: 0;
+}
+
+.chat-messages {
+ flex-grow: 1;
+ padding: 24px;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+/* Custom scrollbar for webkit browsers */
+.chat-messages::-webkit-scrollbar {
+ width: 6px;
+}
+.chat-messages::-webkit-scrollbar-track {
+ background: var(--bg-color);
+}
+.chat-messages::-webkit-scrollbar-thumb {
+ background-color: var(--surface-color);
+ border-radius: 6px;
+}
+
+.message {
+ display: flex;
+ max-width: 75%;
+}
+
+.message-content {
+ padding: 12px 16px;
+ border-radius: var(--border-radius-md);
+ line-height: 1.5;
+}
+
+.message-content p {
+ margin: 0;
+}
+
+.bot-message {
+ align-self: flex-start;
+}
+
+.bot-message .message-content {
+ background-color: var(--surface-color);
+ border-top-left-radius: 0;
+}
+
+.user-message {
+ align-self: flex-end;
+}
+
+.user-message .message-content {
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
+ color: #000;
+ border-top-right-radius: 0;
+}
+
+.chat-input-area {
+ padding: 16px 24px;
+ background-color: var(--surface-color);
+ border-top: 1px solid #333;
+}
+
+#chat-form .form-control {
+ background-color: #333;
+ border: 1px solid #444;
+ color: var(--text-color);
+ border-radius: var(--border-radius-sm);
+ padding: 12px 16px;
+ height: 48px;
+}
+
+#chat-form .form-control:focus {
+ background-color: #333;
+ color: var(--text-color);
+ box-shadow: 0 0 0 2px var(--primary-color);
+ border-color: var(--primary-color);
+}
+
+#chat-form .form-control::placeholder {
+ color: var(--text-muted-color);
+}
+
+#chat-form .btn {
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
+ border: none;
+ border-radius: var(--border-radius-sm);
+ margin-left: 12px;
+ width: 48px;
+ height: 48px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: transform 0.2s ease;
+}
+
+#chat-form .btn:hover {
+ transform: scale(1.05);
+}
+
+#chat-form .btn svg {
+ color: #000;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..169545a
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,84 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const chatForm = document.getElementById('chat-form');
+ const messageInput = document.getElementById('message-input');
+ const chatMessages = document.getElementById('chat-messages');
+
+ chatForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const messageText = messageInput.value.trim();
+
+ if (messageText) {
+ appendMessage(messageText, 'user');
+ messageInput.value = '';
+
+ showBotTyping();
+
+ // Send message to backend
+ fetch('api.php', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ message: messageText })
+ })
+ .then(response => response.json())
+ .then(data => {
+ removeBotTyping();
+ appendMessage(data.reply, 'bot');
+ })
+ .catch(error => {
+ removeBotTyping();
+ console.error('Error:', error);
+ appendMessage('Извините, произошла ошибка. Попробуйте еще раз.', 'bot');
+ });
+ }
+ });
+
+ function appendMessage(text, sender) {
+ const messageWrapper = document.createElement('div');
+ messageWrapper.classList.add('message', `${sender}-message`);
+
+ const messageContent = document.createElement('div');
+ messageContent.classList.add('message-content');
+
+ const paragraph = document.createElement('p');
+ paragraph.innerHTML = text; // Use innerHTML to render potential HTML tags from response
+
+ messageContent.appendChild(paragraph);
+ messageWrapper.appendChild(messageContent);
+ chatMessages.appendChild(messageWrapper);
+
+ scrollToBottom();
+ }
+
+ function showBotTyping() {
+ const typingIndicator = document.createElement('div');
+ typingIndicator.id = 'typing-indicator';
+ typingIndicator.classList.add('message', 'bot-message');
+
+ const content = document.createElement('div');
+ content.classList.add('message-content');
+
+ const p = document.createElement('p');
+ p.textContent = '...';
+
+ content.appendChild(p);
+ typingIndicator.appendChild(content);
+ chatMessages.appendChild(typingIndicator);
+ scrollToBottom();
+ }
+
+ function removeBotTyping() {
+ const typingIndicator = document.getElementById('typing-indicator');
+ if (typingIndicator) {
+ typingIndicator.remove();
+ }
+ }
+
+ function scrollToBottom() {
+ chatMessages.scrollTop = chatMessages.scrollHeight;
+ }
+
+ // Initial scroll to bottom if content is already there
+ scrollToBottom();
+});
\ No newline at end of file
diff --git a/db/knowledge_base.txt b/db/knowledge_base.txt
new file mode 100644
index 0000000..0b869b4
--- /dev/null
+++ b/db/knowledge_base.txt
@@ -0,0 +1 @@
+Это БАЗА знаний 1. Введение в систему HUB Цель: Понять назначение HUB и его роль в управлении складскими данными. HUB — это система для управления складскими предметами (грузами, контейнерами, коробками и т.д.) и процессами их перемещения, хранения и инвентаризации. Она позволяет отслеживать состояние предметов, их историю, взаимодействие с контейнерами и логистическими точками, а также проводить пересчеты и настраивать складскую инфраструктуру. Ключевые понятия: Предмет: Объект хранения (например, ТЯ, коробка, отправление). Логистический контейнер (ЛК): Емкость для хранения/перемещения предметов (статусы: "Формируется", "Сформирован" и др.). Инвентаризация/пересчет: Проверка фактического наличия предметов на складе против учетных данных. КМО: Внутренний термин, предположительно связанный с документацией о материальных ошибках/недостачах (например, "Книга Материальных Остатков"). ЦМН: Цель доставки (место назначения предмета). Тайм-слот: Временной интервал для доставки. 2. Основы интерфейса HUB и карточка предмета Цель: Знакомство с интерфейсом HUB и структурой карточки предмета. HUB содержит главное меню, схему склада и таблицу со списком предметов. Основная работа ведется через карточку предмета — детализированное окно с информацией о конкретном объекте. 2.1 Структура карточки предмета Карточка доступна при клике на ID предмета в таблице "Предметы". Она включает следующие вкладки: Вкладка Описание Основные данные «О предмете» Основная информация о предмете. Тип, статус, ID, номенклатура, принадлежность, стоимость, адрес хранения. «Состав» Текущий и исторический состав контейнера (для предметов, являющихся контейнерами). Список предметов внутри, даты добавления/удаления, статусы элементов состава. «История (перемещения)» История перемещений предмета между ячейками, контейнерами и логистическими точками. Тип события (принято, перемещено, вошло/вышло из контейнера), дата, источник/цель. «Отгрузки» Запись о выдаче предмета (отгрузке) со склада. Дата отгрузки, получате
\ No newline at end of file
diff --git a/index.php b/index.php
index 6f7ffab..ad38765 100644
--- a/index.php
+++ b/index.php
@@ -1,131 +1,59 @@
-
-
-
+
+
-
-
- New Style
-
-
-
-
+
+
+ Your Logistic Koresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWiZZy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+
+
+
+
+
+
+
+
+
Привет. Я — твой логистический кореш. Я здесь, чтобы помочь тебе с вопросами по системе HUB. Спрашивай, не стесняйся.
+
+
+
+
+
-
-
+
+
+
+
+
-
+
\ No newline at end of file