diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml index cf5212ea..266fc74d 100644 --- a/.github/workflows/nextjs.yml +++ b/.github/workflows/nextjs.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Create .env with Github Secrets run: | touch .env @@ -13,13 +13,15 @@ jobs: echo NEXT_PUBLIC_SUPABASE_ANON_KEY=$ENV_VAR_2 >> .env echo SUPABASE_SERVICE_ROLE_KEY=$ENV_VAR_3 >> .env echo OPENAI_API_KEY=$ENV_VAR_4 >> .env + echo MISTRAL_API_KEY=$ENV_VAR_5 >> .env env: ENV_VAR_1: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }} ENV_VAR_2: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }} ENV_VAR_3: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} ENV_VAR_4: ${{ secrets.OPENAI_API_KEY }} + ENV_VAR_5: ${{ secrets.MISTRAL_API_KEY }} - name: Setup Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: 18.x diff --git a/app/[lng]/chat/chat.tsx b/app/[lng]/chat/chat.tsx index 6fe7853f..379dd0dd 100644 --- a/app/[lng]/chat/chat.tsx +++ b/app/[lng]/chat/chat.tsx @@ -15,9 +15,9 @@ import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { sendChatToGpt } from "@/lib/ai-chat"; import { ChatConversation, ChatMessage } from "@/lib/ai-completions"; -import { Database, Tables } from "@/types_db"; +import { Tables } from "@/types_db"; import { Close, DialogClose } from "@radix-ui/react-dialog"; -import { Session, User } from "@supabase/supabase-js"; +import { User } from "@supabase/supabase-js"; import { Check, History, @@ -37,16 +37,11 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { getModelString } from "@/lib/models"; import { Settings } from "@/lib/settings"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { chatSystemPrompts } from "@/lib/prompts/system"; +import ModelSelector from "@/components/model-selector"; +import { getModelProvider, ModelList } from "@/lib/models"; type Subscription = Tables<"subscriptions">; type Product = Tables<"products">; @@ -84,15 +79,8 @@ export default function Chat(props: Props) { const [selectedTemplateId, setSelectedTemplateId] = useState< number | undefined >(); - const defaultMsg: ChatMessage[] = [ - { - role: "system", - content: - lng === "en" - ? "You are a highly skilled AI assistant specializing in document creation, information extraction, and essay writing. You help users generate well-structured documents, summarize and extract key information from texts, and craft high-quality essays based on provided topics. Format response: HTML (use headers only when necessary, otherwise, only provide text)." - : "Vous êtes un assistant IA hautement qualifié, spécialisé dans la création de documents, l'extraction d'informations et la rédaction d'essais. Vous aidez les utilisateurs à générer des documents bien structurés, à résumer et à extraire des informations clés de textes, et à rédiger des essais de haute qualité sur la base de sujets fournis. Format de réponse : HTML (utiliser les titres seulement si nécessaire, sinon, utiliser du texte simple).", - }, - ]; + const [system, setSystem] = useState(chatSystemPrompts[lng]); + const [conversations, setConversations] = useState(getConvs()); const [messages, setMessages] = useState( @@ -101,18 +89,21 @@ export default function Chat(props: Props) { const [model, setModel] = useState("gpt-3.5-turbo"); const defaultModels = () => - hasGpt4Access() ? ["gpt-3.5-turbo", "gpt-4"] : ["gpt-3.5-turbo"]; + hasGpt4Access() + ? { openAiModels: ["gpt-3.5-turbo", "gpt-4"], mistralModels: [] } + : { openAiModels: ["gpt-3.5-turbo"], mistralModels: [] }; function getAvailableModels( - availableModels: string[] | undefined, - ): string[] | undefined { - if (!availableModels) return []; - let models = []; + availableModels: ModelList | undefined, + ): ModelList { + if (!availableModels) return { openAiModels: [], mistralModels: [] }; + let models: ModelList = { openAiModels: [], mistralModels: [] }; let gpt4 = hasGpt4Access(); - for (let i = 0; i < availableModels.length; i++) { - if (availableModels[i].includes("gpt-4") && !gpt4) continue; - models?.push(availableModels[i]); + for (let i = 0; i < availableModels.openAiModels.length; i++) { + if (availableModels.openAiModels[i].includes("gpt-4") && !gpt4) continue; + models.openAiModels.push(availableModels.openAiModels[i]); } + models.mistralModels = models.mistralModels; return models; } @@ -131,7 +122,7 @@ export default function Chat(props: Props) { } const [avModels, setAvModels] = useState( - getAvailableModels(s.models) ?? defaultModels(), + getAvailableModels(s.aiModels) ?? defaultModels(), ); let userMsg = userInput; const [convIndex, setConvIndex] = useState(0); @@ -154,7 +145,13 @@ export default function Chat(props: Props) { setMessages([...msgs2]); } setUserInput(""); - let newMsg = await sendChatToGpt(model, { setContent: setContent }, msgs); + let newMsg = await sendChatToGpt( + model, + { setContent: setContent }, + msgs, + system, + getModelProvider(model, avModels), + ); return newMsg; } @@ -193,12 +190,12 @@ export default function Chat(props: Props) { localStorage.getItem("synapsy_write_conversations") ?? "[]", ); if (convs === undefined || convs.length === 0) { - saveConvs([{ name: t("new-conv"), messages: [...defaultMsg] }]); - return [{ name: t("new-conv"), messages: [...defaultMsg] }]; + saveConvs([{ name: t("new-conv"), messages: [] }]); + return [{ name: t("new-conv"), messages: [] }]; } return convs; } - return [{ name: t("new-convs"), messages: [...defaultMsg] }]; + return [{ name: t("new-convs"), messages: [] }]; } function saveConvs(convs: ChatConversation[]): void { @@ -288,10 +285,10 @@ export default function Chat(props: Props) { c = [ { name: t("new-conv"), - messages: [...defaultMsg], + messages: [], }, ]; - setMessages([...defaultMsg]); + setMessages([]); } setConversations(c); @@ -338,20 +335,12 @@ export default function Chat(props: Props) { } >
- + {messages.length === 1 && ( @@ -372,16 +361,14 @@ export default function Chat(props: Props) { onClick={() => { if (selectedTemplateId === i) { setSelectedTemplateId(undefined); - setMessages(defaultMsg); + setMessages([]); let c = [...conversations]; - c[convIndex].messages = defaultMsg; + c[convIndex].messages = []; setConversations(c); return; } setSelectedTemplateId(i); - setMessages([ - { role: "system", content: template.prompt }, - ]); + setSystem(template.prompt); let c = [...conversations]; c[convIndex].messages = messages; setConversations(c); @@ -457,7 +444,7 @@ export default function Chat(props: Props) {
- {messages.length === 1 && ( + {messages.length === 0 && (

{t("chat-placeholder")}

@@ -503,10 +490,10 @@ export default function Chat(props: Props) {
- -
- {models - ?.filter((s) => - s.toLowerCase().includes(modelQuery.toLowerCase()), - ) - .map((m, i) => ( -

- {m} -

- ))} -
-
+ + + OpenAI + Mistral + + + +
+ {models.openAiModels + ?.filter((s) => s.toLowerCase().startsWith("gpt")) + .filter((s) => + s.toLowerCase().includes(modelQuery.toLowerCase()), + ) + .map((m, i) => ( +

+ {getModelString(m)} +

+ ))} +
+
+ +
+ {models.mistralModels + ?.filter((s) => + s.toLowerCase().includes(modelQuery.toLowerCase()), + ) + .map((m, i) => ( +

+ {getModelString(m)} +

+ ))} +
+
+
+
diff --git a/app/api/models/route.ts b/app/api/models/route.ts index 43117eeb..32b8fee0 100644 --- a/app/api/models/route.ts +++ b/app/api/models/route.ts @@ -1,11 +1,21 @@ import { NextResponse } from "next/server"; import OpenAI from "openai"; +import { Mistral } from "@mistralai/mistralai"; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); +const mistral = new Mistral({ + apiKey: process.env.MISTRAL_API_KEY, +}); + export async function GET(req: Request) { let models = await openai.models.list(); - return new NextResponse(JSON.stringify(models.data)); + let mistralModels = await mistral.models.list(); + let response = { + openAiModels: models.data.map((model) => model.id).sort(), + mistralModels: mistralModels.data?.map((model) => model.id).sort(), + }; + return new NextResponse(JSON.stringify(response)); } diff --git a/app/i18n/locales/en/common.json b/app/i18n/locales/en/common.json index 2cc4b93a..00fadf5a 100644 --- a/app/i18n/locales/en/common.json +++ b/app/i18n/locales/en/common.json @@ -368,5 +368,11 @@ "new-password": "New Password", "confirm-password": "Confirm New Password", "link-text-2": "Don't have an account?", - "sign-in-link-text-2": "Already have an account?" + "sign-in-link-text-2": "Already have an account?", + "models-desc": "See all available models for your account.", + "blog-desc": "Articles and updates from the team", + "privacy-desc": "Learn more about our policies relative to your privacy", + "youtube-desc": "Watch our videos about our products", + "x-desc": "Follow us on X to get te latest updates", + "cgv-desc": "Find out more about our general terms and conditions of sale" } diff --git a/app/i18n/locales/es/common.json b/app/i18n/locales/es/common.json new file mode 100644 index 00000000..78a777d1 --- /dev/null +++ b/app/i18n/locales/es/common.json @@ -0,0 +1,378 @@ +{ + "title": "Write", + "introducing-synapsy": "Su copiloto de escritura", + "introducing-synapsy-text": "Synapsy Write es una nueva forma de escribir textos, utilizando el poder de la IA.", + "launch": "Lanzar", + "home": "Inicio", + "create": "Crear", + "openai-api-key": "Ingrese su clave API de OpenAI", + "content-type": "Tipo", + "email": "Correo electrónico", + "blog-post": "Publicación de blog", + "ideas": "Ideas", + "paragraph": "Párrafo", + "create-desc": "Generar texto utilizando IA generativa.", + "welcome": "¡Bienvenido!", + "welcome-desc": "Bienvenido a la generación de IA, para comenzar, ingrese su clave API de OpenAI.", + "confirm": "Confirmar", + "gen-in-progress": "Generación en progreso", + "please-wait": "Por favor, espere", + "result-ph": "El texto generado aparecerá aquí.", + "generations": "Mis Generaciones", + "no-gen": "No hay generaciones disponibles", + "no-gen-text": "Aquí puede encontrar todas sus generaciones.", + "format": "Formato", + "select-format": "Seleccione un formato de generación", + "regular-category": "Básico", + "light": "Claro", + "dark": "Oscuro", + "system": "Sistema", + "philosophy": "Ensayo (filosofía)", + "essay": "Ensayo (inglés)", + "introduction": "Introducción", + "problematization": "Problematización", + "essay-outline": "Esquema del ensayo", + "conclusion": "Conclusión", + "essay-basic": "Ensayo (Básico)", + "essay-complex": "Ensayo (Complejo)", + "options": "Opciones", + "model-options": "Opciones del modelo", + "model": "Modelo", + "models": "Modelos", + "api-key": "Clave API", + "export": "Exportar", + "import": "Importar", + "error-occured": "Ha ocurrido un error", + "features": "Características", + "features-desc": "Descubra las características versátiles de Synapsy Write", + "feature-ai": "IA Generativa de GPT-4 de OpenAI", + "feature-ai-desc": "Aproveche la tecnología de IA de última generación proporcionada por OpenAI para generar textos de alta calidad basados en su entrada.", + "feature-versatile": "Versátil", + "feature-versatile-desc": "Cree diferentes tipos de escritura a partir de una sola instrucción. Write le permite crear correos electrónicos, párrafos, ensayos y mucho más.", + "feature-easy": "Fácil de usar", + "feature-easy-desc": "La interfaz de usuario intuitiva asegura que incluso los usuarios no técnicos puedan comenzar rápidamente. Puede empezar a generar textos en segundos.", + "open-source": "Código abierto", + "open-source-desc": "Los productos de Synapsy siguen la visión del Grupo Peyronnet: El código abierto como un valor central. Queremos llevar a cabo este viaje con usted y la comunidad.", + "links": "Enlaces", + "socials": "Redes sociales", + "learn-more": "Aprender más", + "print": "Imprimir", + "price": "Precio", + "words": "Palabras", + "characters": "Caracteres", + "copy": "Copiar", + "tokens": "Tokens", + "search-formats": "Buscar formatos...", + "search-models": "Buscar modelos...", + "no-formats": "No se encontraron formatos", + "temp": "Temperatura", + "temp-desc": "Controla la aleatoriedad: reducirla resulta en resultados menos aleatorios. A medida que la temperatura se acerca a cero, el modelo se vuelve más determinista y repetitivo.", + "freq-penalty": "Penalización por frecuencia", + "freq-penalty-desc": "Cuánto penalizar los nuevos tokens en función de su frecuencia existente en el texto hasta ahora. Disminuye la probabilidad de que el modelo repita la misma línea de verbalismo.", + "pres-penalty": "Penalización por presencia", + "pres-penalty-desc": "Cuánto penalizar los nuevos tokens en función de si aparecen en el texto hasta ahora. Aumenta la probabilidad de que el modelo hable sobre nuevos temas.", + "top-p": "Top P", + "top-p-desc": "Controla la diversidad mediante muestreo de núcleo: 0.5 significa que se consideran la mitad de todas las opciones ponderadas por probabilidad.", + "max-length": "Longitud máxima", + "max-length-desc": "El número máximo de tokens a generar. Las solicitudes pueden usar hasta 2,048 o 4,000 tokens, compartidos entre el prompt y la finalización. El límite exacto varía según el modelo.", + "prompt": "Prompt", + "variables": "Variables", + "add-variable": "Agregar variable", + "delete-variable": "Eliminar variable", + "name": "Nombre", + "value": "Valor", + "tone": "Tono", + "tones-none": "Ninguno", + "tones-professional": "Profesional", + "tones-casual": "Informal", + "tones-enthusiastic": "Entusiasta", + "tones-informative": "Informativo", + "tones-funny": "Divertido", + "table": "Tabla", + "format-desc": "Un formato de generación es un modo en el que Synapsy Write genera texto.", + "gen-settings": "Configuración de generación", + "text-to-analyse": "Texto a analizar", + "text-philosophy": "Análisis de texto (filosofía)", + "text-analysis-introduction": "Introducción al análisis", + "text-analysis-conclusion": "Conclusión del análisis", + "text-analysis-basic": "Análisis de texto (Básico)", + "text-analysis-complex": "Análisis de texto (Complejo)", + "text-analysis-outline": "Esquema del análisis", + "text-analysis-dev": "Desarrollo del análisis", + "settings": "Configuración", + "settings-desc": "Gestione la configuración de Synapsy Write.", + "theme": "Tema", + "theme-desc": "Establezca la apariencia de Synapsy Write.", + "show-key": "Mostrar clave", + "language": "Idioma", + "language-desc": "Cambie el idioma de Synapsy Write.", + "openai-options": "Opciones de OpenAI", + "openai-options-desc": "Configure su integración con OpenAI.", + "search-history": "Buscar en su historial", + "generation": "Generación", + "generation-desc": "Vea e imprima su generación.", + "apply": "Aplicar", + "misc": "Misceláneo", + "other-settings": "Otras configuraciones de Synapsy Write.", + "about": "Acerca de", + "about-long": "Acerca de Synapsy Write", + "close": "Cerrar", + "welcome-back": "Bienvenido de nuevo", + "username": "Nombre de usuario", + "full-name": "Nombre completo", + "account-desc": "Bienvenido a la Cuenta Peyronnet: ¡donde comienza su viaje! Unifique su experiencia digital con nosotros y desbloquee un mundo de conectividad sin fisuras. Inicie sesión para acceder a características exclusivas, servicios personalizados y una plataforma diseñada para elevar sus interacciones en línea.", + "account-tip": "Experimente el poder de la integración sin fisuras con la suite de productos de IA de Synapsy. Nuestra tecnología de vanguardia se integra perfectamente con varias plataformas, ofreciendo una compatibilidad y eficiencia incomparables.", + "welcome-msg": "Bienvenido, [[user]].", + "your-info": "Su información", + "your-info-desc": "Gestione y edite la información sobre su cuenta.", + "products": "Productos", + "products-desc": "Gestione sus suscripciones.", + "no-products": "No hay productos disponibles.", + "session": "Sesión", + "sign-in": "Iniciar sesión", + "sign-up": "Crear una cuenta", + "sign-out": "Cerrar sesión", + "my-account": "Mi cuenta", + "update-name": "Actualizar nombre", + "update-email": "Actualizar correo electrónico", + "name-desc": "Por favor, ingrese su nombre completo o un nombre para mostrar con el que se sienta cómodo.", + "email-desc": "Por favor, ingrese la dirección de correo electrónico que desea usar para iniciar sesión.", + "name-char": "Máximo 64 caracteres", + "email-notify": "Le enviaremos un correo electrónico para verificar el cambio.", + "products-available": "Ha comprado/suscrito a algunos de nuestros productos.", + "available-products": "Productos disponibles", + "available-products-desc": "Encuentre todos los productos y planes disponibles del Grupo Peyronnet.", + "synapsy-available-products-desc": "Encuentre todos los planes disponibles de Synapsy Write.", + "subscribe": "Suscribirse", + "manage": "Gestionar", + "monthly-billing": "Facturación mensual", + "yearly-billing": "Facturación anual", + "manage-stripe": "Gestione su suscripción en Stripe.", + "open-portal": "Abrir portal de clientes", + "account-read-only-1": "No puede editar su información en este sitio web. Por favor, visite", + "account-read-only-2": "para gestionar su cuenta.", + "unlock-power-ai": "Desbloquee el poder de la IA con la Cuenta Peyronnet.", + "new": "Nuevo", + "see-plans": "Ver planes", + "unlock-ai-sub": "Desbloquee el poder de la IA eligiendo un plan de suscripción.", + "privacy-policy": "Política de privacidad", + "terms-sell": "Términos y condiciones de venta", + "variables-desc": "Use variables para crear generaciones interactivas y reutilizables.", + "tables": "Tablas", + "tables-desc": "Genere tablas complejas que se ajusten a sus necesidades a partir de una sola instrucción.", + "essays": "Ensayos", + "essays-desc": "Genere ensayos complejos y realistas utilizando el motor de generación personalizado de Write.", + "unlimited-access": "Acceso ilimitado", + "unlimited-access-desc": "Obtenga acceso ilimitado y generaciones infinitas suscribiéndose a un plan.", + "github-desc": "El repositorio de Write está disponible públicamente en GitHub.", + "synapsy-browse": "Explore otros proyectos de Synapsy.", + "login-social": "Iniciar sesión con {{provider}}", + "link-text": "¿No tiene una cuenta? Regístrese", + "sign-in-link-text": "¿Ya tiene una cuenta? Inicie sesión", + "email-label": "Dirección de correo electrónico", + "create-password-label": "Cree una contraseña", + "email-input-placeholder": "Su dirección de correo electrónico", + "password-input-placeholder": "Su contraseña", + "confirmation-text": "Revise su correo electrónico para obtener el enlace de confirmación.", + "password-email-label": "Dirección de correo electrónico", + "password-password-label": "Su contraseña", + "password-email-input-placeholder": "Su dirección de correo electrónico", + "password-button-label": "Enviar instrucciones para restablecer la contraseña", + "password-loading-button-label": "Enviando instrucciones para restablecer...", + "password-link-text": "¿Olvidó su contraseña?", + "password-confirmation-text": "Revise su correo electrónico para obtener el enlace de restablecimiento de contraseña.", + "pricing": "Precios", + "text-analysis": "Análisis de texto", + "variable-editor": "Editor de variables", + "table-generator": "Generador de tablas", + "advanced-instructions": "Instrucciones avanzadas del modelo", + "year": "año", + "month": "mes", + "free-trial": "Prueba gratuita", + "formats": "Formatos de generación", + "dynamic-gens": "Generaciones dinámicas", + "gens": "Generaciones", + "history": "Historial", + "export-gens": "Exportar generaciones", + "import-gens": "Importar generaciones", + "print-generations": "Imprimir generaciones", + "pricing-desc": "Necesita un plan de suscripción para usar Synapsy Write.", + "see-pricing": "Ver planes", + "delete": "Eliminar", + "edit": "Editar", + "save": "Guardar", + "code-inline": "Código en línea", + "code": "Código", + "underline": "Subrayado", + "bold": "Negrita", + "italic": "Cursiva", + "strike": "Tachado", + "h1": "Encabezado 1", + "h2": "Encabezado 2", + "h3": "Encabezado 3", + "todo": "Lista de tareas", + "bullet-list": "Lista con viñetas", + "number-list": "Lista numerada", + "quote": "Cita", + "link": "Enlace", + "text": "Texto", + "color": "Color", + "background": "Fondo", + "default": "Predeterminado", + "purple": "Morado", + "red": "Rojo", + "yellow": "Amarillo", + "blue": "Azul", + "green": "Verde", + "orange": "Naranja", + "pink": "Rosa", + "gray": "Gris", + "no-results": "No hay resultados", + "press-for-commands": "Presione '/' para comandos", + "image": "Imagen", + "text-desc": "Simplemente comience a escribir con texto plano.", + "todo-desc": "Haga un seguimiento de las tareas con una lista de tareas.", + "h1-desc": "Gran encabezado de sección.", + "h2-desc": "Encabezado de sección mediano.", + "h3-desc": "Encabezado de sección pequeño.", + "bullet-list-desc": "Cree una lista con viñetas.", + "number-list-desc": "Cree una lista numerada.", + "quote-desc": "Capture una cita.", + "code-desc": "Capture un fragmento de código.", + "image-desc": "Cargue una imagen desde su computadora.", + "ph-visual-outline": "Esquema del ensayo (visual)", + "gen-editor": "Editor de generación", + "why-synapsy": "¿Por qué Synapsy Write?", + "why-synapsy-desc": "ChatGPT Plus puede ser útil, pero Synapsy Write ofrece características exclusivas que mejorarán enormemente su productividad.", + "text-editor": "Editor de texto", + "available": "Disponible", + "partially-available": "Parcialmente disponible", + "unavailable": "No disponible", + "motivation-letter": "Carta de motivación", + "rephraser": "Reformulador", + "expand-input": "Expandir área de entrada", + "new-creation": "Nueva creación", + "ai": "IA", + "ai-desc": "Use IA por completo para generar documentos o ensayos.", + "manual": "Manual", + "manual-desc": "Escriba un documento manualmente.", + "new-doc": "Nuevo documento", + "doc-title": "Título", + "manual-doc": "Documento (Manual)", + "essay-global": "Ensayo (genérico)", + "gpt-4-remaining-quotas": "Generaciones restantes de GPT-4:", + "unlimited": "Ilimitado", + "active": "Activo", + "trialing": "En prueba", + "canceled": "Cancelado", + "incomplete": "Incompleto", + "incomplete_expired": "Incompleto caducado", + "past_due": "Vencido", + "unpaid": "No pagado", + "paused": "Pausado", + "complex-gen": "Generación de Documento Complejo", + "complex-gen-desc": "Está utilizando una generación compleja que tomará varios pasos para completarse.", + "main-content": "Contenido principal", + "part-1": "Parte I", + "part-2": "Parte II", + "part-3": "Parte III", + "chat": "Chat", + "chat-desc": "Chat con el Asistente Synapsy para mejorar sus documentos u obtener información sobre ellos.", + "send": "Enviar", + "send-msg": "Enviar un mensaje", + "you": "Usted", + "synapsy-assistant": "Asistente de Synapsy", + "chat-placeholder": "¡Vamos a charlar!", + "chat-placeholder-desc": "El Asistente Synapsy está aquí para responder a todas sus preguntas y consultas.", + "chat-placeholder-desc2": "Ingrese un mensaje para comenzar.", + "history-format": "Historial", + "history-paragraph": "Párrafo", + "history-paragraph-long": "Párrafo (Historial)", + "conversations": "Conversaciones", + "new-conv": "Nueva conversación", + "rename": "Renombrar", + "cancel": "Cancelar", + "enter-name": "Ingrese un nombre", + "refresh": "Actualizar", + "refresh-models": "Actualizar modelos", + "most-recent": "Más reciente", + "oldest": "Más antiguo", + "conv-management": "Gestión de conversaciones", + "create-template": "Crear una plantilla", + "system-templates": "Plantillas del sistema", + "system-template-creator": "Creador de plantillas del sistema", + "system-template-creator-desc": "Cree una plantilla para usar como aviso del sistema al crear una conversación con el Asistente Synapsy.", + "no-templates": "No hay plantillas del sistema disponibles", + "no-templates-desc": "Puede crear una plantilla del sistema para influir en la forma en que el Asistente interactuará con usted.", + "oral-presentation": "Presentación oral", + "oral-basic": "Presentación oral (Básica)", + "go-back": "Volver", + "generation-font": "Fuente de generación", + "font-mono": "Mono", + "font-serif": "Serif", + "font-sans": "Sans Serif", + "font-default": "Predeterminado", + "key-features": "Características clave", + "unlock-potential": "Desbloquee Su Potencial de Escritura", + "unlock-potential-desc": "Synapsy Write está diseñado para ayudarle a crear contenido de alta calidad con facilidad. Mejore su productividad, aumente su creatividad y lleve su escritura a nuevas alturas.", + "effortless-text-gen": "Generación de Texto Sin Esfuerzo", + "effortless-text-gen-desc": "Los avanzados algoritmos de IA de Synapsy Write generan texto de alta calidad con solo unos pocos comandos, ahorrándole tiempo y esfuerzo.", + "productivity": "Aumente Su Productividad con Synapsy Write", + "productivity-desc": "Las potentes características e interfaz intuitiva de Synapsy Write le permiten crear contenido de alta calidad más rápido que nunca.", + "try-synapsy": "Pruebe Synapsy Write", + "text-editor-desc": "Synapsy Write le permite editar directamente sus generaciones dentro de la aplicación, eliminando la necesidad de usar otras aplicaciones de terceros.", + "advanced-instructions-desc": "Las avanzadas instrucciones del modelo de Synapsy Write le permiten ajustar finamente la IA a sus necesidades específicas, garantizando contenido de alta calidad y personalizado.", + "text-analysis-desc": "Las avanzadas herramientas de análisis de texto de Synapsy Write proporcionan valiosos conocimientos y comentarios para ayudarle a mejorar su escritura.", + "open-source-title": "Synapsy Write es de Código Abierto", + "generation-font-desc": "Seleccione el estilo de fuente para el contenido del texto.", + "system-templates-desc": "Cree avisos del sistema para el Asistente Synapsy.", + "openai-models": "Modelos de OpenAI", + "openai-models-desc": "Vea todos los Modelos de OpenAI disponibles para su cuenta.", + "general": "General", + "change": "Cambiar", + "prompt-desc": "Ingrese el aviso para que la IA genere el documento.", + "overview": "Descripción general", + "information": "Información", + "date": "Fecha", + "templates": "Plantillas", + "template-new": "Nueva plantilla", + "template-delete": "Eliminar plantilla", + "template-view": "Ver plantilla", + "template-edit": "Editar plantilla", + "add-step": "Añadir un paso", + "recipe": "Receta", + "user-templates": "Sus plantillas", + "default-templates": "Plantillas de Synapsy", + "template-desc": "La función de plantillas permite crear flujos de trabajo estructurados paso a paso para generar documentos complejos.", + "steps": "Pasos", + "user-prompt": "Aviso del usuario", + "sys-prompt": "Aviso del sistema", + "output-var": "Nombre de la Variable de salida", + "none": "Ninguno", + "hide-content": "No incluido en la generación final", + "no-user-templates": "No hay plantillas disponibles", + "no-user-templates-desc": "Cree una plantilla para comenzar.", + "add": "Añadir", + "delete-confirm": "¿Está absolutamente seguro?", + "delete-confirm-desc": "Esta acción no se puede deshacer. Esto eliminará permanentemente esta plantilla.", + "back": "Atrás", + "prompt-var": "La variable PROMPT contiene el aviso proporcionado por el usuario en la página de Creación.", + "var-usage": "Puede usar el contenido almacenado por esta variable utilizando ", + "password-label": "Contraseña", + "sign-in-magic": "Iniciar sesión vía enlace mágico", + "third-party-providers": "Inicio de sesión de terceros", + "email-sign-in": "Ingrese su correo electrónico a continuación para iniciar sesión en su cuenta", + "sign-email-password": "Iniciar sesión con correo electrónico y contraseña", + "reset-password": "Restablecer la contraseña", + "update-password": "Actualizar contraseña", + "new-password": "Nueva contraseña", + "confirm-password": "Confirmar nueva contraseña", + "link-text-2": "¿No tiene una cuenta?", + "sign-in-link-text-2": "¿Ya tiene una cuenta?", + "models-desc": "Ver todos los modelos disponibles para su cuenta.", + "blog-desc": "Artículos y actualizaciones del equipo", + "privacy-desc": "Obtén más información sobre nuestras políticas relativas a su privacidad", + "youtube-desc": "Mira nuestros videos sobre nuestros productos", + "x-desc": "Síguenos en X para obtener las últimas actualizaciones", + "cgv-desc": "Descubre nuestras condiciones generales de venta" +} diff --git a/app/i18n/locales/fr/common.json b/app/i18n/locales/fr/common.json index bcd59c9f..ecf40edc 100644 --- a/app/i18n/locales/fr/common.json +++ b/app/i18n/locales/fr/common.json @@ -366,5 +366,11 @@ "new-password": "Nouveau mot de passe", "confirm-password": "Confirmez votre mot de passe", "link-text-2": "Vous n'avez pas de compte ?", - "sign-in-link-text-2": "Vous avez déjà un compte ?" + "sign-in-link-text-2": "Vous avez déjà un compte ?", + "models-desc": "Voir tous les modèles disponibles pour votre compte.", + "blog-desc": "Articles et mises à jour de l'équipe", + "privacy-desc": "En savoir plus sur nos politiques relatives à votre vie privée", + "youtube-desc": "Regardez nos vidéos sur nos produits", + "x-desc": "Suivez-nous sur X pour obtenir les dernières mises à jour", + "cgv-desc": "Découvrez nos conditions générales de vente" } diff --git a/app/i18n/settings.ts b/app/i18n/settings.ts index cbbc3469..bb13dda7 100644 --- a/app/i18n/settings.ts +++ b/app/i18n/settings.ts @@ -1,5 +1,5 @@ export const fallbackLng = "en"; -export const languages = [fallbackLng, "fr"]; +export const languages = [fallbackLng, "fr", "es"]; export const defaultNS = "translation"; export const cookieName = "i18next"; diff --git a/components/chat-box.tsx b/components/chat-box.tsx index 5be0a847..7110c587 100644 --- a/components/chat-box.tsx +++ b/components/chat-box.tsx @@ -32,49 +32,45 @@ export default function ChatBox(props: ChatBoxProps) {
{msg.map((m, i) => ( <> - {m.role !== "system" && ( -
+

-

- - {t(m.role === "assistant" ? "synapsy-assistant" : "you")} - - {m.role === "assistant" && ( - - )} -

- -
- - - - - - -

{t("copy")}

-
-
-
-
+ + {t(m.role === "assistant" ? "synapsy-assistant" : "you")} + + {m.role === "assistant" && } +

+ +
+ + + + + + +

{t("copy")}

+
+
+
- )} +
))}
diff --git a/components/footer.tsx b/components/footer.tsx index 946c8e83..ecb3f7d6 100644 --- a/components/footer.tsx +++ b/components/footer.tsx @@ -12,69 +12,67 @@ export default function SiteFooter({ }) { const { t } = useTranslation(lng, "common"); return ( -