Merge pull request #109 from n4ze3m/next

v1.1.11
This commit is contained in:
Muhammed Nazeem 2024-06-03 17:01:13 +05:30 committed by GitHub
commit 8bcd4ec5ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 2393 additions and 7945 deletions

View File

@ -19,10 +19,10 @@ Thank you for your interest in contributing to Page Assist! We welcome contribut
3. **Install dependencies** 3. **Install dependencies**
Page Assist uses [Yarn](https://yarnpkg.com/) for dependency management. Install the required dependencies by running the following command in the project root directory: Page Assist uses [Bun](https://bun.sh/) for dependency management. Install the required dependencies by running the following command in the project root directory:
``` ```
yarn install bun install
``` ```
4. **Start the development server** 4. **Start the development server**
@ -30,10 +30,16 @@ Thank you for your interest in contributing to Page Assist! We welcome contribut
To run the extension in development mode, use the following command: To run the extension in development mode, use the following command:
``` ```
yarn dev bun dev
``` ```
This will open a browser window with the extension loaded. This will open a chrome browser window with the extension loaded.
for firefox:
```
bun dev:firefox
```
5. **Install Ollama locally** 5. **Install Ollama locally**

View File

@ -30,13 +30,6 @@ Checkout the Demo (v1.0.0):
want more features? Create an issue and let me know. want more features? Create an issue and let me know.
<!-- ## Installation
### Chrome Web Store
You can install the extension from the [Chrome Web Store](https://chromewebstore.google.com/detail/page-assist-a-web-ui-for/jfgfiigpkhlkbnfnbobbkinehhfdhndo)
Note: You can install the extension on any Chromium-based browser. It is not limited to Chrome. -->
### Manual Installation ### Manual Installation
@ -125,6 +118,8 @@ This will start a development server and watch for changes in the source files.
| Opera | ❌ | ❌ | ✅ | | Opera | ❌ | ❌ | ✅ |
| Arc | ❌ | ❌ | ✅ | | Arc | ❌ | ❌ | ✅ |
## Local AI Provider ## Local AI Provider
- [Ollama](https://github.com/ollama/ollama) (Currently the only supported provider. More providers will be added in the future.) - [Ollama](https://github.com/ollama/ollama) (Currently the only supported provider. More providers will be added in the future.)
@ -132,8 +127,8 @@ This will start a development server and watch for changes in the source files.
## Roadmap ## Roadmap
- [X] Firefox Support - [X] Firefox Support
- [ ] Code Completion support for Web based IDEs (like Colab, Jupyter, etc.)
- [ ] More Local AI Providers - [ ] More Local AI Providers
- [ ] More Features
- [ ] More Customization Options - [ ] More Customization Options
- [ ] Better UI/UX - [ ] Better UI/UX

View File

@ -8,7 +8,7 @@
"dev": "cross-env TARGET=chrome wxt", "dev": "cross-env TARGET=chrome wxt",
"dev:firefox": "cross-env TARGET=firefox wxt -b firefox", "dev:firefox": "cross-env TARGET=firefox wxt -b firefox",
"build": "cross-env TARGET=chrome wxt build", "build": "cross-env TARGET=chrome wxt build",
"build:firefox": "cross-env TARGET=chrome cross-env TARGET=firefox wxt build -b firefox", "build:firefox": "cross-env TARGET=firefox wxt build -b firefox",
"zip": "cross-env TARGET=chrome wxt zip", "zip": "cross-env TARGET=chrome wxt zip",
"zip:firefox": "cross-env TARGET=firefox wxt zip -b firefox", "zip:firefox": "cross-env TARGET=firefox wxt zip -b firefox",
"compile": "tsc --noEmit", "compile": "tsc --noEmit",

View File

@ -38,5 +38,5 @@
"submit": "Submit", "submit": "Submit",
"success": "Knowledge added successfully" "success": "Knowledge added successfully"
}, },
"noEmbeddingModel": "Please add an embedding model first from the Ollama settings page" "noEmbeddingModel": "Please add an embedding model from the RAG settings page first"
} }

View File

@ -7,7 +7,7 @@
}, },
"formError": { "formError": {
"noModel": "Please select a model", "noModel": "Please select a model",
"noEmbeddingModel": "Please set an embedding model on the Settings > Ollama page" "noEmbeddingModel": "Please set an embedding model on the Settings > RAG page"
}, },
"form": { "form": {
"textarea": { "textarea": {

View File

@ -217,41 +217,6 @@
"label": "Ollama URL", "label": "Ollama URL",
"placeholder": "Enter Ollama URL" "placeholder": "Enter Ollama URL"
}, },
"ragSettings": {
"label": "RAG Settings",
"model": {
"label": "Embedding Model",
"required": "Please select a model",
"help": "Highly recommended to use embedding models like `nomic-embed-text`.",
"placeholder": "Select a model"
},
"chunkSize": {
"label": "Chunk Size",
"placeholder": "Enter Chunk Size",
"required": "Please enter a chunk size"
},
"chunkOverlap": {
"label": "Chunk Overlap",
"placeholder": "Enter Chunk Overlap",
"required": "Please enter a chunk overlap"
}
},
"prompt": {
"label": "Configure RAG Prompt",
"option1": "Normal",
"option2": "Web",
"alert": "Configuring the system prompt here is deprecated. Please use the Manage Prompts section to add or edit prompts. This section will be removed in a future release",
"systemPrompt": "System Prompt",
"systemPromptPlaceholder": "Enter System Prompt",
"webSearchPrompt": "Web Search Prompt",
"webSearchPromptHelp": "Do not remove `{search_results}` from the prompt.",
"webSearchPromptError": "Please enter a web search prompt",
"webSearchPromptPlaceholder": "Enter Web Search Prompt",
"webSearchFollowUpPrompt": "Web Search Follow Up Prompt",
"webSearchFollowUpPromptHelp": "Do not remove `{chat_history}` and `{question}` from the prompt.",
"webSearchFollowUpPromptError": "Please input your Web Search Follow Up Prompt!",
"webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt"
},
"advanced": { "advanced": {
"label": "Advance Ollama URL Configuration", "label": "Advance Ollama URL Configuration",
"urlRewriteEnabled": { "urlRewriteEnabled": {
@ -282,5 +247,43 @@
"manageKnowledge": { "manageKnowledge": {
"title": "Manage Knowledge", "title": "Manage Knowledge",
"heading": "Configure Knowledge Base" "heading": "Configure Knowledge Base"
},
"rag": {
"title": "RAG Settings",
"ragSettings": {
"label": "RAG Settings",
"model": {
"label": "Embedding Model",
"required": "Please select a model",
"help": "Highly recommended to use embedding models like `nomic-embed-text`.",
"placeholder": "Select a model"
},
"chunkSize": {
"label": "Chunk Size",
"placeholder": "Enter Chunk Size",
"required": "Please enter a chunk size"
},
"chunkOverlap": {
"label": "Chunk Overlap",
"placeholder": "Enter Chunk Overlap",
"required": "Please enter a chunk overlap"
}
},
"prompt": {
"label": "Configure RAG Prompt",
"option1": "Normal",
"option2": "Web",
"alert": "Configuring the system prompt here is deprecated. Please use the Manage Prompts section to add or edit prompts. This section will be removed in a future release",
"systemPrompt": "System Prompt",
"systemPromptPlaceholder": "Enter System Prompt",
"webSearchPrompt": "Web Search Prompt",
"webSearchPromptHelp": "Do not remove `{search_results}` from the prompt.",
"webSearchPromptError": "Please enter a web search prompt",
"webSearchPromptPlaceholder": "Enter Web Search Prompt",
"webSearchFollowUpPrompt": "Web Search Follow Up Prompt",
"webSearchFollowUpPromptHelp": "Do not remove `{chat_history}` and `{question}` from the prompt.",
"webSearchFollowUpPromptError": "Please input your Web Search Follow Up Prompt!",
"webSearchFollowUpPromptPlaceholder": "Your Web Search Follow Up Prompt"
}
} }
} }

View File

@ -0,0 +1,88 @@
{
"pageAssist": "Page Assist",
"selectAModel": "Sélectionnez un modèle",
"save": "Sauvegarder",
"saved": "Enregistrée",
"cancel": "Annuler",
"retry": "Recommencez",
"share": {
"tooltip": {
"share": "Partager"
},
"modal": {
"title": "Partagez le lien vers le chat"
},
"form": {
"defaultValue": {
"name": "Anonyme",
"title": "Chat sans titre"
},
"title": {
"label": "Titre de chat",
"placeholder": "Entrez le titre du chat",
"required": "Le titre de chat est requis"
},
"name": {
"label": "Votre nom",
"placeholder": "Entrez votre nome",
"required": "Votre nom est requis"
},
"btn": {
"save": "Générer un lien",
"saving": "Génération de lien..."
}
},
"notification": {
"successGenerate": "Lien copié dans le presse-papiers",
"failGenerate": "Échec de la génération de lien"
}
},
"copyToClipboard": "Copier dans le presse-papier",
"webSearch": "Recherche sur le Web",
"regenerate": "Régénérer",
"edit": "Modifier",
"saveAndSubmit": "Enregistrer et soumettre",
"editMessage": {
"placeholder": "Tapez un message..."
},
"submit": "Soumettre",
"noData": "Pas de données",
"noHistory": "Pas d'historique de chat",
"chatWithCurrentPage": "Discuter avec la page actuelle",
"beta": "Bêta",
"tts": "Synthèse vocale",
"currentChatModelSettings":"Paramètres actuels du modèle de chat",
"modelSettings": {
"label": "Paramètres du modèle",
"description": "Définissez les options de modèle globale pour tous les chats",
"form": {
"keepAlive": {
"label": "Maintenir en mémoire",
"help": "contrôle combien de temps le modèle restera chargé en mémoire après la demande (par défaut: 5m)",
"placeholder": "Entrer la durée du maintien en mémoire (p. ex., 5 m, 10 m, 1 h)"
},
"temperature": {
"label": "Température",
"placeholder": "Entrez la valeur de la température (par exemple 0,7, 1,0)"
},
"numCtx": {
"label": "Nombre de contextes",
"placeholder": "Entrez la valeur du nombre de contextes (par défaut: 2048)"
},
"seed": {
"label": "Graine",
"placeholder": "Entrez la valeur des semences (par exemple 1234)",
"help": "Reproductibilité de la sortie du modèle"
},
"topK": {
"label": "Top K",
"placeholder": "Entrez la valeur Top K (par exemple 40, 100)"
},
"topP": {
"label": "Top P",
"placeholder": "Entrez la valeur Top P (par exemple 0,9, 0,95)"
}
},
"advanced": "Plus de paramètres du modèle"
}
}

View File

@ -0,0 +1,42 @@
{
"addBtn": "Ajouter de nouvelles connaissances",
"columns": {
"title": "Titre",
"status": "Statut",
"embeddings": "Modèle d'embedding",
"createdAt": "Créé à",
"action": "actions"
},
"expandedColumns": {
"name": "Nom"
},
"tooltip": {
"delete": "Supprimer"
},
"confirm": {
"delete": "Êtes-vous sûr de vouloir supprimer ces connaissances ?"
},
"deleteSuccess": "Connaissances supprimées avec succès",
"status": {
"pending": "En attente",
"finished": "Terminé",
"processing": "Traitement"
},
"addKnowledge": "Ajouter des connaissances",
"form": {
"title": {
"label": "Titre de la connaissance",
"placeholder": "Entrez le titre de la connaissances",
"required": "Le titre de la connaissance est requis"
},
"uploadFile": {
"label": "Téléverser un fichier",
"uploadText": "Faites glisser et déposez un fichier ici ou cliquez pour téléverser",
"uploadHint": "Types de fichiers pris en charge: .pdf, .csv, .txt, .md, .docx",
"required": "Le fichier est requis"
},
"submit": "Soumettre",
"success": "Les connaissances ont ajouté avec succès"
},
"noEmbeddingModel": "Veuillez d'abord ajouter un modèle d'embedding depuis la page des paramètres de RAG"
}

View File

@ -0,0 +1,12 @@
{
"newChat": "Nouveau chat",
"selectAPrompt": "Sélectionnez un prompt",
"githubRepository": "Référentiel GitHub",
"settings": "Paramètres",
"sidebarTitle": "Historique de chat",
"error": "Erreur",
"somethingWentWrong": "Quelque chose s'est mal passé",
"validationSelectModel": "Veuillez sélectionner un modèle pour continuer",
"deleteHistoryConfirmation": "Êtes-vous sûr de vouloir supprimer cette historique ?",
"editHistoryTitle": "Entrez un nouveau titre"
}

View File

@ -0,0 +1,29 @@
{
"ollamaState": {
"searching": "Searching for Your Ollama 🦙",
"running": "Ollama is running 🦙",
"notRunning": "Unable to connect to Ollama 🦙",
"connectionError": "It seems like you are having a connection error. Please refer to this <anchor>documentation</anchor> for troubleshooting."
},
"formError": {
"noModel": "Please select a model",
"noEmbeddingModel": "Please set an embedding model on the Settings > RAG page"
},
"form": {
"textarea": {
"placeholder": "Type a message..."
},
"webSearch": {
"on": "On",
"off": "Off"
}
},
"tooltip": {
"searchInternet": "Rechercher Internet",
"speechToText": "Parole en texte",
"uploadImage": "Téléverser une image",
"stopStreaming": "Arrêtez la diffusion",
"knowledge": "Connaissance"
},
"sendWhenEnter": "Envoyer en appuyant sur Entrée"
}

View File

@ -0,0 +1,289 @@
{
"generalSettings": {
"title": "Réglages généraux",
"settings": {
"heading": "Paramètres d'interface utilisateur Web",
"speechRecognitionLang": {
"label": "Langue de reconnaissance vocale",
"placeholder": "Sélectionnez une langue"
},
"language": {
"label": "Langue",
"placeholder": "Sélectionnez une langue"
},
"darkMode": {
"label": "Change le thème",
"options": {
"light": "Clair",
"dark": "Sombre"
}
},
"copilotResumeLastChat": {
"label": "Reprendre la dernière conversation lors de l'ouverture du sidepanel (Copilot)"
},
"hideCurrentChatModelSettings": {
"label": "Masquer les paramètres actuels du modèle de chat"
}
},
"webSearch": {
"heading": "Gérer la recherche Web",
"searchMode": {
"label": "Effectuer une simple recherche sur Internet"
},
"provider": {
"label": "Moteur de recherche",
"placeholder": "Sélectionnez un moteur de recherche"
},
"totalSearchResults": {
"label": "Résultats de la recherche totaux",
"placeholder": "Entrez les résultats de la recherche totaux"
}
},
"system": {
"heading": "Les paramètres du système",
"deleteChatHistory": {
"label": "Supprimer l'historique du chat",
"button": "Supprimer",
"confirm": "Êtes-vous sûr de vouloir supprimer l'historique de votre chat? Cette action ne peut pas être annulée."
},
"export": {
"label": "Exporter l'historique du chat, la base de connaissances et les invites",
"button": "Exporter des données",
"success": "Succès de l'exportation"
},
"import": {
"label": "Importer l'historique du chat, la base de connaissances et les invites",
"button": "Importer des données",
"success": "Succès d'importation",
"error": "Erreur d'importation"
}
},
"tts": {
"heading": "Paramètres de synthèse vocale",
"ttsEnabled": {
"label": "Activer la synthèse vocale"
},
"ttsProvider": {
"label": "Fournisseur de synthèse vocale",
"placeholder": "Sélectionnez un fournisseur"
},
"ttsVoice": {
"label": "Voix de synthèse vocale",
"placeholder": "Sélectionnez une voix"
},
"ssmlEnabled": {
"label": "Activer SSML (langage de balisage de synthèse vocale)"
}
}
},
"manageModels": {
"title": "Gérer les modèles",
"addBtn": "Ajouter un nouveau modèle",
"columns": {
"name": "Nom",
"digest": "Digérer",
"modifiedAt": "Modifié à",
"size": "Taille",
"actions": "Actions"
},
"expandedColumns": {
"parentModel": "Modèle parent",
"format": "Format",
"family": "Famille",
"parameterSize": "Taille du paramètre",
"quantizationLevel": "Niveau de quantification"
},
"tooltip": {
"delete": "Supprimer le modèle",
"repull": "Modèle de ré-échoue"
},
"confirm": {
"delete": "Êtes-vous sûr de vouloir supprimer ce modèle?",
"repull": "Êtes-vous sûr de vouloir rétracter ce modèle?"
},
"modal": {
"title": "Ajouter un nouveau modèle",
"placeholder": "Entrez le nom du modèle",
"pull": "Modèle de traction"
},
"notification": {
"pullModel": "Modèle de traction",
"pullModelDescription": "Tirling {{ModelName}} modèle. Pour plus de détails, vérifiez l'icône d'extension.",
"success": "Succès",
"error": "Erreur",
"successDescription": "A réussi à tirer le modèle",
"successDeleteDescription": "Supprimé avec succès le modèle",
"someError": "Quelque chose s'est mal passé.Veuillez réessayer plus tard"
}
},
"managePrompts": {
"title": "Gérer les prompts",
"addBtn": "Ajouter un nouveau prompt",
"option1": "Normale",
"option2": "RAG",
"questionPrompt": "Prompt de question",
"columns": {
"title": "Titre",
"prompt": "Prompt",
"type": "Type de prompt",
"actions": "Actions"
},
"systemPrompt": "Prompt système",
"quickPrompt": "Prompt rapide",
"tooltip": {
"delete": "Supprimer le prompt",
"edit": "Modifier le prompt"
},
"confirm": {
"delete": "Êtes-vous sûr de vouloir supprimer cette invite ? Cette action ne peut pas être annulée."
},
"modal": {
"addTitle": "Ajouter un nouveau prompt",
"editTitle": "Modifier le prompt"
},
"form": {
"title": {
"label": "Titre",
"placeholder": "Mon super prompt",
"required": "Veuillez saisir un titre"
},
"prompt": {
"label": "Prompt",
"placeholder": "Entrer Prompt",
"required": "Veuillez entrer un prompt",
"help": "Vous pouvez utiliser {key} comme variable dans votre prompt."
},
"isSystem": {
"label": "Est un prompt système"
},
"btnSave": {
"saving": "Ajout de Prompt...",
"save": "Ajouter un prompt"
},
"btnEdit": {
"saving": "Mise à jour du Prompt...",
"save": "Modifier le prompt"
}
},
"notification": {
"addSuccess": "Prompt ajouté",
"addSuccessDesc": "Le prompt a été ajoutée avec succès",
"error": "Erreur",
"someError": "Quelque chose s'est mal passé. Veuillez réessayer plus tard",
"updatedSuccess": "Prompt mise à jour",
"updatedSuccessDesc": "Le prompt a été mis à jour avec succès",
"deletedSuccess": "Prompt supprimé",
"deletedSuccessDesc": "Le prompt a été supprimé avec succès"
}
},
"manageShare": {
"title": "Gérer le partage",
"heading": "Configurer l'URL de partage de la page",
"form": {
"url": {
"label": "URL de partage de page",
"placeholder": "Entrez l'URL de partage de la page",
"required": "Veuillez saisir URL de partage de votre page!",
"help": "Pour des raisons de confidentialité, vous pouvez auto-héberger le partage de la page et fournir l'URL ici.<anchor>En savoir plus</anchor>."
}
},
"webshare": {
"heading": "Partage Web",
"columns": {
"title": "Titre",
"url": "URL",
"actions": "Actions"
},
"tooltip": {
"delete": "Supprimer le partage"
},
"confirm": {
"delete": "Êtes-vous sûr de vouloir supprimer ce partage ? Cette action ne peut pas être annulée."
},
"label": "Gérer le partage de pages",
"description": "Activer ou désactiver la fonction de partage de page"
},
"notification": {
"pageShareSuccess": "URL de partage de page mise à jour avec succès",
"someError": "Quelque chose a mal tourné. Veuillez réessayer plus tard",
"webShareDeleteSuccess": "Partage Web supprimé avec succès"
}
},
"ollamaSettings": {
"title": "Réglages de Ollama",
"heading": "Configurer Ollama",
"settings": {
"ollamaUrl": {
"label": "Url de Ollama",
"placeholder": "Entrer l'url de Ollama"
},
"advanced": {
"label": "Configuration avancée de l'URL de Ollama",
"urlRewriteEnabled": {
"label": "Activer ou désactiver l'URL d'origine personnalisée"
},
"rewriteUrl": {
"label": "URL d'origine personnalisée",
"placeholder": "Entrez l'URL d'origine personnalisée"
},
"help": "Si vous avez des problèmes de connexion avec OLLAMA sur Page Assist, vous pouvez configurer une URL d'origine personnalisée. Pour en savoir plus sur la configuration, <anchor>cliquez ici</anchor>."
}
}
},
"manageSearch": {
"title": "Gérer la recherche Web",
"heading": "Configurer la recherche Web"
},
"about": {
"title": "À propos",
"heading": "À propos",
"chromeVersion": "Version de Page Assist",
"ollamaVersion": "Version de Ollama",
"support": "Vous pouvez supporter le projet Page Assist en donnant ou parrainant via les plateformes suivantes:",
"koFi": "Supporter sur ko-fi",
"githubSponsor": "Sponsoriser sur github",
"githubRepo": "Référentiel GitHub"
},
"manageKnowledge": {
"title": "Gérer les connaissances",
"heading": "Configurer la base de connaissances"
},
"rag": {
"title": "Paramètres de RAG",
"ragSettings": {
"label": "Paramètres de RAG",
"model": {
"label": "Modèle d'embedding",
"required": "Veuillez sélectionner un modèle",
"help": "Fortement recommandé d'utiliser des modèles d'embedding comme «momic-embed-text».",
"placeholder": "Sélectionnez un modèle"
},
"chunkSize": {
"label": "Taille",
"placeholder": "Entrez la taille du morceau",
"required": "Veuillez saisir une taille"
},
"chunkOverlap": {
"label": "Chevauchement",
"placeholder": "Entrez le chevauchement des morceaux",
"required": "Veuillez saisir un chevauchement"
}
},
"prompt": {
"label": "Configure RAG Prompt",
"option1": "Normal",
"option2": "Web",
"alert": "La configuration du prompt système ici est déconseillée. Veuillez utiliser la section Gérer les prompts pour ajouter...",
"systemPrompt": "Prompt système",
"systemPromptPlaceholder": "Entrez le prompt système",
"webSearchPrompt": "Prompt de recherche Web",
"webSearchPromptHelp": "Ne supprimez pas `{search_results}` du prompt.",
"webSearchPromptError": "Veuillez saisir un prompt de recherche Web",
"webSearchPromptPlaceholder": "Entrez le prompt de recherche Web",
"webSearchFollowUpPrompt": "Prompt de suivi de recherche Web",
"webSearchFollowUpPromptHelp": "Ne supprimez pas `{chat_history}` et `{question}` du prompt.",
"webSearchFollowUpPromptError": "Veuillez saisir votre prompt de suivi de recherche Web!",
"webSearchFollowUpPromptPlaceholder": "Votre prompt de suivi de recherche Web"
}
}
}

View File

@ -0,0 +1,7 @@
{
"tooltip": {
"embed": "Cela peut prendre quelques minutes pour intégrer la page. S'il vous plaît, patientez...",
"clear": "Effacer l'historique du chat",
"history": "Historique du chat"
}
}

View File

@ -0,0 +1,88 @@
{
"pageAssist": "Page Assist",
"selectAModel": "Seleziona un Modello",
"save": "Salva",
"saved": "Salvato",
"cancel": "Annulla",
"retry": "Riprova",
"share": {
"tooltip": {
"share": "Condividi"
},
"modal": {
"title": "Condividi Collegamento alla Chat"
},
"form": {
"defaultValue": {
"name": "Anonimo",
"title": "Chat Senza Titolo"
},
"title": {
"label": "Titolo della Chat",
"placeholder": "Inserisci il Titolo della Chat",
"required": "Titolo della Chat obbligatorio"
},
"name": {
"label": "Il tuo Nome",
"placeholder": "Inserisci il tuo Nome",
"required": "Nome obbligatorio"
},
"btn": {
"save": "Genera Link",
"saving": "Sto generando il Link..."
}
},
"notification": {
"successGenerate": "Link copiato negli appunti",
"failGenerate": "Impossibile generare il link"
}
},
"copyToClipboard": "Copia negli Appunti",
"webSearch": "Ricerca nel Web",
"regenerate": "Rigenera",
"edit": "Modifica",
"saveAndSubmit": "Salva e Invia",
"editMessage": {
"placeholder": "Scrivi un messaggio..."
},
"submit": "Invia",
"noData": "Nessun Dato",
"noHistory": "Nessuna Cronologia Chat",
"chatWithCurrentPage": "Chatta con la Pagina Corrente",
"beta": "Beta",
"tts": "Leggi ad Alta Voce",
"currentChatModelSettings": "Impostazioni del Modello Corrente",
"modelSettings": {
"label": "Impostazioni del Modello",
"description": "Imposta le opzioni del modello globalmente per tutte le chat",
"form": {
"keepAlive": {
"label": "Keep Alive",
"help": "Imposta il tempo per cui il modello deve rimanere caricato in memoria (default: 5m)",
"placeholder": "Inserisci la durata del Keep Alive (e.g. 5m, 10m, 1h)"
},
"temperature": {
"label": "Temperatura",
"placeholder": "Inserisci la Temperatura (e.g. 0.7, 1.0)"
},
"numCtx": {
"label": "Dimensione del Contesto",
"placeholder": "Inserisci la Dimensione del Contesto (default: 2048)"
},
"seed": {
"label": "Seed",
"placeholder": "Inserisci il Valore Seed (e.g. 1234)",
"help": "Riproducibilità dell'output del modello"
},
"topK": {
"label": "Top K",
"placeholder": "Inserisci il Valore Top K (e.g. 40, 100)"
},
"topP": {
"label": "Top P",
"placeholder": "Inserisci il Valore Top P (e.g. 0.9, 0.95)"
}
},
"advanced": "Altre Impostazioni del Modello"
}
}

View File

@ -0,0 +1,42 @@
{
"addBtn": "Aggiungi nuova Knowledge Base",
"columns": {
"title": "Titolo",
"status": "Stato",
"embeddings": "Modello di Embedding",
"createdAt": "Creato da",
"action": "Azioni"
},
"expandedColumns": {
"name": "Nome"
},
"tooltip": {
"delete": "Elimina"
},
"confirm": {
"delete": "Sei sicuro di voler eliminare questa Knowledge Base?"
},
"deleteSuccess": "Knowledge Base eliminata correttamente",
"status": {
"pending": "In attesa",
"finished": "Completato",
"processing": "In corso"
},
"addKnowledge": "Aggiungi Knowledge Base",
"form": {
"title": {
"label": "Titolo Knowledge Base",
"placeholder": "Inserisci il titolo della Knowledge Base",
"required": "Il Titolo è obbligatorio"
},
"uploadFile": {
"label": "Carica File",
"uploadText": "Trascina un file qui or scegli upload",
"uploadHint": "Tipi di file supportati: .pdf, .csv, .txt, .md, .docx",
"required": "File è obbligatorio"
},
"submit": "Invia",
"success": "Knowledge Base aggiunta correttamente"
},
"noEmbeddingModel": "Aggiungi prima un modello dalla pagina di impostazione di RAG"
}

View File

@ -0,0 +1,12 @@
{
"newChat": "Nuova Chat",
"selectAPrompt": "Scegli un Prompt",
"githubRepository": "GitHub Repository",
"settings": "Impsotazioni",
"sidebarTitle": "Cronologia Chat",
"error": "Errore",
"somethingWentWrong": "Qualcosa è andato storto",
"validationSelectModel": "Scegliere un modello per continuare",
"deleteHistoryConfirmation": "Sei sicuro che vuoi eliminare la cronologia?",
"editHistoryTitle": "Inserisci un nuovo titolo"
}

View File

@ -0,0 +1,29 @@
{
"ollamaState": {
"searching": "Sto cercando Ollama 🦙",
"running": "Ollama è attivo 🦙",
"notRunning": "Impossibile connettersi a Ollama 🦙",
"connectionError": "C'è stato un problema di connessione. Controlla la <anchor>documentazione</anchor> per investigare."
},
"formError": {
"noModel": "Seleziona un modello",
"noEmbeddingModel": "Imposta un modello di embedding da Impostazioni > RAG"
},
"form": {
"textarea": {
"placeholder": "Scrivi un messaggio..."
},
"webSearch": {
"on": "Attivo",
"off": "Disattivato"
}
},
"tooltip": {
"searchInternet": "Cerca su Internet",
"speechToText": "Speech to Text",
"uploadImage": "Carica immagine",
"stopStreaming": "Ferma lo Streaming",
"knowledge": "Conoscenza"
},
"sendWhenEnter": "Invia subito dopo Enter"
}

View File

@ -0,0 +1,289 @@
{
"generalSettings": {
"title": "Impostazioni Generali",
"settings": {
"heading": "Impostazioni Web UI",
"speechRecognitionLang": {
"label": "Lingua per il riconoscimento vocale",
"placeholder": "Scegli una lingua"
},
"language": {
"label": "Lingua",
"placeholder": "Scegli una lingua"
},
"darkMode": {
"label": "Cambia il Tema",
"options": {
"light": "Chiaro",
"dark": "Scuro"
}
},
"copilotResumeLastChat": {
"label": "Riprendi l'ultima chat quando apri il Pannello Laterale (Copilot)"
},
"hideCurrentChatModelSettings": {
"label": "Nascondi le impostazioni correnti del modello Chat"
}
},
"webSearch": {
"heading": "Gestione ricerca Web",
"searchMode": {
"label": "Effettua ricerca web Internet semplice"
},
"provider": {
"label": "Motori di ricerca",
"placeholder": "Scegli un motore di ricerca"
},
"totalSearchResults": {
"label": "Risultati della ricerca",
"placeholder": "Inserisci il totale delle ricerche"
}
},
"system": {
"heading": "Impostazioni di Sistema",
"deleteChatHistory": {
"label": "Elimina cronologia Chat",
"button": "Elimina",
"confirm": "Sei sicuro che vuoi eliminare la tua cronologia delle chat? Questa azione non può essere annullata."
},
"export": {
"label": "Esporta la cronologia Chat, Base di Conoscenza, e Prompts",
"button": "Esporta Dati",
"success": "Esportato con Successo"
},
"import": {
"label": "Imposta la cronologia Chat, Base di Conoscenza, e Prompts",
"button": "Importa Dati",
"success": "Importato con Successo",
"error": "Errore Importazione"
}
},
"tts": {
"heading": "Impostazioni Text-to-Speech",
"ttsEnabled": {
"label": "Abilita Text-to-Speech"
},
"ttsProvider": {
"label": "Text-to-Speech Provider",
"placeholder": "Seleziona un provider"
},
"ttsVoice": {
"label": "Text-to-Speech Voce",
"placeholder": "Seleziona una voce"
},
"ssmlEnabled": {
"label": "Abilita SSML (Speech Synthesis Markup Language)"
}
}
},
"manageModels": {
"title": "Gestione Modelli",
"addBtn": "Aggiungi un nuovo Modello",
"columns": {
"name": "Nome",
"digest": "Digest",
"modifiedAt": "Modificato il",
"size": "Dimensioni",
"actions": "Azioni"
},
"expandedColumns": {
"parentModel": "Modello Padre",
"format": "Formato",
"family": "Famiglia",
"parameterSize": "Numero di Parametri",
"quantizationLevel": "Livello di Quantizzazione"
},
"tooltip": {
"delete": "Elimina Modello",
"repull": "Ri-Scarica Modello"
},
"confirm": {
"delete": "Sei sicuro di voler eliminare questo modello?",
"repull": "Se sicuro che vuoi ri-scaricare questo modello?"
},
"modal": {
"title": "Aggiungi Nuovo Modello",
"placeholder": "Inserisci il Nome Modello",
"pull": "Scarico del Modello"
},
"notification": {
"pullModel": "Scarico del Modello",
"pullModelDescription": "Scaricando il modello {{modelName}}. Per ulteriori dettagli visualizza l'icona dell'estensione.",
"success": "Completato",
"error": "Errore",
"successDescription": "Scarico del modello completato",
"successDeleteDescription": "Eliminazione del modello completato",
"someError": "Qualcosa è andato storto. Riprova più tardi"
}
},
"managePrompts": {
"title": "Gestisci Prompts",
"addBtn": "Aggiungi nuovo Prompt",
"option1": "Normale",
"option2": "RAG",
"questionPrompt": "Question Prompt",
"columns": {
"title": "Titolo",
"prompt": "Prompt",
"type": "Tipo di Prompt",
"actions": "Azioni"
},
"systemPrompt": "Prompt di Sistema",
"quickPrompt": "Prompt Veloce",
"tooltip": {
"delete": "Elimina Prompt",
"edit": "Modifica Prompt"
},
"confirm": {
"delete": "Sei sicuro di voler eliminare questo prompt? L'azione non può essere annullata."
},
"modal": {
"addTitle": "Aggiungi Nuovo Prompt",
"editTitle": "Modifica Prompt"
},
"form": {
"title": {
"label": "Titolo",
"placeholder": "I Miei Prompt",
"required": "Inserisci il Titolo"
},
"prompt": {
"label": "Prompt",
"placeholder": "Inserisci Prompt",
"required": "Scrivi il prompt",
"help": "Puoi usare {key} come variabile nel tuo prompt."
},
"isSystem": {
"label": "Prompt di Sistema"
},
"btnSave": {
"saving": "Aggiungendo Prompt...",
"save": "Aggiungi Prompt"
},
"btnEdit": {
"saving": "Aggiornando Prompt...",
"save": "Aggiorna Prompt"
}
},
"notification": {
"addSuccess": "Prompt Aggiunto",
"addSuccessDesc": "Il Prompt è stato aggiunto correttamente",
"error": "Errore",
"someError": "Qualcosa è andato storto. Riprova più tardi",
"updatedSuccess": "Prompt Aggiornato",
"updatedSuccessDesc": "Il Prompt è stato aggiornato correttmante",
"deletedSuccess": "Prompt Eliminato",
"deletedSuccessDesc": "Il Prompt è stato eliminato correttamente"
}
},
"manageShare": {
"title": "Gestione Condivisioni",
"heading": "Configura l'URL della Pagina di Condivisione",
"form": {
"url": {
"label": "URL Pagina di Condivisione",
"placeholder": "Inserisci URL Pagina di Condivisione",
"required": "Inserisci l'url della pagina di condivisione!",
"help": "Per ragioni di privacy, tu puoi ospitare in self-host la paginacon il seguente URL. <anchor>Leggi altro</anchor>."
}
},
"webshare": {
"heading": "Condivisioni Web",
"columns": {
"title": "Titolo",
"url": "URL",
"actions": "Azioni"
},
"tooltip": {
"delete": "Elimina Condivisione"
},
"confirm": {
"delete": "Sei sicuro che vuoi eliminare questa condivisione? L'azione non può essere annullata."
},
"label": "Gestione Condivisioni",
"description": "Abilita o Disattiva la funzionalità di condivisione"
},
"notification": {
"pageShareSuccess": " URL di condivisione aggiornato correttamente",
"someError": "Qualcosa è andato storto. Riprova più tardi",
"webShareDeleteSuccess": "Condivisione eliminata correttamente"
}
},
"ollamaSettings": {
"title": "Impostazioni Ollama",
"heading": "Configura Ollama",
"settings": {
"ollamaUrl": {
"label": "Ollama URL",
"placeholder": "Inserici l'URL di Ollama"
},
"advanced": {
"label": "Configurazione Avanzata Ollama URL",
"urlRewriteEnabled": {
"label": "Abilita o Disabilita l'URL di Origine Personalizzato"
},
"rewriteUrl": {
"label": "URL di Origine Personalizzato",
"placeholder": "Inserisci URL di Origine Personalizzato"
},
"help": "Se hai problemi di connessione con Ollama su Page Assist, puoi configurare un URL di origine personalizzato. Per saperne di più sulla configurazione, <anchor>clicca qui</anchor>."
}
}
},
"manageSearch": {
"title": "Gestisci Ricerca Web",
"heading": "Configura Ricerca Web"
},
"about": {
"title": "Informazioni",
"heading": "Informazioni",
"chromeVersion": "Versione di Page Assist",
"ollamaVersion": "Versione di Ollama",
"support": "Puoi supportare il progetto Page Assist donando o sponsorizzando attraverso le seguenti piattaforme:",
"koFi": "Supporta su Ko-fi",
"githubSponsor": "Sponsorizza su GitHub",
"githubRepo": "Repository GitHub"
},
"manageKnowledge": {
"title": "Gestisci Conoscenza",
"heading": "Configura Base di Conoscenza"
},
"rag": {
"title": "Impostazioni RAG",
"ragSettings": {
"label": "Impostazioni RAG",
"model": {
"label": "Modello di Embedding",
"required": "Scegliere il modello",
"help": "E' raccomandato l'uso di modelli come `nomic-embed-text`.",
"placeholder": "Seleziona un modello"
},
"chunkSize": {
"label": "Dimensione del Blocco (Chunk Size)",
"placeholder": "Inserisci la Dimensione del Blocco (Chunk Size)",
"required": "Inserisci la Dimensione del Blocco (chunk size)"
},
"chunkOverlap": {
"label": "Sovrapposizione del Blocco (Chunk Overlap)",
"placeholder": "Inserisci la Sovrapposizione del Blocco (Chunk Overlap)",
"required": "Inserisci la Sovrapposizione del Blocco"
}
},
"prompt": {
"label": "Configura il Prompt RAG",
"option1": "Normale",
"option2": "Web",
"alert": "La configurazione del prompt di sistema qui è deprecato. Usa la sezione Gestione Prompt per aggiungere o modificare i prompts.Questa sezione sarà eliminata nelle prossime release",
"systemPrompt": "Prompt di Sistema",
"systemPromptPlaceholder": "Inserisci il Prompt di Sistema",
"webSearchPrompt": "Prompt per la Ricerca Web",
"webSearchPromptHelp": "Non rimuovere `{search_results}` dal prompt.",
"webSearchPromptError": "Inserisci il prompt per la ricerca web",
"webSearchPromptPlaceholder": "Imserosco il Prompt per la Ricerca Web",
"webSearchFollowUpPrompt": "Prompt di Follow Up sulla Ricerca Web",
"webSearchFollowUpPromptHelp": "Non rimuovere `{chat_history}` e `{question}` dal prompt.",
"webSearchFollowUpPromptError": "Inserisci il Prompt di Follow Up della Ricerca Web!",
"webSearchFollowUpPromptPlaceholder": "I tuoi Prompt di Follow Up delle Ricerche Web"
}
}
}

View File

@ -0,0 +1,7 @@
{
"tooltip": {
"embed": "L'inserimento della pagina potrebbe richiedere alcuni minuti. Attendere prego...",
"clear": "Cancella la cronologia della chat",
"history": "Cronologia della chat"
}
}

View File

@ -38,5 +38,5 @@
"submit": "送信", "submit": "送信",
"success": "知識が正常に追加されました" "success": "知識が正常に追加されました"
}, },
"noEmbeddingModel": "最初にOllamaの設定ページから埋め込みモデルを追加してください" "noEmbeddingModel": "最初にRAGの設定ページから埋め込みモデルを追加してください"
} }

View File

@ -7,7 +7,7 @@
}, },
"formError": { "formError": {
"noModel": "モデルを選択してください", "noModel": "モデルを選択してください",
"noEmbeddingModel": "設定 > Ollamaページでembeddingモデルを設定してください" "noEmbeddingModel": "設定 > RAGページでembeddingモデルを設定してください"
}, },
"form": { "form": {
"textarea": { "textarea": {

View File

@ -220,41 +220,6 @@
"label": "OllamaのURL", "label": "OllamaのURL",
"placeholder": "OllamaのURLを入力" "placeholder": "OllamaのURLを入力"
}, },
"ragSettings": {
"label": "RAGの設定",
"model": {
"label": "エンベディングモデル",
"required": "モデルを選択してください",
"help": "`nomic-embed-text`などのエンベディングモデルの使用を強くおすすめします。",
"placeholder": "モデルを選択"
},
"chunkSize": {
"label": "チャンクサイズ",
"placeholder": "チャンクサイズを入力",
"required": "チャンクサイズを入力してください"
},
"chunkOverlap": {
"label": "チャンクオーバーラップ",
"placeholder": "チャンクオーバーラップを入力",
"required": "チャンクオーバーラップを入力してください"
}
},
"prompt": {
"label": "RAGプロンプトを設定",
"option1": "通常",
"option2": "Web",
"alert": "ここでシステムプロンプトを設定することは非推奨となりました。プロンプトの追加や編集には「プロンプトを管理」セクションをご利用ください。このセクションは今後のリリースで削除される予定です。",
"systemPrompt": "システムプロンプト",
"systemPromptPlaceholder": "システムプロンプトを入力",
"webSearchPrompt": "Web検索プロンプト",
"webSearchPromptHelp": "プロンプトから`{search_results}`を削除しないでください。",
"webSearchPromptError": "Web検索プロンプトを入力してください",
"webSearchPromptPlaceholder": "Web検索プロンプトを入力",
"webSearchFollowUpPrompt": "Web検索フォローアッププロンプト",
"webSearchFollowUpPromptHelp": "プロンプトから`{chat_history}`と`{question}`を削除しないでください。",
"webSearchFollowUpPromptError": "Web検索フォローアッププロンプトを入力してください",
"webSearchFollowUpPromptPlaceholder": "Web検索フォローアッププロンプト"
},
"advanced": { "advanced": {
"label": "Ollama URL の高度な設定", "label": "Ollama URL の高度な設定",
"urlRewriteEnabled": { "urlRewriteEnabled": {
@ -285,5 +250,43 @@
"manageKnowledge": { "manageKnowledge": {
"title": "知識を管理する", "title": "知識を管理する",
"heading": "知識ベースを構成する" "heading": "知識ベースを構成する"
},
"rag": {
"title": "RAGの設定",
"ragSettings": {
"label": "RAGの設定",
"model": {
"label": "エンベディングモデル",
"required": "モデルを選択してください",
"help": "`nomic-embed-text`などのエンベディングモデルの使用を強くおすすめします。",
"placeholder": "モデルを選択"
},
"chunkSize": {
"label": "チャンクサイズ",
"placeholder": "チャンクサイズを入力",
"required": "チャンクサイズを入力してください"
},
"chunkOverlap": {
"label": "チャンクオーバーラップ",
"placeholder": "チャンクオーバーラップを入力",
"required": "チャンクオーバーラップを入力してください"
}
},
"prompt": {
"label": "RAGプロンプトを設定",
"option1": "通常",
"option2": "Web",
"alert": "ここでシステムプロンプトを設定することは非推奨となりました。プロンプトの追加や編集には「プロンプトを管理」セクションをご利用ください。このセクションは今後のリリースで削除される予定です。",
"systemPrompt": "システムプロンプト",
"systemPromptPlaceholder": "システムプロンプトを入力",
"webSearchPrompt": "Web検索プロンプト",
"webSearchPromptHelp": "プロンプトから`{search_results}`を削除しないでください。",
"webSearchPromptError": "Web検索プロンプトを入力してください",
"webSearchPromptPlaceholder": "Web検索プロンプトを入力",
"webSearchFollowUpPrompt": "Web検索フォローアッププロンプト",
"webSearchFollowUpPromptHelp": "プロンプトから`{chat_history}`と`{question}`を削除しないでください。",
"webSearchFollowUpPromptError": "Web検索フォローアッププロンプトを入力してください",
"webSearchFollowUpPromptPlaceholder": "Web検索フォローアッププロンプト"
}
} }
} }

View File

@ -38,5 +38,5 @@
"submit": "സമര്‍പ്പിക്കുക", "submit": "സമര്‍പ്പിക്കുക",
"success": "വിജ്ഞാനം വിജയകരമായി ചേര്‍ത്തു" "success": "വിജ്ഞാനം വിജയകരമായി ചേര്‍ത്തു"
}, },
"noEmbeddingModel": "ദയവായി ആദ്യം Ollama ക്രമീകരണ പേജില്‍ നിന്ന് ഒരു എംബെഡിംഗ് മോഡല്‍ ചേര്‍ക്കുക" "noEmbeddingModel": "ദയവായി ആദ്യം RAG ക്രമീകരണ പേജില്‍ നിന്ന് ഒരു എംബെഡിംഗ് മോഡല്‍ ചേര്‍ക്കുക"
} }

View File

@ -7,7 +7,7 @@
}, },
"formError": { "formError": {
"noModel": "ദയവായി ഒരു മോഡല്‍ തിരഞ്ഞെടുക്കുക", "noModel": "ദയവായി ഒരു മോഡല്‍ തിരഞ്ഞെടുക്കുക",
"noEmbeddingModel": "സെറ്റിംഗുകൾ > ഒല്ലാമ പേജിലുള്ള എംബെഡിംഗ് മോഡല്‍ സജ്ജീകരിക്കുക" "noEmbeddingModel": "സെറ്റിംഗുകൾ > RAG പേജിലുള്ള എംബെഡിംഗ് മോഡല്‍ സജ്ജീകരിക്കുക"
}, },
"form": { "form": {
"textarea": { "textarea": {

View File

@ -220,41 +220,6 @@
"label": "Ollama URL", "label": "Ollama URL",
"placeholder": "Ollama URL നല്കുക" "placeholder": "Ollama URL നല്കുക"
}, },
"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": "നിങ്ങളുടെ വെബ് തിരയല്‍ തുടര്‍പ്രോംപ്റ്റ്"
},
"advanced": { "advanced": {
"label": "Advance Ollama URL Configuration", "label": "Advance Ollama URL Configuration",
"urlRewriteEnabled": { "urlRewriteEnabled": {
@ -285,5 +250,43 @@
"manageKnowledge": { "manageKnowledge": {
"title": "വിജ്ഞാനം നിര്‍വ്വഹിക്കുക", "title": "വിജ്ഞാനം നിര്‍വ്വഹിക്കുക",
"heading": "വിജ്ഞാനാധാരം കോണ്‍ഫിഗര്‍ ചെയ്യുക" "heading": "വിജ്ഞാനാധാരം കോണ്‍ഫിഗര്‍ ചെയ്യുക"
},
"rag": {
"title": "RAG സെറ്റിംഗുകൾ",
"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": "നിങ്ങളുടെ വെബ് തിരയല്‍ തുടര്‍പ്രോംപ്റ്റ്"
}
} }
} }

View File

@ -0,0 +1,88 @@
{
"pageAssist": "Page Assist",
"selectAModel": "Selecione um Modelo",
"save": "Salvar",
"saved": "Salvo",
"cancel": "Cancelar",
"retry": "Tentar Novamente",
"share": {
"tooltip": {
"share": "Compartilhar"
},
"modal": {
"title": "Compartilhar link para o Chat"
},
"form": {
"defaultValue": {
"name": "Anônimo",
"title": "Chat sem título"
},
"title": {
"label": "Título do Chat",
"placeholder": "Digite o título do Chat",
"required": "O título do Chat é obrigatório"
},
"name": {
"label": "Seu nome",
"placeholder": "Digite seu nome",
"required": "Seu nome é obrigatório"
},
"btn": {
"save": "Gerar Link",
"saving": "Gerando Link..."
}
},
"notification": {
"successGenerate": "Link copiado para a área de transferência",
"failGenerate": "Falha ao gerar link"
}
},
"copyToClipboard": "Copiar para a área de transferência",
"webSearch": "Pesquisando na web",
"regenerate": "Regenerar",
"edit": "Editar",
"saveAndSubmit": "Salvar e Enviar",
"editMessage": {
"placeholder": "Digite uma mensagem..."
},
"submit": "Enviar",
"noData": "Sem dados",
"noHistory": "Sem histórico de chat",
"chatWithCurrentPage": "Conversar com a página atual",
"beta": "Beta",
"tts": "Ler em voz alta",
"currentChatModelSettings": "Configurações do Modelo de Chat Atual",
"modelSettings": {
"label": "Configurações do Modelo",
"description": "Defina as opções do modelo globalmente para todos os chats",
"form": {
"keepAlive": {
"label": "Manter Vivo",
"help": "controla quanto tempo o modelo permanecerá carregado na memória após a solicitação (padrão: 5m)",
"placeholder": "Digite a duração do Manter Vivo (ex: 5m, 10m, 1h)"
},
"temperature": {
"label": "Temperatura",
"placeholder": "Digite o valor da Temperatura (ex: 0.7, 1.0)"
},
"numCtx": {
"label": "Janela de contexto",
"placeholder": "Digite o valor do tamanho da janela de contexto (padrão: 2048)"
},
"seed": {
"label": "Semente",
"placeholder": "Digite o valor da Semente (ex: 1234)",
"help": "Reprodutibilidade da saída do modelo"
},
"topK": {
"label": "Top K",
"placeholder": "Digite o valor do Top K (ex: 40, 100)"
},
"topP": {
"label": "Top P",
"placeholder": "Digite o valor do Top P (ex: 0.9, 0.95)"
}
},
"advanced": "Mais Configurações do Modelo"
}
}

View File

@ -0,0 +1,42 @@
{
"addBtn": "Adicionar Novo Conhecimento",
"columns": {
"title": "Título",
"status": "Status",
"embeddings": "Modelo de Embedding",
"createdAt": "Criado Em",
"action": "Ações"
},
"expandedColumns": {
"name": "Nome"
},
"tooltip": {
"delete": "Excluir"
},
"confirm": {
"delete": "Você tem certeza que deseja excluir este conhecimento?"
},
"deleteSuccess": "Conhecimento excluído com sucesso",
"status": {
"pending": "Pendente",
"finished": "Concluído",
"processing": "Processando"
},
"addKnowledge": "Adicionar Conhecimento",
"form": {
"title": {
"label": "Título do Conhecimento",
"placeholder": "Insira o título do conhecimento",
"required": "Título do conhecimento é obrigatório"
},
"uploadFile": {
"label": "Upload de Arquivo",
"uploadText": "Arraste e solte um arquivo aqui ou clique para upload",
"uploadHint": "Tipos de arquivo suportados: .pdf, .csv, .txt, .md, .docx",
"required": "Arquivo é obrigatório"
},
"submit": "Enviar",
"success": "Conhecimento adicionado com sucesso"
},
"noEmbeddingModel": "Por favor, adicione um modelo de embedding primeiro na página de configurações do RAG"
}

View File

@ -0,0 +1,12 @@
{
"newChat": "Novo Chat",
"selectAPrompt": "Selecione um Prompt",
"githubRepository": "Repositório do GitHub",
"settings": "Configurações",
"sidebarTitle": "Histórico de Chat",
"error": "Erro",
"somethingWentWrong": "Algo deu errado",
"validationSelectModel": "Selecione um modelo para continuar",
"deleteHistoryConfirmation": "Você tem certeza de que deseja excluir este histórico?",
"editHistoryTitle": "Insira um novo título"
}

View File

@ -0,0 +1,29 @@
{
"ollamaState": {
"searching": "Buscando seu Ollama 🦙",
"running": "O Ollama está rodando 🦙",
"notRunning": "Não foi possível conectar ao Ollama 🦙",
"connectionError": "Parece que você está tendo um erro de conexão. Por favor, consulte a <anchor>documentação</anchor> para solucionar o problema."
},
"formError": {
"noModel": "Por favor, selecione um modelo",
"noEmbeddingModel": "Por favor, defina um modelo de embedding na página de configurações > RAG"
},
"form": {
"textarea": {
"placeholder": "Insira um mensagem..."
},
"webSearch": {
"on": "On",
"off": "Off"
}
},
"tooltip": {
"searchInternet": "Pesquisar Internet",
"speechToText": "Fala para Texto",
"uploadImage": "Carregar Imagem",
"stopStreaming": "Parar Transmissão",
"knowledge": "Conhecimento"
},
"sendWhenEnter": "Enviar quando pressionar Enter"
}

View File

@ -0,0 +1,289 @@
{
"generalSettings": {
"title": "Configurações Gerais",
"settings": {
"heading": "Configurações da Interface Web",
"speechRecognitionLang": {
"label": "Linguagem de Reconhecimento de Fala",
"placeholder": "Selecione uma linguagem"
},
"language": {
"label": "Linguagem",
"placeholder": "Selecione uma linguagem"
},
"darkMode": {
"label": "Alterar Tema",
"options": {
"light": "Claro",
"dark": "Escuro"
}
},
"copilotResumeLastChat": {
"label": "Retomar o último chat ao abrir o Painel Lateral (Copilot)"
},
"hideCurrentChatModelSettings": {
"label": "Ocultar Configurações do Modelo de Chat Atual"
}
},
"webSearch": {
"heading": "Gerenciar Pesquisa na Web",
"searchMode": {
"label": "Realizar Pesquisa Simples na Internet"
},
"provider": {
"label": "Motor de Busca",
"placeholder": "Selecione um motor de busca"
},
"totalSearchResults": {
"label": "Resultados de Pesquisa Totais",
"placeholder": "Insira Resultados de Pesquisa Totais"
}
},
"system": {
"heading": "Configurações do Sistema",
"deleteChatHistory": {
"label": "Excluir Histórico de Chat",
"button": "Excluir",
"confirm": "Você tem certeza de que deseja excluir seu histórico de chat? Esta ação não pode ser desfeita."
},
"export": {
"label": "Exportar Histórico de Chat, Base de Conhecimento e Prompts",
"button": "Exportar Dados",
"success": "Exportação Bem-Sucedida"
},
"import": {
"label": "Importar Histórico de Chat, Base de Conhecimento e Prompts",
"button": "Importar Dados",
"success": "Importação Bem-Sucedida",
"error": "Erro de Importação"
}
},
"tts": {
"heading": "Configurações de Fala",
"ttsEnabled": {
"label": "Habilitar Fala"
},
"ttsProvider": {
"label": "Fornecedor de Fala",
"placeholder": "Selecione um fornecedor"
},
"ttsVoice": {
"label": "Voz de Fala",
"placeholder": "Selecione uma voz"
},
"ssmlEnabled": {
"label": "Habilitar SSML (Linguagem de Marcação de Sintese de Fala)"
}
}
},
"manageModels": {
"title": "Gerenciar Modelos",
"addBtn": "Adicionar Novo Modelo",
"columns": {
"name": "Nome",
"digest": "Resumo",
"modifiedAt": "Modificado Em",
"size": "Tamanho",
"actions": "Ações"
},
"expandedColumns": {
"parentModel": "Modelo Pai",
"format": "Formato",
"family": "Família",
"parameterSize": "Tamanho de Parâmetro",
"quantizationLevel": "Nível de Quantização"
},
"tooltip": {
"delete": "Excluir Modelo",
"repull": "Re-Puxar Modelo"
},
"confirm": {
"delete": "Você tem certeza de que deseja excluir este modelo?",
"repull": "Você tem certeza de que deseja re-puxar este modelo?"
},
"modal": {
"title": "Adicionar Novo Modelo",
"placeholder": "Insira o nome do modelo",
"pull": "Puxar Modelo"
},
"notification": {
"pullModel": "Puxando Modelo",
"pullModelDescription": "Puxando modelo {{modelName}}. Para mais detalhes, verifique o ícone da extensão.",
"success": "Sucesso",
"error": "Erro",
"successDescription": "Modelo puxado com sucesso",
"successDeleteDescription": "Modelo excluído com sucesso",
"someError": "Algo deu errado. Tente novamente mais tarde"
}
},
"managePrompts": {
"title": "Gerenciar Prompts",
"addBtn": "Adicionar Novo Prompt",
"option1": "Normal",
"option2": "RAG",
"questionPrompt": "Prompt de Pergunta",
"columns": {
"title": "Título",
"prompt": "Prompt",
"type": "Tipo de Prompt",
"actions": "Ações"
},
"systemPrompt": "Prompt do Sistema",
"quickPrompt": "Prompt Rápido",
"tooltip": {
"delete": "Excluir Prompt",
"edit": "Editar Prompt"
},
"confirm": {
"delete": "Você tem certeza de que deseja excluir este prompt? Esta ação não pode ser desfeita."
},
"modal": {
"addTitle": "Adicionar Novo Prompt",
"editTitle": "Editar Prompt"
},
"form": {
"title": {
"label": "Título",
"placeholder": "Meu Prompt Incrível",
"required": "Por favor, insira um título"
},
"prompt": {
"label": "Prompt",
"placeholder": "Insira o prompt",
"required": "Por favor, insira um prompt",
"help": "Você pode usar {key} como variável em seu prompt."
},
"isSystem": {
"label": "É um Prompt do Sistema"
},
"btnSave": {
"saving": "Adicionando Prompt...",
"save": "Adicionar Prompt"
},
"btnEdit": {
"saving": "Atualizando Prompt...",
"save": "Atualizar Prompt"
}
},
"notification": {
"addSuccess": "Prompt Adicionado",
"addSuccessDesc": "Prompt adicionado com sucesso",
"error": "Erro",
"someError": "Algo deu errado. Tente novamente mais tarde",
"updatedSuccess": "Prompt Atualizado",
"updatedSuccessDesc": "Prompt atualizado com sucesso",
"deletedSuccess": "Prompt Excluído",
"deletedSuccessDesc": "Prompt excluído com sucesso"
}
},
"manageShare": {
"title": "Gerenciar Compartilhamento",
"heading": "Configurar URL de Compartilhamento de Página",
"form": {
"url": {
"label": "URL de Compartilhamento de Página",
"placeholder": "Insira a URL de Compartilhamento de Página",
"required": "Por favor, insira a URL de Compartilhamento de Página!",
"help": "Por motivos de privacidade, você pode hospedar a página de compartilhamento e fornecer a URL aqui. <anchor>Saiba mais</anchor>."
}
},
"webshare": {
"heading": "Compartilhamento na Web",
"columns": {
"title": "Título",
"url": "URL",
"actions": "Ações"
},
"tooltip": {
"delete": "Excluir Compartilhamento"
},
"confirm": {
"delete": "Você tem certeza de que deseja excluir este compartilhamento? Esta ação não pode ser desfeita."
},
"label": "Gerenciar Compartilhamento de Página",
"description": "Habilitar ou desabilitar o recurso de compartilhamento de página"
},
"notification": {
"pageShareSuccess": "URL de Compartilhamento de Página atualizada com sucesso",
"someError": "Algo deu errado. Tente novamente mais tarde",
"webShareDeleteSuccess": "Compartilhamento na Web excluído com sucesso"
}
},
"ollamaSettings": {
"title": "Configurações do Ollama",
"heading": "Configurar Ollama",
"settings": {
"ollamaUrl": {
"label": "URL do Ollama",
"placeholder": "Insira a URL do Ollama"
},
"advanced": {
"label": "Configuração Avançada da URL do Ollama",
"urlRewriteEnabled": {
"label": "Habilitar ou Desabilitar URL de Origem Personalizada"
},
"rewriteUrl": {
"label": "URL de Origem Personalizada",
"placeholder": "Insira a URL de Origem Personalizada"
},
"help": "Se você tiver problemas de conexão com o Ollama no Page Assist, você pode configurar uma URL de origem personalizada. Para saber mais sobre a configuração, <anchor>clique aqui</anchor>."
}
}
},
"manageSearch": {
"title": "Gerenciar Pesquisa na Web",
"heading": "Configurar Pesquisa na Web"
},
"about": {
"title": "Sobre",
"heading": "Sobre",
"chromeVersion": "Versão do Page Assist",
"ollamaVersion": "Versão do Ollama",
"support": "Você pode apoiar o projeto Page Assist fazendo doações ou patrocínios através das seguintes plataformas:",
"koFi": "Apoiador no Ko-fi",
"githubSponsor": "Patrocinador no GitHub",
"githubRepo": "Repositório do GitHub"
},
"manageKnowledge": {
"title": "Gerenciar Conhecimento",
"heading": "Configurar Base de Conhecimento"
},
"rag": {
"title": "Configurações do RAG",
"ragSettings": {
"label": "Configurações do RAG",
"model": {
"label": "Modelo de Incorporação",
"required": "Por favor, selecione um modelo",
"help": "É altamente recomendável usar modelos de incorporação como `nomic-embed-text`.",
"placeholder": "Selecione um modelo"
},
"chunkSize": {
"label": "Tamanho do Chunk",
"placeholder": "Insira o tamanho do chunk",
"required": "Por favor, insira o tamanho do chunk"
},
"chunkOverlap": {
"label": "Sobreposição do Chunk",
"placeholder": "Insira a sobreposição do chunk",
"required": "Por favor, insira a sobreposição do chunk"
}
},
"prompt": {
"label": "Configurar Prompt do RAG",
"option1": "Normal",
"option2": "Web",
"alert": "Configurar o prompt do sistema aqui está depreciado. Por favor, use a seção Gerenciar Prompts para adicionar ou editar prompts. Esta seção será removida em uma versão futura",
"systemPrompt": "Prompt do Sistema",
"systemPromptPlaceholder": "Insira o prompt do sistema",
"webSearchPrompt": "Prompt de Pesquisa na Web",
"webSearchPromptHelp": "Não remova `{search_results}` do prompt.",
"webSearchPromptError": "Por favor, insira um prompt de pesquisa na web",
"webSearchPromptPlaceholder": "Insira o prompt de pesquisa na web",
"webSearchFollowUpPrompt": "Prompt de Seguimento de Pesquisa na Web",
"webSearchFollowUpPromptHelp": "Não remova `{chat_history}` e `{question}` do prompt.",
"webSearchFollowUpPromptError": "Por favor, insira o prompt de seguimento de pesquisa na web",
"webSearchFollowUpPromptPlaceholder": "Seu prompt de seguimento de pesquisa na web"
}
}
}

View File

@ -0,0 +1,7 @@
{
"tooltip": {
"embed": "Pode demorar alguns minutos para embedear a página. Por favor, aguarde...",
"clear": "Excluir histórico de conversa",
"history": "Histórico de conversa"
}
}

View File

@ -38,5 +38,5 @@
"submit": "Отправить", "submit": "Отправить",
"success": "Знание успешно добавлено" "success": "Знание успешно добавлено"
}, },
"noEmbeddingModel": "Пожалуйста, сначала добавьте модель вложения на странице настроек Ollama" "noEmbeddingModel": "Пожалуйста, сначала добавьте модель вложения на странице настроек RAG"
} }

View File

@ -7,7 +7,7 @@
}, },
"formError": { "formError": {
"noModel": "Пожалуйста, выберите модель", "noModel": "Пожалуйста, выберите модель",
"noEmbeddingModel": "Пожалуйста, установите модель вложения на странице Настройки > Ollama" "noEmbeddingModel": "Пожалуйста, установите модель вложения на странице Настройки > RAG"
}, },
"form": { "form": {
"textarea": { "textarea": {

View File

@ -217,41 +217,7 @@
"label": "URL Ollama", "label": "URL Ollama",
"placeholder": "Введите 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": "Ваша подсказка для последующего веб-поиска"
},
"advanced": { "advanced": {
"label": "Расширенная конфигурация URL Ollama", "label": "Расширенная конфигурация URL Ollama",
"urlRewriteEnabled": { "urlRewriteEnabled": {
@ -282,5 +248,43 @@
"manageKnowledge": { "manageKnowledge": {
"title": "Управление знаниями", "title": "Управление знаниями",
"heading": "Настройка базы знаний" "heading": "Настройка базы знаний"
},
"rag": {
"title": "Настройки RAG",
"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": "Ваша подсказка для последующего веб-поиска"
}
} }
} }

View File

@ -38,5 +38,5 @@
"submit": "提交", "submit": "提交",
"success": "知识添加成功" "success": "知识添加成功"
}, },
"noEmbeddingModel": "请先从Ollama设置页面添加一个嵌入模型" "noEmbeddingModel": "请先从RAG设置页面添加一个嵌入模型"
} }

View File

@ -7,7 +7,7 @@
}, },
"formError": { "formError": {
"noModel": "请选择一个模型", "noModel": "请选择一个模型",
"noEmbeddingModel": "请在设置>Ollama页面设置一个文本嵌入模型" "noEmbeddingModel": "请在设置>RAG页面设置一个文本嵌入模型"
}, },
"form": { "form": {
"textarea": { "textarea": {

View File

@ -221,41 +221,7 @@
"label": "Ollama URL", "label": "Ollama URL",
"placeholder": "输入 Ollama URL" "placeholder": "输入 Ollama URL"
}, },
"ragSettings": {
"label": "RAG 设置",
"model": {
"label": "文本嵌入模型",
"required": "请选择一个模型",
"help": "建议使用文本嵌入模型,如 `nomic-embed-text`。",
"placeholder": "选择一个模型"
},
"chunkSize": {
"label": "嵌入大小",
"placeholder": "1024-∞",
"required": "请输入块大小"
},
"chunkOverlap": {
"label": "嵌入重叠",
"placeholder": "256-∞",
"required": "请输入嵌入重叠"
}
},
"prompt": {
"label": "配置 RAG 提示词",
"option1": "普通",
"option2": "搜索",
"alert": "在此配置系统提示词已过时。请使用管理提示词部分添加或编辑提示词。此部分将在未来版本中删除",
"systemPrompt": "系统提示词",
"systemPromptPlaceholder": "输入系统提示词",
"webSearchPrompt": "网页搜索提示词",
"webSearchPromptHelp": "请勿从提示词中删除 `{search_results}`。",
"webSearchPromptError": "请输入一个网页搜索提示词",
"webSearchPromptPlaceholder": "输入网页搜索提示词",
"webSearchFollowUpPrompt": "网页搜索追问提示词",
"webSearchFollowUpPromptHelp": "请勿从提示词中删除 `{chat_history}` 和 `{question}`。",
"webSearchFollowUpPromptError": "请输入您的网页搜索追问提示词!",
"webSearchFollowUpPromptPlaceholder": "您的网页搜索追问提示词"
},
"advanced": { "advanced": {
"label": "Ollama URL 高级配置", "label": "Ollama URL 高级配置",
"urlRewriteEnabled": { "urlRewriteEnabled": {
@ -286,5 +252,43 @@
"manageKnowledge": { "manageKnowledge": {
"title": "管理知识", "title": "管理知识",
"heading": "配置知识库" "heading": "配置知识库"
},
"rag": {
"title": "RAG 设置",
"ragSettings": {
"label": "RAG 设置",
"model": {
"label": "文本嵌入模型",
"required": "请选择一个模型",
"help": "建议使用文本嵌入模型,如 `nomic-embed-text`。",
"placeholder": "选择一个模型"
},
"chunkSize": {
"label": "嵌入大小",
"placeholder": "1024-∞",
"required": "请输入块大小"
},
"chunkOverlap": {
"label": "嵌入重叠",
"placeholder": "256-∞",
"required": "请输入嵌入重叠"
}
},
"prompt": {
"label": "配置 RAG 提示词",
"option1": "普通",
"option2": "搜索",
"alert": "在此配置系统提示词已过时。请使用管理提示词部分添加或编辑提示词。此部分将在未来版本中删除",
"systemPrompt": "系统提示词",
"systemPromptPlaceholder": "输入系统提示词",
"webSearchPrompt": "网页搜索提示词",
"webSearchPromptHelp": "请勿从提示词中删除 `{search_results}`。",
"webSearchPromptError": "请输入一个网页搜索提示词",
"webSearchPromptPlaceholder": "输入网页搜索提示词",
"webSearchFollowUpPrompt": "网页搜索追问提示词",
"webSearchFollowUpPromptHelp": "请勿从提示词中删除 `{chat_history}` 和 `{question}`。",
"webSearchFollowUpPromptError": "请输入您的网页搜索追问提示词!",
"webSearchFollowUpPromptPlaceholder": "您的网页搜索追问提示词"
}
} }
} }

View File

@ -0,0 +1,66 @@
import { Tooltip } from "antd"
import { CheckIcon, ClipboardIcon } from "lucide-react"
import { FC, useState } from "react"
import { useTranslation } from "react-i18next"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism"
interface Props {
language: string
value: string
}
export const CodeBlock: FC<Props> =({ language, value }) => {
const [isBtnPressed, setIsBtnPressed] = useState(false)
const { t } = useTranslation("common")
return (
<>
<div className="code relative text-base font-sans codeblock bg-zinc-950 rounded-md overflow-hidden">
<div className="flex bg-gray-800 items-center justify-between py-1.5 px-4">
<span className="text-xs lowercase text-gray-200">{language}</span>
<div className="flex items-center">
<Tooltip title={t("copyToClipboard")}>
<button
onClick={() => {
navigator.clipboard.writeText(value)
setIsBtnPressed(true)
setTimeout(() => {
setIsBtnPressed(false)
}, 4000)
}}
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-200 hover:bg-gray-700 hover:text-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-100">
{!isBtnPressed ? (
<ClipboardIcon className="h-4 w-4" />
) : (
<CheckIcon className="h-4 w-4 text-green-400" />
)}
</button>
</Tooltip>
</div>
</div>
<SyntaxHighlighter
language={language}
style={coldarkDark}
PreTag="div"
customStyle={{
margin: 0,
width: "100%",
background: "transparent",
padding: "1.5rem 1rem"
}}
lineNumberStyle={{
userSelect: "none"
}}
codeTagProps={{
style: {
fontSize: "0.9rem",
fontFamily: "var(--font-mono)"
}
}}>
{value}
</SyntaxHighlighter>
</div>
</>
)
}

View File

@ -1,17 +1,13 @@
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import remarkGfm from "remark-gfm" import remarkGfm from "remark-gfm"
import { nightOwl } from "react-syntax-highlighter/dist/cjs/styles/prism"
import remarkMath from "remark-math" import remarkMath from "remark-math"
import ReactMarkdown from "react-markdown" import ReactMarkdown from "react-markdown"
import "property-information" import "property-information"
import React from "react" import React from "react"
import { Tooltip } from "antd" import { CodeBlock } from "./CodeBlock"
import { CheckIcon, ClipboardIcon } from "lucide-react"
import { useTranslation } from "react-i18next"
export default function Markdown({ message }: { message: string }) { export default function Markdown({ message }: { message: string }) {
const [isBtnPressed, setIsBtnPressed] = React.useState(false)
const { t } = useTranslation("common")
return ( return (
<React.Fragment> <React.Fragment>
<ReactMarkdown <ReactMarkdown
@ -21,48 +17,10 @@ export default function Markdown({ message }: { message: string }) {
code({ node, inline, className, children, ...props }) { code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || "") const match = /language-(\w+)/.exec(className || "")
return !inline ? ( return !inline ? (
<div className="code relative text-base bg-gray-800 rounded-md overflow-hidden"> <CodeBlock
<div className="flex items-center justify-between py-1.5 px-4"> language={match ? match[1] : ""}
<span className="text-xs lowercase text-gray-200"> value={String(children).replace(/\n$/, "")}
{className && className.replace("language-", "")} />
</span>
<div className="flex items-center">
<Tooltip title={t("copyToClipboard")}>
<button
onClick={() => {
navigator.clipboard.writeText(children[0] as string)
setIsBtnPressed(true)
setTimeout(() => {
setIsBtnPressed(false)
}, 4000)
}}
className="flex gap-1.5 items-center rounded bg-none p-1 text-xs text-gray-200 hover:bg-gray-700 hover:text-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 focus:ring-offset-gray-100">
{!isBtnPressed ? (
<ClipboardIcon className="h-4 w-4" />
) : (
<CheckIcon className="h-4 w-4 text-green-400" />
)}
</button>
</Tooltip>
</div>
</div>
<SyntaxHighlighter
{...props}
children={String(children).replace(/\n$/, "")}
style={nightOwl}
key={Math.random()}
customStyle={{
margin: 0,
fontSize: "1rem",
lineHeight: "1.5rem"
}}
language={(match && match[1]) || ""}
codeTagProps={{
className: "text-sm"
}}
/>
</div>
) : ( ) : (
<code className={`${className} font-semibold`} {...props}> <code className={`${className} font-semibold`} {...props}>
{children} {children}

View File

@ -49,7 +49,7 @@ export const EditMessageForm = (props: Props) => {
<div className="flex justify-center space-x-2 mt-2"> <div className="flex justify-center space-x-2 mt-2">
<button <button
aria-label={t("save")} aria-label={t("save")}
className="bg-white dark:bg-black px-2.5 py-2 rounded-md text-gray-700 dark:text-gray-300 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-100 dark:hover:bg-gray-900"> className="bg-black px-2.5 py-2 rounded-md text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500 hover:bg-gray-900">
{props.isBot ? t("save") : t("saveAndSubmit")} {props.isBot ? t("save") : t("saveAndSubmit")}
</button> </button>
<button <button

View File

@ -17,7 +17,7 @@ export const AdvanceOllamaSettings = () => {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("ollamaSettings.settings.advanced.urlRewriteEnabled.label")} {t("ollamaSettings.settings.advanced.urlRewriteEnabled.label")}
</span> </span>
<div> <div>
@ -29,7 +29,7 @@ export const AdvanceOllamaSettings = () => {
</div> </div>
</div> </div>
<div className="flex flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 mb-3"> <span className="text-gray-700 dark:text-neutral-50 mb-3">
{t("ollamaSettings.settings.advanced.rewriteUrl.label")} {t("ollamaSettings.settings.advanced.rewriteUrl.label")}
</span> </span>
<div> <div>

View File

@ -0,0 +1,221 @@
import { useStorage } from "@plasmohq/storage/hook"
import {
BrainCog,
ChevronLeft,
CogIcon,
ComputerIcon,
GithubIcon,
PanelLeftIcon,
SquarePen,
ZapIcon
} from "lucide-react"
import { useTranslation } from "react-i18next"
import { useLocation, NavLink } from "react-router-dom"
import { OllamaIcon } from "../Icons/Ollama"
import { SelectedKnowledge } from "../Option/Knowledge/SelectedKnwledge"
import { ModelSelect } from "../Common/ModelSelect"
import { PromptSelect } from "../Common/PromptSelect"
import { useQuery } from "@tanstack/react-query"
import { fetchChatModels } from "~/services/ollama"
import { useMessageOption } from "~/hooks/useMessageOption"
import { Select, Tooltip } from "antd"
import { getAllPrompts } from "@/db"
import { ShareBtn } from "~/components/Common/ShareBtn"
type Props = {
setSidebarOpen: (open: boolean) => void
setOpenModelSettings: (open: boolean) => void
}
export const Header: React.FC<Props> = ({
setOpenModelSettings,
setSidebarOpen
}) => {
const { t } = useTranslation(["option", "common"])
const [shareModeEnabled] = useStorage("shareMode", false)
const [hideCurrentChatModelSettings] = useStorage(
"hideCurrentChatModelSettings",
false
)
const {
selectedModel,
setSelectedModel,
clearChat,
selectedSystemPrompt,
setSelectedQuickPrompt,
setSelectedSystemPrompt,
messages,
streaming
} = useMessageOption()
const {
data: models,
isLoading: isModelsLoading,
isFetching: isModelsFetching
} = useQuery({
queryKey: ["fetchModel"],
queryFn: () => fetchChatModels({ returnEmpty: true }),
refetchInterval: 15000
})
const { data: prompts, isLoading: isPromptLoading } = useQuery({
queryKey: ["fetchAllPromptsLayout"],
queryFn: getAllPrompts
})
const { pathname } = useLocation()
const getPromptInfoById = (id: string) => {
return prompts?.find((prompt) => prompt.id === id)
}
const handlePromptChange = (value?: string) => {
if (!value) {
setSelectedSystemPrompt(undefined)
setSelectedQuickPrompt(undefined)
return
}
const prompt = getPromptInfoById(value)
if (prompt?.is_system) {
setSelectedSystemPrompt(prompt.id)
} else {
setSelectedSystemPrompt(undefined)
setSelectedQuickPrompt(prompt!.content)
}
}
return (
<div className="sticky top-0 z-[999] flex h-16 p-3 bg-gray-50 border-b dark:bg-[#171717] dark:border-gray-600">
<div className="flex gap-2 items-center">
{pathname !== "/" && (
<div>
<NavLink
to="/"
className="text-gray-500 items-center dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<ChevronLeft className="w-8 h-8" />
</NavLink>
</div>
)}
<div>
<button
className="text-gray-500 dark:text-gray-400"
onClick={() => setSidebarOpen(true)}>
<PanelLeftIcon className="w-6 h-6" />
</button>
</div>
<div>
<button
onClick={clearChat}
className="inline-flex dark:bg-transparent bg-white items-center rounded-lg border dark:border-gray-700 bg-transparent px-3 py-2.5 text-xs lg:text-sm font-medium leading-4 text-gray-800 dark:text-white disabled:opacity-50 ease-in-out transition-colors duration-200 hover:bg-gray-100 dark:hover:bg-gray-800 dark:hover:text-white">
<SquarePen className="h-5 w-5 " />
<span className=" truncate ml-3">{t("newChat")}</span>
</button>
</div>
<span className="text-lg font-thin text-zinc-300 dark:text-zinc-600">
{"/"}
</span>
<div className="hidden lg:block">
<Select
value={selectedModel}
onChange={(e) => {
setSelectedModel(e)
localStorage.setItem("selectedModel", e)
}}
size="large"
loading={isModelsLoading || isModelsFetching}
filterOption={(input, option) =>
option.label.key.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
showSearch
placeholder={t("common:selectAModel")}
className="w-72"
options={models?.map((model) => ({
label: (
<span
key={model.model}
className="flex flex-row gap-3 items-center truncate">
<OllamaIcon className="w-5 h-5" />
<span className="truncate">{model.name}</span>
</span>
),
value: model.model
}))}
/>
</div>
<div className="lg:hidden">
<ModelSelect />
</div>
<span className="text-lg font-thin text-zinc-300 dark:text-zinc-600">
{"/"}
</span>
<div className="hidden lg:block">
<Select
size="large"
loading={isPromptLoading}
showSearch
placeholder={t("selectAPrompt")}
className="w-60"
allowClear
onChange={handlePromptChange}
value={selectedSystemPrompt}
filterOption={(input, option) =>
//@ts-ignore
option.label.key.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
options={prompts?.map((prompt) => ({
label: (
<span
key={prompt.title}
className="flex flex-row gap-3 items-center">
{prompt.is_system ? (
<ComputerIcon className="w-4 h-4" />
) : (
<ZapIcon className="w-4 h-4" />
)}
{prompt.title}
</span>
),
value: prompt.id
}))}
/>
</div>
<div className="lg:hidden">
<PromptSelect />
</div>
<SelectedKnowledge />
</div>
<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">
{!hideCurrentChatModelSettings && (
<Tooltip title={t("common:currentChatModelSettings")}>
<button
onClick={() => setOpenModelSettings(true)}
className="!text-gray-500 dark:text-gray-300 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<BrainCog className="w-6 h-6" />
</button>
</Tooltip>
)}
{pathname === "/" &&
messages.length > 0 &&
!streaming &&
shareModeEnabled && <ShareBtn messages={messages} />}
<Tooltip title={t("githubRepository")}>
<a
href="https://github.com/n4ze3m/page-assist"
target="_blank"
className="!text-gray-500 hidden lg:block dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<GithubIcon className="w-6 h-6" />
</a>
</Tooltip>
<Tooltip title={t("settings")}>
<NavLink
to="/settings"
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<CogIcon className="w-6 h-6" />
</NavLink>
</Tooltip>
</div>
</div>
</div>
</div>
)
}

View File

@ -1,30 +1,12 @@
import React, { useState } from "react" import React, { useState } from "react"
import { useLocation, NavLink } from "react-router-dom"
import { Sidebar } from "../Option/Sidebar" import { Sidebar } from "../Option/Sidebar"
import { Drawer, Select, Tooltip } from "antd" import { Drawer } from "antd"
import { useQuery } from "@tanstack/react-query"
import { fetchChatModels, getAllModels } from "~/services/ollama"
import { useMessageOption } from "~/hooks/useMessageOption"
import {
BrainCog,
ChevronLeft,
CogIcon,
ComputerIcon,
GithubIcon,
PanelLeftIcon,
SquarePen,
ZapIcon
} from "lucide-react"
import { getAllPrompts } from "@/db"
import { ShareBtn } from "~/components/Common/ShareBtn"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { OllamaIcon } from "../Icons/Ollama"
import { SelectedKnowledge } from "../Option/Knowledge/SelectedKnwledge"
import { useStorage } from "@plasmohq/storage/hook"
import { ModelSelect } from "../Common/ModelSelect"
import { PromptSelect } from "../Common/PromptSelect"
import { CurrentChatModelSettings } from "../Common/Settings/CurrentChatModelSettings" import { CurrentChatModelSettings } from "../Common/Settings/CurrentChatModelSettings"
import { Header } from "./Header"
export default function OptionLayout({ export default function OptionLayout({
children children
@ -33,204 +15,16 @@ export default function OptionLayout({
}) { }) {
const [sidebarOpen, setSidebarOpen] = useState(false) const [sidebarOpen, setSidebarOpen] = useState(false)
const { t } = useTranslation(["option", "common"]) const { t } = useTranslation(["option", "common"])
const [shareModeEnabled] = useStorage("shareMode", false)
const [openModelSettings, setOpenModelSettings] = useState(false) const [openModelSettings, setOpenModelSettings] = useState(false)
const [hideCurrentChatModelSettings] = useStorage(
"hideCurrentChatModelSettings",
false
)
const {
selectedModel,
setSelectedModel,
clearChat,
selectedSystemPrompt,
setSelectedQuickPrompt,
setSelectedSystemPrompt,
messages,
streaming
} = useMessageOption()
const {
data: models,
isLoading: isModelsLoading,
isFetching: isModelsFetching
} = useQuery({
queryKey: ["fetchModel"],
queryFn: () => fetchChatModels({ returnEmpty: true }),
refetchInterval: 15000
})
const { data: prompts, isLoading: isPromptLoading } = useQuery({
queryKey: ["fetchAllPromptsLayout"],
queryFn: getAllPrompts
})
const { pathname } = useLocation()
const getPromptInfoById = (id: string) => {
return prompts?.find((prompt) => prompt.id === id)
}
const handlePromptChange = (value?: string) => {
if (!value) {
setSelectedSystemPrompt(undefined)
setSelectedQuickPrompt(undefined)
return
}
const prompt = getPromptInfoById(value)
if (prompt?.is_system) {
setSelectedSystemPrompt(prompt.id)
} else {
setSelectedSystemPrompt(undefined)
setSelectedQuickPrompt(prompt!.content)
}
}
return ( return (
<div> <>
<div> <div className="flex flex-col min-h-screen">
<div className="flex flex-col"> <Header
<div className="sticky top-0 z-[999] flex h-16 p-3 bg-gray-50 border-b dark:bg-[#171717] dark:border-gray-600"> setSidebarOpen={setSidebarOpen}
<div className="flex gap-2 items-center"> setOpenModelSettings={setOpenModelSettings}
{pathname !== "/" && ( />
<div> <main className="flex-1">{children}</main>
<NavLink
to="/"
className="text-gray-500 items-center dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<ChevronLeft className="w-4 h-4" />
</NavLink>
</div>
)}
<div>
<button
className="text-gray-500 dark:text-gray-400"
onClick={() => setSidebarOpen(true)}>
<PanelLeftIcon className="w-6 h-6" />
</button>
</div>
<div>
<button
onClick={clearChat}
className="inline-flex dark:bg-transparent bg-white items-center rounded-lg border dark:border-gray-700 bg-transparent px-3 py-2.5 text-xs lg:text-sm font-medium leading-4 text-gray-800 dark:text-white disabled:opacity-50 ease-in-out transition-colors duration-200 hover:bg-gray-100 dark:hover:bg-gray-800 dark:hover:text-white">
<SquarePen className="h-5 w-5 " />
<span className=" truncate ml-3">{t("newChat")}</span>
</button>
</div>
<span className="text-lg font-thin text-zinc-300 dark:text-zinc-600">
{"/"}
</span>
<div className="hidden lg:block">
<Select
value={selectedModel}
onChange={(e) => {
setSelectedModel(e)
localStorage.setItem("selectedModel", e)
}}
size="large"
loading={isModelsLoading || isModelsFetching}
filterOption={(input, option) =>
option.label.key
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
}
showSearch
placeholder={t("common:selectAModel")}
className="w-64 "
options={models?.map((model) => ({
label: (
<span
key={model.model}
className="flex flex-row gap-3 items-center">
<OllamaIcon className="w-5 h-5" />
{model.name}
</span>
),
value: model.model
}))}
/>
</div>
<div className="lg:hidden">
<ModelSelect />
</div>
<span className="text-lg font-thin text-zinc-300 dark:text-zinc-600">
{"/"}
</span>
<div className="hidden lg:block">
<Select
size="large"
loading={isPromptLoading}
showSearch
placeholder={t("selectAPrompt")}
className="w-60"
allowClear
onChange={handlePromptChange}
value={selectedSystemPrompt}
filterOption={(input, option) =>
//@ts-ignore
option.label.key
.toLowerCase()
.indexOf(input.toLowerCase()) >= 0
}
options={prompts?.map((prompt) => ({
label: (
<span
key={prompt.title}
className="flex flex-row gap-3 items-center">
{prompt.is_system ? (
<ComputerIcon className="w-4 h-4" />
) : (
<ZapIcon className="w-4 h-4" />
)}
{prompt.title}
</span>
),
value: prompt.id
}))}
/>
</div>
<div className="lg:hidden">
<PromptSelect />
</div>
<SelectedKnowledge />
</div>
<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">
{!hideCurrentChatModelSettings && (
<Tooltip title={t("common:currentChatModelSettings")}>
<button
onClick={() => setOpenModelSettings(true)}
className="!text-gray-500 dark:text-gray-300 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<BrainCog className="w-6 h-6" />
</button>
</Tooltip>
)}
{pathname === "/" &&
messages.length > 0 &&
!streaming &&
shareModeEnabled && <ShareBtn messages={messages} />}
<Tooltip title={t("githubRepository")}>
<a
href="https://github.com/n4ze3m/page-assist"
target="_blank"
className="!text-gray-500 hidden lg:block dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<GithubIcon className="w-6 h-6" />
</a>
</Tooltip>
<Tooltip title={t("settings")}>
<NavLink
to="/settings"
className="!text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
<CogIcon className="w-6 h-6" />
</NavLink>
</Tooltip>
</div>
</div>
</div>
</div>
<main className="flex-1">{children}</main>
</div>
</div> </div>
<Drawer <Drawer
@ -246,6 +40,6 @@ export default function OptionLayout({
open={openModelSettings} open={openModelSettings}
setOpen={setOpenModelSettings} setOpen={setOpenModelSettings}
/> />
</div> </>
) )
} }

View File

@ -1,10 +1,11 @@
import { import {
Book, BookIcon,
BrainCircuit, BrainCircuitIcon,
Orbit, OrbitIcon,
Share, ShareIcon,
BlocksIcon, BlocksIcon,
InfoIcon InfoIcon,
CombineIcon,
} from "lucide-react" } from "lucide-react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link, useLocation } from "react-router-dom" import { Link, useLocation } from "react-router-dom"
@ -35,7 +36,7 @@ const LinkComponent = (item: {
className={classNames( className={classNames(
item.current === item.href item.current === item.href
? "text-gray-600 dark:text-white" ? "text-gray-600 dark:text-white"
: "text-gray-400 group-hover:text-gray-600 dark:text-gray-200 dark:group-hover:text-white", : "text-gray-500 group-hover:text-gray-600 dark:text-gray-200 dark:group-hover:text-white",
"h-6 w-6 shrink-0" "h-6 w-6 shrink-0"
)} )}
aria-hidden="true" aria-hidden="true"
@ -61,7 +62,13 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
<LinkComponent <LinkComponent
href="/settings" href="/settings"
name={t("generalSettings.title")} name={t("generalSettings.title")}
icon={Orbit} icon={OrbitIcon}
current={location.pathname}
/>
<LinkComponent
href="/settings/rag"
name={t("rag.title")}
icon={CombineIcon}
current={location.pathname} current={location.pathname}
/> />
<LinkComponent <LinkComponent
@ -74,7 +81,7 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
href="/settings/model" href="/settings/model"
name={t("manageModels.title")} name={t("manageModels.title")}
current={location.pathname} current={location.pathname}
icon={BrainCircuit} icon={BrainCircuitIcon}
/> />
<LinkComponent <LinkComponent
href="/settings/knowledge" href="/settings/knowledge"
@ -89,13 +96,13 @@ export const SettingsLayout = ({ children }: { children: React.ReactNode }) => {
<LinkComponent <LinkComponent
href="/settings/prompt" href="/settings/prompt"
name={t("managePrompts.title")} name={t("managePrompts.title")}
icon={Book} icon={BookIcon}
current={location.pathname} current={location.pathname}
/> />
<LinkComponent <LinkComponent
href="/settings/share" href="/settings/share"
name={t("manageShare.title")} name={t("manageShare.title")}
icon={Share} icon={ShareIcon}
current={location.pathname} current={location.pathname}
/> />
<LinkComponent <LinkComponent

View File

@ -155,7 +155,7 @@ export const ModelsBody = () => {
pullOllamaModel(record.model) pullOllamaModel(record.model)
} }
}} }}
className="text-gray-500 dark:text-gray-400"> className="text-gray-700 dark:text-gray-400">
<RotateCcw className="w-5 h-5" /> <RotateCcw className="w-5 h-5" />
</button> </button>
</Tooltip> </Tooltip>

View File

@ -1,7 +1,7 @@
import { Tabs } from "antd" import { Tabs } from "antd"
import { SettingsOllama } from "./Settings/ollama" import { SettingsOllama } from "./Settings/ollama"
import { SettingPrompt } from "./Settings/prompt" import { SettingPrompt } from "./Settings/prompt"
import { SettingOther } from "./Settings/other" import { SettingOther } from "./Settings/general-settings"
type Props = { type Props = {
setClose: (close: boolean) => void setClose: (close: boolean) => void

View File

@ -56,11 +56,37 @@ export const AboutApp = () => {
key: 1, key: 1,
label: t("about.ollamaVersion"), label: t("about.ollamaVersion"),
children: data.ollama children: data.ollama
},
{
key: 2,
label: "Community",
children: (
<a
href="https://discord.com/invite/bu54382uBd"
target="_blank"
rel="noreferrer"
className="text-blue-500 dark:text-blue-400">
Discord Server
</a>
)
},
{
key: 3,
label: "X (formerly Twitter)",
children: (
<a
href="https://twitter.com/n4ze3m"
target="_blank"
rel="noreferrer"
className="text-blue-500 dark:text-blue-400">
@n4ze3m
</a>
)
} }
]} ]}
/> />
<div> <div>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-4"> <p className="text-sm text-gray-700 dark:text-gray-400 mb-4">
{t("about.support")} {t("about.support")}
</p> </p>

View File

@ -16,7 +16,7 @@ import {
import { BetaTag } from "@/components/Common/Beta" import { BetaTag } from "@/components/Common/Beta"
import { useStorage } from "@plasmohq/storage/hook" import { useStorage } from "@plasmohq/storage/hook"
export const SettingOther = () => { export const GeneralSettings = () => {
const { clearChat, speechToTextLanguage, setSpeechToTextLanguage } = const { clearChat, speechToTextLanguage, setSpeechToTextLanguage } =
useMessageOption() useMessageOption()
@ -43,7 +43,7 @@ export const SettingOther = () => {
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div> <div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div>
</div> </div>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span className="text-gray-500 dark:text-neutral-50"> <span className="text-gray-700 dark:text-neutral-50">
{t("generalSettings.settings.speechRecognitionLang.label")} {t("generalSettings.settings.speechRecognitionLang.label")}
</span> </span>
@ -65,7 +65,7 @@ export const SettingOther = () => {
/> />
</div> </div>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span className="text-gray-500 dark:text-neutral-50"> <span className="text-gray-700 dark:text-neutral-50">
{t("generalSettings.settings.language.label")} {t("generalSettings.settings.language.label")}
</span> </span>
@ -88,7 +88,7 @@ export const SettingOther = () => {
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-2">
<BetaTag /> <BetaTag />
<span className="text-gray-500 dark:text-neutral-50"> <span className="text-gray-700 dark:text-neutral-50">
{t("generalSettings.settings.copilotResumeLastChat.label")} {t("generalSettings.settings.copilotResumeLastChat.label")}
</span> </span>
</div> </div>
@ -100,7 +100,7 @@ export const SettingOther = () => {
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<div className="inline-flex items-center gap-2"> <div className="inline-flex items-center gap-2">
<BetaTag /> <BetaTag />
<span className="text-gray-500 dark:text-neutral-50"> <span className="text-gray-700 dark:text-neutral-50">
{t("generalSettings.settings.hideCurrentChatModelSettings.label")} {t("generalSettings.settings.hideCurrentChatModelSettings.label")}
</span> </span>
</div> </div>
@ -111,7 +111,7 @@ export const SettingOther = () => {
/> />
</div> </div>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.settings.darkMode.label")} {t("generalSettings.settings.darkMode.label")}
</span> </span>
@ -138,7 +138,7 @@ export const SettingOther = () => {
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div> <div className="border border-b border-gray-200 dark:border-gray-600 mt-3"></div>
</div> </div>
<div className="flex flex-row mb-3 justify-between"> <div className="flex flex-row mb-3 justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.system.deleteChatHistory.label")} {t("generalSettings.system.deleteChatHistory.label")}
</span> </span>
@ -162,7 +162,7 @@ export const SettingOther = () => {
</button> </button>
</div> </div>
<div className="flex flex-row mb-3 justify-between"> <div className="flex flex-row mb-3 justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.system.export.label")} {t("generalSettings.system.export.label")}
</span> </span>
<button <button
@ -172,7 +172,7 @@ export const SettingOther = () => {
</button> </button>
</div> </div>
<div className="flex flex-row mb-3 justify-between"> <div className="flex flex-row mb-3 justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.system.import.label")} {t("generalSettings.system.import.label")}
</span> </span>
<label <label

View File

@ -29,7 +29,7 @@ export const ModelSettings = () => {
{t("modelSettings.label")} {t("modelSettings.label")}
</h2> </h2>
</div> </div>
<p className="text-sm text-gray-500 dark:text-neutral-400 mt-1"> <p className="text-sm text-gray-700 dark:text-neutral-400 mt-1">
{t("modelSettings.description")} {t("modelSettings.description")}
</p> </p>
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div> <div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>

View File

@ -1,19 +1,9 @@
import { useMutation, useQuery } from "@tanstack/react-query" import { useQuery } from "@tanstack/react-query"
import { Collapse, Form, InputNumber, Select, Skeleton } from "antd" import { Collapse, Skeleton } from "antd"
import { useState } from "react" import { useState } from "react"
import { SaveButton } from "~/components/Common/SaveButton" import { SaveButton } from "~/components/Common/SaveButton"
import { import { getOllamaURL, setOllamaURL as saveOllamaURL } from "~/services/ollama"
defaultEmbeddingChunkOverlap,
defaultEmbeddingChunkSize,
defaultEmbeddingModelForRag,
getAllModels,
getOllamaURL,
saveForRag,
setOllamaURL as saveOllamaURL
} from "~/services/ollama"
import { SettingPrompt } from "./prompt"
import { Trans, useTranslation } from "react-i18next" import { Trans, useTranslation } from "react-i18next"
import { useStorage } from "@plasmohq/storage/hook"
import { AdvanceOllamaSettings } from "@/components/Common/Settings/AdvanceOllamaSettings" import { AdvanceOllamaSettings } from "@/components/Common/Settings/AdvanceOllamaSettings"
import { ModelSettings } from "./model-settings" import { ModelSettings } from "./model-settings"
@ -22,34 +12,12 @@ export const SettingsOllama = () => {
const { t } = useTranslation("settings") const { t } = useTranslation("settings")
const { data: ollamaInfo, status } = useQuery({ const { status } = useQuery({
queryKey: ["fetchOllamURL"], queryKey: ["fetchOllamURL"],
queryFn: async () => { queryFn: async () => {
const [ollamaURL, allModels, chunkOverlap, chunkSize, defaultEM] = const [ollamaURL] = await Promise.all([getOllamaURL()])
await Promise.all([
getOllamaURL(),
getAllModels({ returnEmpty: true }),
defaultEmbeddingChunkOverlap(),
defaultEmbeddingChunkSize(),
defaultEmbeddingModelForRag()
])
setOllamaURL(ollamaURL) setOllamaURL(ollamaURL)
return { return {}
models: allModels,
chunkOverlap,
chunkSize,
defaultEM
}
}
})
const { mutate: saveRAG, isPending: isSaveRAGPending } = useMutation({
mutationFn: async (data: {
model: string
chunkSize: number
overlap: number
}) => {
await saveForRag(data.model, data.chunkSize, data.overlap)
} }
}) })
@ -92,7 +60,7 @@ export const SettingsOllama = () => {
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white"> <h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
{t("ollamaSettings.settings.advanced.label")} {t("ollamaSettings.settings.advanced.label")}
</h2> </h2>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-4"> <p className="text-xs text-gray-700 dark:text-gray-400 mb-4">
<Trans <Trans
i18nKey="settings:ollamaSettings.settings.advanced.help" i18nKey="settings:ollamaSettings.settings.advanced.help"
components={{ components={{
@ -122,117 +90,7 @@ export const SettingsOllama = () => {
</div> </div>
</div> </div>
<div>
<div>
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
{t("ollamaSettings.settings.ragSettings.label")}
</h2>
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>
</div>
<Form
layout="vertical"
onFinish={(data) => {
saveRAG({
model: data.defaultEM,
chunkSize: data.chunkSize,
overlap: data.chunkOverlap
})
}}
initialValues={{
chunkSize: ollamaInfo?.chunkSize,
chunkOverlap: ollamaInfo?.chunkOverlap,
defaultEM: ollamaInfo?.defaultEM
}}>
<Form.Item
name="defaultEM"
label={t("ollamaSettings.settings.ragSettings.model.label")}
help={t("ollamaSettings.settings.ragSettings.model.help")}
rules={[
{
required: true,
message: t(
"ollamaSettings.settings.ragSettings.model.required"
)
}
]}>
<Select
size="large"
filterOption={(input, option) =>
option!.label.toLowerCase().indexOf(input.toLowerCase()) >=
0 ||
option!.value.toLowerCase().indexOf(input.toLowerCase()) >=
0
}
showSearch
placeholder={t(
"ollamaSettings.settings.ragSettings.model.placeholder"
)}
style={{ width: "100%" }}
className="mt-4"
options={ollamaInfo.models?.map((model) => ({
label: model.name,
value: model.model
}))}
/>
</Form.Item>
<Form.Item
name="chunkSize"
label={t("ollamaSettings.settings.ragSettings.chunkSize.label")}
rules={[
{
required: true,
message: t(
"ollamaSettings.settings.ragSettings.chunkSize.required"
)
}
]}>
<InputNumber
style={{ width: "100%" }}
placeholder={t(
"ollamaSettings.settings.ragSettings.chunkSize.placeholder"
)}
/>
</Form.Item>
<Form.Item
name="chunkOverlap"
label={t(
"ollamaSettings.settings.ragSettings.chunkOverlap.label"
)}
rules={[
{
required: true,
message: t(
"ollamaSettings.settings.ragSettings.chunkOverlap.required"
)
}
]}>
<InputNumber
style={{ width: "100%" }}
placeholder={t(
"ollamaSettings.settings.ragSettings.chunkOverlap.placeholder"
)}
/>
</Form.Item>
<div className="flex justify-end">
<SaveButton disabled={isSaveRAGPending} btnType="submit" />
</div>
</Form>
</div>
<ModelSettings /> <ModelSettings />
<div>
<div>
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
{t("ollamaSettings.settings.prompt.label")}
</h2>
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>
</div>
<SettingPrompt />
</div>
</div> </div>
)} )}
</div> </div>

View File

@ -19,7 +19,7 @@ export const SettingPrompt = () => {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { status, data } = useQuery({ const { status, data } = useQuery({
queryKey: ["fetchOllaPrompt"], queryKey: ["fetchRagPrompt"],
queryFn: async () => { queryFn: async () => {
const [prompt, webSearchPrompt, webSearchFollowUpPrompt] = const [prompt, webSearchPrompt, webSearchFollowUpPrompt] =
await Promise.all([ await Promise.all([
@ -47,9 +47,7 @@ export const SettingPrompt = () => {
defaultValue={selectedValue} defaultValue={selectedValue}
onChange={(e) => setSelectedValue(e.target.value)}> onChange={(e) => setSelectedValue(e.target.value)}>
<Radio.Button value="rag">RAG</Radio.Button> <Radio.Button value="rag">RAG</Radio.Button>
<Radio.Button value="web"> <Radio.Button value="web">{t("rag.prompt.option2")}</Radio.Button>
{t("ollamaSettings.settings.prompt.option2")}
</Radio.Button>
</Radio.Group> </Radio.Group>
</div> </div>
@ -63,7 +61,7 @@ export const SettingPrompt = () => {
values?.questionPrompt || "" values?.questionPrompt || ""
) )
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: ["fetchOllaPrompt"] queryKey: ["fetchRagPrompt"]
}) })
}} }}
initialValues={{ initialValues={{
@ -98,7 +96,7 @@ export const SettingPrompt = () => {
value={data.webSearchFollowUpPrompt} value={data.webSearchFollowUpPrompt}
rows={5} rows={5}
placeholder={t( placeholder={t(
"ollamaSettings.settings.prompt.webSearchFollowUpPromptPlaceholder" "rag.prompt.webSearchFollowUpPromptPlaceholder"
)} )}
/> />
</Form.Item> </Form.Item>
@ -119,7 +117,7 @@ export const SettingPrompt = () => {
values?.webSearchFollowUpPrompt || "" values?.webSearchFollowUpPrompt || ""
) )
queryClient.invalidateQueries({ queryClient.invalidateQueries({
queryKey: ["fetchOllaPrompt"] queryKey: ["fetchRagPrompt"]
}) })
}} }}
initialValues={{ initialValues={{
@ -127,46 +125,36 @@ export const SettingPrompt = () => {
webSearchFollowUpPrompt: data.webSearchFollowUpPrompt webSearchFollowUpPrompt: data.webSearchFollowUpPrompt
}}> }}>
<Form.Item <Form.Item
label={t("ollamaSettings.settings.prompt.webSearchPrompt")} label={t("rag.prompt.webSearchPrompt")}
name="webSearchPrompt" name="webSearchPrompt"
help={t("ollamaSettings.settings.prompt.webSearchPromptHelp")} help={t("rag.prompt.webSearchPromptHelp")}
rules={[ rules={[
{ {
required: true, required: true,
message: t( message: t("rag.prompt.webSearchPromptError")
"ollamaSettings.settings.prompt.webSearchPromptError"
)
} }
]}> ]}>
<Input.TextArea <Input.TextArea
value={data.webSearchPrompt} value={data.webSearchPrompt}
rows={5} rows={5}
placeholder={t( placeholder={t("rag.prompt.webSearchPromptPlaceholder")}
"ollamaSettings.settings.prompt.webSearchPromptPlaceholder"
)}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t( label={t("rag.prompt.webSearchFollowUpPrompt")}
"ollamaSettings.settings.prompt.webSearchFollowUpPrompt"
)}
name="webSearchFollowUpPrompt" name="webSearchFollowUpPrompt"
help={t( help={t("rag.prompt.webSearchFollowUpPromptHelp")}
"ollamaSettings.settings.prompt.webSearchFollowUpPromptHelp"
)}
rules={[ rules={[
{ {
required: true, required: true,
message: t( message: t("rag.prompt.webSearchFollowUpPromptError")
"ollamaSettings.settings.prompt.webSearchFollowUpPromptError"
)
} }
]}> ]}>
<Input.TextArea <Input.TextArea
value={data.webSearchFollowUpPrompt} value={data.webSearchFollowUpPrompt}
rows={5} rows={5}
placeholder={t( placeholder={t(
"ollamaSettings.settings.prompt.webSearchFollowUpPromptPlaceholder" "rag.prompt.webSearchFollowUpPromptPlaceholder"
)} )}
/> />
</Form.Item> </Form.Item>

View File

@ -0,0 +1,172 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { Form, InputNumber, Select, Skeleton } from "antd"
import { SaveButton } from "~/components/Common/SaveButton"
import {
defaultEmbeddingChunkOverlap,
defaultEmbeddingChunkSize,
defaultEmbeddingModelForRag,
getAllModels,
saveForRag
} from "~/services/ollama"
import { SettingPrompt } from "./prompt"
import { useTranslation } from "react-i18next"
export const RagSettings = () => {
const { t } = useTranslation("settings")
const queryClient = useQueryClient()
const { data: ollamaInfo, status } = useQuery({
queryKey: ["fetchRAGSettings"],
queryFn: async () => {
const [allModels, chunkOverlap, chunkSize, defaultEM] = await Promise.all(
[
getAllModels({ returnEmpty: true }),
defaultEmbeddingChunkOverlap(),
defaultEmbeddingChunkSize(),
defaultEmbeddingModelForRag()
]
)
return {
models: allModels,
chunkOverlap,
chunkSize,
defaultEM
}
}
})
const { mutate: saveRAG, isPending: isSaveRAGPending } = useMutation({
mutationFn: async (data: {
model: string
chunkSize: number
overlap: number
}) => {
await saveForRag(data.model, data.chunkSize, data.overlap)
return true
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["fetchRAGSettings"]
})
}
})
return (
<div className="flex flex-col space-y-3">
{status === "pending" && <Skeleton paragraph={{ rows: 4 }} active />}
{status === "success" && (
<div className="flex flex-col space-y-6">
<div>
<div>
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
{t("rag.ragSettings.label")}
</h2>
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>
</div>
<Form
layout="vertical"
onFinish={(data) => {
saveRAG({
model: data.defaultEM,
chunkSize: data.chunkSize,
overlap: data.chunkOverlap
})
}}
initialValues={{
chunkSize: ollamaInfo?.chunkSize,
chunkOverlap: ollamaInfo?.chunkOverlap,
defaultEM: ollamaInfo?.defaultEM
}}>
<Form.Item
name="defaultEM"
label={t("rag.ragSettings.model.label")}
help={t("rag.ragSettings.model.help")}
rules={[
{
required: true,
message: t(
"rag.ragSettings.model.required"
)
}
]}>
<Select
size="large"
filterOption={(input, option) =>
option!.label.toLowerCase().indexOf(input.toLowerCase()) >=
0 ||
option!.value.toLowerCase().indexOf(input.toLowerCase()) >=
0
}
showSearch
placeholder={t(
"rag.ragSettings.model.placeholder"
)}
style={{ width: "100%" }}
className="mt-4"
options={ollamaInfo.models?.map((model) => ({
label: model.name,
value: model.model
}))}
/>
</Form.Item>
<Form.Item
name="chunkSize"
label={t("rag.ragSettings.chunkSize.label")}
rules={[
{
required: true,
message: t(
"rag.ragSettings.chunkSize.required"
)
}
]}>
<InputNumber
style={{ width: "100%" }}
placeholder={t(
"rag.ragSettings.chunkSize.placeholder"
)}
/>
</Form.Item>
<Form.Item
name="chunkOverlap"
label={t(
"rag.ragSettings.chunkOverlap.label"
)}
rules={[
{
required: true,
message: t(
"rag.ragSettings.chunkOverlap.required"
)
}
]}>
<InputNumber
style={{ width: "100%" }}
placeholder={t(
"rag.ragSettings.chunkOverlap.placeholder"
)}
/>
</Form.Item>
<div className="flex justify-end">
<SaveButton disabled={isSaveRAGPending} btnType="submit" />
</div>
</Form>
</div>
<div>
<div>
<h2 className="text-base font-semibold leading-7 text-gray-900 dark:text-white">
{t("rag.prompt.label")}
</h2>
<div className="border border-b border-gray-200 dark:border-gray-600 mt-3 mb-6"></div>
</div>
<SettingPrompt />
</div>
</div>
)}
</div>
)
}

View File

@ -44,7 +44,7 @@ export const SearchModeSettings = () => {
})} })}
className="space-y-4"> className="space-y-4">
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.webSearch.provider.label")} {t("generalSettings.webSearch.provider.label")}
</span> </span>
<div> <div>
@ -62,7 +62,7 @@ export const SearchModeSettings = () => {
</div> </div>
</div> </div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.webSearch.searchMode.label")} {t("generalSettings.webSearch.searchMode.label")}
</span> </span>
<div> <div>
@ -75,7 +75,7 @@ export const SearchModeSettings = () => {
</div> </div>
</div> </div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.webSearch.totalSearchResults.label")} {t("generalSettings.webSearch.totalSearchResults.label")}
</span> </span>
<div> <div>

View File

@ -49,7 +49,7 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
})} })}
className="space-y-4"> className="space-y-4">
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ttsEnabled.label")} {t("generalSettings.tts.ttsEnabled.label")}
</span> </span>
<div> <div>
@ -62,7 +62,7 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
</div> </div>
</div> </div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ttsProvider.label")} {t("generalSettings.tts.ttsProvider.label")}
</span> </span>
<div> <div>
@ -75,7 +75,7 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
</div> </div>
</div> </div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ttsVoice.label")} {t("generalSettings.tts.ttsVoice.label")}
</span> </span>
<div> <div>
@ -94,7 +94,7 @@ export const TTSModeSettings = ({ hideBorder }: { hideBorder?: boolean }) => {
</div> </div>
</div> </div>
<div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between"> <div className="flex sm:flex-row flex-col space-y-4 sm:space-y-0 sm:justify-between">
<span className="text-gray-500 dark:text-neutral-50 "> <span className="text-gray-700 dark:text-neutral-50 ">
{t("generalSettings.tts.ssmlEnabled.label")} {t("generalSettings.tts.ssmlEnabled.label")}
</span> </span>
<div> <div>

View File

@ -146,7 +146,7 @@ export const OptionShareBody = () => {
<label className="text-sm font-semibold leading-5 text-gray-900 dark:text-white"> <label className="text-sm font-semibold leading-5 text-gray-900 dark:text-white">
{t("manageShare.webshare.label")} {t("manageShare.webshare.label")}
</label> </label>
<p className="text-sm font-normal leading-5 text-gray-500 dark:text-gray-400"> <p className="text-sm font-normal leading-5 text-gray-700 dark:text-gray-400">
{t("manageShare.webshare.description")} {t("manageShare.webshare.description")}
</p> </p>
</div> </div>

View File

@ -94,7 +94,7 @@ export const EmptySidePanel = () => {
</button> </button>
{ollamaURL && {ollamaURL &&
cleanUrl(ollamaURL) !== "http://127.0.0.1:11434" && ( cleanUrl(ollamaURL) !== "http://127.0.0.1:11434" && (
<p className="text-xs text-gray-500 dark:text-gray-400 mb-4 text-center"> <p className="text-xs text-gray-700 dark:text-gray-400 mb-4 text-center">
<Trans <Trans
i18nKey="playground:ollamaState.connectionError" i18nKey="playground:ollamaState.connectionError"
components={{ components={{

View File

@ -250,7 +250,7 @@ export const SettingsBody = () => {
<div className="border border-gray-300 dark:border-gray-700 rounded p-4 bg-white dark:bg-[#171717]"> <div className="border border-gray-300 dark:border-gray-700 rounded p-4 bg-white dark:bg-[#171717]">
<h2 className="text-md mb-4 font-semibold dark:text-white"> <h2 className="text-md mb-4 font-semibold dark:text-white">
{t("ollamaSettings.settings.ragSettings.label")} {t("rag.ragSettings.label")}
</h2> </h2>
<Form <Form
onFinish={(data) => { onFinish={(data) => {
@ -267,12 +267,12 @@ export const SettingsBody = () => {
}}> }}>
<Form.Item <Form.Item
name="defaultEM" name="defaultEM"
label={t("ollamaSettings.settings.ragSettings.model.label")} label={t("rag.ragSettings.model.label")}
help={t("ollamaSettings.settings.ragSettings.model.help")} help={t("rag.ragSettings.model.help")}
rules={[ rules={[
{ {
required: true, required: true,
message: t("ollamaSettings.settings.ragSettings.model.required") message: t("rag.ragSettings.model.required")
} }
]}> ]}>
<Select <Select
@ -294,37 +294,37 @@ export const SettingsBody = () => {
<Form.Item <Form.Item
name="chunkSize" name="chunkSize"
label={t("ollamaSettings.settings.ragSettings.chunkSize.label")} label={t("rag.ragSettings.chunkSize.label")}
rules={[ rules={[
{ {
required: true, required: true,
message: t( message: t(
"ollamaSettings.settings.ragSettings.chunkSize.required" "rag.ragSettings.chunkSize.required"
) )
} }
]}> ]}>
<InputNumber <InputNumber
style={{ width: "100%" }} style={{ width: "100%" }}
placeholder={t( placeholder={t(
"ollamaSettings.settings.ragSettings.chunkSize.placeholder" "rag.ragSettings.chunkSize.placeholder"
)} )}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="chunkOverlap" name="chunkOverlap"
label={t("ollamaSettings.settings.ragSettings.chunkOverlap.label")} label={t("rag.ragSettings.chunkOverlap.label")}
rules={[ rules={[
{ {
required: true, required: true,
message: t( message: t(
"ollamaSettings.settings.ragSettings.chunkOverlap.required" "rag.ragSettings.chunkOverlap.required"
) )
} }
]}> ]}>
<InputNumber <InputNumber
style={{ width: "100%" }} style={{ width: "100%" }}
placeholder={t( placeholder={t(
"ollamaSettings.settings.ragSettings.chunkOverlap.placeholder" "rag.ragSettings.chunkOverlap.placeholder"
)} )}
/> />
</Form.Item> </Form.Item>

View File

@ -0,0 +1,87 @@
import { useCallback, useEffect, useRef, useState } from "react"
export const useScrollAnchor = () => {
const messagesRef = useRef<HTMLDivElement>(null)
const scrollRef = useRef<HTMLDivElement>(null)
const visibilityRef = useRef<HTMLDivElement>(null)
const [isAtBottom, setIsAtBottom] = useState(true)
const [isVisible, setIsVisible] = useState(false)
const scrollToBottom = useCallback(() => {
if (messagesRef.current) {
messagesRef.current.scrollIntoView({
block: "end",
behavior: "smooth"
})
}
}, [])
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,
isAtBottom,
isVisible
}
}

View File

@ -1,10 +1,13 @@
import i18n from "i18next"; import i18n from "i18next";
import { initReactI18next } from "react-i18next"; import { initReactI18next } from "react-i18next";
import { en } from "./lang/en"; import { en } from "./lang/en";
import { pt } from "./lang/pt";
import { fr } from "./lang/fr";
import { ru } from "./lang/ru"; import { ru } from "./lang/ru";
import { ml } from "./lang/ml"; import { ml } from "./lang/ml";
import { zh } from "./lang/zh"; import { zh } from "./lang/zh";
import { ja } from "./lang/ja"; import { ja } from "./lang/ja";
import { it } from "./lang/it";
import LanguageDetector from 'i18next-browser-languagedetector'; import LanguageDetector from 'i18next-browser-languagedetector';
i18n i18n
@ -13,7 +16,10 @@ i18n
.init({ .init({
resources: { resources: {
en: en, en: en,
fr: fr,
"it": it,
ml: ml, ml: ml,
"pt-BR": pt,
"zh-CN": zh, "zh-CN": zh,
ru: ru, ru: ru,
"ru-RU": ru, "ru-RU": ru,

15
src/i18n/lang/fr.ts Normal file
View File

@ -0,0 +1,15 @@
import option from "@/assets/locale/fr/option.json";
import playground from "@/assets/locale/fr/playground.json";
import common from "@/assets/locale/fr/common.json";
import sidepanel from "@/assets/locale/fr/sidepanel.json";
import settings from "@/assets/locale/fr/settings.json";
import knowledge from "@/assets/locale/fr/knowledge.json";
export const fr = {
option,
playground,
common,
sidepanel,
settings,
knowledge
}

15
src/i18n/lang/it.ts Normal file
View File

@ -0,0 +1,15 @@
import option from "@/assets/locale/it/option.json";
import playground from "@/assets/locale/it/playground.json";
import common from "@/assets/locale/it/common.json";
import sidepanel from "@/assets/locale/it/sidepanel.json";
import settings from "@/assets/locale/it/settings.json";
import knowledge from "@/assets/locale/it/knowledge.json";
export const it = {
option,
playground,
common,
sidepanel,
settings,
knowledge
}

15
src/i18n/lang/pt.ts Normal file
View File

@ -0,0 +1,15 @@
import option from "@/assets/locale/pt-BR/option.json";
import playground from "@/assets/locale/pt-BR/playground.json";
import common from "@/assets/locale/pt-BR/common.json";
import sidepanel from "@/assets/locale/pt-BR/sidepanel.json";
import settings from "@/assets/locale/pt-BR/settings.json";
import knowledge from "@/assets/locale/pt-BR/knowledge.json";
export const pt = {
option,
playground,
common,
sidepanel,
settings,
knowledge
}

View File

@ -4,10 +4,22 @@ export const supportLanguage = [
label: "English", label: "English",
value: "en" value: "en"
}, },
{
label: "Français",
value: "fr"
},
{
label: "Italiano",
value: "it"
},
{ {
label: "Russian", label: "Russian",
value: "ru" value: "ru"
}, },
{
label: "Português (Brasil)",
value: "pt-BR"
},
{ {
label: "മലയാളം", label: "മലയാളം",
value: "ml" value: "ml"

View File

@ -2,7 +2,8 @@ import { getKnowledgeById, updateKnowledgeStatus } from "@/db/knowledge"
import { PageAssistPDFUrlLoader } from "@/loader/pdf-url" import { PageAssistPDFUrlLoader } from "@/loader/pdf-url"
import { import {
defaultEmbeddingChunkOverlap, defaultEmbeddingChunkOverlap,
defaultEmbeddingChunkSize defaultEmbeddingChunkSize,
getOllamaURL
} from "@/services/ollama" } from "@/services/ollama"
import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama" import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter" import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
@ -10,22 +11,14 @@ import { PageAssistVectorStore } from "./PageAssistVectorStore"
import { PageAssisCSVUrlLoader } from "@/loader/csv" import { PageAssisCSVUrlLoader } from "@/loader/csv"
import { PageAssisTXTUrlLoader } from "@/loader/txt" import { PageAssisTXTUrlLoader } from "@/loader/txt"
import { PageAssistDocxLoader } from "@/loader/docx" import { PageAssistDocxLoader } from "@/loader/docx"
import { cleanUrl } from "./clean-url"
const readAsArrayBuffer = (file: File): Promise<ArrayBuffer> => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => {
resolve(reader.result as ArrayBuffer)
}
reader.onerror = reject
reader.readAsArrayBuffer(file)
})
}
export const processKnowledge = async (msg: any, id: string): Promise<void> => { export const processKnowledge = async (msg: any, id: string): Promise<void> => {
console.log(`Processing knowledge with id: ${id}`) console.log(`Processing knowledge with id: ${id}`)
try { try {
const knowledge = await getKnowledgeById(id) const knowledge = await getKnowledgeById(id)
const ollamaUrl = await getOllamaURL()
if (!knowledge) { if (!knowledge) {
console.error(`Knowledge with id ${id} not found`) console.error(`Knowledge with id ${id} not found`)
@ -35,6 +28,7 @@ export const processKnowledge = async (msg: any, id: string): Promise<void> => {
await updateKnowledgeStatus(id, "processing") await updateKnowledgeStatus(id, "processing")
const ollamaEmbedding = new OllamaEmbeddings({ const ollamaEmbedding = new OllamaEmbeddings({
baseUrl: cleanUrl(ollamaUrl),
model: knowledge.embedding_model model: knowledge.embedding_model
}) })
const chunkSize = await defaultEmbeddingChunkSize() const chunkSize = await defaultEmbeddingChunkSize()

View File

@ -0,0 +1,11 @@
{
"extName": {
"message": "Page Assist - Une interface Web pour les modèles d'IA locaux"
},
"extDescription": {
"message": "Utilisez vos modèles d'IA locaux pour vous aider dans votre navigation web."
},
"openSidePanelToChat": {
"message": "Ouvrir Copilot pour discuter"
}
}

View File

@ -0,0 +1,11 @@
{
"extName": {
"message": "Page Assist - Un'interfaccia web per modelli AI locali"
},
"extDescription": {
"message": "Usa i tuoi modelli AI in esecuzione locale per assisterti nella navigazione web."
},
"openSidePanelToChat": {
"message": "Apri Copilot per chattare"
}
}

View File

@ -9,6 +9,7 @@ import OptionKnowledgeBase from "./option-settings-knowledge"
import OptionAbout from "./option-settings-about" import OptionAbout from "./option-settings-about"
import SidepanelChat from "./sidepanel-chat" import SidepanelChat from "./sidepanel-chat"
import SidepanelSettings from "./sidepanel-settings" import SidepanelSettings from "./sidepanel-settings"
import OptionRagSettings from "./option-rag"
export const OptionRoutingChrome = () => { export const OptionRoutingChrome = () => {
return ( return (
@ -20,6 +21,7 @@ export const OptionRoutingChrome = () => {
<Route path="/settings/ollama" element={<OptionOllamaSettings />} /> <Route path="/settings/ollama" element={<OptionOllamaSettings />} />
<Route path="/settings/share" element={<OptionShare />} /> <Route path="/settings/share" element={<OptionShare />} />
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} /> <Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
<Route path="/settings/rag" element={<OptionRagSettings />} />
<Route path="/settings/about" element={<OptionAbout />} /> <Route path="/settings/about" element={<OptionAbout />} />
</Routes> </Routes>
) )

View File

@ -1,7 +1,7 @@
// this is a temp fix for firefox // this is a temp fix for firefox
// because chunks getting 4mb+ and it's not working on firefox addon store // because chunks getting 4mb+ and it's not working on firefox addon store
import { lazy } from "react" import { lazy } from "react"
import { Route , Routes} from "react-router-dom" import { Route, Routes } from "react-router-dom"
const SidepanelChat = lazy(() => import("./sidepanel-chat")) const SidepanelChat = lazy(() => import("./sidepanel-chat"))
const SidepanelSettings = lazy(() => import("./sidepanel-settings")) const SidepanelSettings = lazy(() => import("./sidepanel-settings"))
@ -13,6 +13,7 @@ const OptionSettings = lazy(() => import("./option-settings"))
const OptionShare = lazy(() => import("./option-settings-share")) const OptionShare = lazy(() => import("./option-settings-share"))
const OptionKnowledgeBase = lazy(() => import("./option-settings-knowledge")) const OptionKnowledgeBase = lazy(() => import("./option-settings-knowledge"))
const OptionAbout = lazy(() => import("./option-settings-about")) const OptionAbout = lazy(() => import("./option-settings-about"))
const OptionRagSettings = lazy(() => import("./option-rag"))
export const OptionRoutingFirefox = () => { export const OptionRoutingFirefox = () => {
return ( return (
@ -25,6 +26,7 @@ export const OptionRoutingFirefox = () => {
<Route path="/settings/share" element={<OptionShare />} /> <Route path="/settings/share" element={<OptionShare />} />
<Route path="/settings/knowledge" element={<OptionKnowledgeBase />} /> <Route path="/settings/knowledge" element={<OptionKnowledgeBase />} />
<Route path="/settings/about" element={<OptionAbout />} /> <Route path="/settings/about" element={<OptionAbout />} />
<Route path="/settings/rag" element={<OptionRagSettings />} />
</Routes> </Routes>
) )
} }

15
src/routes/option-rag.tsx Normal file
View File

@ -0,0 +1,15 @@
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
import OptionLayout from "~/components/Layouts/Layout"
import { RagSettings } from "@/components/Option/Settings/rag"
const OptionRagSettings = () => {
return (
<OptionLayout>
<SettingsLayout>
<RagSettings />
</SettingsLayout>
</OptionLayout>
)
}
export default OptionRagSettings

View File

@ -1,12 +1,12 @@
import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout" import { SettingsLayout } from "~/components/Layouts/SettingsOptionLayout"
import OptionLayout from "~/components/Layouts/Layout" import OptionLayout from "~/components/Layouts/Layout"
import { SettingOther } from "~/components/Option/Settings/other" import { GeneralSettings } from "~/components/Option/Settings/general-settings"
const OptionSettings = () => { const OptionSettings = () => {
return ( return (
<OptionLayout> <OptionLayout>
<SettingsLayout> <SettingsLayout>
<SettingOther /> <GeneralSettings />
</SettingsLayout> </SettingsLayout>
</OptionLayout> </OptionLayout>
) )

View File

@ -48,7 +48,7 @@ export default defineConfig({
outDir: "build", outDir: "build",
manifest: { manifest: {
version: "1.1.10", version: "1.1.11",
name: name:
process.env.TARGET === "firefox" process.env.TARGET === "firefox"
? "Page Assist - A Web UI for Local AI Models" ? "Page Assist - A Web UI for Local AI Models"

7246
yarn.lock

File diff suppressed because it is too large Load Diff