commit
ba654f9574
@ -21,6 +21,7 @@
|
||||
"@langchain/community": "^0.0.41",
|
||||
"@mantine/form": "^7.5.0",
|
||||
"@mantine/hooks": "^7.5.3",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@plasmohq/storage": "^1.9.0",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
|
@ -37,6 +37,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "Total Search Results",
|
||||
"placeholder": "Enter Total Search Results"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Visit the website mentioned in the message"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
88
src/assets/locale/es/common.json
Normal file
88
src/assets/locale/es/common.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"pageAssist": "Page Assist",
|
||||
"selectAModel": "Selecione un Modelo",
|
||||
"save": "Guardar",
|
||||
"saved": "Guardado",
|
||||
"cancel": "Cancelar",
|
||||
"retry": "Reintentar",
|
||||
"share": {
|
||||
"tooltip": {
|
||||
"share": "Compartir"
|
||||
},
|
||||
"modal": {
|
||||
"title": "Compartir enlace para chat"
|
||||
},
|
||||
"form": {
|
||||
"defaultValue": {
|
||||
"name": "Anónimo",
|
||||
"title": "Chat sin título"
|
||||
},
|
||||
"title": {
|
||||
"label": "Título del Chat",
|
||||
"placeholder": "Ingresar el título del Chat",
|
||||
"required": "El título del Chat es obligatorio"
|
||||
},
|
||||
"name": {
|
||||
"label": "Tu nombre",
|
||||
"placeholder": "Ingresar tu nombre",
|
||||
"required": "Tu nombre es obligatorio"
|
||||
},
|
||||
"btn": {
|
||||
"save": "Generar enlace",
|
||||
"saving": "Generando enlace..."
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"successGenerate": "Enlace copiado al Clipboard",
|
||||
"failGenerate": "Fallo al generar el enlace"
|
||||
}
|
||||
},
|
||||
"copyToClipboard": "Copiar al clipboard",
|
||||
"webSearch": "Buscando en la web",
|
||||
"regenerate": "Regenerar",
|
||||
"edit": "Editar",
|
||||
"saveAndSubmit": "Guardar y Enviar",
|
||||
"editMessage": {
|
||||
"placeholder": "Ingresar un mensaje..."
|
||||
},
|
||||
"submit": "Enviar",
|
||||
"noData": "Sin datos",
|
||||
"noHistory": "Chat sin histórico",
|
||||
"chatWithCurrentPage": "Conversar con la página actual",
|
||||
"beta": "Beta",
|
||||
"tts": "Leer en voz alta",
|
||||
"currentChatModelSettings": "Configuraciones del Modelo de Chat Actual",
|
||||
"modelSettings": {
|
||||
"label": "Configuraciones del Modelo",
|
||||
"description": "Definir las opciones del modelo globalmente para todos los chats",
|
||||
"form": {
|
||||
"keepAlive": {
|
||||
"label": "Mantener vivo",
|
||||
"help": "controlar cuanto tiempo el modelo permanecera cargado en la memoria luego de su utilización (por defecto: 5m)",
|
||||
"placeholder": "Ingresar duración para mantenerlo vivo (ej: 5m, 10m, 1h)"
|
||||
},
|
||||
"temperature": {
|
||||
"label": "Temperatura",
|
||||
"placeholder": "Ingresar valor de la Temperatura (ej: 0.7, 1.0)"
|
||||
},
|
||||
"numCtx": {
|
||||
"label": "Cantidad de contextos",
|
||||
"placeholder": "Ingresar el valor de tamaño de la ventana de contexto (por defecto: 2048)"
|
||||
},
|
||||
"seed": {
|
||||
"label": "Semilla",
|
||||
"placeholder": "Ingresar el valor de la semilla (ej: 1234)",
|
||||
"help": "Reproductibilidad de la salida del modelo"
|
||||
},
|
||||
"topK": {
|
||||
"label": "Top K",
|
||||
"placeholder": "Ingresar el valor de Top K (ej: 40, 100)"
|
||||
},
|
||||
"topP": {
|
||||
"label": "Top P",
|
||||
"placeholder": "Ingresar el valor de Top P (ej: 0.9, 0.95)"
|
||||
}
|
||||
},
|
||||
"advanced": "Más Configuraciones del Modelo"
|
||||
}
|
||||
}
|
42
src/assets/locale/es/knowledge.json
Normal file
42
src/assets/locale/es/knowledge.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"addBtn": "Agregar Nuevo Conocimiento",
|
||||
"columns": {
|
||||
"title": "Título",
|
||||
"status": "Estado",
|
||||
"embeddings": "Modelo de Embedding",
|
||||
"createdAt": "Creado",
|
||||
"action": "Acciones"
|
||||
},
|
||||
"expandedColumns": {
|
||||
"name": "Nombre"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Borrar"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "¿Esta seguro que desea borrar este conocimiento?"
|
||||
},
|
||||
"deleteSuccess": "Conocimiento borrado",
|
||||
"status": {
|
||||
"pending": "Pendiente",
|
||||
"finished": "Finalizado",
|
||||
"processing": "Procesando"
|
||||
},
|
||||
"addKnowledge": "Agregar Conocimiento",
|
||||
"form": {
|
||||
"title": {
|
||||
"label": "Título del Conocimiento",
|
||||
"placeholder": "Ingresar un título de conocimiento",
|
||||
"required": "El Título de conocimiento es obligatorio"
|
||||
},
|
||||
"uploadFile": {
|
||||
"label": "Subir un Archivo",
|
||||
"uploadText": "Arraste y suelte un archivo aquí o haga click para subirlo",
|
||||
"uploadHint": "Tipos de archivo soportados: .pdf, .csv, .txt, .md, .docx",
|
||||
"required": "El archivo es obligatorio"
|
||||
},
|
||||
"submit": "Enviar",
|
||||
"success": "Conocimiento agregado exitosamente"
|
||||
},
|
||||
"noEmbeddingModel": "Por favor, agregue un modelo de embedding de la página de configuraciones de RAG primero"
|
||||
}
|
12
src/assets/locale/es/option.json
Normal file
12
src/assets/locale/es/option.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"newChat": "Nuevo Chat",
|
||||
"selectAPrompt": "Selecione un Prompt",
|
||||
"githubRepository": "Repositorio de GitHub",
|
||||
"settings": "Configuraciones",
|
||||
"sidebarTitle": "Histórico del Chat",
|
||||
"error": "Error",
|
||||
"somethingWentWrong": "Hubo un error",
|
||||
"validationSelectModel": "Selecione un modelo para continuar",
|
||||
"deleteHistoryConfirmation": "¿Esta seguro que quiere borrar éste histórico?",
|
||||
"editHistoryTitle": "Ingrese un nuevo título"
|
||||
}
|
29
src/assets/locale/es/playground.json
Normal file
29
src/assets/locale/es/playground.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"ollamaState": {
|
||||
"searching": "Buscando tu Ollama 🦙",
|
||||
"running": "Ollama está funcionando 🦙",
|
||||
"notRunning": "No fue posible conectar con Ollama 🦙",
|
||||
"connectionError": "Hubo un error de conexión. Por favor, consulte la <anchor>documentación</anchor> para solucionar el problema."
|
||||
},
|
||||
"formError": {
|
||||
"noModel": "Por favor, selecione un modelo",
|
||||
"noEmbeddingModel": "Por favor, defina un modelo de embedding para la página de configuraciones > RAG"
|
||||
},
|
||||
"form": {
|
||||
"textarea": {
|
||||
"placeholder": "Ingrese un mensaje..."
|
||||
},
|
||||
"webSearch": {
|
||||
"on": "On",
|
||||
"off": "Off"
|
||||
}
|
||||
},
|
||||
"tooltip": {
|
||||
"searchInternet": "Buscar en Internet",
|
||||
"speechToText": "Voz a Texto",
|
||||
"uploadImage": "Subir Imagén",
|
||||
"stopStreaming": "Parar Transmisión",
|
||||
"knowledge": "Conocimiento"
|
||||
},
|
||||
"sendWhenEnter": "Enviar cuando presione Enter"
|
||||
}
|
292
src/assets/locale/es/settings.json
Normal file
292
src/assets/locale/es/settings.json
Normal file
@ -0,0 +1,292 @@
|
||||
{
|
||||
"generalSettings": {
|
||||
"title": "Configuraciones Generales",
|
||||
"settings": {
|
||||
"heading": "Configuraciones de la Interfaz Web",
|
||||
"speechRecognitionLang": {
|
||||
"label": "Idioma de Reconocimiento de Voz",
|
||||
"placeholder": "Selecione un idioma"
|
||||
},
|
||||
"language": {
|
||||
"label": "Idioma",
|
||||
"placeholder": "Selecione un idioma"
|
||||
},
|
||||
"darkMode": {
|
||||
"label": "Cambiar Tema",
|
||||
"options": {
|
||||
"light": "Claro",
|
||||
"dark": "Oscuro"
|
||||
}
|
||||
},
|
||||
"copilotResumeLastChat": {
|
||||
"label": "Retomar el último chat al abrir el Panel Lateral (Copilot)"
|
||||
},
|
||||
"hideCurrentChatModelSettings": {
|
||||
"label": "Ocultar Configuraciones del Modelo de Chat Actual"
|
||||
}
|
||||
},
|
||||
"webSearch": {
|
||||
"heading": "Manejo de la busqueda Web",
|
||||
"searchMode": {
|
||||
"label": "Realizar busquedas Simples en Internet"
|
||||
},
|
||||
"provider": {
|
||||
"label": "Motor de Busqueda",
|
||||
"placeholder": "Selecione un motor de busqueda"
|
||||
},
|
||||
"totalSearchResults": {
|
||||
"label": "Resultados totales de la busqueda",
|
||||
"placeholder": "Ingresar el total de Resultados de la busqueda"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Visita el sitio web mencionado en el mensaje"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"heading": "Configuraciones del Sistema",
|
||||
"deleteChatHistory": {
|
||||
"label": "Borrar Histórico del Chat",
|
||||
"button": "Borrar",
|
||||
"confirm": "¿Esta seguro que desea borrar su histórico del chat? Esta acción no podra ser desecha."
|
||||
},
|
||||
"export": {
|
||||
"label": "Exportar Histórico del Chat, Base de Conocimiento y Prompts",
|
||||
"button": "Exportar Datos",
|
||||
"success": "Exportación exitosa"
|
||||
},
|
||||
"import": {
|
||||
"label": "Importar Histórico del Chat, Base de Conocimiento y Prompts",
|
||||
"button": "Importar Datos",
|
||||
"success": "Importación existosa",
|
||||
"error": "Error de importación"
|
||||
}
|
||||
},
|
||||
"tts": {
|
||||
"heading": "Configuraciones de Text-to-speech",
|
||||
"ttsEnabled": {
|
||||
"label": "Habilitar Texto-a-Voz"
|
||||
},
|
||||
"ttsProvider": {
|
||||
"label": "Proveedor de Text-to-speech",
|
||||
"placeholder": "Selecione un proveedor"
|
||||
},
|
||||
"ttsVoice": {
|
||||
"label": "Voz de Text-to-speech",
|
||||
"placeholder": "Selecione una voz"
|
||||
},
|
||||
"ssmlEnabled": {
|
||||
"label": "Habilitar SSML (Speech Synthesis Markup Language)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"manageModels": {
|
||||
"title": "Administar de Modelos",
|
||||
"addBtn": "Agregar Nuevo Modelo",
|
||||
"columns": {
|
||||
"name": "Nombre",
|
||||
"digest": "Resumen",
|
||||
"modifiedAt": "Modificado",
|
||||
"size": "Tamaño",
|
||||
"actions": "Acciones"
|
||||
},
|
||||
"expandedColumns": {
|
||||
"parentModel": "Modelo Padre",
|
||||
"format": "Formato",
|
||||
"family": "Familia",
|
||||
"parameterSize": "Tamaño de Parametros",
|
||||
"quantizationLevel": "Nível de Quantización"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Borrar Modelo",
|
||||
"repull": "Traer nuevamente el Modelo"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "¿Esta seguro que desea borrar este modelos?",
|
||||
"repull": "¿Esta seguro que desea traer nuevamente este modelo?"
|
||||
},
|
||||
"modal": {
|
||||
"title": "Traer Nuevo Modelo",
|
||||
"placeholder": "Ingresar el nombre del modelo",
|
||||
"pull": "Traer Modelo"
|
||||
},
|
||||
"notification": {
|
||||
"pullModel": "Trayendo Modelo",
|
||||
"pullModelDescription": "Trayendo modelo {{modelName}}. Para más detalles, verifique el ícono de la extensión.",
|
||||
"success": "Exito",
|
||||
"error": "Error",
|
||||
"successDescription": "Modelo traido exitosamente",
|
||||
"successDeleteDescription": "Modelo borrado exitosamente",
|
||||
"someError": "Hubo un error. Intente nuevamente más tarde"
|
||||
}
|
||||
},
|
||||
"managePrompts": {
|
||||
"title": "Administrar de Prompts",
|
||||
"addBtn": "Agregar Nuevo Prompt",
|
||||
"option1": "Normal",
|
||||
"option2": "RAG",
|
||||
"questionPrompt": "Prompt de Pregunta",
|
||||
"columns": {
|
||||
"title": "Título",
|
||||
"prompt": "Prompt",
|
||||
"type": "Tipo de Prompt",
|
||||
"actions": "Acciones"
|
||||
},
|
||||
"systemPrompt": "Prompt del Sistema",
|
||||
"quickPrompt": "Prompt Rápido",
|
||||
"tooltip": {
|
||||
"delete": "Borrar Prompt",
|
||||
"edit": "Editar Prompt"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "¿Esta seguro que desea borrar este prompt? Esta acción no tiene vuelta a atrás."
|
||||
},
|
||||
"modal": {
|
||||
"addTitle": "Agregar Nuevo Prompt",
|
||||
"editTitle": "Editar Prompt"
|
||||
},
|
||||
"form": {
|
||||
"title": {
|
||||
"label": "Título",
|
||||
"placeholder": "Mi Prompt genial",
|
||||
"required": "Por favor, ingrese un título"
|
||||
},
|
||||
"prompt": {
|
||||
"label": "Prompt",
|
||||
"placeholder": "Ingrese un prompt",
|
||||
"required": "Por favor, ingrese un prompt",
|
||||
"help": "Puede usar {key} como variable en su prompt."
|
||||
},
|
||||
"isSystem": {
|
||||
"label": "Es un Prompt del Sistema"
|
||||
},
|
||||
"btnSave": {
|
||||
"saving": "Agregando un Prompt...",
|
||||
"save": "Agregar Prompt"
|
||||
},
|
||||
"btnEdit": {
|
||||
"saving": "Actualizando Prompt...",
|
||||
"save": "Actualizar Prompt"
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"addSuccess": "Prompt Agregado",
|
||||
"addSuccessDesc": "Prompt agregado exitosamente",
|
||||
"error": "Error",
|
||||
"someError": "Hubo un error. Intente nuevamente más tarde",
|
||||
"updatedSuccess": "Prompt Actualizado",
|
||||
"updatedSuccessDesc": "Prompt actualizado exitosamente",
|
||||
"deletedSuccess": "Prompt Borrado",
|
||||
"deletedSuccessDesc": "Prompt borrado exitosamente"
|
||||
}
|
||||
},
|
||||
"manageShare": {
|
||||
"title": "Administrar los recursos compartidos",
|
||||
"heading": "Configurar URL de Página Compartida",
|
||||
"form": {
|
||||
"url": {
|
||||
"label": "URL de Página compartida",
|
||||
"placeholder": "Ingresar URL de Página compartida",
|
||||
"required": "Por favor, ingrese URL de Página compartida",
|
||||
"help": "Por motivos de privacidad, podes hacer self-host de la página compartida y proveer una URL aqui. <anchor>Aprende más</anchor>."
|
||||
}
|
||||
},
|
||||
"webshare": {
|
||||
"heading": "Compartir una Web",
|
||||
"columns": {
|
||||
"title": "Título",
|
||||
"url": "URL",
|
||||
"actions": "Acciones"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Borrar lo compartido"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "¿Esta seguro de desear borrar esta web compartida? Esta acción no tiene vuelta a atrás."
|
||||
},
|
||||
"label": "Administrar páginas compartidas",
|
||||
"description": "Habilitar o deshabilitar el recurso de páginas compartidas"
|
||||
},
|
||||
"notification": {
|
||||
"pageShareSuccess": "URL compartida actualizada exitosamente",
|
||||
"someError": "Hubo un error. Intente nuevamente más tarde",
|
||||
"webShareDeleteSuccess": "Web compartida borrada exitosamente com sucesso"
|
||||
}
|
||||
},
|
||||
"ollamaSettings": {
|
||||
"title": "Configuraciones de Ollama",
|
||||
"heading": "Configurar Ollama",
|
||||
"settings": {
|
||||
"ollamaUrl": {
|
||||
"label": "URL de Ollama",
|
||||
"placeholder": "Ingrese la URL de Ollama"
|
||||
},
|
||||
"advanced": {
|
||||
"label": "Configuración avanzada de URL de Ollama",
|
||||
"urlRewriteEnabled": {
|
||||
"label": "Habilitar o Deshabilitar URL Personalizada"
|
||||
},
|
||||
"rewriteUrl": {
|
||||
"label": "URL Personalizada",
|
||||
"placeholder": "Ingresar URL Personalizada"
|
||||
},
|
||||
"help": "Si tenes problemas de conexión con Ollama en Page Assist, podes configurar una URL de personalizada. Para saber más sobre la configuración, <anchor>click aqui</anchor>."
|
||||
}
|
||||
}
|
||||
},
|
||||
"manageSearch": {
|
||||
"title": "Administrar Busqueda Web",
|
||||
"heading": "Configurar Busqueda Web"
|
||||
},
|
||||
"about": {
|
||||
"title": "Sobre",
|
||||
"heading": "Sobre",
|
||||
"chromeVersion": "Versión de Page Assist",
|
||||
"ollamaVersion": "Versión de Ollama",
|
||||
"support": "Podes apoyar el proyecto Page Assist haciendo donaciones o patrocinarnos a través de las seguientes plataformas:",
|
||||
"koFi": "Apoyar en Ko-fi",
|
||||
"githubSponsor": "Patrocinarnos en GitHub",
|
||||
"githubRepo": "Repositorio de GitHub"
|
||||
},
|
||||
"manageKnowledge": {
|
||||
"title": "Administrar Conocimiento",
|
||||
"heading": "Configurar Bases de Conocimiento"
|
||||
},
|
||||
"rag": {
|
||||
"title": "Configuraciones de RAG",
|
||||
"ragSettings": {
|
||||
"label": "Configuraciones de RAG",
|
||||
"model": {
|
||||
"label": "Modelo de embeddings",
|
||||
"required": "Por favor, selecione un modelo",
|
||||
"help": "Es recomendable usar modelos de embeddings como `nomic-embed-text`.",
|
||||
"placeholder": "Selecione un modelo"
|
||||
},
|
||||
"chunkSize": {
|
||||
"label": "Tamaño del Chunk",
|
||||
"placeholder": "Ingresar el tamaño del chunk",
|
||||
"required": "Por favor, ingrese el tamaño del chunk"
|
||||
},
|
||||
"chunkOverlap": {
|
||||
"label": "Solapamiento del Chunk",
|
||||
"placeholder": "Ingrese el solapamiento del chunk",
|
||||
"required": "Por favor, ingresar el solapamiento del chunk"
|
||||
}
|
||||
},
|
||||
"prompt": {
|
||||
"label": "Configurar el Prompt del RAG",
|
||||
"option1": "Normal",
|
||||
"option2": "Web",
|
||||
"alert": "Es obsoleto configurar aquí el prompt del sistema. Por favor, use la sección de Administrar Prompts para agregar o editar prompts. Esta sección se quitará en una versión futura",
|
||||
"systemPrompt": "Prompt del Sistema",
|
||||
"systemPromptPlaceholder": "Ingresar el prompt del sistema",
|
||||
"webSearchPrompt": "Prompt de la busqueda Web",
|
||||
"webSearchPromptHelp": "No borre `{search_results}` del prompt.",
|
||||
"webSearchPromptError": "Por favor, ingresar un prompt de busqueda web",
|
||||
"webSearchPromptPlaceholder": "Ingrese un prompt de busqueda web",
|
||||
"webSearchFollowUpPrompt": "Prompt de Seguimiento de busqueda Web",
|
||||
"webSearchFollowUpPromptHelp": "No borre `{chat_history}` y `{question}` del prompt.",
|
||||
"webSearchFollowUpPromptError": "Por favor, ingrese el prompt de seguimiento de la busqueda web",
|
||||
"webSearchFollowUpPromptPlaceholder": "Su prompt de seguimiento de busqueda web"
|
||||
}
|
||||
}
|
||||
}
|
7
src/assets/locale/es/sidepanel.json
Normal file
7
src/assets/locale/es/sidepanel.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"tooltip": {
|
||||
"embed": "Puede demorar algunos minutos para incluir la página. Por favor, aguarde...",
|
||||
"clear": "Borrar el histórico de conversación",
|
||||
"history": "Histórico de la conversación"
|
||||
}
|
||||
}
|
@ -37,6 +37,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "Résultats de la recherche totaux",
|
||||
"placeholder": "Entrez les résultats de la recherche totaux"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Visitez le site web mentionné dans le message"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -37,6 +37,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "Risultati della ricerca",
|
||||
"placeholder": "Inserisci il totale delle ricerche"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Visita il sito web menzionato nel messaggio"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -40,6 +40,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "合計検索結果",
|
||||
"placeholder": "合計検索結果を入力する"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "メッセージに記載されたウェブサイトを訪問してください"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -40,6 +40,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "ആകെ തിരച്ചിൽ ഫലങ്ങൾ",
|
||||
"placeholder": "ആകെ തിരച്ചിൽ ഫലങ്ങളുടെ എണ്ണം നൽകുക"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "സന്ദേശത്തിൽ പറയുന്ന വെബ്സൈറ്റ് സന്ദർശിക്കുക."
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -37,6 +37,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "Resultados de Pesquisa Totais",
|
||||
"placeholder": "Insira Resultados de Pesquisa Totais"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Visite o site mencionado na mensagem."
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -37,6 +37,9 @@
|
||||
"totalSearchResults": {
|
||||
"label": "Общее количество результатов поиска",
|
||||
"placeholder": "Введите общее количество результатов поиска"
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "Посетите веб-сайт, указанный в сообщении."
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
|
@ -40,7 +40,10 @@
|
||||
"totalSearchResults": {
|
||||
"label": "总搜索结果",
|
||||
"placeholder": "输入总搜索结果"
|
||||
}
|
||||
},
|
||||
"visitSpecificWebsite": {
|
||||
"label": "访问消息中提到的网站。"
|
||||
}
|
||||
},
|
||||
"system": {
|
||||
"heading": "系统设置",
|
||||
|
@ -14,6 +14,7 @@ import { useTranslation } from "react-i18next"
|
||||
import { KnowledgeSelect } from "../Knowledge/KnowledgeSelect"
|
||||
import { useSpeechRecognition } from "@/hooks/useSpeechRecognition"
|
||||
import { PiGlobe } from "react-icons/pi"
|
||||
import { extractReadabilityContent } from "@/parser/reader"
|
||||
|
||||
type Props = {
|
||||
dropedFile: File | undefined
|
||||
|
@ -13,7 +13,8 @@ export const SearchModeSettings = () => {
|
||||
initialValues: {
|
||||
isSimpleInternetSearch: false,
|
||||
searchProvider: "",
|
||||
totalSearchResults: 0
|
||||
totalSearchResults: 0,
|
||||
visitSpecificWebsite: false
|
||||
}
|
||||
})
|
||||
|
||||
@ -67,7 +68,7 @@ export const SearchModeSettings = () => {
|
||||
</span>
|
||||
<div>
|
||||
<Switch
|
||||
className="mt-4 sm:mt-0"
|
||||
className="mt-4 sm:mt-0"
|
||||
{...form.getInputProps("isSimpleInternetSearch", {
|
||||
type: "checkbox"
|
||||
})}
|
||||
@ -89,6 +90,20 @@ export const SearchModeSettings = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
|
||||
<span className="text-gray-700 dark:text-neutral-50 ">
|
||||
{t("generalSettings.webSearch.visitSpecificWebsite.label")}
|
||||
</span>
|
||||
<div>
|
||||
<Switch
|
||||
className="mt-4 sm:mt-0"
|
||||
{...form.getInputProps("visitSpecificWebsite", {
|
||||
type: "checkbox"
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<SaveButton btnType="submit" />
|
||||
</div>
|
||||
|
@ -1,87 +1,106 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
import { useMessageOption } from "./useMessageOption"
|
||||
|
||||
export const useScrollAnchor = () => {
|
||||
const messagesRef = useRef<HTMLDivElement>(null)
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const visibilityRef = useRef<HTMLDivElement>(null)
|
||||
const { isProcessing, messages } = useMessageOption()
|
||||
|
||||
const [isAtTop, setIsAtTop] = useState(false)
|
||||
const [isAtBottom, setIsAtBottom] = useState(true)
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [userScrolled, setUserScrolled] = useState(false)
|
||||
const [isOverflowing, setIsOverflowing] = useState(false)
|
||||
|
||||
const messagesStartRef = useRef<HTMLDivElement>(null)
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const isAutoScrolling = useRef(false)
|
||||
|
||||
console.log(`isAtTop: ${isAtTop}, isAtBottom: ${isAtBottom}, userScrolled: ${userScrolled}, isOverflowing: ${isOverflowing}`)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isProcessing && userScrolled) {
|
||||
console.log("userScrolled")
|
||||
setUserScrolled(false)
|
||||
}
|
||||
}, [isProcessing])
|
||||
|
||||
useEffect(() => {
|
||||
if (isProcessing && !userScrolled) {
|
||||
scrollToBottom()
|
||||
}
|
||||
}, [messages])
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current
|
||||
if (!container) return
|
||||
|
||||
const topObserver = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
setIsAtTop(entry.isIntersecting)
|
||||
},
|
||||
{ threshold: 1 }
|
||||
)
|
||||
|
||||
const bottomObserver = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
setIsAtBottom(entry.isIntersecting)
|
||||
if (entry.isIntersecting) {
|
||||
setUserScrolled(false)
|
||||
} else if (!isAutoScrolling.current) {
|
||||
setUserScrolled(true)
|
||||
}
|
||||
},
|
||||
{ threshold: 1 }
|
||||
)
|
||||
|
||||
if (messagesStartRef.current) {
|
||||
topObserver.observe(messagesStartRef.current)
|
||||
}
|
||||
|
||||
if (messagesEndRef.current) {
|
||||
bottomObserver.observe(messagesEndRef.current)
|
||||
}
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
setIsOverflowing(container.scrollHeight > container.clientHeight)
|
||||
})
|
||||
|
||||
resizeObserver.observe(container)
|
||||
|
||||
return () => {
|
||||
topObserver.disconnect()
|
||||
bottomObserver.disconnect()
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const scrollToTop = useCallback(() => {
|
||||
if (messagesStartRef.current) {
|
||||
messagesStartRef.current.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
}, [])
|
||||
|
||||
const scrollToBottom = useCallback(() => {
|
||||
if (messagesRef.current) {
|
||||
messagesRef.current.scrollIntoView({
|
||||
block: "end",
|
||||
behavior: "smooth"
|
||||
})
|
||||
}
|
||||
isAutoScrolling.current = true
|
||||
|
||||
setTimeout(() => {
|
||||
if (messagesEndRef.current) {
|
||||
messagesEndRef.current.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
|
||||
isAutoScrolling.current = false
|
||||
}, 100)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (messagesRef.current) {
|
||||
if (isAtBottom && !isVisible) {
|
||||
messagesRef.current.scrollIntoView({
|
||||
block: "end"
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [isAtBottom, isVisible])
|
||||
|
||||
useEffect(() => {
|
||||
const { current } = scrollRef
|
||||
|
||||
if (current) {
|
||||
const handleScroll = (event: Event) => {
|
||||
const target = event.target as HTMLDivElement
|
||||
const offset = 25
|
||||
const isAtBottom =
|
||||
target.scrollTop + target.clientHeight >= target.scrollHeight - offset
|
||||
console.log(target.scrollTop, target.clientHeight, target.scrollHeight)
|
||||
setIsAtBottom(isAtBottom)
|
||||
}
|
||||
|
||||
current.addEventListener("scroll", handleScroll, {
|
||||
passive: true
|
||||
})
|
||||
|
||||
return () => {
|
||||
current.removeEventListener("scroll", handleScroll)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (visibilityRef.current) {
|
||||
let observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
console.log(entry.isIntersecting)
|
||||
if (entry.isIntersecting) {
|
||||
setIsVisible(true)
|
||||
} else {
|
||||
setIsVisible(false)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
rootMargin: "0px 0px -100px 0px"
|
||||
}
|
||||
)
|
||||
|
||||
observer.observe(visibilityRef.current)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
messagesRef,
|
||||
scrollRef,
|
||||
visibilityRef,
|
||||
scrollToBottom,
|
||||
messagesStartRef,
|
||||
messagesEndRef,
|
||||
containerRef,
|
||||
isAtTop,
|
||||
isAtBottom,
|
||||
isVisible
|
||||
userScrolled,
|
||||
isOverflowing,
|
||||
scrollToTop,
|
||||
scrollToBottom,
|
||||
setIsAtBottom
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import { ml } from "./lang/ml";
|
||||
import { zh } from "./lang/zh";
|
||||
import { ja } from "./lang/ja";
|
||||
import { it } from "./lang/it";
|
||||
import { es } from "./lang/es";
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
i18n
|
||||
@ -16,6 +17,7 @@ i18n
|
||||
.init({
|
||||
resources: {
|
||||
en: en,
|
||||
es: es,
|
||||
fr: fr,
|
||||
"it": it,
|
||||
ml: ml,
|
||||
@ -31,4 +33,4 @@ i18n
|
||||
lng: localStorage.getItem("i18nextLng") || "en",
|
||||
})
|
||||
|
||||
export default i18n;
|
||||
export default i18n;
|
||||
|
15
src/i18n/lang/es.ts
Normal file
15
src/i18n/lang/es.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import option from "@/assets/locale/es/option.json";
|
||||
import playground from "@/assets/locale/es/playground.json";
|
||||
import common from "@/assets/locale/es/common.json";
|
||||
import sidepanel from "@/assets/locale/es/sidepanel.json";
|
||||
import settings from "@/assets/locale/es/settings.json";
|
||||
import knowledge from "@/assets/locale/es/knowledge.json";
|
||||
|
||||
export const es = {
|
||||
option,
|
||||
playground,
|
||||
common,
|
||||
sidepanel,
|
||||
settings,
|
||||
knowledge
|
||||
}
|
@ -4,6 +4,10 @@ export const supportLanguage = [
|
||||
label: "English",
|
||||
value: "en"
|
||||
},
|
||||
{
|
||||
label: "Español",
|
||||
value: "es"
|
||||
},
|
||||
{
|
||||
label: "Français",
|
||||
value: "fr"
|
||||
@ -19,7 +23,7 @@ export const supportLanguage = [
|
||||
{
|
||||
label: "Português (Brasil)",
|
||||
value: "pt-BR"
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "മലയാളം",
|
||||
value: "ml"
|
||||
@ -32,4 +36,4 @@ export const supportLanguage = [
|
||||
label: "日本語",
|
||||
value: "ja-JP"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { BaseDocumentLoader } from "langchain/document_loaders/base"
|
||||
import { Document } from "@langchain/core/documents"
|
||||
import { compile } from "html-to-text"
|
||||
import { urlRewriteRuntime } from "~/libs/runtime"
|
||||
import { YtTranscript } from "yt-transcript"
|
||||
import { isWikipedia, parseWikipedia } from "@/parser/wiki"
|
||||
import { extractReadabilityContent } from "@/parser/reader"
|
||||
|
||||
const YT_REGEX =
|
||||
/(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?([a-zA-Z0-9_-]+)/
|
||||
@ -24,8 +24,7 @@ export interface WebLoaderParams {
|
||||
|
||||
export class PageAssistHtmlLoader
|
||||
extends BaseDocumentLoader
|
||||
implements WebLoaderParams
|
||||
{
|
||||
implements WebLoaderParams {
|
||||
html: string
|
||||
url: string
|
||||
|
||||
@ -52,30 +51,14 @@ export class PageAssistHtmlLoader
|
||||
{
|
||||
metadata: {
|
||||
source: this.url,
|
||||
url: this.url,
|
||||
audio: { chunks: transcript }
|
||||
},
|
||||
pageContent: text
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// let html = this.html
|
||||
|
||||
// if (isWikipedia(this.url)) {
|
||||
// console.log("Wikipedia URL detected")
|
||||
// html = parseWikipedia(html)
|
||||
// }
|
||||
|
||||
// // else if (isTwitter(this.url)) {
|
||||
// // console.log("Twitter URL detected")
|
||||
// // html = parseTweet(html, this.url)
|
||||
// // }
|
||||
|
||||
// const htmlCompiler = compile({
|
||||
// wordwrap: false
|
||||
// })
|
||||
// const text = htmlCompiler(html)
|
||||
const metadata = { source: this.url }
|
||||
const metadata = { source: this.url, url: this.url, }
|
||||
return [new Document({ pageContent: this.html, metadata })]
|
||||
}
|
||||
|
||||
@ -95,6 +78,7 @@ export class PageAssistHtmlLoader
|
||||
return [
|
||||
{
|
||||
metadata: {
|
||||
url: this.url,
|
||||
source: this.url,
|
||||
audio: { chunks: transcript }
|
||||
},
|
||||
@ -103,22 +87,15 @@ export class PageAssistHtmlLoader
|
||||
]
|
||||
}
|
||||
await urlRewriteRuntime(this.url, "web")
|
||||
const fetchHTML = await fetch(this.url)
|
||||
let html = await fetchHTML.text()
|
||||
|
||||
let text = "";
|
||||
if (isWikipedia(this.url)) {
|
||||
console.log("Wikipedia URL detected")
|
||||
html = parseWikipedia(await fetchHTML.text())
|
||||
const fetchHTML = await fetch(this.url)
|
||||
text = parseWikipedia(await fetchHTML.text())
|
||||
} else {
|
||||
text = await extractReadabilityContent(this.url)
|
||||
}
|
||||
|
||||
const htmlCompiler = compile({
|
||||
wordwrap: false,
|
||||
selectors: [
|
||||
{ selector: "img", format: "skip" },
|
||||
{ selector: "script", format: "skip" }
|
||||
]
|
||||
})
|
||||
const text = htmlCompiler(html)
|
||||
const metadata = { url: this.url }
|
||||
return [new Document({ pageContent: text, metadata })]
|
||||
}
|
||||
|
19
src/parser/reader.ts
Normal file
19
src/parser/reader.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Readability } from "@mozilla/readability"
|
||||
import { defaultExtractContent } from "./default"
|
||||
export const extractReadabilityContent = async (url: string) => {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch ${url}`)
|
||||
}
|
||||
|
||||
const html = await response.text()
|
||||
|
||||
// create a fake dom for Readability
|
||||
const doc = new DOMParser().parseFromString(html, "text/html")
|
||||
const reader = new Readability(doc)
|
||||
const article = reader.parse()
|
||||
|
||||
// convert the article to markdown
|
||||
const markdown = defaultExtractContent(article.content)
|
||||
return markdown
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import * as cheerio from "cheerio"
|
||||
import { defaultExtractContent } from "./default"
|
||||
|
||||
export const isWikipedia = (url: string) => {
|
||||
const WIKI_REGEX = /wikipedia\.org\/wiki\//g
|
||||
@ -24,5 +25,5 @@ export const parseWikipedia = (html: string) => {
|
||||
content?.find("div.toc")?.remove()
|
||||
const newHtml = content?.html()
|
||||
|
||||
return `<div>TITLE: ${title?.text()}</div><div>${newHtml}</div>`
|
||||
return defaultExtractContent(`<div>TITLE: ${title?.text()}</div><div>${newHtml}</div>`)
|
||||
}
|
||||
|
@ -38,4 +38,18 @@ export const getAdvancedOllamaSettings = async () => {
|
||||
|
||||
export const copilotResumeLastChat = async () => {
|
||||
return await storage.get<boolean>("copilotResumeLastChat")
|
||||
}
|
||||
|
||||
|
||||
export const defaultSidebarOpen = async () => {
|
||||
const sidebarOpen = await storage.get("sidebarOpen")
|
||||
if (!sidebarOpen || sidebarOpen === "") {
|
||||
return "right_clk"
|
||||
}
|
||||
return sidebarOpen
|
||||
}
|
||||
|
||||
|
||||
export const setSidebarOpen = async (sidebarOpen: string) => {
|
||||
await storage.set("sidebarOpen", sidebarOpen)
|
||||
}
|
@ -15,6 +15,21 @@ export const getIsSimpleInternetSearch = async () => {
|
||||
return isSimpleInternetSearch === "true"
|
||||
}
|
||||
|
||||
export const getIsVisitSpecificWebsite = async () => {
|
||||
const isVisitSpecificWebsite = await storage.get("isVisitSpecificWebsite")
|
||||
if (!isVisitSpecificWebsite || isVisitSpecificWebsite.length === 0) {
|
||||
return true
|
||||
}
|
||||
return isVisitSpecificWebsite === "true"
|
||||
}
|
||||
|
||||
|
||||
export const setIsVisitSpecificWebsite = async (
|
||||
isVisitSpecificWebsite: boolean
|
||||
) => {
|
||||
await storage.set("isVisitSpecificWebsite", isVisitSpecificWebsite.toString())
|
||||
}
|
||||
|
||||
export const setIsSimpleInternetSearch = async (
|
||||
isSimpleInternetSearch: boolean
|
||||
) => {
|
||||
@ -48,32 +63,37 @@ export const setTotalSearchResults = async (totalSearchResults: number) => {
|
||||
}
|
||||
|
||||
export const getSearchSettings = async () => {
|
||||
const [isSimpleInternetSearch, searchProvider, totalSearchResult] =
|
||||
const [isSimpleInternetSearch, searchProvider, totalSearchResult, visitSpecificWebsite] =
|
||||
await Promise.all([
|
||||
getIsSimpleInternetSearch(),
|
||||
getSearchProvider(),
|
||||
totalSearchResults()
|
||||
totalSearchResults(),
|
||||
getIsVisitSpecificWebsite()
|
||||
])
|
||||
|
||||
return {
|
||||
isSimpleInternetSearch,
|
||||
searchProvider,
|
||||
totalSearchResults: totalSearchResult
|
||||
totalSearchResults: totalSearchResult,
|
||||
visitSpecificWebsite
|
||||
}
|
||||
}
|
||||
|
||||
export const setSearchSettings = async ({
|
||||
isSimpleInternetSearch,
|
||||
searchProvider,
|
||||
totalSearchResults
|
||||
totalSearchResults,
|
||||
visitSpecificWebsite
|
||||
}: {
|
||||
isSimpleInternetSearch: boolean
|
||||
searchProvider: string
|
||||
totalSearchResults: number
|
||||
visitSpecificWebsite: boolean
|
||||
}) => {
|
||||
await Promise.all([
|
||||
setIsSimpleInternetSearch(isSimpleInternetSearch),
|
||||
setSearchProvider(searchProvider),
|
||||
setTotalSearchResults(totalSearchResults)
|
||||
setTotalSearchResults(totalSearchResults),
|
||||
setIsVisitSpecificWebsite(visitSpecificWebsite)
|
||||
])
|
||||
}
|
||||
|
44
src/utils/rerank.ts
Normal file
44
src/utils/rerank.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import type { Embeddings } from "@langchain/core/embeddings"
|
||||
import type { Document } from "@langchain/core/documents"
|
||||
import * as ml_distance from "ml-distance"
|
||||
|
||||
export const rerankDocs = async ({
|
||||
query,
|
||||
docs,
|
||||
embedding
|
||||
}: {
|
||||
query: string
|
||||
docs: Document[]
|
||||
embedding: Embeddings
|
||||
}) => {
|
||||
if (docs.length === 0) {
|
||||
return docs
|
||||
}
|
||||
|
||||
const docsWithContent = docs.filter(
|
||||
(doc) => doc.pageContent && doc.pageContent.length > 0
|
||||
)
|
||||
|
||||
const [docEmbeddings, queryEmbedding] = await Promise.all([
|
||||
embedding.embedDocuments(docsWithContent.map((doc) => doc.pageContent)),
|
||||
embedding.embedQuery(query)
|
||||
])
|
||||
|
||||
const similarity = docEmbeddings.map((docEmbedding, i) => {
|
||||
// perform cosine similarity between query and document
|
||||
const sim = ml_distance.similarity.cosine(queryEmbedding, docEmbedding)
|
||||
|
||||
return {
|
||||
index: i,
|
||||
similarity: sim
|
||||
}
|
||||
})
|
||||
|
||||
const sortedDocs = similarity
|
||||
.sort((a, b) => b.similarity - a.similarity)
|
||||
.filter((sim) => sim.similarity > 0.5)
|
||||
.slice(0, 15)
|
||||
.map((sim) => docsWithContent[sim.index])
|
||||
|
||||
return sortedDocs
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
import { getWebSearchPrompt } from "~/services/ollama"
|
||||
import { webGoogleSearch } from "./search-engines/google"
|
||||
import { webDuckDuckGoSearch } from "./search-engines/duckduckgo"
|
||||
import { getSearchProvider } from "@/services/search"
|
||||
import { getIsVisitSpecificWebsite, getSearchProvider } from "@/services/search"
|
||||
import { webSogouSearch } from "./search-engines/sogou"
|
||||
import { webBraveSearch } from "./search-engines/brave"
|
||||
import { getWebsiteFromQuery, processSingleWebsite } from "./website"
|
||||
|
||||
const getHostName = (url: string) => {
|
||||
try {
|
||||
@ -29,8 +30,27 @@ const searchWeb = (provider: string, query: string) => {
|
||||
|
||||
export const getSystemPromptForWeb = async (query: string) => {
|
||||
try {
|
||||
const searchProvider = await getSearchProvider()
|
||||
const search = await searchWeb(searchProvider, query)
|
||||
|
||||
const websiteVisit = getWebsiteFromQuery(query)
|
||||
let search: {
|
||||
url: any;
|
||||
content: string;
|
||||
}[] = []
|
||||
|
||||
const isVisitSpecificWebsite = await getIsVisitSpecificWebsite()
|
||||
|
||||
if (isVisitSpecificWebsite && websiteVisit.hasUrl) {
|
||||
|
||||
const url = websiteVisit.url
|
||||
const queryWithoutUrl = websiteVisit.queryWithouUrls
|
||||
search = await processSingleWebsite(url, queryWithoutUrl)
|
||||
|
||||
} else {
|
||||
const searchProvider = await getSearchProvider()
|
||||
search = await searchWeb(searchProvider, query)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const search_results = search
|
||||
.map(
|
||||
|
76
src/web/website/index.ts
Normal file
76
src/web/website/index.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { cleanUrl } from "@/libs/clean-url"
|
||||
import { PageAssistHtmlLoader } from "@/loader/html"
|
||||
import { defaultEmbeddingChunkOverlap, defaultEmbeddingChunkSize, defaultEmbeddingModelForRag, getOllamaURL } from "@/services/ollama"
|
||||
import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"
|
||||
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
|
||||
import { MemoryVectorStore } from "langchain/vectorstores/memory"
|
||||
|
||||
export const processSingleWebsite = async (url: string, query: string) => {
|
||||
const loader = new PageAssistHtmlLoader({
|
||||
html: "",
|
||||
url
|
||||
})
|
||||
const docs = await loader.loadByURL()
|
||||
|
||||
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, 4)
|
||||
|
||||
const searchResult = resultsWithEmbeddings.map((result) => {
|
||||
return {
|
||||
url: result.metadata.url,
|
||||
content: result.pageContent
|
||||
}
|
||||
})
|
||||
|
||||
return searchResult
|
||||
}
|
||||
|
||||
|
||||
export const getWebsiteFromQuery = (query: string): {
|
||||
queryWithouUrls: string,
|
||||
url: string,
|
||||
hasUrl: boolean
|
||||
} => {
|
||||
|
||||
const urlRegex = /https?:\/\/[^\s]+/g
|
||||
|
||||
const urls = query.match(urlRegex)
|
||||
|
||||
if (!urls) {
|
||||
return {
|
||||
queryWithouUrls: query,
|
||||
url: "",
|
||||
hasUrl: false
|
||||
}
|
||||
}
|
||||
|
||||
const url = urls[0]
|
||||
|
||||
const queryWithouUrls = query.replace(url, "")
|
||||
|
||||
return {
|
||||
queryWithouUrls,
|
||||
url,
|
||||
hasUrl: true
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ export default defineConfig({
|
||||
outDir: "build",
|
||||
|
||||
manifest: {
|
||||
version: "1.1.12",
|
||||
version: "1.1.13",
|
||||
name:
|
||||
process.env.TARGET === "firefox"
|
||||
? "Page Assist - A Web UI for Local AI Models"
|
||||
|
Loading…
x
Reference in New Issue
Block a user