mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01: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) ||
|
isEnabled(process.env.SHOW_BIRTHDAY_ICON) ||
|
||||||
process.env.SHOW_BIRTHDAY_ICON === '',
|
process.env.SHOW_BIRTHDAY_ICON === '',
|
||||||
helpAndFaqURL: process.env.HELP_AND_FAQ_URL || 'https://librechat.ai',
|
helpAndFaqURL: process.env.HELP_AND_FAQ_URL || 'https://librechat.ai',
|
||||||
|
interface: req.app.locals.interface,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof process.env.CUSTOM_FOOTER === 'string') {
|
if (typeof process.env.CUSTOM_FOOTER === 'string') {
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ const AppService = async (app) => {
|
||||||
availableTools,
|
availableTools,
|
||||||
fileStrategy,
|
fileStrategy,
|
||||||
fileConfig: config?.fileConfig,
|
fileConfig: config?.fileConfig,
|
||||||
|
interface: config?.interface,
|
||||||
paths,
|
paths,
|
||||||
...endpointLocals,
|
...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 (
|
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="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">
|
<div className="absolute bottom-0 left-0 m-4">
|
||||||
|
|
@ -139,6 +162,13 @@ function Login() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex justify-center gap-4 align-middle">
|
||||||
|
{privacyPolicyRender}
|
||||||
|
{privacyPolicyRender && termsOfServiceRender && (
|
||||||
|
<div className="border-r-[1px] border-gray-300" />
|
||||||
|
)}
|
||||||
|
{termsOfServiceRender}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,61 @@ import { useLocalize } from '~/hooks';
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
const { data: config } = useGetStartupConfig();
|
const { data: config } = useGetStartupConfig();
|
||||||
const localize = useLocalize();
|
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 (
|
return (
|
||||||
<div className="relative px-2 py-2 text-center text-xs text-gray-600 dark:text-gray-300 md:px-[60px]">
|
<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]">
|
||||||
<span>
|
{footerElements.map((contentRender, index) => {
|
||||||
{typeof config?.customFooter === 'string' ? (
|
const isLastElement = index === footerElements.length - 1;
|
||||||
config.customFooter
|
|
||||||
) : (
|
return (
|
||||||
<>
|
<>
|
||||||
<a href="https://librechat.ai" target="_blank" rel="noreferrer" className="underline">
|
{contentRender}
|
||||||
{config?.appTitle || 'LibreChat'} v0.6.10
|
{!isLastElement && <div className="h-2 border-r-[1px] border-gray-300" />}
|
||||||
</a>
|
|
||||||
{' - '} {localize('com_ui_new_footer')}
|
|
||||||
</>
|
</>
|
||||||
)}
|
);
|
||||||
</span>
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,8 @@ export default {
|
||||||
com_ui_preview: 'Preview',
|
com_ui_preview: 'Preview',
|
||||||
com_ui_upload: 'Upload',
|
com_ui_upload: 'Upload',
|
||||||
com_ui_connect: 'Connect',
|
com_ui_connect: 'Connect',
|
||||||
|
com_ui_privacy_policy: 'Privacy policy',
|
||||||
|
com_ui_terms_of_service: 'Terms of service',
|
||||||
com_auth_error_login:
|
com_auth_error_login:
|
||||||
'Unable to login with the information provided. Please check your credentials and try again.',
|
'Unable to login with the information provided. Please check your credentials and try again.',
|
||||||
com_auth_error_login_rl:
|
com_auth_error_login_rl:
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,23 @@ version: 1.0.4
|
||||||
# Cache settings: Set to true to enable caching
|
# Cache settings: Set to true to enable caching
|
||||||
cache: true
|
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)
|
# Example Registration Object Structure (optional)
|
||||||
registration:
|
registration:
|
||||||
socialLogins: ["github", "google", "discord", "openid", "facebook"]
|
socialLogins: ['github', 'google', 'discord', 'openid', 'facebook']
|
||||||
# allowedDomains:
|
# allowedDomains:
|
||||||
# - "gmail.com"
|
# - "gmail.com"
|
||||||
|
|
||||||
# fileConfig:
|
# fileConfig:
|
||||||
# endpoints:
|
# endpoints:
|
||||||
|
|
@ -49,44 +61,40 @@ endpoints:
|
||||||
# # excludedIds: ["asst_excludedAssistantId"]
|
# # excludedIds: ["asst_excludedAssistantId"]
|
||||||
custom:
|
custom:
|
||||||
# Groq Example
|
# Groq Example
|
||||||
- name: "groq"
|
- name: 'groq'
|
||||||
apiKey: "${GROQ_API_KEY}"
|
apiKey: '${GROQ_API_KEY}'
|
||||||
baseURL: "https://api.groq.com/openai/v1/"
|
baseURL: 'https://api.groq.com/openai/v1/'
|
||||||
models:
|
models:
|
||||||
default: [
|
default: ['llama2-70b-4096', 'mixtral-8x7b-32768', 'gemma-7b-it']
|
||||||
"llama2-70b-4096",
|
|
||||||
"mixtral-8x7b-32768",
|
|
||||||
"gemma-7b-it"
|
|
||||||
]
|
|
||||||
fetch: false
|
fetch: false
|
||||||
titleConvo: true
|
titleConvo: true
|
||||||
titleModel: "mixtral-8x7b-32768"
|
titleModel: 'mixtral-8x7b-32768'
|
||||||
modelDisplayLabel: "groq"
|
modelDisplayLabel: 'groq'
|
||||||
|
|
||||||
# Mistral AI Example
|
# 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.
|
# For `apiKey` and `baseURL`, you can use environment variables that you define.
|
||||||
# recommended environment variables:
|
# recommended environment variables:
|
||||||
apiKey: "${MISTRAL_API_KEY}"
|
apiKey: '${MISTRAL_API_KEY}'
|
||||||
baseURL: "https://api.mistral.ai/v1"
|
baseURL: 'https://api.mistral.ai/v1'
|
||||||
|
|
||||||
# Models configuration
|
# Models configuration
|
||||||
models:
|
models:
|
||||||
# List of default models to use. At least one value is required.
|
# 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 option: Set to true to fetch models from API.
|
||||||
fetch: true # Defaults to false.
|
fetch: true # Defaults to false.
|
||||||
|
|
||||||
# Optional configurations
|
# Optional configurations
|
||||||
|
|
||||||
# Title Conversation setting
|
# 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".
|
# Title Method: Choose between "completion" or "functions".
|
||||||
# titleMethod: "completion" # Defaults to "completion" if omitted.
|
# titleMethod: "completion" # Defaults to "completion" if omitted.
|
||||||
|
|
||||||
# Title Model: Specify the model to use for titles.
|
# 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 setting: Set to true to enable summarization.
|
||||||
# summarize: false
|
# summarize: false
|
||||||
|
|
@ -98,31 +106,30 @@ endpoints:
|
||||||
# forcePrompt: false
|
# forcePrompt: false
|
||||||
|
|
||||||
# The label displayed for the AI model in messages.
|
# 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.
|
# Add additional parameters to the request. Default params will be overwritten.
|
||||||
# addParams:
|
# 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.
|
# 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:
|
# 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
|
# OpenRouter Example
|
||||||
- name: "OpenRouter"
|
- name: 'OpenRouter'
|
||||||
# For `apiKey` and `baseURL`, you can use environment variables that you define.
|
# For `apiKey` and `baseURL`, you can use environment variables that you define.
|
||||||
# recommended environment variables:
|
# 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.
|
# 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}"
|
apiKey: '${OPENROUTER_KEY}'
|
||||||
baseURL: "https://openrouter.ai/api/v1"
|
baseURL: 'https://openrouter.ai/api/v1'
|
||||||
models:
|
models:
|
||||||
default: ["gpt-3.5-turbo"]
|
default: ['gpt-3.5-turbo']
|
||||||
fetch: true
|
fetch: true
|
||||||
titleConvo: 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.
|
# Recommended: Drop the stop parameter from the request as Openrouter models use a variety of stop tokens.
|
||||||
dropParams: ["stop"]
|
dropParams: ['stop']
|
||||||
modelDisplayLabel: "OpenRouter"
|
modelDisplayLabel: 'OpenRouter'
|
||||||
|
|
||||||
# See the Custom Configuration Guide for more information:
|
# See the Custom Configuration Guide for more information:
|
||||||
# https://docs.librechat.ai/install/configuration/custom_config.html
|
# 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": {
|
"packages/data-provider": {
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.4.6",
|
"version": "0.4.7",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,22 @@ export const rateLimitSchema = z.object({
|
||||||
export const configSchema = z.object({
|
export const configSchema = z.object({
|
||||||
version: z.string(),
|
version: z.string(),
|
||||||
cache: z.boolean(),
|
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(),
|
fileStrategy: fileSourceSchema.optional(),
|
||||||
registration: z
|
registration: z
|
||||||
.object({
|
.object({
|
||||||
|
|
|
||||||
|
|
@ -193,9 +193,21 @@ export type TResetPassword = {
|
||||||
confirm_password?: string;
|
confirm_password?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TInterfaceConfig = {
|
||||||
|
privacyPolicy?: {
|
||||||
|
externalUrl?: string;
|
||||||
|
openNewTab?: boolean;
|
||||||
|
};
|
||||||
|
termsOfService?: {
|
||||||
|
externalUrl?: string;
|
||||||
|
openNewTab?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export type TStartupConfig = {
|
export type TStartupConfig = {
|
||||||
appTitle: string;
|
appTitle: string;
|
||||||
socialLogins?: string[];
|
socialLogins?: string[];
|
||||||
|
interface?: TInterfaceConfig;
|
||||||
discordLoginEnabled: boolean;
|
discordLoginEnabled: boolean;
|
||||||
facebookLoginEnabled: boolean;
|
facebookLoginEnabled: boolean;
|
||||||
githubLoginEnabled: boolean;
|
githubLoginEnabled: boolean;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue