diff --git a/.env.dev.example b/.env.dev.example new file mode 100644 index 00000000000..98c548324c9 --- /dev/null +++ b/.env.dev.example @@ -0,0 +1,11 @@ +# .env for docker-compose.dev.yaml + +# False = no login screen, the developer is automatically logged in upon opening the root +WEBUI_AUTH=False +# Set this to an arbitrary random string if WEBUI_AUTH=True +WEBUI_SECRET_KEY="< generate some random string >" + +# DO NOT TRACK +SCARF_NO_ANALYTICS=true +DO_NOT_TRACK=true +ANONYMIZED_TELEMETRY=false diff --git a/.gitignore b/.gitignore index 32271f8087e..8901e1dc42e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ node_modules .env .env.* !.env.example +!.env.dev.example vite.config.js.timestamp-* vite.config.ts.timestamp-* # Byte-compiled / optimized / DLL files diff --git a/Dockerfile b/Dockerfile index 274e23dbfc7..c61ddd4b020 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,6 +31,10 @@ RUN npm ci COPY . . ENV APP_BUILD_HASH=${BUILD_HASH} +# Necessary on some systems, maybe only for Podman otherwise the build fails with +# FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory +ENV NODE_OPTIONS=--max-old-space-size=3100 +RUN echo "PUBLIC_FEEDBACK_BASE_URL=" > .env RUN npm run build ######## WebUI backend ######## diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index a5adbb0f170..41aae2ffbe4 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -827,6 +827,8 @@ def load_oauth_providers(): "WEBHOOK_URL", "webhook_url", os.environ.get("WEBHOOK_URL", "") ) +ENABLE_MODEL_INFOS = os.environ.get("ENABLE_MODEL_INFOS", "True").lower() == "true" + ENABLE_ADMIN_EXPORT = os.environ.get("ENABLE_ADMIN_EXPORT", "True").lower() == "true" ENABLE_ADMIN_CHAT_ACCESS = ( diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index c145ca1b82a..8925ec10fc7 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -72,6 +72,7 @@ DEFAULT_LOCALE, ENABLE_ADMIN_CHAT_ACCESS, ENABLE_ADMIN_EXPORT, + ENABLE_MODEL_INFOS, ENABLE_OLLAMA_API, ENABLE_OPENAI_API, ENABLE_TAGS_GENERATION, @@ -2439,6 +2440,7 @@ async def get_app_config(request: Request): "enable_message_rating": webui_app.state.config.ENABLE_MESSAGE_RATING, "enable_admin_export": ENABLE_ADMIN_EXPORT, "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS, + "enable_model_infos": ENABLE_MODEL_INFOS, } if user is not None else {} diff --git a/backend/open_webui/static/favicon.png b/backend/open_webui/static/favicon.png index 2b207478084..169948c2859 100644 Binary files a/backend/open_webui/static/favicon.png and b/backend/open_webui/static/favicon.png differ diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml new file mode 100644 index 00000000000..42e0e6f6f79 --- /dev/null +++ b/docker-compose.dev.yaml @@ -0,0 +1,42 @@ +name: open-webui-dev + +services: + frontend: + build: + context: . + target: build + command: ["sh", "/app/src/frontend-dev.sh"] + env_file: ".env" + depends_on: + - backend + ports: + - "3000:5173" + extra_hosts: + - host.docker.internal:127.0.0.1 + volumes: + - ./src:/app/src + - ./package.json:/app/package.json + - ./package-lock.json:/app/package-lock.json + - ./vite.config.ts:/app/vite.config.ts + - ./svelte.config.js:/app/svelte.config.js + - ./tsconfig.json:/app/tsconfig.json + - ./tailwind.config.js:/app/tailwind.config.js + + backend: + build: + context: . + target: base + command: ["bash", "dev.sh"] + env_file: ".env" + environment: + - ENV=dev + ports: + - "8080:8080" + extra_hosts: + - host.docker.internal:127.0.0.1 + volumes: + - ./backend:/app/backend + - data:/app/backend/data + +volumes: + data: {} diff --git a/src/app.css b/src/app.css index 9d073d05ded..d3a73992990 100644 --- a/src/app.css +++ b/src/app.css @@ -61,7 +61,7 @@ math { } .font-primary { - font-family: 'Archivo', sans-serif; + font-family: var(--default-font-regular, 'OpenSansSemibold', arial, sans-serif); } iframe { @@ -215,3 +215,7 @@ input[type='number'] { @apply absolute inset-0 z-0 text-gray-500; } + +body { + background-color: var(--primary-background-color); +} diff --git a/src/app.html b/src/app.html index f6e46c9cfbe..c35eebb6715 100644 --- a/src/app.html +++ b/src/app.html @@ -28,6 +28,9 @@ + + + + + + {#if !feedbackSent} + +

{$i18n.t('Feedback', { ns: 'ionos' })}

+
+ +

{$i18n.t('Pass on your impressions, suggestions etc. to us...', { ns: 'ionos' })}

+
+
+ + + {#if noRating} +
+

{$i18n.t('General evaluation', { ns: 'ionos' })}

+ {#each Array(5) as _, index} + + {/each} +
+ {/if} +
+ + + {/if} + + {#if feedbackSent} + {#await postFeedback(feedbackText, rating)} +
+
    +
  • +
    +
  • +
  • +

    + {$i18n.t('Feedback is being sent', { ns: 'ionos' })} +

    +
  • +
+
+ {:then} + +

{$i18n.t('Thanks!', { ns: 'ionos' })}

+
+ +
+
+

+ {$i18n.t('We have received your feedback', { ns: 'ionos' })} +

+
+
+ + {:catch} + +

+ {$i18n.t('Something went wrong', { ns: 'ionos' })} +

+
+
+
+

+ {$i18n.t('Feedback could not be sent', { ns: 'ionos' })} +

+
+
+ + {/await} + {/if} +
+
+ + diff --git a/src/lib/IONOS/components/IonosFooter.svelte b/src/lib/IONOS/components/IonosFooter.svelte new file mode 100644 index 00000000000..3c3bf176828 --- /dev/null +++ b/src/lib/IONOS/components/IonosFooter.svelte @@ -0,0 +1,106 @@ + + + + + diff --git a/src/lib/IONOS/components/IonosHeader.svelte b/src/lib/IONOS/components/IonosHeader.svelte new file mode 100644 index 00000000000..b29fe24b7d1 --- /dev/null +++ b/src/lib/IONOS/components/IonosHeader.svelte @@ -0,0 +1,95 @@ + + +
+
+ + + +
+ +
+ + {$i18n.t('Sign up')} + + + + {#if $user} + + + {#if $mobile} + {$i18n.t('Feedback', { ns: 'ionos' })} + {:else} + {$i18n.t('Feedback', { ns: 'ionos' })} + {/if} + + + + {/if} +
+
+ + diff --git a/src/lib/IONOS/components/IonosHelp.svelte b/src/lib/IONOS/components/IonosHelp.svelte new file mode 100644 index 00000000000..e52b40cf3dd --- /dev/null +++ b/src/lib/IONOS/components/IonosHelp.svelte @@ -0,0 +1,19 @@ + + + + + + + + +

{$i18n.t('Further information', { ns: 'ionos' })}

+
+
+
diff --git a/src/lib/IONOS/components/IonosRegister.svelte b/src/lib/IONOS/components/IonosRegister.svelte new file mode 100644 index 00000000000..0526bcc5d50 --- /dev/null +++ b/src/lib/IONOS/components/IonosRegister.svelte @@ -0,0 +1,126 @@ + + + + + + + {#if !registrationSent} + +

{$i18n.t('Stay informed', { ns: 'ionos' })}

+
+ +

+ {$i18n.t( + 'We are still working on it and will keep you up to date when there is news. Just give us your email address', + { ns: 'ionos' } + )} +

+
+
+ + + + + +
+ + {:else} + {#await postRegistration(mailInput)} +
+
    +
  • +
    +
  • +
  • +

    + {$i18n.t('Saving email address', { ns: 'ionos' })} +

    +
  • +
+
+ {:then} + +

{$i18n.t('Vielen Dank!', { ns: 'ionos' })}

+
+
+
+

+ {$i18n.t('The e-mail address has been saved', { ns: 'ionos' })} +

+
+
+ + {:catch} + +

+ {$i18n.t('Something went wrong', { ns: 'ionos' })} +

+
+
+
+

+ {$i18n.t('Your e-mail address could not be saved', { ns: 'ionos' })} +

+
+
+ + {/await} + {/if} +
+
diff --git a/src/lib/IONOS/components/ModelIcons.svelte b/src/lib/IONOS/components/ModelIcons.svelte new file mode 100644 index 00000000000..170bea6f212 --- /dev/null +++ b/src/lib/IONOS/components/ModelIcons.svelte @@ -0,0 +1,150 @@ + + +{#if selectedModel === Models.CHAT} + + + + + + + + + + + + + +{:else if selectedModel === Models.CODE} + + + + + + + + + + + + + + + +{:else if selectedModel === Models.IMAGE} + + + + + + + + + + + + +{:else if selectedModel === Models.TEXT} + + + + + + + + + + + + + + +{/if} diff --git a/src/lib/IONOS/components/ModelSelector.svelte b/src/lib/IONOS/components/ModelSelector.svelte new file mode 100644 index 00000000000..225c992d182 --- /dev/null +++ b/src/lib/IONOS/components/ModelSelector.svelte @@ -0,0 +1,45 @@ + + +
+ {#each models as currentModel, promptIdx} + + + {/each} +
+ +
+

{modelName}

+
diff --git a/src/lib/IONOS/components/SendMessageButton.svelte b/src/lib/IONOS/components/SendMessageButton.svelte new file mode 100644 index 00000000000..741ed6e20d9 --- /dev/null +++ b/src/lib/IONOS/components/SendMessageButton.svelte @@ -0,0 +1,45 @@ + + +
+ + + +
+ + diff --git a/src/lib/IONOS/components/Suggestions.svelte b/src/lib/IONOS/components/Suggestions.svelte new file mode 100644 index 00000000000..e1cd56e0447 --- /dev/null +++ b/src/lib/IONOS/components/Suggestions.svelte @@ -0,0 +1,63 @@ + + +
+ {#each promptSelection as prompt, promptIdx} +
(hoveredId = promptIdx)} + on:mouseleave={() => (hoveredId = null)} + > + +
+ {/each} +
+ + diff --git a/src/lib/IONOS/components/Trailer.svelte b/src/lib/IONOS/components/Trailer.svelte new file mode 100644 index 00000000000..d32cfdb9895 --- /dev/null +++ b/src/lib/IONOS/components/Trailer.svelte @@ -0,0 +1,8 @@ + + +
+

{$i18n.t("By sending messages to IONOS GPT, you agree to our terms and conditions and confirm that you have read our privacy policy.", { ns: "ionos" })}

+
diff --git a/src/lib/IONOS/components/ionos-variables.css b/src/lib/IONOS/components/ionos-variables.css new file mode 100644 index 00000000000..931c9a2ce23 --- /dev/null +++ b/src/lib/IONOS/components/ionos-variables.css @@ -0,0 +1,365 @@ +:root, +[data-exos-theme='ionos'] { + --default-font-regular: "OpenSansRegular",arial,arial narrow,sans-serif; + --default-font-bold: "OpenSansSemibold",arial,sans-serif; + --corporate-font-regular: "OverpassRegular",arial,arial narrow,sans-serif; + --corporate-font-bold: "OverpassSemibold",arial,sans-serif; + --default-text-size: 14px; + --default-text-line-height: 20px; + --large-text-size: 16px; + --large-text-line-height: 22px; + --small-text-size: 12px; + --small-text-line-height: 18px; + --default-border-radius: 16px; + --small-border-radius: 8px; + --xsmall-border-radius: 4px; + --xxsmall-border-radius: 2px; + --default-border-width: 1px; + --thick-border-width: 2px; + --button-font-size: var(--default-text-size); + --button-border-width: 2px; + --button-border-radius: 24px; + --button-padding: 4px 20px; + --palette-black: #000; + --palette-white: #fff; + --palette-corporate-1: #dbedf8; + --palette-corporate-2: #95caeb; + --palette-corporate-3: #3196d6; + --palette-corporate-4: #1474c4; + --palette-corporate-5: #095bb1; + --palette-corporate-6: #003d8f; + --palette-corporate-7: #0b2a63; + --palette-corporate-8: #001b41; + --palette-corporate-9: #02102b; + --palette-success-1: #c7fae2; + --palette-success-2: #46efa0; + --palette-success-3: #12cf76; + --palette-success-4: #0fa954; + --palette-success-5: #0c8a44; + --palette-success-6: #096b35; + --palette-success-7: #074d26; + --palette-warning-1: #ffedca; + --palette-warning-2: #ffd176; + --palette-warning-3: #fa0; + --palette-warning-4: #ef8300; + --palette-warning-5: #c36b00; + --palette-warning-6: #8e4e00; + --palette-warning-7: #603500; + --palette-critical-1: #ffe4e2; + --palette-critical-2: #ffa8a3; + --palette-critical-3: #ff6159; + --palette-critical-4: #f50c00; + --palette-critical-5: #c80a00; + --palette-critical-6: #9c0800; + --palette-critical-7: #6e0500; + --palette-neutral-1: #f4f7fa; + --palette-neutral-2: #dbe2e8; + --palette-neutral-3: #bcc8d4; + --palette-neutral-4: #97a3b4; + --palette-neutral-5: #718095; + --palette-neutral-6: #465a75; + --palette-neutral-7: #2e4360; + --palette-neutral-8: #1d2d42; + --palette-neutral-9: #0a121c; + --palette-activating-1: #d2f6fc; + --palette-activating-2: #7fe4f6; + --palette-activating-3: #11c7e6; + --palette-activating-4: #08a5c5; + --palette-activating-5: #007e9c; + --palette-activating-6: #005b72; + --palette-activating-7: #003d4b; + --palette-promoting-1: #fae7fe; + --palette-promoting-2: #f0b7fb; + --palette-promoting-3: #e480f8; + --palette-promoting-4: #d746f5; + --palette-promoting-5: #b410e7; + --palette-promoting-6: #8212c2; + --palette-promoting-7: #560e8a; + --black: var(--palette-black); + --white: var(--palette-white); + --primary-text-color: var(--palette-corporate-9); + --default-text-color: var(--palette-corporate-8); + --secondary-text-color: var(--palette-neutral-6); + --tertiary-text-color: var(--palette-neutral-5); + --primary-text-color-inverted: var(--palette-neutral-1); + --default-text-color-inverted: var(--palette-neutral-2); + --secondary-text-color-inverted: var(--palette-neutral-3); + --primary-shape-color: var(--palette-neutral-7); + --default-shape-color: var(--palette-neutral-6); + --secondary-shape-color: var(--palette-neutral-5); + --tertiary-shape-color: var(--palette-neutral-3); + --primary-background-color: var(--palette-white); + --default-background-color: var(--palette-neutral-1); + --secondary-background-color: var(--palette-white); + --tertiary-background-color: var(--palette-neutral-3); + --quaternary-background-color: var(--palette-neutral-4); + --primary-background-color-inverted: var(--palette-corporate-8); + --default-background-color-inverted: var(--palette-corporate-7); + --secondary-background-color-inverted: var(--palette-neutral-6); + --tertiary-background-color-inverted: var(--palette-neutral-5); + --success-text-color: var(--palette-success-6); + --success-shape-color: var(--palette-success-4); + --caution-text-color: var(--palette-warning-4); + --caution-shape-color: var(--palette-warning-2); + --warning-text-color: var(--palette-warning-5); + --warning-shape-color: var(--palette-warning-3); + --critical-text-color: var(--palette-critical-5); + --critical-shape-color: var(--palette-critical-4); + --neutral-text-color: var(--palette-neutral-6); + --neutral-shape-color: var(--palette-neutral-5); + --activating-text-color: var(--palette-activating-5); + --activating-shape-color: var(--palette-activating-3); + --promoting-text-color: var(--palette-promoting-7); + --promoting-shape-color: var(--palette-promoting-5); + --corporate-text-color: var(--palette-corporate-7); + --corporate-shape-color: var(--palette-corporate-8); + --inactive-success-text-color: var(--palette-success-3); + --inactive-success-shape-color: var(--palette-success-3); + --inactive-warning-text-color: var(--palette-warning-2); + --inactive-warning-shape-color: var(--palette-warning-2); + --inactive-critical-text-color: var(--palette-critical-2); + --inactive-critical-shape-color: var(--palette-critical-2); + --inactive-neutral-text-color: var(--palette-neutral-3); + --inactive-neutral-shape-color: var(--palette-neutral-3); + --inactive-activating-text-color: var(--palette-activating-2); + --inactive-activating-shape-color: var(--palette-activating-2); + --inactive-promoting-text-color: var(--palette-promoting-2); + --inactive-promoting-shape-color: var(--palette-promoting-2); + --inactive-corporate-text-color: var(--palette-corporate-2); + --inactive-corporate-shape-color: var(--palette-corporate-2); + --solid-success-background-color: var(--palette-success-3); + --solid-caution-background-color: var(--palette-warning-2); + --solid-warning-background-color: var(--palette-warning-3); + --solid-critical-background-color: var(--palette-critical-3); + --solid-neutral-background-color: var(--palette-neutral-6); + --solid-activating-background-color: var(--palette-activating-3); + --solid-promoting-background-color: var(--palette-promoting-3); + --solid-corporate-background-color: var(--palette-corporate-7); + --solid-bright-background-color: var(--palette-white); + --success-background-color: var(--palette-white); + --hovered-success-background-color: var(--palette-success-1); + --warning-background-color: var(--palette-white); + --hovered-warning-background-color: var(--palette-warning-1); + --critical-background-color: var(--palette-white); + --hovered-critical-background-color: var(--palette-critical-1); + --neutral-background-color: var(--palette-white); + --hovered-neutral-background-color: var(--palette-neutral-1); + --activating-background-color: var(--palette-white); + --hovered-activating-background-color: var(--palette-activating-1); + --promoting-background-color: var(--palette-white); + --hovered-promoting-background-color: var(--palette-promoting-1); + --corporate-background-color: var(--palette-white); + --hovered-corporate-background-color: var(--palette-corporate-1); + --advertising-background-gradient-start: var(--palette-corporate-6); + --advertising-background-gradient-end: var(--palette-corporate-4); + --hovered-advertising-background-gradient-start: var(--palette-corporate-8); + --hovered-advertising-background-gradient-end: var(--palette-corporate-6); + --interactive-text-color: var(--palette-corporate-4); + --interactive-shape-color: var(--palette-corporate-4); + --hovered-interactive-text-color: var(--palette-corporate-5); + --default-shadow-color: #71809580; + --default-shadow: 0 1px 2px 0 var(--default-shadow-color); + --primary-shadow: 0 2px 8px 0 var(--default-shadow-color); + --secondary-shadow: 0 1px 0 0 var(--default-shadow-color); + --semantic-container-border-width: 0; + --semantic-section-border-width: var(--thick-border-width); + --semantic-section-border-overlapping-margin: -1px 0 0 0; + --primary-button-background-color: var(--palette-corporate-7); + --primary-button-border-color: var(--palette-corporate-7); + --primary-button-text-color: var(--palette-white); + --hovered-primary-button-background-color: var(--palette-corporate-4); + --hovered-primary-button-border-color: var(--palette-corporate-4); + --hovered-primary-button-text-color: var(--palette-white); + --bright-primary-button-background-color: var(--palette-white); + --bright-primary-button-border-color: var(--palette-white); + --bright-primary-button-text-color: var(--palette-corporate-7); + --hovered-bright-primary-button-background-color: var(--palette-corporate-2); + --hovered-bright-primary-button-border-color: var(--palette-corporate-2); + --hovered-bright-primary-button-text-color: var(--palette-corporate-7); + --activating-primary-button-background-color: var(--palette-activating-3); + --activating-primary-button-border-color: var(--palette-activating-3); + --activating-primary-button-text-color: var(--palette-corporate-7); + --hovered-activating-primary-button-background-color: var(--palette-activating-2); + --hovered-activating-primary-button-border-color: var(--palette-activating-2); + --hovered-activating-primary-button-text-color: var(--palette-corporate-7); + --promoting-primary-button-background-color: var(--palette-promoting-3); + --promoting-primary-button-border-color: var(--palette-promoting-3); + --promoting-primary-button-text-color: var(--palette-white); + --hovered-promoting-primary-button-background-color: var(--palette-promoting-2); + --hovered-promoting-primary-button-border-color: var(--palette-promoting-2); + --hovered-promoting-primary-button-text-color: var(--palette-white); + --disabled-primary-button-background-color: var(--palette-neutral-4); + --disabled-primary-button-border-color: var(--palette-neutral-4); + --disabled-primary-button-text-color: var(--palette-white); + --secondary-button-background-color: #0000; + --secondary-button-border-color: var(--palette-corporate-7); + --secondary-button-text-color: var(--palette-corporate-7); + --hovered-secondary-button-background-color: var(--palette-corporate-7); + --hovered-secondary-button-border-color: var(--palette-corporate-7); + --hovered-secondary-button-text-color: var(--palette-white); + --bright-secondary-button-background-color: #0000; + --bright-secondary-button-border-color: var(--palette-white); + --bright-secondary-button-text-color: var(--palette-white); + --hovered-bright-secondary-button-background-color: var(--palette-white); + --hovered-bright-secondary-button-border-color: var(--palette-white); + --hovered-bright-secondary-button-text-color: var(--palette-corporate-7); + --activating-secondary-button-background-color: #0000; + --activating-secondary-button-border-color: var(--palette-activating-3); + --activating-secondary-button-text-color: var(--palette-activating-3); + --hovered-activating-secondary-button-background-color: var(--palette-activating-3); + --hovered-activating-secondary-button-border-color: var(--palette-activating-3); + --hovered-activating-secondary-button-text-color: var(--palette-corporate-7); + --promoting-secondary-button-background-color: #0000; + --promoting-secondary-button-border-color: var(--palette-promoting-3); + --promoting-secondary-button-text-color: var(--palette-promoting-3); + --hovered-promoting-secondary-button-background-color: var(--palette-promoting-2); + --hovered-promoting-secondary-button-border-color: var(--palette-promoting-2); + --hovered-promoting-secondary-button-text-color: var(--palette-white); + --disabled-secondary-button-background-color: #0000; + --disabled-secondary-button-border-color: var(--palette-neutral-4); + --disabled-secondary-button-text-color: var(--palette-neutral-4); + --ghost-button-background-color: #0000; + --ghost-button-text-color: var(--palette-corporate-4); + --hovered-ghost-button-background-color: var(--palette-corporate-1); + --hovered-ghost-button-text-color: var(--palette-corporate-5); + --bright-ghost-button-background-color: #0000; + --bright-ghost-button-text-color: var(--palette-corporate-2); + --hovered-bright-ghost-button-background-color: var(--palette-corporate-6); + --hovered-bright-ghost-button-text-color: var(--palette-corporate-2); + --activating-ghost-button-background-color: #0000; + --activating-ghost-button-text-color: var(--palette-corporate-2); + --hovered-activating-ghost-button-background-color: var(--palette-corporate-6); + --hovered-activating-ghost-button-text-color: var(--palette-corporate-2); + --promoting-ghost-button-background-color: #0000; + --promoting-ghost-button-text-color: var(--palette-corporate-2); + --hovered-promoting-ghost-button-background-color: var(--palette-corporate-6); + --hovered-promoting-ghost-button-text-color: var(--palette-corporate-2); + --disabled-ghost-button-background-color: #0000; + --disabled-ghost-button-text-color: var(--palette-neutral-4); + --table-background-color: var(--white); + --table-border: 0 none #0000; + --table-border-radius: var(--default-border-radius); + --table-shadow: none; + --table-row-shadow: inset 0 -1px 0 0 var(--tertiary-shape-color); + --table-header-background-color: #0000; + --table-footer-background-color: var(--white); + --hovered-table-row-background-color: var(--palette-corporate-1); + --highlighted-table-cell-background-color: #dbedf840; + --table-search-background-color: var(--white); + --secondary-table-search-background-color: var(--white); + --table-search-border: var(--table-border); + --table-search-shadow: var(--table-shadow); + --table-search-separator: 0 none #0000; + --table-toolbar-background-color: var(--white); + --table-toolbar-border: var(--table-border); + --table-toolbar-border-bottom: 1px solid var(--tertiary-shape-color); + --table-toolbar-shadow: var(--table-shadow); + --table-toolbar-padding: 24px 16px; + --table-toolbar-bottom-spacing: 0; + --price-badge-background-color: var(--solid-warning-background-color); + --price-badge-text-color: var(--corporate-text-color); + --promoting-badge-text-color: var(--corporate-text-color); + --card-background-color: var(--white); + --card-border: 0 none #0000; + --card-shadow: none; + --distinct-card-background-color: var(--default-background-color); + --distinct-card-footer-background-color: var(--secondary-background-color); + --hovered-card-background-color: var(--hovered-corporate-background-color); + --hovered-card-border: 0 none #0000; + --hovered-card-shadow: none; + --hovered-card-visual-filter: invert(0.125) contrast(1.5); + --sheet-background-color: var(--white); + --sheet-border: 0 none #0000; + --sheet-shadow: none; + --distinct-sheet-background-color: var(--secondary-background-color); + --sheet-header-background-color: var(--secondary-background-color); + --page-message-background-color: var(--white); + --page-message-border: var(--default-border-width) solid var(--neutral-shape-color); + --page-message-border-width: var(--default-border-width); + --accordion-border: 0 none #0000; + --accordion-item-background-color: var(--white); + --accordion-item-border: 1px solid var(--tertiary-shape-color); + --hovered-accordion-shadow: none; + --panel-background-color: var(--white); + --panel-border: 0 none #0000; + --panel-shadow: none; + --hovered-panel-border: 0 none #0000; + --hovered-panel-shadow: 0 0 0 0 #0000; + --hovered-panel-headline-color: var(--interactive-text-color); + --tile-background-color: #0000; + --tile-border: 0 none #0000; + --tile-shadow: none; + --hovered-tile-background-color: var(--palette-corporate-1); + --hovered-tile-border: 0 none #0000; + --hovered-tile-shadow: none; + --filled-tile-background-color: var(--white); + --filled-tile-border: 0 none #0000; + --filled-tile-shadow: none; + --hovered-filled-tile-background-color: var(--palette-corporate-1); + --hovered-filled-tile-border: 0 none #0000; + --hovered-filled-tile-shadow: none; + --outlined-tile-background-color: #0000; + --outlined-tile-border: 1px solid var(--corporate-text-color); + --outlined-tile-shadow: none; + --hovered-outlined-tile-background-color: var(--palette-corporate-1); + --hovered-outlined-tile-border: 1px solid var(--corporate-text-color); + --hovered-outlined-tile-shadow: none; + --bright-tile-background-color: var(--white); + --bright-tile-border: 0 none #0000; + --bright-tile-shadow: none; + --hovered-bright-tile-background-color: var(--palette-corporate-1); + --hovered-bright-tile-border: 0 none #0000; + --hovered-bright-tile-shadow: none; + --checkbox-border-width: var(--default-border-width); + --checkbox-square-size: 16px; + --input-select-border-width: var(--default-border-width); + --input-select-height: 36px; + --input-text-border-width: var(--default-border-width); + --input-text-group-height: 34px; + --input-text-group-line-height: 44px; + --input-text-height: 36px; + --secondary-textarea-background-color: var(--palette-neutral-2); + --hovered-textarea-background-color: var(--palette-corporate-1); + --check-list-icon-background-color: var(--palette-corporate-2); + --check-list-icon-color: var(--palette-corporate-6); + --inverted-check-list-icon-background-color: #fff3; + --inverted-check-list-icon-color: var(--white); + --context-menu-border: 2px solid var(--palette-corporate-4); + --context-menu-separator: 1px solid var(--tertiary-shape-color); + --page-tabbar-bottom-border: 0 none #0000; + --page-footer-border: 1px solid var(--tertiary-shape-color); + --global-navigation-background-color: var(--palette-corporate-6); + --global-navigation-border1: #095bb1; + --global-navigation-border2: #0b2a63; +} + +@media (prefers-color-scheme: dark) { + :root { + /* disable dark mode values for now */ + /*--ion-background-color: #0d0d0d;*/ + /*--ion-brand-color: #f4f7fa;*/ + /*--secondary-button-border-color: #f4f7fa;*/ + /*--secondary-button-background-color: #fff;*/ + /*--ion-text-color: var(--primary-text-color-inverted);*/ + /*--powered-by-text-color: var(--primary-text-color-inverted);*/ + } +} + +@media (prefers-color-scheme: light) { + :root { + --ion-background-color: #f9f9f9; + --ion-brand-color: var(--palette-corporate-6); + --ion-text-color: var(--primary-text-color); + --powered-by-text-color: var(--primary-text-color); + } +} + +/** + * override prefers-color-scheme dependent values for now + */ +:root { + --ion-background-color: #f9f9f9; + --ion-brand-color: var(--palette-corporate-6); + --ion-text-color: var(--primary-text-color); + --powered-by-text-color: var(--palette-corporate-6); +} diff --git a/src/lib/IONOS/configs/ionosPromptSuggestions.json b/src/lib/IONOS/configs/ionosPromptSuggestions.json new file mode 100644 index 00000000000..042b035fb13 --- /dev/null +++ b/src/lib/IONOS/configs/ionosPromptSuggestions.json @@ -0,0 +1,107 @@ +[ + { + "description": "Text zusammenfassen", + "detail": "Geben Sie der AI längere Texte und lassen Sie sich diese schnell zusammenfassen.", + "modelName": "IONOS Chat-Assistent", + "model": "ionos-chat-assistent", + "content": "Fasse mir einen Text zusammen." + }, + { + "description": "Texte überarbeiten", + "detail": "Lassen Sie von Ihnen geschriebene Texte automatisiert verbessern.", + "modelName": "IONOS Chat-Assistent", + "model": "ionos-chat-assistent", + "content": "Verbessere meinen Text, um ihn professioneller klingen zu lassen." + }, + { + "description": "in neue Themen eintauchen", + "detail": "Bekommen Sie einen Überblick über neue Themen und lassen Sie sich diese erklären.", + "modelName": "IONOS Chat-Assistent", + "model": "ionos-chat-assistent", + "content": "Helfe mir ein Thema besser zu verstehen." + }, + { + "description": "Ideen sammeln", + "detail": "Erzeugen Sie vielseitige Ideen zu einem Thema Ihrer Wahl.", + "modelName": "IONOS Chat-Assistent", + "model": "ionos-chat-assistent", + "content": "Helfe mir dabei Ideen zu sammeln." + }, + { + "description": "Programmieren", + "detail": "Lassen Sie Funktionen oder ganze Skripte in der Programmiersprache Ihrer Wahl generieren.", + "modelName": "Codegenerierung", + "model": "codegenerierung", + "content": "Schreibe eine Python-Funktion für mich. Frage mich zunächst nach meinen Anforderungen daran." + }, + { + "description": "Code Überarbeiten", + "detail": "Lassen Sie Ihren Code automatisiert überarbeiten.", + "modelName": "Codegenerierung", + "model": "codegenerierung", + "content": "Hilf mir meinen Code effizienter und kompakter zu machen. Frage mich zunächst, meinen Code einzugeben." + }, + { + "description": "Tests erstellen", + "detail": "Erstellen Sie passende Tests für Ihren Code.", + "modelName": "Codegenerierung", + "model": "codegenerierung", + "content": "Erstelle mir passende Tests für meine Funktionen. Frage mich zunächst, die entsprechende Funktion einzugeben." + }, + { + "description": "einen Plan erstellen", + "detail": "Lassen Sie sich einen Plan für Ihren nächsten Workshop, Ihre nächste Reise oder Ihr nächstes Training erstellen.", + "modelName": "IONOS Chat-Assistent", + "model": "ionos-chat-assistent", + "content": "Erstelle mir einen Plan. " + }, + { + "description": "einen Firmentext schreiben", + "detail": "Erstellen Sie passende Texte für Ihre Firmenkanäle.", + "modelName": "KI Texter", + "model": "copywriter", + "content": "Hilf mir einen Firmentext zu verfassen." + }, + { + "description": "etwas in seinem Style schreiben lassen", + "detail": "Stellen Sie Beispieltexte zur Verfügung, um Inhalte in Ihrem spezifischen Firmenstil erstellen zu lassen.", + "modelName": "KI Texter", + "model": "copywriter", + "content": "Schreibe einen Text und orientiere dich dabei am Schreibstil meines Beispieltextes." + }, + { + "description": "einen Blogartikel schreiben", + "detail": "Erstellen Sie Blogartikel für Ihre Firmenplattform.", + "modelName": "KI Texter", + "model": "copywriter", + "content": "Schreibe einen Blogartikel für meine Firmenwebseite." + }, + { + "description": "einen Social Media Post schreiben", + "detail": "Erstellen Sie Social Media Posts für Ihren Firmenaccount.", + "modelName": "KI Texter", + "model": "copywriter", + "content": "Schreibe einen Social Media Post für mein LinkedIn Profil." + }, + { + "description": "ein Bild erstellen", + "detail": "Generieren Sie visuelle Inhalte für Ihre Webseite, einen Blog oder Ihre nächste Präsentation.", + "modelName": "Bildgenerierung", + "model": "ionos-image-pipeline", + "content": "Stilisiertes Bild, verschiedene Blautöne, abstrakt, runde formen, flächig" + }, + { + "description": "ein Bild erstellen", + "detail": "Generieren Sie visuelle Inhalte für Ihre Webseite, einen Blog oder Ihre nächste Präsentation.", + "modelName": "Bildgenerierung", + "model": "ionos-image-pipeline", + "content": "Fotorealistisches Bild eines Waldes am Tag, Tau, high quality" + }, + { + "description": "ein Bild erstellen", + "detail": "Generieren Sie visuelle Inhalte für Ihre Webseite, einen Blog oder Ihre nächste Präsentation.", + "modelName": "Bildgenerierung", + "model": "ionos-image-pipeline", + "content": "Stilisiertes Bild, künstlicher Intelligenz, futuristisch." + } +] diff --git a/src/lib/IONOS/utils/getModels.ts b/src/lib/IONOS/utils/getModels.ts new file mode 100644 index 00000000000..1e6d30edd78 --- /dev/null +++ b/src/lib/IONOS/utils/getModels.ts @@ -0,0 +1,17 @@ +import prompts from '$lib/IONOS/configs/ionosPromptSuggestions.json'; + +/** + * Select the models from the array. + * + * @param {Array} array of something + * @param {Number} maxPicks max number of picks + */ +export default (): Array => { + const models = new Map(); + + for (const { model, modelName } of prompts ) { + models.set(model, modelName); + } + + return [...models.entries().map(([model, modelName]) => ([model, modelName]))]; +} diff --git a/src/lib/IONOS/utils/randomSelection.ts b/src/lib/IONOS/utils/randomSelection.ts new file mode 100644 index 00000000000..246e0704c8a --- /dev/null +++ b/src/lib/IONOS/utils/randomSelection.ts @@ -0,0 +1,25 @@ +/** Select max picks from the array. + * + * @param {Array} array of someting + * @param {Number} maxPicks max number of picks + */ +export default (array: Array, maxPicks: number): Array => { + let pickedIndexes = { }; + let result = []; + + for (let index = 0, counter = 0; counter < Math.min(array.length, maxPicks);) { + index = Math.floor(Math.random() * array.length); + + if (index in pickedIndexes) { + continue; + } + + counter++ + + pickedIndexes[index] = true; + + result.push(array[index]); + } + + return result; +} diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 8a1ef2d9162..2dfc3899047 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -508,7 +508,8 @@ await showArtifacts.set(false); if ($page.url.pathname.includes('/c/')) { - window.history.replaceState(history.state, '', `/`); + goto('/start'); + return; } autoScroll = true; @@ -552,8 +553,9 @@ showControls.set(true); } - if ($page.url.searchParams.get('q')) { - prompt = $page.url.searchParams.get('q') ?? ''; + if (sessionStorage.ionosGptDemoPrompt) { + prompt = sessionStorage.ionosGptDemoPrompt ?? ''; + sessionStorage.removeItem('ionosGptDemoPrompt'); if (prompt) { await tick(); @@ -2190,7 +2192,7 @@ {#if !chatIdProp || (loaded && chatIdProp)}
+ import { getContext } from 'svelte'; + import { fade } from 'svelte/transition'; + + const i18n = getContext('i18n'); + + export let greeting: string | null = null; + + +
+

+ {$i18n.t('Welcome at IONOS GPT', { ns: 'ionos' })} +

+
+ + diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index a869a1d99ba..d61f2009fc5 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1068,7 +1068,7 @@
diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 392a9e7322a..52fc0ee40fc 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -67,6 +67,8 @@ let folders = {}; + const showUserMenu = false; + const initFolders = async () => { const folderList = await getFolders(localStorage.token).catch((error) => { toast.error(error); @@ -403,14 +405,14 @@ diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts index 172c42f91bd..5d3396476a3 100644 --- a/src/lib/i18n/index.ts +++ b/src/lib/i18n/index.ts @@ -60,7 +60,7 @@ export const initI18n = (defaultLocale: string | undefined) => { fallbackLng: { default: fallbackDefaultLocale }, - ns: 'translation', + ns: ['translation', 'ionos'], returnEmptyString: false, interpolation: { escapeValue: false // not needed for svelte as it escapes by default diff --git a/src/lib/i18n/locales/de-DE/ionos.json b/src/lib/i18n/locales/de-DE/ionos.json new file mode 100644 index 00000000000..10dc51dcb31 --- /dev/null +++ b/src/lib/i18n/locales/de-DE/ionos.json @@ -0,0 +1,24 @@ +{ + "By sending messages to IONOS GPT, you agree to our terms and conditions and confirm that you have read our privacy policy.": "Durch das Austauschen von Nachrichten mit IONOS GPT stimmst Du unseren Nutzungsbedingungen zu und bestätigst, dass Du unsere Datenschutzrichtlinie gelesen hast.", + "Choose the AI assistant that suits you.": "Wähle den für dich passenden KI-Assistenten.", + "Email address": "E-Mail-Adresse", + "Feedback": "Feedback", + "Feedback could not be sent": "Feedback konnte nicht gesendet werden", + "Feedback is being sent": "Feedback wurde gesendet...", + "Further information": "Weitere Informationen", + "General evaluation": "Allgemeine Bewertung", + "Imprint": "Impressum", + "Pass on your impressions, suggestions etc. to us...": "Geben Sie Ihre Eindrücke, Anregungen etc. an uns weiter...", + "Privacy Policy": "Datenschutz", + "Saving email address": "E-Mail-Adresse wird gespeichert...", + "Something went wrong": "Etwas ist schief gelaufen", + "Stay informed": "Bleiben Sie informiert...", + "Terms and Conditions": "AGB", + "Thanks!": "Vielen Dank!", + "The e-mail address has been saved": "Die E-Mail-Adresse wurde gespeichert", + "We are still working on it and will keep you up to date when there is news. Just give us your email address": "Wir arbeiten weiterhin an IONOS GPT und halten Sie auf dem Laufenden, wenn es Neuigkeiten gibt. Geben Sie einfach Ihre Email Adresse an.", + "We have received your feedback": "Wir haben Ihr Feedback erhalten", + "Welcome at IONOS GPT": "Willkommen bei IONOS GPT", + "Your e-mail address could not be saved": "Ihre E-Mail-Adresse konnte nicht gespeichert werden", + "Your feedback to us": "Ihr Feedback an uns" +} diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index 2e3976bf906..e76b73e6f85 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -52,6 +52,13 @@ export const temporaryChatEnabled = writable(false); export const scrollPaginationEnabled = writable(false); export const currentChatPage = writable(1); +export const feedbackDialog:Writable = writable({ open: false }); + +type FeedbackDialog = { + open: boolean; + rating?: number | null; +} + export type Model = OpenAIModel | OllamaModel; type BaseModel = { @@ -180,6 +187,7 @@ type Config = { enable_admin_export: boolean; enable_admin_chat_access: boolean; enable_community_sharing: boolean; + enable_model_infos: boolean; }; oauth: { providers: { diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 6ce1612b763..7fca19a75ba 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -52,6 +52,8 @@ let version; + const showUpdateInfoToast = false; + onMount(async () => { if ($user === undefined) { await goto('/auth'); @@ -207,6 +209,7 @@ +{#if showUpdateInfoToast} {#if version && compareVersion(version.latest, version.current) && ($settings?.showUpdateToast ?? true)}
{/if} +{/if}
- diff --git a/src/routes/(app)/c/[id]/+page.svelte b/src/routes/(app)/c/[id]/+page.svelte index 2cc68782eb6..2426fad5414 100644 --- a/src/routes/(app)/c/[id]/+page.svelte +++ b/src/routes/(app)/c/[id]/+page.svelte @@ -5,5 +5,4 @@ import Help from '$lib/components/layout/Help.svelte'; - diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d1c30a96b6a..4881df703c7 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,4 @@ + +
+ + +

{$i18n.t('Choose the AI assistant that suits you.', { ns: 'ionos' })} +

+ + + +
submit(prompt, model)} + class="flex relative items-center {$mobile ? 'min-w-full' : 'min-w-[580px]'} h-fit my-4 border rounded-xl" + > + +