commit
						914e358ee8
					
				| @ -193,7 +193,9 @@ | ||||
|             }, | ||||
|             "confirm": { | ||||
|                 "delete": "Are you sure you want to delete this share? This action cannot be undone." | ||||
|             } | ||||
|             }, | ||||
|             "label": "Manage Page Share", | ||||
|             "description": "Enable or disable the page share feature. By default, the page share feature is enabled." | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pageShareSuccess": "Page Share URL updated successfully", | ||||
|  | ||||
| @ -196,7 +196,9 @@ | ||||
|             }, | ||||
|             "confirm": { | ||||
|                 "delete": "本当にこの共有を削除しますか?この操作は元に戻せません。" | ||||
|             } | ||||
|             }, | ||||
|             "label": "ページ共有を管理する", | ||||
|             "description": "ページ共有機能を有効または無効にします。デフォルトでは、ページ共有機能は有効になっています。" | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pageShareSuccess": "ページ共有URLが正常に更新されました", | ||||
|  | ||||
| @ -196,7 +196,9 @@ | ||||
|             }, | ||||
|             "confirm": { | ||||
|                 "delete": "ഈ പങ്കിടല് ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ? ഈ പ്രവർത്തനം പിന്നീട് പിൻവലിക്കാനാകില്ല." | ||||
|             } | ||||
|             }, | ||||
|             "label": "പേജ് ഷെയർ നിയന്ത്രിക്കുക", | ||||
|             "description": "പേജ് ഷെയർ സവിശേഷത സജീവമാക്കുകയോ അക്ഷമമാക്കുകയോ ചെയ്യുക. സ്ഥിരംമായി, പേജ് ഷെയർ സവിശേഷത സജീവമാക്കപ്പെടുന്നു." | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pageShareSuccess": "പേജ് പങ്കിടാനുള്ള URL വിജയകരമായി അപ്ഡേറ്റ് ചെയ്തു", | ||||
|  | ||||
							
								
								
									
										54
									
								
								src/assets/locale/ru/common.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/assets/locale/ru/common.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| { | ||||
|     "pageAssist": "Помощник страницы", | ||||
|     "selectAModel": "Выберите модель", | ||||
|     "save": "Сохранить", | ||||
|     "saved": "Сохранено", | ||||
|     "cancel": "Отмена", | ||||
|     "retry": "Повторить", | ||||
|     "share": { | ||||
|         "tooltip": { | ||||
|             "share": "Поделиться" | ||||
|         }, | ||||
|         "modal": { | ||||
|             "title": "Поделиться ссылкой на чат" | ||||
|         }, | ||||
|         "form": { | ||||
|             "defaultValue": { | ||||
|                 "name": "Аноним", | ||||
|                 "title": "Безымянный чат" | ||||
|             }, | ||||
|             "title": { | ||||
|                 "label": "Название чата", | ||||
|                 "placeholder": "Введите название чата", | ||||
|                 "required": "Название чата обязательно" | ||||
|             }, | ||||
|             "name": { | ||||
|                 "label": "Ваше имя", | ||||
|                 "placeholder": "Введите ваше имя", | ||||
|                 "required": "Ваше имя обязательно" | ||||
|             }, | ||||
|             "btn": { | ||||
|                 "save": "Создать ссылку", | ||||
|                 "saving": "Создание ссылки..." | ||||
|             } | ||||
|         }, | ||||
|         "notification": { | ||||
|             "successGenerate": "Ссылка скопирована в буфер обмена", | ||||
|             "failGenerate": "Не удалось создать ссылку" | ||||
|         } | ||||
|     }, | ||||
|     "copyToClipboard": "Копировать в буфер обмена", | ||||
|     "webSearch": "Поиск в интернете", | ||||
|     "regenerate": "Пересоздать", | ||||
|     "edit": "Редактировать", | ||||
|     "saveAndSubmit": "Сохранить и отправить", | ||||
|     "editMessage": { | ||||
|         "placeholder": "Введите сообщение..." | ||||
|     }, | ||||
|     "submit": "Отправить", | ||||
|     "noData": "Нет данных", | ||||
|     "noHistory": "Нет истории чата", | ||||
|     "chatWithCurrentPage": "Чат с текущей страницей", | ||||
|     "beta": "Бета", | ||||
|     "tts": "Прочитать вслух" | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/assets/locale/ru/knowledge.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/assets/locale/ru/knowledge.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| { | ||||
|     "addBtn": "Добавить новое знание", | ||||
|     "columns": { | ||||
|         "title": "Название", | ||||
|         "status": "Статус", | ||||
|         "embeddings": "Модель вложения", | ||||
|         "createdAt": "Создано", | ||||
|         "action": "Действия" | ||||
|     }, | ||||
|     "expandedColumns": { | ||||
|         "name": "Имя" | ||||
|     }, | ||||
|     "tooltip": { | ||||
|         "delete": "Удалить" | ||||
|     }, | ||||
|     "confirm": { | ||||
|         "delete": "Вы уверены, что хотите удалить это знание?" | ||||
|     }, | ||||
|     "deleteSuccess": "Знание успешно удалено", | ||||
|     "status": { | ||||
|         "pending": "Ожидание", | ||||
|         "finished": "Завершено", | ||||
|         "processing": "Обработка" | ||||
|     }, | ||||
|     "addKnowledge": "Добавить знание", | ||||
|     "form": { | ||||
|         "title": { | ||||
|             "label": "Название знания", | ||||
|             "placeholder": "Введите название знания", | ||||
|             "required": "Название знания обязательно" | ||||
|         }, | ||||
|         "uploadFile": { | ||||
|             "label": "Загрузить файл", | ||||
|             "uploadText": "Перетащите файл сюда или нажмите, чтобы загрузить", | ||||
|             "uploadHint": "Поддерживаемые типы файлов: .pdf, .csv, .txt, .md", | ||||
|             "required": "Файл обязателен" | ||||
|         }, | ||||
|         "submit": "Отправить", | ||||
|         "success": "Знание успешно добавлено" | ||||
|     }, | ||||
|     "noEmbeddingModel": "Пожалуйста, сначала добавьте модель вложения на странице настроек Ollama" | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/assets/locale/ru/option.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/assets/locale/ru/option.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| { | ||||
|     "newChat": "Новый чат", | ||||
|     "selectAPrompt": "Выберите подсказку", | ||||
|     "githubRepository": "Репозиторий GitHub", | ||||
|     "settings": "Настройки", | ||||
|     "sidebarTitle": "История чата", | ||||
|     "error": "Ошибка", | ||||
|     "somethingWentWrong": "Что-то пошло не так", | ||||
|     "validationSelectModel": "Пожалуйста, выберите модель, чтобы продолжить", | ||||
|     "deleteHistoryConfirmation": "Вы уверены, что хотите удалить эту историю?", | ||||
|     "editHistoryTitle": "Введите новое название" | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/assets/locale/ru/playground.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/assets/locale/ru/playground.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| { | ||||
|     "ollamaState": { | ||||
|         "searching": "Поиск вашего Ollama 🦙", | ||||
|         "running": "Ollama работает 🦙", | ||||
|         "notRunning": "Не удалось подключиться к Ollama 🦙" | ||||
|     }, | ||||
|     "formError": { | ||||
|         "noModel": "Пожалуйста, выберите модель", | ||||
|         "noEmbeddingModel": "Пожалуйста, установите модель вложения на странице Настройки > Ollama" | ||||
|     }, | ||||
|     "form": { | ||||
|         "textarea": { | ||||
|             "placeholder": "Введите сообщение..." | ||||
|         }, | ||||
|         "webSearch": { | ||||
|             "on": "Вкл", | ||||
|             "off": "Выкл" | ||||
|         } | ||||
|     }, | ||||
|     "tooltip": { | ||||
|         "searchInternet": "Поиск в Интернете", | ||||
|         "speechToText": "Речь в текст", | ||||
|         "uploadImage": "Загрузить изображение", | ||||
|         "stopStreaming": "Остановить поток", | ||||
|         "knowledge": "Знание" | ||||
|     }, | ||||
|     "sendWhenEnter": "Отправить при нажатии клавиши Enter" | ||||
| } | ||||
							
								
								
									
										269
									
								
								src/assets/locale/ru/settings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								src/assets/locale/ru/settings.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,269 @@ | ||||
| { | ||||
|     "generalSettings": { | ||||
|         "title": "Общие настройки", | ||||
|         "settings": { | ||||
|             "heading": "Настройки веб-интерфейса", | ||||
|             "speechRecognitionLang": { | ||||
|                 "label": "Язык распознавания речи", | ||||
|                 "placeholder": "Выберите язык" | ||||
|             }, | ||||
|             "language": { | ||||
|                 "label": "Язык", | ||||
|                 "placeholder": "Выберите язык" | ||||
|             }, | ||||
|             "darkMode": { | ||||
|                 "label": "Сменить тему", | ||||
|                 "options": { | ||||
|                     "light": "Светлая", | ||||
|                     "dark": "Темная" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "webSearch": { | ||||
|             "heading": "Управление веб-поиском", | ||||
|             "searchMode": { | ||||
|                 "label": "Выполнить простой интернет-поиск" | ||||
|             }, | ||||
|             "provider": { | ||||
|                 "label": "Поисковый движок", | ||||
|                 "placeholder": "Выберите поисковый движок" | ||||
|             }, | ||||
|             "totalSearchResults": { | ||||
|                 "label": "Общее количество результатов поиска", | ||||
|                 "placeholder": "Введите общее количество результатов поиска" | ||||
|             } | ||||
|         }, | ||||
|         "system": { | ||||
|             "heading": "Настройки системы", | ||||
|             "deleteChatHistory": { | ||||
|                 "label": "Удалить историю чата", | ||||
|                 "button": "Удалить", | ||||
|                 "confirm": "Вы уверены, что хотите удалить историю чата? Это действие нельзя отменить." | ||||
|             }, | ||||
|             "export": { | ||||
|                 "label": "Экспорт истории чата, настроек и подсказок", | ||||
|                 "button": "Экспорт данных", | ||||
|                 "success": "Экспорт успешен" | ||||
|             }, | ||||
|             "import": { | ||||
|                 "label": "Импорт истории чата, настроек и подсказок", | ||||
|                 "button": "Импорт данных", | ||||
|                 "success": "Импорт успешен", | ||||
|                 "error": "Ошибка импорта" | ||||
|             } | ||||
|         }, | ||||
|         "tts": { | ||||
|             "heading": "Настройки текст в речь", | ||||
|             "ttsEnabled": { | ||||
|                 "label": "Включить текст в речь" | ||||
|             }, | ||||
|             "ttsProvider": { | ||||
|                 "label": "Поставщик текста в речь", | ||||
|                 "placeholder": "Выберите поставщика" | ||||
|             }, | ||||
|             "ttsVoice": { | ||||
|                 "label": "Голос текста в речь", | ||||
|                 "placeholder": "Выберите голос" | ||||
|             }, | ||||
|             "ssmlEnabled": { | ||||
|                 "label": "Включить SSML (язык разметки синтеза речи)" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "manageModels": { | ||||
|         "title": "Управление моделями", | ||||
|         "addBtn": "Добавить новую модель", | ||||
|         "columns": { | ||||
|             "name": "Название", | ||||
|             "digest": "Дайджест", | ||||
|             "modifiedAt": "Изменено", | ||||
|             "size": "Размер", | ||||
|             "actions": "Действия" | ||||
|         }, | ||||
|         "expandedColumns": { | ||||
|             "parentModel": "Родительская модель", | ||||
|             "format": "Формат", | ||||
|             "family": "Семейство", | ||||
|             "parameterSize": "Размер параметров", | ||||
|             "quantizationLevel": "Уровень квантования" | ||||
|         }, | ||||
|         "tooltip": { | ||||
|             "delete": "Удалить модель", | ||||
|             "repull": "Переполучить модель" | ||||
|         }, | ||||
|         "confirm": { | ||||
|             "delete": "Вы уверены, что хотите удалить эту модель?", | ||||
|             "repull": "Вы уверены, что хотите переполучить эту модель?" | ||||
|         }, | ||||
|         "modal": { | ||||
|             "title": "Добавить новую модель", | ||||
|             "placeholder": "Введите название модели", | ||||
|             "pull": "Получить модель" | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pullModel": "Получение модели", | ||||
|             "pullModelDescription": "Получение модели {{modelName}}. Для получения дополнительной информации проверьте значок расширения.", | ||||
|             "success": "Успех", | ||||
|             "error": "Ошибка", | ||||
|             "successDescription": "Модель успешно получена", | ||||
|             "successDeleteDescription": "Модель успешно удалена", | ||||
|             "someError": "Что-то пошло не так. Пожалуйста, попробуйте позже" | ||||
|         } | ||||
|     }, | ||||
|     "managePrompts": { | ||||
|         "title": "Управление подсказками", | ||||
|         "addBtn": "Добавить новую подсказку", | ||||
|         "option1": "Обычная", | ||||
|         "option2": "RAG", | ||||
|         "questionPrompt": "Вопросная подсказка", | ||||
|         "columns": { | ||||
|             "title": "Название", | ||||
|             "prompt": "Подсказка", | ||||
|             "type": "Тип подсказки", | ||||
|             "actions": "Действия" | ||||
|         }, | ||||
|         "systemPrompt": "Системная подсказка", | ||||
|         "quickPrompt": "Быстрая подсказка", | ||||
|         "tooltip": { | ||||
|             "delete": "Удалить подсказку", | ||||
|             "edit": "Редактировать подсказку" | ||||
|         }, | ||||
|         "confirm": { | ||||
|             "delete": "Вы уверены, что хотите удалить эту подсказку? Это действие нельзя отменить." | ||||
|         }, | ||||
|         "modal": { | ||||
|             "addTitle": "Добавить новую подсказку", | ||||
|             "editTitle": "Редактировать подсказку" | ||||
|         }, | ||||
|         "form": { | ||||
|             "title": { | ||||
|                 "label": "Название", | ||||
|                 "placeholder": "Моя замечательная подсказка", | ||||
|                 "required": "Пожалуйста, введите название" | ||||
|             }, | ||||
|             "prompt": { | ||||
|                 "label": "Подсказка", | ||||
|                 "placeholder": "Введите подсказку", | ||||
|                 "required": "Пожалуйста, введите подсказку", | ||||
|                 "help": "Вы можете использовать {key} в качестве переменной в своей подсказке." | ||||
|             }, | ||||
|             "isSystem": { | ||||
|                 "label": "Это системная подсказка" | ||||
|             }, | ||||
|             "btnSave": { | ||||
|                 "saving": "Добавление подсказки...", | ||||
|                 "save": "Добавить подсказку" | ||||
|             }, | ||||
|             "btnEdit": { | ||||
|                 "saving": "Обновление подсказки...", | ||||
|                 "save": "Обновить подсказку" | ||||
|             } | ||||
|         }, | ||||
|         "notification": { | ||||
|             "addSuccess": "Подсказка добавлена", | ||||
|             "addSuccessDesc": "Подсказка успешно добавлена", | ||||
|             "error": "Ошибка", | ||||
|             "someError": "Что-то пошло не так. Пожалуйста, попробуйте позже", | ||||
|             "updatedSuccess": "Подсказка обновлена", | ||||
|             "updatedSuccessDesc": "Подсказка успешно обновлена", | ||||
|             "deletedSuccess": "Подсказка удалена", | ||||
|             "deletedSuccessDesc": "Подсказка успешно удалена" | ||||
|         } | ||||
|     }, | ||||
|     "manageShare": { | ||||
|         "title": "Управление обменом", | ||||
|         "heading": "Настройка URL обмена страницей", | ||||
|         "form": { | ||||
|             "url": { | ||||
|                 "label": "URL обмена страницей", | ||||
|                 "placeholder": "Введите URL обмена страницей", | ||||
|                 "required": "Пожалуйста, введите ваш URL обмена страницей!", | ||||
|                 "help": "По соображениям конфиденциальности вы можете самостоятельно разместить страницу обмена и указать здесь URL. <anchor>Узнать больше</anchor>." | ||||
|             } | ||||
|         }, | ||||
|         "webshare": { | ||||
|             "heading": "Веб-обмен", | ||||
|             "columns": { | ||||
|                 "title": "Название", | ||||
|                 "url": "URL", | ||||
|                 "actions": "Действия" | ||||
|             }, | ||||
|             "tooltip": { | ||||
|                 "delete": "Удалить обмен" | ||||
|             }, | ||||
|             "confirm": { | ||||
|                 "delete": "Вы уверены, что хотите удалить этот обмен? Это действие нельзя отменить." | ||||
|             }, | ||||
|             "label": "Управление общим доступом к странице", | ||||
|             "description": "Включите или отключите функцию общего доступа к странице. По умолчанию функция общего доступа к странице включена." | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pageShareSuccess": "URL обмена страницей успешно обновлен", | ||||
|             "someError": "Что-то пошло не так. Пожалуйста, попробуйте позже", | ||||
|             "webShareDeleteSuccess": "Веб-обмен успешно удален" | ||||
|         } | ||||
|     }, | ||||
|     "ollamaSettings": { | ||||
|         "title": "Настройки Ollama", | ||||
|         "heading": "Настройка Ollama", | ||||
|         "settings": { | ||||
|             "ollamaUrl": { | ||||
|                 "label": "URL Ollama", | ||||
|                 "placeholder": "Введите URL Ollama" | ||||
|             }, | ||||
|             "ragSettings": { | ||||
|                 "label": "Настройки RAG", | ||||
|                 "model": { | ||||
|                     "label": "Модель вложения", | ||||
|                     "required": "Пожалуйста, выберите модель", | ||||
|                     "help": "Настоятельно рекомендуется использовать модели вложения, например, `nomic-embed-text`.", | ||||
|                     "placeholder": "Выберите модель" | ||||
|                 }, | ||||
|                 "chunkSize": { | ||||
|                     "label": "Размер фрагмента", | ||||
|                     "placeholder": "Введите размер фрагмента", | ||||
|                     "required": "Пожалуйста, введите размер фрагмента" | ||||
|                 }, | ||||
|                 "chunkOverlap": { | ||||
|                     "label": "Перекрытие фрагментов", | ||||
|                     "placeholder": "Введите перекрытие фрагментов", | ||||
|                     "required": "Пожалуйста, введите перекрытие фрагментов" | ||||
|                 } | ||||
|             }, | ||||
|             "prompt": { | ||||
|                 "label": "Настройка системной подсказки RAG", | ||||
|                 "option1": "Обычная", | ||||
|                 "option2": "Веб", | ||||
|                 "alert": "Настройка системной подсказки здесь устарела. Используйте раздел Управление подсказками для добавления или редактирования подсказок. Этот раздел будет удален в будущем выпуске", | ||||
|                 "systemPrompt": "Системная подсказка", | ||||
|                 "systemPromptPlaceholder": "Введите системную подсказку", | ||||
|                 "webSearchPrompt": "Подсказка для веб-поиска", | ||||
|                 "webSearchPromptHelp": "Не удаляйте `{search_results}` из подсказки.", | ||||
|                 "webSearchPromptError": "Пожалуйста, введите подсказку для веб-поиска", | ||||
|                 "webSearchPromptPlaceholder": "Введите подсказку для веб-поиска", | ||||
|                 "webSearchFollowUpPrompt": "Последующая подсказка для веб-поиска", | ||||
|                 "webSearchFollowUpPromptHelp": "Не удаляйте `{chat_history}` и `{question}` из подсказки.", | ||||
|                 "webSearchFollowUpPromptError": "Введите подсказку для последующего веб-поиска!", | ||||
|                 "webSearchFollowUpPromptPlaceholder": "Ваша подсказка для последующего веб-поиска" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "manageSearch": { | ||||
|         "title": "Управление веб-поиском", | ||||
|         "heading": "Настройка веб-поиска" | ||||
|     }, | ||||
|     "about": { | ||||
|         "title": "О программе", | ||||
|         "heading": "О программе", | ||||
|         "chromeVersion": "Версия Page Assist", | ||||
|         "ollamaVersion": "Версия Ollama", | ||||
|         "support": "Вы можете поддержать проект Page Assist, сделав пожертвование или спонсорирование через следующие платформы:", | ||||
|         "koFi": "Поддержать на Ko-fi", | ||||
|         "githubSponsor": "Стать спонсором на GitHub", | ||||
|         "githubRepo": "Репозиторий GitHub" | ||||
|     }, | ||||
|     "manageKnowledge": { | ||||
|         "title": "Управление знаниями", | ||||
|         "heading": "Настройка базы знаний" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								src/assets/locale/ru/sidepanel.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/assets/locale/ru/sidepanel.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| { | ||||
|     "tooltip": { | ||||
|         "embed": "Внедрение страницы может занять несколько минут. Пожалуйста, подождите...", | ||||
|         "clear": "Очистить историю чата", | ||||
|         "history": "История чата" | ||||
|     } | ||||
| } | ||||
| @ -197,7 +197,9 @@ | ||||
|             }, | ||||
|             "confirm": { | ||||
|                 "delete": "您确定要删除此对话共享吗?这个操作不能撤销。" | ||||
|             } | ||||
|             }, | ||||
|             "label": "管理页面分享", | ||||
|             "description": "启用或禁用页面分享功能。默认情况下,页面分享功能已启用。" | ||||
|         }, | ||||
|         "notification": { | ||||
|             "pageShareSuccess": "对话共享服务 URL 已成功更新", | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/onest.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/onest.ttf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -1,9 +1,19 @@ | ||||
| @font-face { | ||||
|   font-family: "font"; | ||||
|   src: url("font.ttf") format("truetype"); | ||||
|   font-family: "Inter"; | ||||
|   src: url("inter.ttf") format("truetype"); | ||||
| } | ||||
| * { | ||||
|   font-family: "font" !important; | ||||
| 
 | ||||
| @font-face { | ||||
|   font-family: "Onest"; | ||||
|   src: url("onest.ttf") format("truetype"); | ||||
| } | ||||
| 
 | ||||
| .inter { | ||||
|   font-family: "Inter", sans-serif !important; | ||||
| } | ||||
| 
 | ||||
| .onest { | ||||
|   font-family: "Onest", sans-serif !important; | ||||
| } | ||||
| 
 | ||||
| @tailwind base; | ||||
| @ -62,6 +72,6 @@ | ||||
| 
 | ||||
| /* Hide scrollbar for IE, Edge and Firefox */ | ||||
| .no-scrollbar { | ||||
|   -ms-overflow-style: none;  /* IE and Edge */ | ||||
|   scrollbar-width: none;  /* Firefox */ | ||||
|   -ms-overflow-style: none; /* IE and Edge */ | ||||
|   scrollbar-width: none; /* Firefox */ | ||||
| } | ||||
| @ -20,6 +20,7 @@ import { ShareBtn } from "~/components/Common/ShareBtn" | ||||
| import { useTranslation } from "react-i18next" | ||||
| import { OllamaIcon } from "../Icons/Ollama" | ||||
| import { SelectedKnowledge } from "../Option/Knowledge/SelectedKnwledge" | ||||
| import { useStorage } from "@plasmohq/storage/hook" | ||||
| 
 | ||||
| export default function OptionLayout({ | ||||
|   children | ||||
| @ -28,6 +29,7 @@ export default function OptionLayout({ | ||||
| }) { | ||||
|   const [sidebarOpen, setSidebarOpen] = useState(false) | ||||
|   const { t } = useTranslation(["option", "common"]) | ||||
|   const [shareModeEnabled] = useStorage("shareMode", true) | ||||
| 
 | ||||
|   const { | ||||
|     selectedModel, | ||||
| @ -107,7 +109,7 @@ export default function OptionLayout({ | ||||
|               <div> | ||||
|                 <Select | ||||
|                   value={selectedModel} | ||||
|                   onChange={(e) =>  { | ||||
|                   onChange={(e) => { | ||||
|                     setSelectedModel(e) | ||||
|                     localStorage.setItem("selectedModel", e) | ||||
|                   }} | ||||
| @ -175,9 +177,10 @@ export default function OptionLayout({ | ||||
|             <div className="flex flex-1 justify-end px-4"> | ||||
|               <div className="ml-4 flex items-center md:ml-6"> | ||||
|                 <div className="flex gap-4 items-center"> | ||||
|                   {pathname === "/" && messages.length > 0 && !streaming && ( | ||||
|                     <ShareBtn messages={messages} /> | ||||
|                   )} | ||||
|                   {pathname === "/" && | ||||
|                     messages.length > 0 && | ||||
|                     !streaming && | ||||
|                     shareModeEnabled && <ShareBtn messages={messages} />} | ||||
|                   <Tooltip title={t("githubRepository")}> | ||||
|                     <a | ||||
|                       href="https://github.com/n4ze3m/page-assist" | ||||
|  | ||||
| @ -1,15 +1,17 @@ | ||||
| import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" | ||||
| import { Form, Input, Skeleton, Table, Tooltip, message } from "antd" | ||||
| import { Form, Input, Skeleton, Switch, Table, Tooltip, message } from "antd" | ||||
| import { Trash2 } from "lucide-react" | ||||
| import { Trans, useTranslation } from "react-i18next" | ||||
| import { SaveButton } from "~/components/Common/SaveButton" | ||||
| import { deleteWebshare, getAllWebshares, getUserId } from "@/db" | ||||
| import { getPageShareUrl, setPageShareUrl } from "~/services/ollama" | ||||
| import { verifyPageShareURL } from "~/utils/verify-page-share" | ||||
| import { useStorage } from "@plasmohq/storage/hook" | ||||
| 
 | ||||
| export const OptionShareBody = () => { | ||||
|   const queryClient = useQueryClient() | ||||
|   const { t } = useTranslation(["settings"]) | ||||
|   const [shareModeEnabled, setShareModelEnabled] = useStorage("shareMode", true) | ||||
| 
 | ||||
|   const { status, data } = useQuery({ | ||||
|     queryKey: ["fetchShareInfo"], | ||||
| @ -132,6 +134,20 @@ export const OptionShareBody = () => { | ||||
|                 </div> | ||||
|               </Form.Item> | ||||
|             </Form> | ||||
|             <div className="space-y-2 flex mb-4 flex-row items-center justify-between rounded-lg  dark:border-gray-600 "> | ||||
|               <div className="space-y-0.5"> | ||||
|                 <label className="text-sm font-semibold leading-5 text-gray-900 dark:text-white"> | ||||
|                   {t("manageShare.webshare.label")} | ||||
|                 </label> | ||||
|                 <p className="text-sm font-normal leading-5 text-gray-500 dark:text-gray-400"> | ||||
|                   {t("manageShare.webshare.description")} | ||||
|                 </p> | ||||
|               </div> | ||||
|               <Switch | ||||
|                 checked={shareModeEnabled} | ||||
|                 onChange={setShareModelEnabled} | ||||
|               /> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div> | ||||
|             <div> | ||||
|  | ||||
| @ -11,13 +11,16 @@ import { PageAssistProvider } from "@/components/Common/PageAssistProvider" | ||||
| 
 | ||||
| function IndexOption() { | ||||
|   const { mode } = useDarkMode() | ||||
|   const { t } = useTranslation() | ||||
|   const { t, i18n } = useTranslation() | ||||
|   return ( | ||||
|     <MemoryRouter> | ||||
|       <ConfigProvider | ||||
|         theme={{ | ||||
|           algorithm: | ||||
|             mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm | ||||
|             mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm, | ||||
|           token: { | ||||
|             fontFamily: i18n.language === "ru" ? "Onest" : "Inter" | ||||
|           } | ||||
|         }} | ||||
|         renderEmpty={() => ( | ||||
|           <Empty | ||||
|  | ||||
| @ -11,14 +11,17 @@ import { PageAssistProvider } from "@/components/Common/PageAssistProvider" | ||||
| 
 | ||||
| function IndexSidepanel() { | ||||
|   const { mode } = useDarkMode() | ||||
|   const { t } = useTranslation() | ||||
|   const { t, i18n } = useTranslation() | ||||
| 
 | ||||
|   return ( | ||||
|     <MemoryRouter> | ||||
|       <ConfigProvider | ||||
|         theme={{ | ||||
|           algorithm: | ||||
|             mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm | ||||
|             mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm, | ||||
|           token: { | ||||
|             fontFamily: i18n.language === "ru" ? "Onest" : "Inter" | ||||
|           } | ||||
|         }} | ||||
|         renderEmpty={() => ( | ||||
|           <Empty | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import i18n from "i18next"; | ||||
| import { initReactI18next } from "react-i18next"; | ||||
| import { en } from "./lang/en"; | ||||
| import { ru } from "./lang/ru"; | ||||
| import { ml } from "./lang/ml"; | ||||
| import { zh } from "./lang/zh"; | ||||
| import { ja } from "./lang/ja"; | ||||
| @ -14,6 +15,8 @@ i18n | ||||
|             en: en, | ||||
|             ml: ml, | ||||
|             "zh-CN": zh, | ||||
|             ru: ru, | ||||
|             "ru-RU": ru, | ||||
|             zh: zh, | ||||
|             ja: ja, | ||||
|             "ja-JP": ja | ||||
|  | ||||
							
								
								
									
										15
									
								
								src/i18n/lang/ru.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/i18n/lang/ru.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| import option from "@/assets/locale/ru/option.json"; | ||||
| import playground from "@/assets/locale/ru/playground.json"; | ||||
| import common from "@/assets/locale/ru/common.json"; | ||||
| import sidepanel from "@/assets/locale/ru/sidepanel.json"; | ||||
| import settings from "@/assets/locale/ru/settings.json"; | ||||
| import knowledge from "@/assets/locale/ru/knowledge.json"; | ||||
| 
 | ||||
| export const ru = { | ||||
|     option, | ||||
|     playground, | ||||
|     common, | ||||
|     sidepanel, | ||||
|     settings, | ||||
|     knowledge | ||||
| } | ||||
| @ -4,6 +4,10 @@ export const supportLanguage = [ | ||||
|         label: "English", | ||||
|         value: "en" | ||||
|     }, | ||||
|     { | ||||
|         label: "Russian", | ||||
|         value: "ru" | ||||
|     },     | ||||
|     { | ||||
|         label: "മലയാളം", | ||||
|         value: "ml" | ||||
|  | ||||
							
								
								
									
										11
									
								
								src/public/_locales/ru/messages.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/public/_locales/ru/messages.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| { | ||||
|     "extName": { | ||||
|         "message": "Page Assist - Веб-интерфейс для локальных моделей искусственного интеллекта" | ||||
|     }, | ||||
|     "extDescription": { | ||||
|         "message": "Используйте запущенные локально модели искусственного интеллекта для помощи в веб-просмотре." | ||||
|     }, | ||||
|     "openSidePanelToChat": { | ||||
|         "message": "Открыть Copilot для чата" | ||||
|     } | ||||
| } | ||||
| @ -10,12 +10,17 @@ import { OptionSettings } from "./option-settings" | ||||
| import { OptionShare } from "./option-settings-share" | ||||
| import { OptionKnowledgeBase } from "./option-settings-knowledge" | ||||
| import { OptionAbout } from "./option-settings-about" | ||||
| import { useTranslation } from "react-i18next" | ||||
| 
 | ||||
| export const OptionRouting = () => { | ||||
|   const { mode } = useDarkMode() | ||||
|   const { i18n } = useTranslation() | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={mode === "dark" ? "dark" : "light"}> | ||||
|     <div | ||||
|       className={`${mode === "dark" ? "dark" : "light"} ${ | ||||
|         i18n.language === "ru" ? "onest" : "inter" | ||||
|       }`}>
 | ||||
|       <Routes> | ||||
|         <Route path="/" element={<OptionIndex />} /> | ||||
|         <Route path="/settings" element={<OptionSettings />} /> | ||||
| @ -32,9 +37,13 @@ export const OptionRouting = () => { | ||||
| 
 | ||||
| export const SidepanelRouting = () => { | ||||
|   const { mode } = useDarkMode() | ||||
|   const { i18n } = useTranslation() | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={mode === "dark" ? "dark" : "light"}> | ||||
|     <div | ||||
|       className={`${mode === "dark" ? "dark" : "light"} ${ | ||||
|         i18n.language === "ru" ? "onest" : "inter" | ||||
|       }`}>
 | ||||
|       <Routes> | ||||
|         <Route path="/" element={<SidepanelChat />} /> | ||||
|         <Route path="/settings" element={<SidepanelSettings />} /> | ||||
|  | ||||
| @ -6,5 +6,9 @@ export const SUPPORTED_SERACH_PROVIDERS = [ | ||||
|     { | ||||
|         label: "DuckDuckGo", | ||||
|         value: "duckduckgo" | ||||
|     }, | ||||
|     { | ||||
|         label: "Sogou", | ||||
|         value: "sogou" | ||||
|     } | ||||
| ] | ||||
							
								
								
									
										127
									
								
								src/web/search-engines/sogou.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/web/search-engines/sogou.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| import { cleanUrl } from "@/libs/clean-url" | ||||
| import { chromeRunTime } from "@/libs/runtime" | ||||
| import { PageAssistHtmlLoader } from "@/loader/html" | ||||
| import { | ||||
|   defaultEmbeddingChunkOverlap, | ||||
|   defaultEmbeddingChunkSize, | ||||
|   defaultEmbeddingModelForRag, | ||||
|   getOllamaURL | ||||
| } from "@/services/ollama" | ||||
| import { | ||||
|   getIsSimpleInternetSearch, | ||||
|   totalSearchResults | ||||
| } from "@/services/search" | ||||
| import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama" | ||||
| import type { Document } from "@langchain/core/documents" | ||||
| import * as cheerio from "cheerio" | ||||
| import { RecursiveCharacterTextSplitter } from "langchain/text_splitter" | ||||
| import { MemoryVectorStore } from "langchain/vectorstores/memory" | ||||
| const getCorrectTargeUrl = async (url: string) => { | ||||
|   if (!url) return "" | ||||
|   const res = await fetch(url) | ||||
|   const $ = cheerio.load(await res.text()) | ||||
|   const link = $("script").text() | ||||
|   const matches = link.match(/"(.*?)"/) | ||||
|   return matches?.[1] || "" | ||||
| } | ||||
| export const localSogouSearch = async (query: string) => { | ||||
|   await chromeRunTime(cleanUrl("https://www.sogou.com/web?query=" + query)) | ||||
| 
 | ||||
|   const abortController = new AbortController() | ||||
| 
 | ||||
|   setTimeout(() => abortController.abort(), 10000) | ||||
| 
 | ||||
|   const htmlString = await fetch("https://www.sogou.com/web?query=" + query, { | ||||
|     signal: abortController.signal | ||||
|   }) | ||||
|     .then((response) => response.text()) | ||||
|     .catch() | ||||
| 
 | ||||
|   const $ = cheerio.load(htmlString) | ||||
|   const $result = $("#main .results") | ||||
|   const nodes = $result.children().map(async (i, el) => { | ||||
|     const $el = $(el) | ||||
|     const title = $el.find(".vr-title").text().replace(/\n/g, "").trim() | ||||
|     let link = $el.find(".vr-title > a").get(0)?.attribs.href | ||||
|     const content = [".star-wiki", ".fz-mid", ".attribute-centent"] | ||||
|       .map((selector) => { | ||||
|         ;[".text-lightgray", ".zan-box", ".tag-website"].forEach((cls) => { | ||||
|           $el.find(cls).remove() | ||||
|         }) | ||||
|         return $el.find(selector).text().trim() ?? "" | ||||
|       }) | ||||
|       .join(" ") | ||||
|     if (link?.startsWith("/")) { | ||||
|       link = await getCorrectTargeUrl(`https://www.sogou.com${link}`) | ||||
|     } | ||||
|     return { title, link, content } | ||||
|   }) | ||||
| 
 | ||||
|   const searchResults = await Promise.all(nodes) | ||||
|   return searchResults.filter( | ||||
|     (result) => result.link && result.title && result.content | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| export const webSogouSearch = async (query: string) => { | ||||
|   const results = await localSogouSearch(query) | ||||
|   const TOTAL_SEARCH_RESULTS = await totalSearchResults() | ||||
|   const searchResults = results.slice(0, TOTAL_SEARCH_RESULTS) | ||||
| 
 | ||||
|   const isSimpleMode = await getIsSimpleInternetSearch() | ||||
| 
 | ||||
|   if (isSimpleMode) { | ||||
|     await getOllamaURL() | ||||
|     return searchResults.map((result) => { | ||||
|       return { | ||||
|         url: result.link, | ||||
|         content: result.content | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   const docs: Document<Record<string, any>>[] = [] | ||||
|   for (const result of searchResults) { | ||||
|     const loader = new PageAssistHtmlLoader({ | ||||
|       html: "", | ||||
|       url: result.link | ||||
|     }) | ||||
| 
 | ||||
|     const documents = await loader.loadByURL() | ||||
| 
 | ||||
|     documents.forEach((doc) => { | ||||
|       docs.push(doc) | ||||
|     }) | ||||
|   } | ||||
|   const ollamaUrl = await getOllamaURL() | ||||
| 
 | ||||
|   const embeddingModle = await defaultEmbeddingModelForRag() | ||||
|   const ollamaEmbedding = new OllamaEmbeddings({ | ||||
|     model: embeddingModle || "", | ||||
|     baseUrl: cleanUrl(ollamaUrl) | ||||
|   }) | ||||
| 
 | ||||
|   const chunkSize = await defaultEmbeddingChunkSize() | ||||
|   const chunkOverlap = await defaultEmbeddingChunkOverlap() | ||||
|   const textSplitter = new RecursiveCharacterTextSplitter({ | ||||
|     chunkSize, | ||||
|     chunkOverlap | ||||
|   }) | ||||
| 
 | ||||
|   const chunks = await textSplitter.splitDocuments(docs) | ||||
| 
 | ||||
|   const store = new MemoryVectorStore(ollamaEmbedding) | ||||
| 
 | ||||
|   await store.addDocuments(chunks) | ||||
| 
 | ||||
|   const resultsWithEmbeddings = await store.similaritySearch(query, 3) | ||||
| 
 | ||||
|   const searchResult = resultsWithEmbeddings.map((result) => { | ||||
|     return { | ||||
|       url: result.metadata.url, | ||||
|       content: result.pageContent | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   return searchResult | ||||
| } | ||||
| @ -1,7 +1,8 @@ | ||||
| import { getWebSearchPrompt } from "~/services/ollama" | ||||
| import { webGoogleSearch } from "./local-google" | ||||
| import { webDuckDuckGoSearch } from "./local-duckduckgo" | ||||
| import { webGoogleSearch } from "./search-engines/google" | ||||
| import { webDuckDuckGoSearch } from "./search-engines/duckduckgo" | ||||
| import { getSearchProvider } from "@/services/search" | ||||
| import { webSogouSearch } from "./search-engines/sogou" | ||||
| 
 | ||||
| const getHostName = (url: string) => { | ||||
|   try { | ||||
| @ -16,6 +17,8 @@ const searchWeb = (provider: string, query: string) => { | ||||
|   switch (provider) { | ||||
|     case "duckduckgo": | ||||
|       return webDuckDuckGoSearch(query) | ||||
|     case "sogou": | ||||
|       return webSogouSearch(query) | ||||
|     default: | ||||
|       return webGoogleSearch(query) | ||||
|   } | ||||
|  | ||||
| @ -24,7 +24,7 @@ export default defineConfig({ | ||||
|   srcDir: "src", | ||||
|   outDir: "build", | ||||
|   manifest: { | ||||
|     version: "1.1.4", | ||||
|     version: "1.1.5", | ||||
|     name: '__MSG_extName__', | ||||
|     description: '__MSG_extDescription__', | ||||
|     default_locale: 'en', | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user