mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-21 21:50:49 +02:00
📜 feat: Customize Privacy Policy & Terms of Service (#2091)
This commit is contained in:
parent
d4190c9320
commit
1b243c6f8c
9 changed files with 155 additions and 45 deletions
|
@ -44,6 +44,7 @@ router.get('/', async function (req, res) {
|
|||
isEnabled(process.env.SHOW_BIRTHDAY_ICON) ||
|
||||
process.env.SHOW_BIRTHDAY_ICON === '',
|
||||
helpAndFaqURL: process.env.HELP_AND_FAQ_URL || 'https://librechat.ai',
|
||||
interface: req.app.locals.interface,
|
||||
};
|
||||
|
||||
if (typeof process.env.CUSTOM_FOOTER === 'string') {
|
||||
|
|
|
@ -135,6 +135,7 @@ const AppService = async (app) => {
|
|||
availableTools,
|
||||
fileStrategy,
|
||||
fileConfig: config?.fileConfig,
|
||||
interface: config?.interface,
|
||||
paths,
|
||||
...endpointLocals,
|
||||
};
|
||||
|
|
|
@ -91,6 +91,29 @@ function Login() {
|
|||
),
|
||||
};
|
||||
|
||||
const privacyPolicy = startupConfig.interface?.privacyPolicy;
|
||||
const termsOfService = startupConfig.interface?.termsOfService;
|
||||
|
||||
const privacyPolicyRender = privacyPolicy?.externalUrl && (
|
||||
<a
|
||||
className="text-xs font-medium text-gray-500"
|
||||
href={privacyPolicy.externalUrl}
|
||||
target={privacyPolicy.openNewTab ? '_blank' : undefined} rel="noreferrer"
|
||||
>
|
||||
{localize('com_ui_privacy_policy')}
|
||||
</a>
|
||||
);
|
||||
|
||||
const termsOfServiceRender = termsOfService?.externalUrl && (
|
||||
<a
|
||||
className="text-xs font-medium text-gray-500"
|
||||
href={termsOfService.externalUrl}
|
||||
target={termsOfService.openNewTab ? '_blank' : undefined} rel="noreferrer"
|
||||
>
|
||||
{localize('com_ui_terms_of_service')}
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col items-center justify-center bg-white pt-6 dark:bg-gray-900 sm:pt-0">
|
||||
<div className="absolute bottom-0 left-0 m-4">
|
||||
|
@ -139,6 +162,13 @@ function Login() {
|
|||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 align-middle">
|
||||
{privacyPolicyRender}
|
||||
{privacyPolicyRender && termsOfServiceRender && (
|
||||
<div className="border-r-[1px] border-gray-300" />
|
||||
)}
|
||||
{termsOfServiceRender}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,20 +4,61 @@ import { useLocalize } from '~/hooks';
|
|||
export default function Footer() {
|
||||
const { data: config } = useGetStartupConfig();
|
||||
const localize = useLocalize();
|
||||
|
||||
const privacyPolicy = config?.interface?.privacyPolicy;
|
||||
const termsOfService = config?.interface?.termsOfService;
|
||||
|
||||
const privacyPolicyRender = privacyPolicy?.externalUrl && (
|
||||
<a
|
||||
className=" text-gray-500 underline"
|
||||
href={privacyPolicy.externalUrl}
|
||||
target={privacyPolicy.openNewTab ? '_blank' : undefined} rel="noreferrer"
|
||||
>
|
||||
{localize('com_ui_privacy_policy')}
|
||||
</a>
|
||||
);
|
||||
|
||||
const termsOfServiceRender = termsOfService?.externalUrl && (
|
||||
<a
|
||||
className=" text-gray-500 underline"
|
||||
href={termsOfService.externalUrl}
|
||||
target={termsOfService.openNewTab ? '_blank' : undefined} rel="noreferrer"
|
||||
>
|
||||
{localize('com_ui_terms_of_service')}
|
||||
</a>
|
||||
);
|
||||
|
||||
const mainContentRender = (
|
||||
<span>
|
||||
{typeof config?.customFooter === 'string' ? (
|
||||
config.customFooter
|
||||
) : (
|
||||
<>
|
||||
<a href="https://librechat.ai" target="_blank" rel="noreferrer" className="underline">
|
||||
{config?.appTitle || 'LibreChat'} v0.6.10
|
||||
</a>
|
||||
{' - '} {localize('com_ui_new_footer')}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
|
||||
const footerElements = [mainContentRender, privacyPolicyRender, termsOfServiceRender].filter(
|
||||
Boolean,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="relative px-2 py-2 text-center text-xs text-gray-600 dark:text-gray-300 md:px-[60px]">
|
||||
<span>
|
||||
{typeof config?.customFooter === 'string' ? (
|
||||
config.customFooter
|
||||
) : (
|
||||
<div className="relative flex items-center justify-center gap-2 px-2 py-2 text-xs text-gray-600 dark:text-gray-300 md:px-[60px]">
|
||||
{footerElements.map((contentRender, index) => {
|
||||
const isLastElement = index === footerElements.length - 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
<a href="https://librechat.ai" target="_blank" rel="noreferrer" className="underline">
|
||||
{config?.appTitle || 'LibreChat'} v0.6.10
|
||||
</a>
|
||||
{' - '} {localize('com_ui_new_footer')}
|
||||
{contentRender}
|
||||
{!isLastElement && <div className="h-2 border-r-[1px] border-gray-300" />}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ export default {
|
|||
com_ui_preview: 'Preview',
|
||||
com_ui_upload: 'Upload',
|
||||
com_ui_connect: 'Connect',
|
||||
com_ui_privacy_policy: 'Privacy policy',
|
||||
com_ui_terms_of_service: 'Terms of service',
|
||||
com_auth_error_login:
|
||||
'Unable to login with the information provided. Please check your credentials and try again.',
|
||||
com_auth_error_login_rl:
|
||||
|
|
|
@ -7,11 +7,23 @@ version: 1.0.4
|
|||
# Cache settings: Set to true to enable caching
|
||||
cache: true
|
||||
|
||||
# Custom nterface configuration
|
||||
interface:
|
||||
# Privacy policy settings
|
||||
privacyPolicy:
|
||||
externalUrl: 'https://librechat.ai/privacy-policy'
|
||||
openNewTab: true
|
||||
|
||||
# Terms of service
|
||||
termsOfService:
|
||||
externalUrl: 'https://librechat.ai/tos'
|
||||
openNewTab: true
|
||||
|
||||
# Example Registration Object Structure (optional)
|
||||
registration:
|
||||
socialLogins: ["github", "google", "discord", "openid", "facebook"]
|
||||
socialLogins: ['github', 'google', 'discord', 'openid', 'facebook']
|
||||
# allowedDomains:
|
||||
# - "gmail.com"
|
||||
# - "gmail.com"
|
||||
|
||||
# fileConfig:
|
||||
# endpoints:
|
||||
|
@ -49,44 +61,40 @@ endpoints:
|
|||
# # excludedIds: ["asst_excludedAssistantId"]
|
||||
custom:
|
||||
# Groq Example
|
||||
- name: "groq"
|
||||
apiKey: "${GROQ_API_KEY}"
|
||||
baseURL: "https://api.groq.com/openai/v1/"
|
||||
- name: 'groq'
|
||||
apiKey: '${GROQ_API_KEY}'
|
||||
baseURL: 'https://api.groq.com/openai/v1/'
|
||||
models:
|
||||
default: [
|
||||
"llama2-70b-4096",
|
||||
"mixtral-8x7b-32768",
|
||||
"gemma-7b-it"
|
||||
]
|
||||
default: ['llama2-70b-4096', 'mixtral-8x7b-32768', 'gemma-7b-it']
|
||||
fetch: false
|
||||
titleConvo: true
|
||||
titleModel: "mixtral-8x7b-32768"
|
||||
modelDisplayLabel: "groq"
|
||||
titleModel: 'mixtral-8x7b-32768'
|
||||
modelDisplayLabel: 'groq'
|
||||
|
||||
# Mistral AI Example
|
||||
- name: "Mistral" # Unique name for the endpoint
|
||||
- name: 'Mistral' # Unique name for the endpoint
|
||||
# For `apiKey` and `baseURL`, you can use environment variables that you define.
|
||||
# recommended environment variables:
|
||||
apiKey: "${MISTRAL_API_KEY}"
|
||||
baseURL: "https://api.mistral.ai/v1"
|
||||
apiKey: '${MISTRAL_API_KEY}'
|
||||
baseURL: 'https://api.mistral.ai/v1'
|
||||
|
||||
# Models configuration
|
||||
models:
|
||||
models:
|
||||
# List of default models to use. At least one value is required.
|
||||
default: ["mistral-tiny", "mistral-small", "mistral-medium"]
|
||||
default: ['mistral-tiny', 'mistral-small', 'mistral-medium']
|
||||
# Fetch option: Set to true to fetch models from API.
|
||||
fetch: true # Defaults to false.
|
||||
fetch: true # Defaults to false.
|
||||
|
||||
# Optional configurations
|
||||
|
||||
|
||||
# Title Conversation setting
|
||||
titleConvo: true # Set to true to enable title conversation
|
||||
titleConvo: true # Set to true to enable title conversation
|
||||
|
||||
# Title Method: Choose between "completion" or "functions".
|
||||
# titleMethod: "completion" # Defaults to "completion" if omitted.
|
||||
|
||||
# Title Model: Specify the model to use for titles.
|
||||
titleModel: "mistral-tiny" # Defaults to "gpt-3.5-turbo" if omitted.
|
||||
titleModel: 'mistral-tiny' # Defaults to "gpt-3.5-turbo" if omitted.
|
||||
|
||||
# Summarize setting: Set to true to enable summarization.
|
||||
# summarize: false
|
||||
|
@ -98,31 +106,30 @@ endpoints:
|
|||
# forcePrompt: false
|
||||
|
||||
# The label displayed for the AI model in messages.
|
||||
modelDisplayLabel: "Mistral" # Default is "AI" when not set.
|
||||
modelDisplayLabel: 'Mistral' # Default is "AI" when not set.
|
||||
|
||||
# Add additional parameters to the request. Default params will be overwritten.
|
||||
# addParams:
|
||||
# safe_prompt: true # This field is specific to Mistral AI: https://docs.mistral.ai/api/
|
||||
|
||||
# safe_prompt: true # This field is specific to Mistral AI: https://docs.mistral.ai/api/
|
||||
|
||||
# Drop Default params parameters from the request. See default params in guide linked below.
|
||||
# NOTE: For Mistral, it is necessary to drop the following parameters or you will encounter a 422 Error:
|
||||
dropParams: ["stop", "user", "frequency_penalty", "presence_penalty"]
|
||||
dropParams: ['stop', 'user', 'frequency_penalty', 'presence_penalty']
|
||||
|
||||
# OpenRouter Example
|
||||
- name: "OpenRouter"
|
||||
- name: 'OpenRouter'
|
||||
# For `apiKey` and `baseURL`, you can use environment variables that you define.
|
||||
# recommended environment variables:
|
||||
# Known issue: you should not use `OPENROUTER_API_KEY` as it will then override the `openAI` endpoint to use OpenRouter as well.
|
||||
apiKey: "${OPENROUTER_KEY}"
|
||||
baseURL: "https://openrouter.ai/api/v1"
|
||||
apiKey: '${OPENROUTER_KEY}'
|
||||
baseURL: 'https://openrouter.ai/api/v1'
|
||||
models:
|
||||
default: ["gpt-3.5-turbo"]
|
||||
default: ['gpt-3.5-turbo']
|
||||
fetch: true
|
||||
titleConvo: true
|
||||
titleModel: "gpt-3.5-turbo"
|
||||
titleModel: 'gpt-3.5-turbo'
|
||||
# Recommended: Drop the stop parameter from the request as Openrouter models use a variety of stop tokens.
|
||||
dropParams: ["stop"]
|
||||
modelDisplayLabel: "OpenRouter"
|
||||
|
||||
dropParams: ['stop']
|
||||
modelDisplayLabel: 'OpenRouter'
|
||||
# See the Custom Configuration Guide for more information:
|
||||
# https://docs.librechat.ai/install/configuration/custom_config.html
|
||||
|
|
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -27994,7 +27994,7 @@
|
|||
},
|
||||
"packages/data-provider": {
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.4.6",
|
||||
"version": "0.4.7",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
|
|
|
@ -147,6 +147,22 @@ export const rateLimitSchema = z.object({
|
|||
export const configSchema = z.object({
|
||||
version: z.string(),
|
||||
cache: z.boolean(),
|
||||
interface: z
|
||||
.object({
|
||||
privacyPolicy: z
|
||||
.object({
|
||||
externalUrl: z.string().optional(),
|
||||
openNewTab: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
termsOfService: z
|
||||
.object({
|
||||
externalUrl: z.string().optional(),
|
||||
openNewTab: z.boolean().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
fileStrategy: fileSourceSchema.optional(),
|
||||
registration: z
|
||||
.object({
|
||||
|
|
|
@ -193,9 +193,21 @@ export type TResetPassword = {
|
|||
confirm_password?: string;
|
||||
};
|
||||
|
||||
export type TInterfaceConfig = {
|
||||
privacyPolicy?: {
|
||||
externalUrl?: string;
|
||||
openNewTab?: boolean;
|
||||
};
|
||||
termsOfService?: {
|
||||
externalUrl?: string;
|
||||
openNewTab?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type TStartupConfig = {
|
||||
appTitle: string;
|
||||
socialLogins?: string[];
|
||||
interface?: TInterfaceConfig;
|
||||
discordLoginEnabled: boolean;
|
||||
facebookLoginEnabled: boolean;
|
||||
githubLoginEnabled: boolean;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue