Merge branch 'master' of github.com:Mintplex-Labs/anything-llm into render

This commit is contained in:
timothycarambat 2024-07-19 09:52:26 -07:00
commit 78e2a59170
28 changed files with 2187 additions and 1340 deletions

View File

@ -81,13 +81,14 @@ jobs:
type=ref,event=tag
type=ref,event=pr
- name: Build and push multi-platform Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
push: true
sbom: true
provenance: mode=max
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -12,16 +12,18 @@ The output of this Terraform configuration will be:
- Follow the instructions in the [official Terraform documentation](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) for your operating system.
## How to deploy on DigitalOcean
Open your terminal and navigate to the `digitalocean/terraform` folder
1. Replace the token value in the provider "digitalocean" block in main.tf with your DigitalOcean API token.
2. Run the following commands to initialize Terraform, review the infrastructure changes, and apply them:
Open your terminal and navigate to the `docker` folder
1. Create a `.env` file by cloning the `.env.example`.
2. Navigate to `digitalocean/terraform` folder.
3. Replace the token value in the provider "digitalocean" block in main.tf with your DigitalOcean API token.
4. Run the following commands to initialize Terraform, review the infrastructure changes, and apply them:
```
terraform init
terraform plan
terraform apply
```
Confirm the changes by typing yes when prompted.
4. Once the deployment is complete, Terraform will output the public IP address of your droplet. You can access your application using this IP address.
5. Once the deployment is complete, Terraform will output the public IP address of your droplet. You can access your application using this IP address.
## How to deploy on DigitalOcean
To delete the resources created by Terraform, run the following command in the terminal:

View File

@ -16,7 +16,7 @@ provider "digitalocean" {
resource "digitalocean_droplet" "anything_llm_instance" {
image = "ubuntu-22-10-x64"
image = "ubuntu-24-04-x64"
name = "anything-llm-instance"
region = "nyc3"
size = "s-2vcpu-2gb"

View File

@ -1,5 +1,4 @@
const fs = require("fs").promises;
const pdf = require("pdf-parse");
class PDFLoader {
constructor(filePath, { splitPages = true } = {}) {
@ -9,54 +8,90 @@ class PDFLoader {
async load() {
const buffer = await fs.readFile(this.filePath);
const { getDocument, version } = await this.getPdfJS();
const options = {
pagerender: this.splitPages ? this.renderPage : null,
};
const pdf = await getDocument({
data: new Uint8Array(buffer),
useWorkerFetch: false,
isEvalSupported: false,
useSystemFonts: true,
}).promise;
const { text, numpages, info, metadata, version } = await pdf(
buffer,
options
);
const meta = await pdf.getMetadata().catch(() => null);
const documents = [];
if (!this.splitPages) {
return [
{
pageContent: text.trim(),
metadata: {
source: this.filePath,
pdf: { version, info, metadata, totalPages: numpages },
for (let i = 1; i <= pdf.numPages; i += 1) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
if (content.items.length === 0) {
continue;
}
let lastY;
const textItems = [];
for (const item of content.items) {
if ("str" in item) {
if (lastY === item.transform[5] || !lastY) {
textItems.push(item.str);
} else {
textItems.push(`\n${item.str}`);
}
lastY = item.transform[5];
}
}
const text = textItems.join("");
documents.push({
pageContent: text.trim(),
metadata: {
source: this.filePath,
pdf: {
version,
info: meta?.info,
metadata: meta?.metadata,
totalPages: pdf.numPages,
},
loc: { pageNumber: i },
},
});
}
if (this.splitPages) {
return documents;
}
if (documents.length === 0) {
return [];
}
return [
{
pageContent: documents.map((doc) => doc.pageContent).join("\n\n"),
metadata: {
source: this.filePath,
pdf: {
version,
info: meta?.info,
metadata: meta?.metadata,
totalPages: pdf.numPages,
},
},
];
}
return this.pages.map((pageContent, index) => ({
pageContent: pageContent.trim(),
metadata: {
source: this.filePath,
pdf: { version, info, metadata, totalPages: numpages },
loc: { pageNumber: index + 1 },
},
}));
];
}
pages = [];
renderPage = async (pageData) => {
const textContent = await pageData.getTextContent();
let lastY,
text = "";
for (const item of textContent.items) {
if (lastY !== item.transform[5] && lastY !== undefined) {
text += "\n";
}
text += item.str;
lastY = item.transform[5];
async getPdfJS() {
try {
const pdfjs = await import("pdf-parse/lib/pdf.js/v1.10.100/build/pdf.js");
return { getDocument: pdfjs.getDocument, version: pdfjs.version };
} catch (e) {
console.error(e);
throw new Error(
"Failed to load pdf-parse. Please install it with eg. `npm install pdf-parse`."
);
}
this.pages.push(text);
return text;
};
}
}
module.exports = PDFLoader;

View File

@ -1,5 +1,5 @@
# Setup base image
FROM ubuntu:jammy-20230916 AS base
FROM ubuntu:jammy-20240627.1 AS base
# Build arguments
ARG ARG_UID=1000
@ -138,7 +138,7 @@ USER anythingllm
FROM frontend-deps AS build-stage
COPY ./frontend/ ./frontend/
WORKDIR /app/frontend
RUN yarn build && yarn cache clean
RUN yarn build && yarn cache clean && rm -rf node_modules
WORKDIR /app
# Setup the server

View File

@ -16,6 +16,7 @@ const HistoricalMessage = forwardRef(
const textSize = !!embedderSettings.settings.textSize
? `allm-text-[${embedderSettings.settings.textSize}px]`
: "allm-text-sm";
if (error) console.error(`ANYTHING_LLM_CHAT_WIDGET_ERROR: ${error}`);
return (
<div className="py-[5px]">
@ -66,7 +67,7 @@ const HistoricalMessage = forwardRef(
Could not respond to message.
</span>
<p className="allm-text-xs allm-font-mono allm-mt-2 allm-border-l-2 allm-border-red-500 allm-pl-2 allm-bg-red-300 allm-p-2 allm-rounded-sm">
{error}
Server error
</p>
</div>
) : (

View File

@ -8,6 +8,7 @@ import { formatDate } from "@/utils/date";
const PromptReply = forwardRef(
({ uuid, reply, pending, error, sources = [] }, ref) => {
if (!reply && sources.length === 0 && !pending && !error) return null;
if (error) console.error(`ANYTHING_LLM_CHAT_WIDGET_ERROR: ${error}`);
if (pending) {
return (
@ -54,9 +55,7 @@ const PromptReply = forwardRef(
>
<Warning className="allm-h-4 allm-w-4 allm-mb-1 allm-inline-block" />{" "}
Could not respond to message.
<span className="allm-text-xs">
Reason: {error || "unknown"}
</span>
<span className="allm-text-xs">Server error</span>
</span>
</div>
</div>

File diff suppressed because one or more lines are too long

View File

@ -17,6 +17,7 @@ import UserIcon from "../UserIcon";
import { userFromStorage } from "@/utils/request";
import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants";
import useUser from "@/hooks/useUser";
import { useTranslation, Trans } from "react-i18next";
export default function DefaultChatContainer() {
const [mockMsgs, setMockMessages] = useState([]);
@ -28,6 +29,7 @@ export default function DefaultChatContainer() {
hideModal: hideNewWsModal,
} = useNewWorkspaceModal();
const popMsg = !window.localStorage.getItem("anythingllm_intro");
const { t } = useTranslation();
useEffect(() => {
const fetchData = async () => {
@ -38,7 +40,7 @@ export default function DefaultChatContainer() {
}, []);
const MESSAGES = [
<React.Fragment>
<React.Fragment key="msg1">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR} md:mt-0 mt-[40px]`}
>
@ -51,18 +53,14 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
Welcome to AnythingLLM, AnythingLLM is an open-source AI tool by
Mintplex Labs that turns anything into a trained chatbot you can
query and chat with. AnythingLLM is a BYOK (bring-your-own-keys)
software so there is no subscription, fee, or charges for this
software outside of the services you want to use with it.
{t("welcomeMessage.part1")}
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg2">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR}`}
>
@ -75,17 +73,14 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
AnythingLLM is the easiest way to put powerful AI products like
OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB, and other services
together in a neat package with no fuss to increase your
productivity by 100x.
{t("welcomeMessage.part2")}
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg3">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR}`}
>
@ -98,20 +93,16 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
AnythingLLM can run totally locally on your machine with little
overhead you wont even notice it's there! No GPU needed. Cloud
and on-premises installation is available as well.
<br />
The AI tooling ecosystem gets more powerful everyday.
AnythingLLM makes it easy to use.
{t("welcomeMessage.part3")}
</span>
<a
href={paths.github()}
target="_blank"
rel="noreferrer"
className="mt-5 w-fit transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
<GitMerge className="h-4 w-4" />
<p>Create an issue on Github</p>
<p>{t("welcomeMessage.githubIssue")}</p>
</a>
</div>
</div>
@ -119,7 +110,7 @@ export default function DefaultChatContainer() {
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg4">
<div
className={`flex justify-center items-end w-full ${USER_BACKGROUND_COLOR}`}
>
@ -135,14 +126,14 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
How do I get started?!
{t("welcomeMessage.user1")}
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg5">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR}`}
>
@ -155,13 +146,7 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
It's simple. All collections are organized into buckets we call{" "}
"Workspaces". Workspaces are buckets of files, documents,
images, PDFs, and other files which will be transformed into
something LLM's can understand and use in conversation.
<br />
<br />
You can add and remove files at anytime.
{t("welcomeMessage.part4")}
</span>
{(!user || user?.role !== "default") && (
@ -170,7 +155,7 @@ export default function DefaultChatContainer() {
className="mt-5 w-fit transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
<Plus className="h-4 w-4" />
<p>Create your first workspace</p>
<p>{t("welcomeMessage.createWorkspace")}</p>
</button>
)}
</div>
@ -179,7 +164,7 @@ export default function DefaultChatContainer() {
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg6">
<div
className={`flex justify-center items-end w-full ${USER_BACKGROUND_COLOR}`}
>
@ -195,15 +180,14 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
Is this like an AI dropbox or something? What about chatting? It
is a chatbot isn't it?
{t("welcomeMessage.user2")}
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg7">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR}`}
>
@ -216,32 +200,20 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
AnythingLLM is more than a smarter Dropbox.
<br />
<br />
AnythingLLM offers two ways of talking with your data:
<br />
<br />
<i>Query:</i> Your chats will return data or inferences found with
the documents in your workspace it has access to. Adding more
documents to the Workspace make it smarter!
<br />
<br />
<i>Conversational:</i> Your documents + your on-going chat history
both contribute to the LLM knowledge at the same time. Great for
appending real-time text-based info or corrections and
misunderstandings the LLM might have.
<br />
<br />
You can toggle between either mode{" "}
<i>in the middle of chatting!</i>
<Trans
i18nKey="welcomeMessage.part5"
components={{
i: <i />,
br: <br />,
}}
/>
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg8">
<div
className={`flex justify-center items-end w-full ${USER_BACKGROUND_COLOR}`}
>
@ -257,14 +229,14 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
Wow, this sounds amazing, let me try it out already!
{t("welcomeMessage.user3")}
</span>
</div>
</div>
</div>
</React.Fragment>,
<React.Fragment>
<React.Fragment key="msg9">
<div
className={`flex justify-center items-end w-full ${AI_BACKGROUND_COLOR}`}
>
@ -277,24 +249,25 @@ export default function DefaultChatContainer() {
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
>
Have Fun!
{t("welcomeMessage.part6")}
</span>
<div className="flex flex-col md:flex-row items-start md:items-center gap-1 md:gap-4">
<a
href={paths.github()}
target="_blank"
rel="noreferrer"
className="mt-5 w-fit transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
<GithubLogo className="h-4 w-4" />
<p>Star on GitHub</p>
<p>{t("welcomeMessage.starOnGithub")}</p>
</a>
<a
href={paths.mailToMintplex()}
className="mt-5 w-fit transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
<EnvelopeSimple className="h-4 w-4" />
<p>Contact Mintplex Labs</p>
<p>{t("welcomeMessage.contact")}</p>
</a>
</div>
</div>

View File

@ -1,47 +1,116 @@
import { useState, useEffect } from "react";
import { useEffect, useState } from "react";
import System from "@/models/system";
import PreLoader from "@/components/Preloader";
import { KOBOLDCPP_COMMON_URLS } from "@/utils/constants";
import { CaretDown, CaretUp } from "@phosphor-icons/react";
import useProviderEndpointAutoDiscovery from "@/hooks/useProviderEndpointAutoDiscovery";
export default function KoboldCPPOptions({ settings }) {
const [basePathValue, setBasePathValue] = useState(
settings?.KoboldCPPBasePath
const {
autoDetecting: loading,
basePath,
basePathValue,
showAdvancedControls,
setShowAdvancedControls,
handleAutoDetectClick,
} = useProviderEndpointAutoDiscovery({
provider: "koboldcpp",
initialBasePath: settings?.KoboldCPPBasePath,
ENDPOINTS: KOBOLDCPP_COMMON_URLS,
});
const [tokenLimit, setTokenLimit] = useState(
settings?.KoboldCPPTokenLimit || 4096
);
const [basePath, setBasePath] = useState(settings?.KoboldCPPBasePath);
const handleTokenLimitChange = (e) => {
setTokenLimit(Number(e.target.value));
};
return (
<div className="flex gap-[36px] mt-1.5 flex-wrap">
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Base URL
</label>
<input
type="url"
name="KoboldCPPBasePath"
className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="http://127.0.0.1:5000/v1"
defaultValue={settings?.KoboldCPPBasePath}
required={true}
autoComplete="off"
spellCheck={false}
onChange={(e) => setBasePathValue(e.target.value)}
onBlur={() => setBasePath(basePathValue)}
<div className="w-full flex flex-col gap-y-7">
<div className="w-full flex items-start gap-[36px] mt-1.5">
<KoboldCPPModelSelection
settings={settings}
basePath={basePath.value}
/>
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-2">
Token context window
</label>
<input
type="number"
name="KoboldCPPTokenLimit"
className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="4096"
min={1}
value={tokenLimit}
onChange={handleTokenLimitChange}
onScroll={(e) => e.target.blur()}
required={true}
autoComplete="off"
/>
<p className="text-xs leading-[18px] font-base text-white text-opacity-60 mt-2">
Maximum number of tokens for context and response.
</p>
</div>
</div>
<KoboldCPPModelSelection settings={settings} basePath={basePath} />
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Token context window
</label>
<input
type="number"
name="KoboldCPPTokenLimit"
className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="4096"
min={1}
onScroll={(e) => e.target.blur()}
defaultValue={settings?.KoboldCPPTokenLimit}
required={true}
autoComplete="off"
/>
<div className="flex justify-start mt-4">
<button
onClick={(e) => {
e.preventDefault();
setShowAdvancedControls(!showAdvancedControls);
}}
className="border-none text-white hover:text-white/70 flex items-center text-sm"
>
{showAdvancedControls ? "Hide" : "Show"} Manual Endpoint Input
{showAdvancedControls ? (
<CaretUp size={14} className="ml-1" />
) : (
<CaretDown size={14} className="ml-1" />
)}
</button>
</div>
<div hidden={!showAdvancedControls}>
<div className="w-full flex items-start gap-4">
<div className="flex flex-col w-60">
<div className="flex justify-between items-center mb-2">
<label className="text-white text-sm font-semibold">
KoboldCPP Base URL
</label>
{loading ? (
<PreLoader size="6" />
) : (
<>
{!basePathValue.value && (
<button
onClick={handleAutoDetectClick}
className="border-none bg-primary-button text-xs font-medium px-2 py-1 rounded-lg hover:bg-secondary hover:text-white shadow-[0_4px_14px_rgba(0,0,0,0.25)]"
>
Auto-Detect
</button>
)}
</>
)}
</div>
<input
type="url"
name="KoboldCPPBasePath"
className="border-none bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="http://127.0.0.1:5000/v1"
value={basePathValue.value}
required={true}
autoComplete="off"
spellCheck={false}
onChange={basePath.onChange}
onBlur={basePath.onBlur}
/>
<p className="text-xs leading-[18px] font-base text-white text-opacity-60 mt-2">
Enter the URL where KoboldCPP is running.
</p>
</div>
</div>
</div>
</div>
);
@ -59,8 +128,17 @@ function KoboldCPPModelSelection({ settings, basePath = null }) {
return;
}
setLoading(true);
const { models } = await System.customModels("koboldcpp", null, basePath);
setCustomModels(models || []);
try {
const { models } = await System.customModels(
"koboldcpp",
null,
basePath
);
setCustomModels(models || []);
} catch (error) {
console.error("Failed to fetch custom models:", error);
setCustomModels([]);
}
setLoading(false);
}
findCustomModels();
@ -69,44 +147,51 @@ function KoboldCPPModelSelection({ settings, basePath = null }) {
if (loading || customModels.length === 0) {
return (
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Chat Model Selection
<label className="text-white text-sm font-semibold block mb-2">
KoboldCPP Model
</label>
<select
name="KoboldCPPModelPref"
disabled={true}
className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
className="border-none bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
<option disabled={true} selected={true}>
{basePath?.includes("/v1")
? "-- loading available models --"
: "-- waiting for URL --"}
? "--loading available models--"
: "Enter KoboldCPP URL first"}
</option>
</select>
<p className="text-xs leading-[18px] font-base text-white text-opacity-60 mt-2">
Select the KoboldCPP model you want to use. Models will load after
entering a valid KoboldCPP URL.
</p>
</div>
);
}
return (
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Chat Model Selection
<label className="text-white text-sm font-semibold block mb-2">
KoboldCPP Model
</label>
<select
name="KoboldCPPModelPref"
required={true}
className="bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
className="border-none bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
{customModels.map((model) => (
<option
key={model.id}
value={model.id}
selected={settings?.KoboldCPPModelPref === model.id}
selected={settings.KoboldCPPModelPref === model.id}
>
{model.id}
</option>
))}
</select>
<p className="text-xs leading-[18px] font-base text-white text-opacity-60 mt-2">
Choose the KoboldCPP model you want to use for your conversations.
</p>
</div>
);
}

View File

@ -2,11 +2,13 @@ import React, { useRef, useState } from "react";
import { X } from "@phosphor-icons/react";
import Workspace from "@/models/workspace";
import paths from "@/utils/paths";
import { useTranslation } from "react-i18next";
const noop = () => false;
export default function NewWorkspaceModal({ hideModal = noop }) {
const formEl = useRef(null);
const [error, setError] = useState(null);
const { t } = useTranslation();
const handleCreate = async (e) => {
setError(null);
e.preventDefault();
@ -29,7 +31,9 @@ export default function NewWorkspaceModal({ hideModal = noop }) {
<div className="relative w-[500px] max-h-full">
<div className="relative bg-modal-gradient rounded-lg shadow-md border-2 border-accent">
<div className="flex items-start justify-between p-4 border-b rounded-t border-white/10">
<h3 className="text-xl font-semibold text-white">New Workspace</h3>
<h3 className="text-xl font-semibold text-white">
{t("new-workspace.title")}
</h3>
<button
onClick={hideModal}
type="button"
@ -46,14 +50,14 @@ export default function NewWorkspaceModal({ hideModal = noop }) {
htmlFor="name"
className="block mb-2 text-sm font-medium text-white"
>
Workspace Name
{t("common.workspaces-name")}
</label>
<input
name="name"
type="text"
id="name"
className="bg-zinc-900 w-full text-white placeholder:text-white/20 text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="My Workspace"
placeholder={t("new-workspace.placeholder")}
required={true}
autoComplete="off"
/>

View File

@ -7,6 +7,7 @@ import ModalWrapper from "@/components/ModalWrapper";
import { useModal } from "@/hooks/useModal";
import RecoveryCodeModal from "@/components/Modals/DisplayRecoveryCodeModal";
import { useTranslation } from "react-i18next";
import { t } from "i18next";
const RecoveryForm = ({ onSubmit, setShowRecoveryForm }) => {
const [username, setUsername] = useState("");
@ -36,21 +37,23 @@ const RecoveryForm = ({ onSubmit, setShowRecoveryForm }) => {
<div className="flex items-start justify-between pt-11 pb-9 w-screen md:w-full md:px-12 px-6 ">
<div className="flex flex-col gap-y-4 w-full">
<h3 className="text-4xl md:text-lg font-bold text-white text-center md:text-left">
Password Reset
{t("login.password-reset.title")}
</h3>
<p className="text-sm text-white/90 md:text-left md:max-w-[300px] px-4 md:px-0 text-center">
Provide the necessary information below to reset your password.
{t("login.password-reset.description")}
</p>
</div>
</div>
<div className="md:px-12 px-6 space-y-6 flex h-full w-full">
<div className="w-full flex flex-col gap-y-4">
<div className="flex flex-col gap-y-2">
<label className="text-white text-sm font-bold">Username</label>
<label className="text-white text-sm font-bold">
{t("login.multi-user.placeholder-username")}
</label>
<input
name="username"
type="text"
placeholder="Username"
placeholder={t("login.multi-user.placeholder-username")}
value={username}
onChange={(e) => setUsername(e.target.value)}
className="bg-zinc-900 text-white placeholder-white/20 text-sm rounded-md p-2.5 w-full h-[48px] md:w-[300px] md:h-[34px]"
@ -59,14 +62,16 @@ const RecoveryForm = ({ onSubmit, setShowRecoveryForm }) => {
</div>
<div className="flex flex-col gap-y-2">
<label className="text-white text-sm font-bold">
Recovery Codes
{t("login.password-reset.recovery-codes")}
</label>
{recoveryCodeInputs.map((code, index) => (
<div key={index}>
<input
type="text"
name={`recoveryCode${index + 1}`}
placeholder={`Recovery Code ${index + 1}`}
placeholder={t("login.password-reset.recovery-code", {
index: index + 1,
})}
value={code}
onChange={(e) =>
handleRecoveryCodeChange(index, e.target.value)
@ -84,14 +89,14 @@ const RecoveryForm = ({ onSubmit, setShowRecoveryForm }) => {
type="submit"
className="md:text-primary-button md:bg-transparent md:w-[300px] text-dark-text text-sm font-bold focus:ring-4 focus:outline-none rounded-md border-[1.5px] border-primary-button md:h-[34px] h-[48px] md:hover:text-white md:hover:bg-primary-button bg-primary-button focus:z-10 w-full"
>
Reset Password
{t("login.password-reset.title")}
</button>
<button
type="button"
className="text-white text-sm flex gap-x-1 hover:text-primary-button hover:underline -mb-8"
onClick={() => setShowRecoveryForm(false)}
>
Back to Login
{t("login.password-reset.back-to-login")}
</button>
</div>
</form>

View File

@ -116,7 +116,7 @@ export default function SettingsSidebar() {
to={paths.settings.privacy()}
className="text-darker hover:text-white text-xs leading-[18px] mx-3"
>
Privacy & Data
{t("settings.privacy")}
</Link>
</div>
</div>
@ -163,7 +163,7 @@ export default function SettingsSidebar() {
to={paths.settings.privacy()}
className="text-darker hover:text-white text-xs leading-[18px] mx-3"
>
Privacy & Data
{t("settings.privacy")}
</Link>
</div>
</div>
@ -179,6 +179,7 @@ export default function SettingsSidebar() {
function SupportEmail() {
const [supportEmail, setSupportEmail] = useState(paths.mailToMintplex());
const { t } = useTranslation();
useEffect(() => {
const fetchSupportEmail = async () => {
@ -197,7 +198,7 @@ function SupportEmail() {
to={supportEmail}
className="text-darker hover:text-white text-xs leading-[18px] mx-3 mt-1"
>
Contact Support
{t("settings.contact")}
</Link>
);
}
@ -234,7 +235,7 @@ const SidebarOptions = ({ user = null, t }) => (
roles: ["admin"],
},
{
btnText: "Voice & Speech",
btnText: t("settings.voice-speech"),
href: paths.settings.audioPreference(),
flex: true,
roles: ["admin"],
@ -338,7 +339,7 @@ const SidebarOptions = ({ user = null, t }) => (
/>
<HoldToReveal key="exp_features">
<Option
btnText="Experimental Features"
btnText={t("settings.experimental-features")}
icon={<Flask className="h-5 w-5 flex-shrink-0" />}
href={paths.settings.experimental()}
user={user}

View File

@ -11,6 +11,7 @@ import Footer from "../Footer";
import SettingsButton from "../SettingsButton";
import { Link } from "react-router-dom";
import paths from "@/utils/paths";
import { useTranslation } from "react-i18next";
export default function Sidebar() {
const { user } = useUser();
@ -21,6 +22,7 @@ export default function Sidebar() {
showModal: showNewWsModal,
hideModal: hideNewWsModal,
} = useNewWorkspaceModal();
const { t } = useTranslation();
return (
<div>
@ -51,7 +53,7 @@ export default function Sidebar() {
>
<Plus size={18} weight="bold" />
<p className="text-sidebar text-sm font-semibold">
New Workspace
{t("new-workspace.title")}
</p>
</button>
)}
@ -81,6 +83,7 @@ export function SidebarMobileHeader() {
hideModal: hideNewWsModal,
} = useNewWorkspaceModal();
const { user } = useUser();
const { t } = useTranslation();
useEffect(() => {
// Darkens the rest of the screen
@ -167,7 +170,7 @@ export function SidebarMobileHeader() {
>
<Plus className="h-5 w-5" />
<p className="text-sidebar text-sm font-semibold">
New Workspace
{t("new-workspace.title")}
</p>
</button>
)}

View File

@ -25,6 +25,7 @@ const TRANSLATIONS = {
transcription: "Transcription",
embedder: "Embedder",
"text-splitting": "Text Splitter & Chunking",
"voice-speech": "Voice & Speech",
"vector-database": "Vector Database",
embeds: "Chat Embed",
"embed-chats": "Chat Embed History",
@ -35,6 +36,8 @@ const TRANSLATIONS = {
"agent-skills": "Agent Skills",
admin: "Admin",
tools: "Tools",
"experimental-features": "Experimental Features",
contact: "Contact Support",
},
// Page Definitions
@ -52,6 +55,41 @@ const TRANSLATIONS = {
start: "Sign in to your",
end: "account.",
},
"password-reset": {
title: "Password Reset",
description:
"Provide the necessary information below to reset your password.",
"recovery-codes": "Recovery Codes",
"recovery-code": "Recovery Code {{index}}",
"back-to-login": "Back to Login",
},
},
welcomeMessage: {
part1:
"Welcome to AnythingLLM, AnythingLLM is an open-source AI tool by Mintplex Labs that turns anything into a trained chatbot you can query and chat with. AnythingLLM is a BYOK (bring-your-own-keys) software so there is no subscription, fee, or charges for this software outside of the services you want to use with it.",
part2:
"AnythingLLM is the easiest way to put powerful AI products like OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB, and other services together in a neat package with no fuss to increase your productivity by 100x.",
part3:
"AnythingLLM can run totally locally on your machine with little overhead you wont even notice it's there! No GPU needed. Cloud and on-premises installation is available as well.\nThe AI tooling ecosystem gets more powerful everyday. AnythingLLM makes it easy to use.",
githubIssue: "Create an issue on Github",
user1: "How do I get started?!",
part4:
"It's simple. All collections are organized into buckets we call \"Workspaces\". Workspaces are buckets of files, documents, images, PDFs, and other files which will be transformed into something LLM's can understand and use in conversation.\n\nYou can add and remove files at anytime.",
createWorkspace: "Create your first workspace",
user2:
"Is this like an AI dropbox or something? What about chatting? It is a chatbot isn't it?",
part5:
"AnythingLLM is more than a smarter Dropbox.\n\nAnythingLLM offers two ways of talking with your data:\n\n<i>Query:</i> Your chats will return data or inferences found with the documents in your workspace it has access to. Adding more documents to the Workspace make it smarter! \n\n<i>Conversational:</i> Your documents + your on-going chat history both contribute to the LLM knowledge at the same time. Great for appending real-time text-based info or corrections and misunderstandings the LLM might have. \n\nYou can toggle between either mode \n<i>in the middle of chatting!</i>",
user3: "Wow, this sounds amazing, let me try it out already!",
part6: "Have Fun!",
starOnGithub: "Star on GitHub",
contact: "Contact Mintplex Labs",
},
"new-workspace": {
title: "New Workspace",
placeholder: "My Workspace",
},
// Workspace Settings menu items

View File

@ -24,6 +24,7 @@ const TRANSLATIONS = {
transcription: "Modelo de transcripción",
embedder: "Preferencias de incrustación",
"text-splitting": "Divisor y fragmentación de texto",
"voice-speech": "Voz y Habla",
"vector-database": "Base de datos de vectores",
embeds: "Widgets de chat incrustados",
"embed-chats": "Historial de chats incrustados",
@ -34,6 +35,8 @@ const TRANSLATIONS = {
"agent-skills": "Habilidades del agente",
admin: "Administrador",
tools: "Herramientas",
"experimental-features": "Funciones Experimentales",
contact: "Contactar Soporte",
},
login: {
@ -50,6 +53,41 @@ const TRANSLATIONS = {
start: "Iniciar sesión en tu",
end: "cuenta.",
},
"password-reset": {
title: "Restablecer la contraseña",
description:
"Proporcione la información necesaria a continuación para restablecer su contraseña.",
"recovery-codes": "Códigos de recuperación",
"recovery-code": "Código de recuperación {{index}}",
"back-to-login": "Volver al inicio de sesión",
},
},
welcomeMessage: {
part1:
"Bienvenido a AnythingLLM, una herramienta de inteligencia artificial de código abierto creada por Mintplex Labs que convierte cualquier cosa en un chatbot entrenado con el que puedes consultar y conversar. AnythingLLM es un software BYOK (bring-your-own-keys), por lo que no hay suscripciones, tarifas ni cargos por este software, salvo por los servicios que deseas utilizar.",
part2:
"AnythingLLM es la forma más sencilla de integrar productos de inteligencia artificial potentes como OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB y otros servicios en un paquete ordenado, sin complicaciones, para aumentar tu productividad en un 100x.",
part3:
"AnythingLLM puede ejecutarse completamente en tu máquina local con poco impacto, ¡ni siquiera notarás que está ahí! No se necesita GPU. También está disponible la instalación en la nube y en instalaciones locales.\nEl ecosistema de herramientas de inteligencia artificial se vuelve más poderoso cada día. AnythingLLM facilita su uso.",
githubIssue: "Crear un problema en Github",
user1: "¿Cómo empiezo?!",
part4:
'Es simple. Todas las colecciones se organizan en contenedores que llamamos "Workspaces". Los Workspaces son contenedores de archivos, documentos, imágenes, PDFs y otros archivos que se transformarán en algo que los LLM puedan entender y usar en una conversación.\n\nPuedes agregar y eliminar archivos en cualquier momento.',
createWorkspace: "Crea tu primer workspace",
user2:
"¿Es esto como un Dropbox de IA o algo así? ¿Qué hay de chatear? ¿Es un chatbot, no?",
part5:
"AnythingLLM es más que un Dropbox más inteligente.\n\nAnythingLLM ofrece dos formas de interactuar con tus datos:\n\n<i>Consulta:</i> Tus chats devolverán datos o inferencias encontradas con los documentos en tu workspace al que tiene acceso. ¡Agregar más documentos al workspace lo hace más inteligente! \n\n<i>Conversacional:</i> Tus documentos y tu historial de chat en curso contribuyen al conocimiento del LLM al mismo tiempo. Ideal para agregar información en tiempo real basada en texto o correcciones y malentendidos que el LLM pueda tener.\n\n¡Puedes alternar entre ambos modos <i>en medio de una conversación!</i>",
user3: "¡Vaya, esto suena increíble, déjame probarlo ya!",
part6: "¡Diviértete!",
starOnGithub: "Estrella en GitHub",
contact: "Contactar a Mintplex Labs",
},
"new-workspace": {
title: "Nuevo Espacio de Trabajo",
placeholder: "Mi Espacio de Trabajo",
},
"workspaces—settings": {

View File

@ -25,6 +25,7 @@ const TRANSLATIONS = {
transcription: "Modèle de transcription",
embedder: "Préférences d'intégration",
"text-splitting": "Diviseur de texte et découpage",
"voice-speech": "Voix et Parole",
"vector-database": "Base de données vectorielle",
embeds: "Widgets de chat intégrés",
"embed-chats": "Historique des chats intégrés",
@ -35,6 +36,8 @@ const TRANSLATIONS = {
"agent-skills": "Compétences de l'agent",
admin: "Admin",
tools: "Outils",
"experimental-features": "Fonctionnalités Expérimentales",
contact: "Contacter le Support",
},
// Page Definitions
@ -52,6 +55,41 @@ const TRANSLATIONS = {
start: "Connectez-vous à votre",
end: "compte.",
},
"password-reset": {
title: "Réinitialisation du mot de passe",
description:
"Fournissez les informations nécessaires ci-dessous pour réinitialiser votre mot de passe.",
"recovery-codes": "Codes de récupération",
"recovery-code": "Code de récupération {{index}}",
"back-to-login": "Retour à la connexion",
},
},
welcomeMessage: {
part1:
"Bienvenue sur AnythingLLM, un outil d'intelligence artificielle open-source créé par Mintplex Labs qui transforme n'importe quoi en un chatbot entraîné avec lequel vous pouvez interroger et discuter. AnythingLLM est un logiciel BYOK (apportez vos propres clés), il n'y a donc pas d'abonnement, de frais ou de charges pour ce logiciel en dehors des services que vous souhaitez utiliser.",
part2:
"AnythingLLM est le moyen le plus simple de regrouper des produits d'intelligence artificielle puissants tels que OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB et d'autres services dans un package soigné, sans tracas, pour augmenter votre productivité de 100x.",
part3:
"AnythingLLM peut fonctionner totalement localement sur votre machine avec peu d'impact, vous ne remarquerez même pas qu'il est là ! Pas besoin de GPU. L'installation en cloud et sur site est également disponible.\nL'écosystème des outils d'IA devient plus puissant chaque jour. AnythingLLM le rend facile à utiliser.",
githubIssue: "Créer un problème sur Github",
user1: "Comment commencer?!",
part4:
'C\'est simple. Toutes les collections sont organisées en compartiments que nous appelons "Workspaces". Les Workspaces sont des compartiments de fichiers, documents, images, PDFs et autres fichiers qui seront transformés en quelque chose que les LLM peuvent comprendre et utiliser dans une conversation.\n\nVous pouvez ajouter et supprimer des fichiers à tout moment.',
createWorkspace: "Créez votre premier workspace",
user2:
"Est-ce comme un Dropbox IA ou quelque chose comme ça ? Et le chat ? C'est bien un chatbot, non ?",
part5:
"AnythingLLM est plus qu'un Dropbox plus intelligent.\n\nAnythingLLM offre deux façons de parler avec vos données:\n\n<i>Interrogation :</i> Vos chats renverront des données ou des inférences trouvées avec les documents dans votre workspace auquel il a accès. Ajouter plus de documents au workspace le rend plus intelligent !\n\n<i>Conversationnel :</i> Vos documents et votre historique de chat en cours contribuent tous deux aux connaissances du LLM en même temps. Idéal pour ajouter des informations en temps réel basées sur du texte ou des corrections et des malentendus que le LLM pourrait avoir.\n\nVous pouvez basculer entre les deux modes <i>en plein milieu d'une conversation !</i>",
user3: "Wow, cela semble incroyable, laissez-moi l'essayer tout de suite !",
part6: "Amusez-vous bien !",
starOnGithub: "Étoile sur GitHub",
contact: "Contacter Mintplex Labs",
},
"new-workspace": {
title: "Nouveau Espace de Travail",
placeholder: "Mon Espace de Travail",
},
// Workspace Settings menu items

View File

@ -0,0 +1,483 @@
const TRANSLATIONS = {
common: {
"workspaces-name": "워크스페이스 이름",
error: "오류",
success: "성공",
user: "사용자",
selection: "모델 선택",
saving: "저장 중...",
save: "저장",
previous: "이전",
next: "다음",
},
// Setting Sidebar menu items.
settings: {
title: "인스턴스 설정",
system: "일반 설정",
invites: "초대",
users: "사용자",
workspaces: "워크스페이스",
"workspace-chats": "워크스페이스 채팅",
customization: "사용자 정의",
"api-keys": "개발자 API",
llm: "LLM",
transcription: "텍스트 변환",
embedder: "임베더",
"text-splitting": "텍스트 분할과 청킹",
"voice-speech": "음성과 말하기",
"vector-database": "벡터 데이터베이스",
embeds: "채팅 임베드",
"embed-chats": "채팅 임베드 기록",
security: "보안",
"event-logs": "이벤트 로그",
privacy: "사생활 보호와 데이터",
"ai-providers": "AI 제공자",
"agent-skills": "에이전트 스킬",
admin: "관리자",
tools: "도구",
"experimental-features": "실험적 기능",
contact: "지원팀 연락",
},
// Page Definitions
login: {
"multi-user": {
welcome: "웰컴!",
"placeholder-username": "사용자 이름",
"placeholder-password": "비밀번호",
login: "로그인",
validating: "유효성 검사 중...",
"forgot-pass": "비밀번호를 잊으셨나요",
reset: "재설정",
},
"sign-in": {
start: "사용자 계정으로 ",
end: "에 로그인하세요.",
},
"password-reset": {
title: "비밀번호 재설정",
description: "비밀번호를 재설정하려면 아래에 필요한 정보를 입력하세요.",
"recovery-codes": "복구 코드",
"recovery-code": "복구 코드 {{index}}",
"back-to-login": "로그인으로 돌아가기",
},
},
"new-workspace": {
title: "새 워크스페이스",
placeholder: "내 워크스페이스",
},
// Workspace Settings menu items
"workspaces—settings": {
general: "일반 설정",
chat: "채팅 설정",
vector: "벡터 데이터베이스",
members: "구성원",
agent: "에이전트 구성",
},
welcomeMessage: {
part1:
"AnythingLLM에 오신 것을 환영합니다. AnythingLLM은 Mintplex Labs에서 개발한 오픈 소스 AI 도구로, 어떤 것이든 훈련된 챗봇으로 변환하여 쿼리하고 대화할 수 있습니다. AnythingLLM은 BYOK(Bring Your Own Key) 소프트웨어이므로 사용하려는 서비스 외에는 구독료나 기타 비용이 없습니다.",
part2:
"AnythingLLM은 OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB 등 강력한 AI 제품을 번거로움 없이 깔끔하게 패키지로 묶어 생산성을 100배 향상시키는 가장 쉬운 방법입니다.",
part3:
"AnythingLLM은 로컬 컴퓨터에서 완전히 작동하며, 거의 리소스를 사용하지 않으므로 존재조차 느끼지 못할 것입니다! GPU가 필요하지 않습니다. 클라우드 및 온프레미스 설치도 가능합니다.\nAI 도구 생태계는 날로 강력해지고 있습니다. AnythingLLM은 이를 쉽게 사용할 수 있게 해줍니다.",
githubIssue: "Github에 이슈 생성하기",
user1: "어떻게 시작하나요?!",
part4:
'간단합니다. 모든 컬렉션은 "워크스페이스"라고 부르는 버킷으로 구성됩니다. 워크스페이스는 문서, 이미지, PDF 및 기타 파일의 버킷으로, LLM이 이해하고 대화에서 사용할 수 있는 형태로 변환합니다.\n\n언제든지 파일을 추가하고 삭제할 수 있습니다.',
createWorkspace: "첫 번째 워크스페이스 생성하기",
user2:
"이것은 AI 드롭박스와 같은 건가요? 채팅은 어떤가요? 이건 챗봇 아닌가요?",
part5:
"AnythingLLM은 더 스마트한 Dropbox 이상의 것입니다.\n\nAnythingLLM은 데이터와 대화할 수 있는 두 가지 방법을 제공합니다:\n\n<i>쿼리:</i> 워크스페이스 내 문서에서 찾아낸 데이터나 추론 결과만 채팅으로 제공합니다. 워크스페이스에 문서를 더 많이 추가할수록 더 똑똑해집니다!\n\n<i>대화:</i> 문서와 실시간 채팅 기록이 동시에 LLM의 지식에 기여합니다. 실시간 텍스트 정보나 LLM의 오해를 바로잡는 데 매우 유용합니다.\n\n채팅 중간에 <i>모드를 전환할 수 있습니다!</i>",
user3: "와, 이거 정말 놀랍네요, 당장 사용해보고 싶어요!",
part6: "즐기세요!",
starOnGithub: "GitHub에 별표 달기",
contact: "Mintplex Labs에 연락하기",
},
// General Appearance
general: {
vector: {
title: "벡터 수",
description: "벡터 데이터베이스에 있는 총 벡터 수입니다.",
},
names: {
description: "이것은 워크스페이스의 표시 이름만 변경합니다.",
},
message: {
title: "제안된 채팅 메시지",
description: "워크스페이스 사용자가 사용할 메시지를 수정합니다.",
add: "새 메시지 추가",
save: "메시지 저장",
heading: "저에게 설명해주세요",
body: "AnythingLLM의 장점",
},
pfp: {
title: "어시스턴트 프로필 이미지",
description: "이 워크스페이스의 어시스턴트 프로필 이미지를 수정합니다.",
image: "워크스페이스 이미지",
remove: "워크스페이스 이미지 제거",
},
delete: {
title: "워크스페이스 삭제",
description:
"이 워크스페이스와 모든 데이터를 삭제합니다. 이 작업은 모든 사용자에 대해 워크스페이스를 삭제합니다.",
delete: "워크스페이스 삭제",
deleting: "워크스페이스 삭제 중...",
"confirm-start": "이 작업은",
"confirm-end":
"워크스페이스 전체를 삭제합니다. 이 작업은 벡터 데이터베이스에 있는 모든 벡터 임베딩을 제거합니다.\n\n원본 소스 파일은 그대로 유지됩니다. 이 작업은 되돌릴 수 없습니다.",
},
},
// Chat Settings
chat: {
llm: {
title: "워크스페이스 LLM 제공자",
description:
"이 워크스페이스에서 사용할 특정 LLM 제공자와 모델입니다. 기본적으로 시스템 LLM 제공자와 설정을 사용합니다.",
search: "모든 LLM 제공자 검색",
},
model: {
title: "워크스페이스 채팅 모델",
description:
"이 워크스페이스에서 사용할 특정 채팅 모델입니다. 비어 있으면 시스템 LLM 기본 설정을 사용합니다.",
wait: "-- 모델 기다리는 중 --",
},
mode: {
title: "채팅 모드",
chat: {
title: "채팅",
"desc-start": "문서 내용을 찾습니다.",
and: "그리고",
"desc-end": "LLM의 일반 지식을 같이 사용하여 답변을 제공합니다",
},
query: {
title: "쿼리",
"desc-start": "문서 컨텍스트를 찾을 ",
only: "때만",
"desc-end": "답변을 제공합니다.",
},
},
history: {
title: "채팅 기록",
"desc-start": "응답의 단기 메모리에 포함될 이전 채팅의 수입니다.",
recommend: "추천 20개 ",
"desc-end":
" 45개 이상은 메시지 크기에 따라 채팅 실패가 발생할 수 있습니다.",
},
prompt: {
title: "프롬프트",
description:
"이 워크스페이스에서 사용할 프롬프트입니다. AI가 응답을 생성하기 위해 문맥과 지침을 정의합니다. AI가 질문에 대하여 정확한 응답을 생성할 수 있도록 신중하게 프롬프트를 제공해야 합니다.",
},
refusal: {
title: "쿼리 모드 거부 응답 메시지",
"desc-start": "쿼리 모드에서",
query: "응답에 사용할 수 있는",
"desc-end": "컨텍스트를 찾을 수 없을 때 거부 응답 내용을 작성합니다.",
},
temperature: {
title: "LLM 온도",
"desc-start": '이 설정은 LLM 응답이 얼마나 "창의적"일지를 제어합니다.',
"desc-end":
"숫자가 높을수록 창의적입니다. 일부 모델에서는 너무 높게 설정하면 일관성 없는 응답이 나올 수 있습니다.",
hint: "대부분의 LLM은 유효한 값의 다양한 허용 범위를 가지고 있습니다. 해당 정보는 LLM 제공자에게 문의하세요.",
},
},
// Vector Database
"vector-workspace": {
identifier: "벡터 데이터베이스 식별자",
snippets: {
title: "최대 문맥 조각",
description:
"이 설정은 채팅 또는 쿼리당 LLM에 전송될 최대 문맥 조각 수를 제어합니다.",
recommend: "추천: 4",
},
doc: {
title: "문서 유사성 임계값",
description:
"채팅과 관련이 있다고 판단되는 문서의 유사성 점수입니다. 숫자가 높을수록 질문에 대한 문서의 내용이 유사합니다.",
zero: "제한 없음",
low: "낮음 (유사성 점수 ≥ .25)",
medium: "중간 (유사성 점수 ≥ .50)",
high: "높음 (유사성 점수 ≥ .75)",
},
reset: {
reset: "벡터 데이터베이스 재설정",
resetting: "벡터 지우는 중...",
confirm:
"이 워크스페이스의 벡터 데이터베이스를 재설정하려고 합니다. 현재 임베딩된 모든 벡터 임베딩을 제거합니다.\n\n원본 소스 파일은 그대로 유지됩니다. 이 작업은 되돌릴 수 없습니다.",
error: "워크스페이스 벡터 데이터베이스를 재설정할 수 없습니다!",
success: "워크스페이스 벡터 데이터베이스가 재설정되었습니다!",
},
},
// Agent Configuration
agent: {
"performance-warning":
"도구 호출을 명시적으로 지원하지 않는 LLM의 성능은 모델의 기능과 정확도에 크게 좌우됩니다. 일부 기능은 제한되거나 작동하지 않을 수 있습니다.",
provider: {
title: "워크스페이스 에이전트 LLM 제공자",
description:
"이 워크스페이스의 @agent 에이전트에 사용할 특정 LLM 제공자 및 모델입니다.",
},
mode: {
chat: {
title: "워크스페이스 에이전트 채팅 모델",
description:
"이 워크스페이스의 @agent 에이전트에 사용할 특정 채팅 모델입니다.",
},
title: "워크스페이스 에이전트 모델",
description:
"이 워크스페이스의 @agent 에이전트에 사용할 특정 LLM 모델입니다.",
wait: "-- 모델 기다리는 중 --",
},
skill: {
title: "기본 에이전트 스킬",
description:
"기본 에이전트의 능력을 사전 정의된 스킬을 사용하여 향상시킵니다. 이 설정은 모든 워크스페이스에 적용됩니다.",
rag: {
title: "RAG와 장기 메모리",
description:
'에이전트가 제공된 문서를 활용하여 쿼리에 답변하거나 에이전트에게 "기억"할 내용을 요청하여 장기 메모리 검색을 허용합니다.',
},
view: {
title: "문서 보기 및 요약",
description:
"에이전트가 현재 임베딩된 워크스페이스의 문서 내용을 나열하고 요약할 수 있도록 합니다.",
},
scrape: {
title: "웹사이트 스크래핑",
description:
"에이전트가 웹사이트를 방문하고 내용을 스크래핑할 수 있도록 합니다.",
},
generate: {
title: "차트 생성",
description:
"기본 에이전트가 채팅에서 제공된 데이터를 이용하여 다양한 유형의 차트를 생성할 수 있도록 합니다.",
},
save: {
title: "브라우저에서 파일 생성과 저장",
description:
"기본 에이전트가 브라우저에서 파일을 생성하고 다운로드할 수 있도록 합니다.",
},
web: {
title: "실시간 웹 검색 및 탐색",
"desc-start":
"에이전트가 웹을 검색하여 질문에 답변할 수 있도록 허용합니다.",
"desc-end":
"에이전트 세션 중 웹 검색은 설정되지 않으면 작동하지 않습니다.",
},
},
},
// Workspace Chats
recorded: {
title: "워크스페이스 채팅",
description:
"이것들은 사용자들이 보낸 모든 채팅과 메시지입니다. 생성 날짜별로 정렬되어 있습니다.",
export: "내보내기",
table: {
id: "ID",
by: "보낸 사람",
workspace: "워크스페이스",
prompt: "프롬프트",
response: "응답",
at: "보낸 시각",
},
},
// Appearance
appearance: {
title: "외관",
description: "플랫폼의 외관 설정을 수정합니다.",
logo: {
title: "사용자 로고",
description:
"사용자의 로고를 업로드하여 챗봇을 자신의 것으로 만드십시오.",
add: "사용자 로고 추가",
recommended: "추천 크기: 800 x 200",
remove: "제거",
replace: "교체",
},
message: {
title: "사용자 메시지",
description: "사용자에게 표시되는 자동 메시지를 작성합니다.",
new: "새로운",
system: "시스템",
user: "사용자",
message: "메시지",
assistant: "AnythingLLM 채팅 어시스턴트",
"double-click": "더블 클릭하여 편집...",
save: "메시지 저장",
},
icons: {
title: "맞춤형 바닥글 아이콘",
description: "사이드바 하단에 표시되는 아이콘을 수정합니다.",
icon: "아이콘",
link: "링크",
},
},
// API Keys
api: {
title: "API 키",
description:
"API 키는 소유자가 프로그래밍 방식으로 이 AnythingLLM 인스턴스에 액세스하고 관리할 수 있도록 합니다.",
link: "API 문서 읽기",
generate: "새 API 키 생성",
table: {
key: "API 키",
by: "생성한 사람",
created: "생성일",
},
},
llm: {
title: "LLM 기본 설정",
description:
"이것은 채팅과 임베딩을 하기 위한 선호하는 LLM 제공자의 인증입니다. 이 키가 현재 활성 상태이고 정확해야 AnythingLLM이 제대로 작동합니다.",
provider: "LLM 제공자",
},
transcription: {
title: "텍스트 변환 모델 기본 설정",
description:
"이것은 선호하는 텍스트 변환 모델 제공자의 인증입니다. 이 키가 현재 활성 상태이고 정확해야 미디어 파일 및 오디오가 텍스트 변환됩니다.",
provider: "텍스트 변환 제공자",
"warn-start":
"RAM 또는 CPU 성능이 제한된 머신에서 로컬 위스퍼 모델을 사용하면 미디어 파일을 처리할 때 AnythingLLM이 중단될 수 있습니다.",
"warn-recommend": "최소 2GB RAM과 10Mb 보다 작은 파일 업로드를 권장합니다.",
"warn-end": "내장된 모델은 첫 번째 사용 시 자동으로 다운로드됩니다.",
},
embedding: {
title: "임베딩 기본 설정",
"desc-start":
"임베딩 엔진을 지원하지 않는 LLM을 사용할 때 텍스트를 임베딩하는 데 다른 임베딩 엔진 제공자의 인증이 필요할 수 있습니다.",
"desc-end":
"임베딩은 텍스트를 벡터로 변환하는 과정입니다. 파일과 프롬프트를 AnythingLLM이 처리할 수 있는 형식으로 변환하려면 이러한 인증이 필요합니다.",
provider: {
title: "임베딩 제공자",
description:
"AnythingLLM의 기본 임베딩 엔진을 사용할 때는 설정이 필요하지 않습니다.",
},
},
text: {
title: "텍스트 분할 및 청킹 기본 설정",
"desc-start":
"새 문서를 벡터 데이터베이스에 삽입하기 전에 기본 텍스트 분할 방식을 변경할 수 있습니다.",
"desc-end":
"텍스트 분할 방식과 그 영향을 이해하고 있는 경우에만 이 설정을 변경해야 합니다.",
"warn-start": "여기의 변경 사항은",
"warn-center": "새로 임베딩되는 문서",
"warn-end": "에만 적용됩니다. 기존 문서에는 적용되지 않습니다.",
size: {
title: "텍스트 청크 크기",
description: "단일 벡터에 들어갈 수 있는 최대 문자 길이입니다.",
recommend: "임베드 모델 최대 길이는",
},
overlap: {
title: "텍스트 청크 겹침",
description:
"청킹 동안 두 인접 텍스트 청크 간에 겹칠 수 있는 최대 문자 수입니다.",
},
},
// Vector Database
vector: {
title: "벡터 데이터베이스",
description:
"이것은 AnythingLLM 인스턴스가 벡터 데이터베이스 사용을 위한 인증 설정입니다. 이 키가 활성 상태이고 정확해야 합니다.",
provider: {
title: "벡터 데이터베이스 제공자",
description: "LanceDB를 선택하면 설정이 필요 없습니다.",
},
},
// Embeddable Chat Widgets
embeddable: {
title: "임베드 가능한 채팅 위젯",
description:
"임베드 가능한 채팅 위젯은 하나의 워크스페이스에 연결된 공개용 채팅방입니다. 이를 통해 워크스페이스 설정이 적용된 채팅방을 일반인들에게 공개할 수 있습니다.",
create: "임베드 생성",
table: {
workspace: "워크스페이스",
chats: "보낸 채팅",
Active: "활성 도메인",
},
},
"embed-chats": {
title: "임베드 채팅",
description: "게시한 임베드에서의 모든 채팅과 메시지의 기록입니다.",
table: {
embed: "임베드",
sender: "보낸 사람",
message: "메시지",
response: "응답",
at: "보낸 시각",
},
},
multi: {
title: "다중 사용자 모드",
description:
"다중 사용자 모드를 활성화하여 인스턴스가 팀 사용을 지원하도록 설정합니다.",
enable: {
"is-enable": "다중 사용자 모드가 활성화되었습니다",
enable: "다중 사용자 모드 활성화",
description:
"당신은 기본 관리자가 됩니다. 관리자로서 모든 신규 사용자 또는 관리자의 계정을 생성해야 합니다. 비밀번호를 잃어버리면 관리자만 비밀번호를 재설정할 수 있습니다.",
username: "관리자 계정 사용자 이름",
password: "관리자 계정 비밀번호",
},
password: {
title: "비밀번호 보호",
description:
"AnythingLLM 인스턴스를 비밀번호로 보호하십시오. 이 비밀번호를 잊어버리면 복구 방법이 없으므로 반드시 저장하세요.",
},
instance: {
title: "인스턴스 비밀번호 보호",
description:
"당신은 기본 관리자가 됩니다. 관리자로서 모든 신규 사용자 또는 관리자의 계정을 생성해야 합니다. 비밀번호를 잃어버리면 관리자만 비밀번호를 재설정할 수 있습니다.",
password: "인스턴스 비밀번호",
},
},
// Event Logs
event: {
title: "이벤트 로그",
description:
"모니터링을 위해 이 인스턴스에서 발생하는 모든 작업과 이벤트를 확인합니다.",
clear: "이벤트 로그 지우기",
table: {
type: "이벤트 유형",
user: "사용자",
occurred: "발생 시각",
},
},
// Privacy & Data-Handling
privacy: {
title: "개인정보와 데이터 처리",
description:
"연결된 타사 제공자와 AnythingLLM이 데이터를 처리하는 방식을 구성합니다.",
llm: "LLM 선택",
embedding: "임베딩 기본 설정",
vector: "벡터 데이터베이스",
anonymous: "익명 원격 분석 활성화",
},
};
export default TRANSLATIONS;

View File

@ -15,6 +15,7 @@
// from the primary dictionary.
import English from "./en/common.js";
import Korean from "./ko/common.js";
import Spanish from "./es/common.js";
import French from "./fr/common.js";
import Mandarin from "./zh/common.js";
@ -25,6 +26,9 @@ export const resources = {
en: {
common: English,
},
ko: {
common: Korean,
},
zh: {
common: Mandarin,
},

View File

@ -10,6 +10,7 @@ const TRANSLATIONS = {
previous: "Предыдущая страница",
next: "Следующая страница",
},
settings: {
title: "Настройки экземпляра",
system: "Системные настройки",
@ -23,6 +24,7 @@ const TRANSLATIONS = {
transcription: "Модель транскрипции",
embedder: "Настройки встраивания",
"text-splitting": "Разделение и сегментация текста",
"voice-speech": "Голос и Речь",
"vector-database": "Векторная база данных",
embeds: "Виджеты встраивания чата",
"embed-chats": "История встраивания чатов",
@ -33,7 +35,10 @@ const TRANSLATIONS = {
"agent-skills": "Навыки агента",
admin: "Администратор",
tools: "Инструменты",
"experimental-features": "Экспериментальные функции",
contact: "联系支持Связаться с Поддержкой",
},
login: {
"multi-user": {
welcome: "Добро пожаловать в",
@ -48,7 +53,43 @@ const TRANSLATIONS = {
start: "Войти в ваш",
end: "аккаунт.",
},
"password-reset": {
title: "Сброс пароля",
description:
"Предоставьте необходимую информацию ниже, чтобы сбросить ваш пароль.",
"recovery-codes": "Коды восстановления",
"recovery-code": "Код восстановления {{index}}",
"back-to-login": "Вернуться к входу",
},
},
welcomeMessage: {
part1:
"Добро пожаловать в AnythingLLM, открытый инструмент искусственного интеллекта от Mintplex Labs, который превращает что угодно в обученный чат-бот, с которым вы можете общаться и задавать вопросы. AnythingLLM - это ПО BYOK (принеси свои собственные ключи), поэтому за использование этого ПО нет подписки, платы или других сборов, кроме тех, что вы хотите использовать.",
part2:
"AnythingLLM - это самый простой способ объединить мощные продукты ИИ, такие как OpenAi, GPT-4, LangChain, PineconeDB, ChromaDB и другие сервисы, в аккуратный пакет без лишних хлопот, чтобы повысить вашу продуктивность в 100 раз.",
part3:
"AnythingLLM может работать полностью локально на вашем компьютере с минимальной нагрузкой, вы даже не заметите его присутствия! GPU не требуется. Также доступна установка в облаке и на локальных серверах.\nЭкосистема инструментов ИИ становится мощнее с каждым днем. AnythingLLM упрощает их использование.",
githubIssue: "Создать задачу на Github",
user1: "Как начать?!",
part4:
'Это просто. Все коллекции организованы в корзины, которые мы называем "Workspaces". Workspaces - это корзины файлов, документов, изображений, PDF и других файлов, которые будут преобразованы в нечто, что LLM сможет понять и использовать в беседе.\n\nВы можете добавлять и удалять файлы в любое время.',
createWorkspace: "Создайте свою первую workspace",
user2:
"Это что-то вроде ИИ-дропбокса? А как насчет чата? Это ведь чат-бот, верно?",
part5:
"AnythingLLM - это больше, чем просто умный Dropbox.\n\nAnythingLLM предлагает два способа общения с вашими данными:\n\n<i>Запрос:</i> Ваши чаты будут возвращать данные или выводы, найденные в документах в вашем workspace, к которому у него есть доступ. Добавление большего количества документов в workspace делает его умнее!\n\n<i>Беседа:</i> Ваши документы и история чатов вместе способствуют знаниям LLM одновременно. Отлично подходит для добавления информации в реальном времени на основе текста или исправления и недоразумений, которые может иметь LLM.\n\nВы можете переключаться между режимами <i>прямо во время чата!</i>",
user3: "Вау, это звучит потрясающе, дайте попробовать прямо сейчас!",
part6: "Веселитесь!",
starOnGithub: "Звезда на GitHub",
contact: "Связаться с Mintplex Labs",
},
"new-workspace": {
title: "Новая Рабочая Область",
placeholder: "Моя Рабочая Область",
},
"workspaces—settings": {
general: "Общие настройки",
chat: "Настройки чата",

View File

@ -26,6 +26,7 @@ const TRANSLATIONS = {
transcription: "Transcription 模型",
embedder: "Embedder 首选项",
"text-splitting": "文本分割",
"voice-speech": "语音和讲话",
"vector-database": "向量数据库",
embeds: "嵌入式对话",
"embed-chats": "嵌入式对话历史",
@ -36,6 +37,8 @@ const TRANSLATIONS = {
"agent-skills": "代理技能",
admin: "管理员",
tools: "工具",
"experimental-features": "实验功能",
contact: "联系支持",
},
// Page Definitions
@ -53,6 +56,39 @@ const TRANSLATIONS = {
start: "登录你的",
end: "账户",
},
"password-reset": {
title: "重置密码",
description: "请提供以下必要信息以重置您的密码。",
"recovery-codes": "恢复代码",
"recovery-code": "恢复代码 {{index}}",
"back-to-login": "返回登录",
},
},
welcomeMessage: {
part1:
"欢迎使用 AnythingLLM这是由 Mintplex Labs 开发的开源 AI 工具可以将任何东西转换为您可以查询和聊天的训练有素的聊天机器人。AnythingLLM 是一款 BYOK自带密钥软件因此除了您想使用的服务外此软件不收取订阅费、费用或其他费用。",
part2:
"AnythingLLM 是将强大的 AI 产品(如 OpenAi、GPT-4、LangChain、PineconeDB、ChromaDB 等)整合在一个整洁的包中而无需繁琐操作的最简单方法,可以将您的生产力提高 100 倍。",
part3:
"AnythingLLM 可以完全在您的本地计算机上运行,几乎没有开销,您甚至不会注意到它的存在!无需 GPU。也可以进行云端和本地安装。\nAI 工具生态系统每天都在变得更强大。AnythingLLM 使其易于使用。",
githubIssue: "在 Github 上创建问题",
user1: "我该如何开始?!",
part4:
"很简单。所有集合都组织成我们称之为“工作区”的桶。工作区是文件、文档、图像、PDF 和其他文件的存储桶,这些文件将被转换为 LLM 可以理解和在对话中使用的内容。\n\n您可以随时添加和删除文件。",
createWorkspace: "创建您的第一个工作区",
user2: "这像是一个 AI Dropbox 吗?那么聊天呢?它是一个聊天机器人,不是吗?",
part5:
"AnythingLLM 不仅仅是一个更智能的 Dropbox。\n\nAnythingLLM 提供了两种与您的数据交流的方式:\n\n<i>查询:</i> 您的聊天将返回在您的工作区中访问的文档中找到的数据或推论。向工作区添加更多文档会使其更智能!\n\n<i>对话:</i> 您的文档和正在进行的聊天记录同时为 LLM 知识做出贡献。非常适合添加基于文本的实时信息或纠正 LLM 可能存在的误解。\n\n您可以在聊天过程中 <i>切换模式!</i>",
user3: "哇,这听起来很棒,让我马上试试!",
part6: "玩得开心!",
starOnGithub: "在 GitHub 上加星",
contact: "联系 Mintplex Labs",
},
"new-workspace": {
title: "新工作区",
placeholder: "我的工作区",
},
// Workspace Settings menu items

View File

@ -23,6 +23,13 @@ export const LMSTUDIO_COMMON_URLS = [
"http://172.17.0.1:1234/v1",
];
export const KOBOLDCPP_COMMON_URLS = [
"http://127.0.0.1:5000/v1",
"http://localhost:5000/v1",
"http://host.docker.internal:5000/v1",
"http://172.17.0.1:5000/v1",
];
export function fullApiUrl() {
if (API_BASE !== "/api") return API_BASE;
return `${window.location.origin}/api`;

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,15 @@ const User = {
throw new Error(e.message);
}
},
role: (role = "default") => {
const VALID_ROLES = ["default", "admin", "manager"];
if (!VALID_ROLES.includes(role)) {
throw new Error(
`Invalid role. Allowed roles are: ${VALID_ROLES.join(", ")}`
);
}
return String(role);
},
},
// validations for the above writable fields.
@ -52,7 +61,7 @@ const User = {
data: {
username: this.validations.username(username),
password: hashedPassword,
role: String(role),
role: this.validations.role(role),
},
});
return { user: this.filterFields(user), error: null };

View File

@ -1,5 +1,5 @@
const prisma = require("../utils/prisma");
const slugify = require("slugify");
const slugifyModule = require("slugify");
const { Document } = require("./documents");
const { WorkspaceUser } = require("./workspaceUsers");
const { ROLES } = require("../utils/middleware/multiUserProtected");
@ -28,16 +28,27 @@ const Workspace = {
"agentModel",
"queryRefusalResponse",
],
/**
* The default Slugify module requires some additional mapping to prevent downstream issues
* with some vector db providers and instead of building a normalization method for every provider
* we can capture this on the table level to not have to worry about it.
* @param {...any} args - slugify args for npm package.
* @returns {string}
*/
slugify: function (...args) {
slugifyModule.extend({ "+": " plus ", "!": " bang " });
return slugifyModule(...args);
},
new: async function (name = null, creatorId = null) {
if (!name) return { result: null, message: "name cannot be null" };
var slug = slugify(name, { lower: true });
var slug = this.slugify(name, { lower: true });
slug = slug || uuidv4();
const existingBySlug = await this.get({ slug });
if (existingBySlug !== null) {
const slugSeed = Math.floor(10000000 + Math.random() * 90000000);
slug = slugify(`${name}-${slugSeed}`, { lower: true });
slug = this.slugify(`${name}-${slugSeed}`, { lower: true });
}
try {

View File

@ -63,7 +63,7 @@
"moment": "^2.29.4",
"mssql": "^10.0.2",
"multer": "^1.4.5-lts.1",
"mysql2": "^3.9.7",
"mysql2": "^3.9.8",
"node-html-markdown": "^1.3.0",
"node-llama-cpp": "^2.8.0",
"ollama": "^0.5.0",
@ -101,4 +101,4 @@
"nodemon": "^2.0.22",
"prettier": "^3.0.3"
}
}
}

View File

@ -3,6 +3,7 @@
const { Workspace } = require("../../../models/workspace");
const { WorkspaceChats } = require("../../../models/workspaceChats");
const { safeJsonParse } = require("../../http");
async function convertToCSV(preparedData) {
const rows = ["id,username,workspace,prompt,response,sent_at,rating"];
@ -66,12 +67,24 @@ async function prepareWorkspaceChatsForExport(format = "jsonl") {
return preparedData;
}
const workspaceIds = [...new Set(chats.map((chat) => chat.workspaceId))];
const workspacesWithPrompts = await Promise.all(
workspaceIds.map((id) => Workspace.get({ id: Number(id) }))
);
const workspacePromptsMap = workspacesWithPrompts.reduce((acc, workspace) => {
acc[workspace.id] = workspace.openAiPrompt;
return acc;
}, {});
if (format === "jsonAlpaca") {
const preparedData = chats.map((chat) => {
const responseJson = JSON.parse(chat.response);
return {
instruction: chat.prompt,
input: "",
instruction: buildSystemPrompt(
chat,
workspacePromptsMap[chat.workspaceId]
),
input: chat.prompt,
output: responseJson.text,
};
});
@ -79,17 +92,6 @@ async function prepareWorkspaceChatsForExport(format = "jsonl") {
return preparedData;
}
const workspaceIds = [...new Set(chats.map((chat) => chat.workspaceId))];
const workspacesWithPrompts = await Promise.all(
workspaceIds.map((id) => Workspace.get({ id: Number(id) }))
);
const workspacePromptsMap = workspacesWithPrompts.reduce((acc, workspace) => {
acc[workspace.id] = workspace.openAiPrompt;
return acc;
}, {});
const workspaceChatsMap = chats.reduce((acc, chat) => {
const { prompt, response, workspaceId } = chat;
const responseJson = JSON.parse(response);
@ -157,6 +159,23 @@ async function exportChatsAsType(workspaceChatsMap, format = "jsonl") {
};
}
const STANDARD_PROMPT =
"Given the following conversation, relevant context, and a follow up question, reply with an answer to the current question the user is asking. Return only your response to the question given the above information following the users instructions as needed.";
function buildSystemPrompt(chat, prompt = null) {
const sources = safeJsonParse(chat.response)?.sources || [];
const contextTexts = sources.map((source) => source.text);
const context =
sources.length > 0
? "\nContext:\n" +
contextTexts
.map((text, i) => {
return `[CONTEXT ${i}]:\n${text}\n[END CONTEXT ${i}]\n\n`;
})
.join("")
: "";
return `${prompt ?? STANDARD_PROMPT}${context}`;
}
module.exports = {
prepareWorkspaceChatsForExport,
exportChatsAsType,

View File

@ -1598,6 +1598,11 @@ available-typed-arrays@^1.0.7:
dependencies:
possible-typed-array-names "^1.0.0"
aws-ssl-profiles@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz#21ef8ad77d753927f6c01b144c5ef4cc4f150cdc"
integrity sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==
axios@^1.4.0, axios@^1.6.2, axios@^1.6.5:
version "1.6.8"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
@ -4749,11 +4754,12 @@ mute-stream@^1.0.0:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
mysql2@^3.9.7:
version "3.9.7"
resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.9.7.tgz#843755daf65b5ef08afe545fe14b8fb62824741a"
integrity sha512-KnJT8vYRcNAZv73uf9zpXqNbvBG7DJrs+1nACsjZP1HMJ1TgXEy8wnNilXAn/5i57JizXKtrUtwDB7HxT9DDpw==
mysql2@^3.9.8:
version "3.10.3"
resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.10.3.tgz#82646a2b9018370769ae1bb590e015af190e070d"
integrity sha512-k43gmH9i79rZD4hGPdj7pDuT0UBiFjs4UzXEy1cJrV0QqcSABomoLwvejqdbcXN+Vd7gi999CVM6o9vCPKq29g==
dependencies:
aws-ssl-profiles "^1.1.1"
denque "^2.1.0"
generate-function "^2.3.1"
iconv-lite "^0.6.3"