Compare commits

..

11 Commits

Author SHA1 Message Date
bhattaraijay05
458d810b2b v1.1.4 2023-05-06 23:38:30 +05:30
bhattaraijay05
3a7c45e3a9 added local model support 2023-05-05 19:10:13 +05:30
bhattaraijay05
5702725005 added local model runner 2023-05-05 18:57:44 +05:30
bhattaraijay05
b5df983bb6 v1.1.3 2023-05-05 13:06:37 +05:30
bhattaraijay05
679642e866 changed models path 2023-05-05 13:05:12 +05:30
bhattaraijay05
7f5d34afea Merge branch 'multiple-models' 2023-05-05 12:52:34 +05:30
bhattaraijay05
a70b604f50 added multiple models support 2023-05-05 12:21:06 +05:30
bhattaraijay05
a71633a525 ui updates 2023-04-25 18:41:08 +05:30
bhattaraijay05
64f592298b ui updates 2023-04-25 18:38:33 +05:30
bhattaraijay05
e5eb7a9f5e multiple model support added 2023-04-23 12:42:11 +05:30
bhattaraijay05
ee7ed285d1 multiple model support added 2023-04-23 12:42:07 +05:30
29 changed files with 1979 additions and 507 deletions

View File

@ -7,33 +7,55 @@ on:
jobs:
build-macArm:
name: Build (macos-latest)
name: Build Arm Mac
if: startsWith(github.ref, 'refs/tags/')
runs-on: macos-latest
runs-on: self-hosted
strategy:
matrix:
os: [macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Checkout code with submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Use node 18.x
uses: actions/setup-node@v1
with:
node-version: "18.x"
- name: Yarn install
run: yarn install
- name: Add MacOS certs
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
run: chmod +x add-osx-cert.sh && ./add-osx-cert.sh
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
# - name: Add MacOS certs
# if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
# run: chmod +x add-osx-cert.sh && ./add-osx-cert.sh
# env:
# CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
# CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
- name: Build
id: make_build
run: |
cd llama.cpp && make && cd ..
- name: Make directory
id: make_directory
run: |
mkdir -p models/llama
- name: Copy mac
id: copy_mac
run: |
cp llama.cpp/main models/llama
- name: Make
if: startsWith(github.ref, 'refs/tags/')
run: yarn make-macArm
run: yarn make
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
@ -45,33 +67,55 @@ jobs:
**/*.zip
build-macIntel:
name: Build (macos-latest)
name: Build Intel Mac
if: startsWith(github.ref, 'refs/tags/')
runs-on: macos-latest
strategy:
matrix:
os: [macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Checkout code with submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Use node 18.x
uses: actions/setup-node@v1
with:
node-version: "18.x"
- name: Yarn install
run: yarn install
- name: Add MacOS certs
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
run: chmod +x add-osx-cert.sh && ./add-osx-cert.sh
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
- name: Build
id: make_build
run: |
cd llama.cpp && make && cd ..
- name: Make directory
id: make_directory
run: |
mkdir -p models/llama
- name: Copy mac
id: copy_mac
run: |
cp llama.cpp/main models/llama
- name: Make
if: startsWith(github.ref, 'refs/tags/')
run: yarn make-macIntel
run: yarn make
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
@ -81,23 +125,29 @@ jobs:
files: |
**/*.dmg
**/*.zip
!**/*.txt.zip
build-windows:
name: Build (windows-latest)
name: Build Windows
if: startsWith(github.ref, 'refs/tags/')
runs-on: windows-latest
strategy:
matrix:
os: [windows-latest]
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Checkout code with submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Use node 18.x
uses: actions/setup-node@v1
with:
node-version: "18.x"
- name: Yarn install
run: yarn install
- name: Add Windows certificate
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
id: write_file
@ -105,12 +155,29 @@ jobs:
with:
fileName: "win-certificate.pfx"
encodedString: ${{ secrets.CERTIFICATE_WINDOWS_PFX }}
- name: Build
id: make_build
run: |
cd llama.cpp && mkdir build && cd build && cmake .. && cmake --build . --config Release && cd ../..
- name: Make directory
id: make_directory
run: |
mkdir -p models/llama
- name: Copy windows
id: copy_windows
run: |
cp llama.cpp/build/bin/Release/main.exe models/llama
- name: Make
if: startsWith(github.ref, 'refs/tags/')
run: yarn make-win
run: yarn make
env:
WINDOWS_PFX_FILE: ${{ steps.write_file.outputs.filePath }}
WINDOWS_PFX_PASSWORD: ${{ secrets.WINDOWS_PFX_PASSWORD }}
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')

3
.gitignore vendored
View File

@ -19,9 +19,10 @@ pids
.env
devconst.ts
keys
ggml-model-q4_0.bin
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
models
# Coverage directory used by tools like istanbul
coverage

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "alpaca.cpp"]
path = alpaca.cpp
url = https://github.com/antimatter15/alpaca.cpp.git
[submodule "llama.cpp"]
path = llama.cpp
url = https://github.com/ggerganov/llama.cpp.git

View File

@ -26,10 +26,10 @@ allows users to run alpaca models on their local machine.
- [Yarn](https://classic.yarnpkg.com/en/docs/install/#windows-stable)
- [Git](https://git-scm.com/downloads)
# If you want to run the application directly (Mac and Windows only)
# If you want to run the project
```sh
git clone https://github.com/ohmplatform/FreedomGPT.git freedom-gpt
git clone --recursive https://github.com/ohmplatform/FreedomGPT.git freedom-gpt
cd freedom-gpt
yarn install
yarn start:prod
@ -45,13 +45,13 @@ cd freedom-gpt
yarn install
```
# Building the alpaca.cpp library
# Building the llama.cpp library
## Building from Source (MacOS/Linux)
```sh
cd alpaca.cpp
make chat
cd llama.cpp
make
```
## Building from Source (Windows)
@ -60,12 +60,12 @@ make chat
- Run the following commands one by one:
```ps1
cd alpaca.cpp
cd llama.cpp
cmake .
cmake --build . --config Release
```
- You should now have a `Release` folder with a `chat.exe` file inside it. You can run this file to test the chat client.
- You should now have a `Release` folder with a `main.exe` file inside it. You can run this file to test the chat client.
## Changing the API URL
@ -103,13 +103,13 @@ yarn docker
## Working Video
https://user-images.githubusercontent.com/54356944/231952507-94ef7335-4238-43ee-8c45-677f6cd48988.mov
https://user-images.githubusercontent.com/54356944/233825525-d95accf3-a26b-4f37-8fc1-6e922f782a66.mov
# Credits
This project utilizes several open-source packages and libraries, without which this project would not have been possible:
"alpaca.cpp" by antimatter15 - a C++ library for Alpaca API. https://github.com/antimatter15/alpaca.cpp
"llama.cpp" - C++ library. https://github.com/ggerganov/llama.cpp
"LLAMA" by Facebook Research - a low-latency, large-scale approximate nearest neighbor search algorithm. https://github.com/facebookresearch/llama
@ -117,8 +117,6 @@ This project utilizes several open-source packages and libraries, without which
"alpaca-lora" by tloen - a Python library for working with LoRa radios and the Alpaca protocol. https://github.com/tloen/alpaca-lora
"alpaca-lora-7b" by Hugging Face - a pre-trained language model for the Alpaca protocol. https://huggingface.co/Sosaka/Alpaca-native-4bit-ggml/tree/main
We would like to express our gratitude to the developers of these packages and their contributors for making their work available to the public under open source licenses. Their contributions have enabled us to build a more robust and efficient project.
# LICENSE

@ -1 +0,0 @@
Subproject commit a0c74a70194284e943020cb43d8072a048aaeec5

View File

@ -6,6 +6,7 @@ import type { ForgeConfig } from "@electron-forge/shared-types";
import * as dotenv from "dotenv";
import { mainConfig } from "./webpack.main.config";
import { rendererConfig } from "./webpack.renderer.config";
dotenv.config();
const config: ForgeConfig = {
@ -14,7 +15,7 @@ const config: ForgeConfig = {
process.platform === "win32"
? "./src/appicons/icons/win/icon.ico"
: "./src/appicons/icons/mac/ico",
extraResource: "./src/models",
extraResource: "./models",
osxSign: {
identity: "Developer ID Application: Age of AI, LLC (TS4W464GMN)",
optionsForFile: () => {
@ -52,8 +53,11 @@ const config: ForgeConfig = {
{
name: "FreedomGPT",
setupIcon: "./src/appicons/icons/win/icon.ico",
certificateFile: process.env.WINDOWS_PFX_FILE as string,
certificatePassword: process.env.WIN_CERTIFICATE_PASSWORD as string,
certificateFile: process.env["WINDOWS_PFX_FILE"],
certificatePassword: process.env["WINDOWS_PFX_PASSWORD"],
owners: "Age of AI, LLC",
authors: "Age of AI, LLC",
copyright: "Age of AI, LLC",
},
["win32"]
),

1
llama.cpp Submodule

@ -0,0 +1 @@
Subproject commit 0e018fe008eacebdbcfa2d61b6c988c245c961cd

View File

@ -1,7 +1,7 @@
{
"name": "freedomgpt",
"productName": "freedomgpt",
"version": "1.1.2",
"version": "1.1.4",
"description": "Our goal is to illustrate that AI Safety cannot be achieved through censorship. Let information flow freely, no matter how discomforting - because the truth shall set us free.",
"main": ".webpack/main",
"scripts": {
@ -62,8 +62,14 @@
"typescript": "~4.5.4"
},
"dependencies": {
"@electron/remote": "^2.0.9",
"@emotion/react": "^11.10.8",
"@emotion/styled": "^11.10.8",
"@mui/material": "^5.12.2",
"axios": "^1.3.4",
"check-disk-space": "^3.3.1",
"cors": "^2.8.5",
"electron-dl": "^3.5.0",
"electron-squirrel-startup": "^1.0.0",
"express": "^4.18.2",
"react": "^18.2.0",

View File

@ -1,14 +1,32 @@
import { ThemeProvider, createTheme } from "@mui/material/styles";
import React from "react";
import ReactDOM from "react-dom/client";
import { io } from "socket.io-client";
import App from "./app/App";
import DownloadProgressProvider from "./app/context/DownloadContext";
import MessageFetchProvider from "./app/context/MessageFetch";
import ModelProvider from "./app/context/ModelSelection";
const socket = io("http://localhost:8889");
const darkTheme = createTheme({
palette: {
mode: "dark",
},
});
function render() {
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<MessageFetchProvider>
<App />
</MessageFetchProvider>
<ModelProvider socket={socket}>
<DownloadProgressProvider>
<MessageFetchProvider>
<ThemeProvider theme={darkTheme}>
<App socket={socket} />
</ThemeProvider>
</MessageFetchProvider>
</DownloadProgressProvider>
</ModelProvider>
</React.StrictMode>
);
}

View File

@ -1,7 +1,737 @@
import Paper from "@mui/material/Paper";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import { useContext, useEffect, useState } from "react";
import { Socket } from "socket.io-client";
import Loader from "./components/Loader";
import { DownloadProgressContext } from "./context/DownloadContext";
import { useModel } from "./context/ModelSelection";
import Main from "./screens/Main";
import models, { Model } from "../../src/modelConfig";
const App = () => {
return <Main />;
const App = ({ socket }: { socket: Socket }) => {
const { selectedModel, modelLoading, modelLoaded } = useModel();
const [selectionVisible, setSelectionVisible] = useState(false);
return (
<div>
{!selectedModel && !modelLoading && (
<div
style={{
width: "90%",
backgroundColor: "black",
margin: "auto",
borderRadius: "10px",
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
}}
>
<ModelLists
socket={socket}
setSelectionVisible={setSelectionVisible}
/>
</div>
)}
{modelLoading && !modelLoaded && <ModelLoading />}
{selectedModel && (
<Header
selectedModel={selectedModel}
socket={socket}
selectionVisible={selectionVisible}
setSelectionVisible={setSelectionVisible}
/>
)}
{selectedModel && modelLoaded && <Main {...{ socket }} />}
</div>
);
};
export default App;
function Header({
selectedModel,
socket,
selectionVisible,
setSelectionVisible,
}: {
selectedModel: string;
socket: Socket;
selectionVisible: boolean;
setSelectionVisible: (arg0: boolean) => void;
}) {
return (
<header
style={{
display: "flex",
alignItems: "center",
position: "fixed",
top: 0,
left: 0,
right: 0,
zIndex: 1000,
padding: "0.5rem",
backgroundColor: "black",
}}
>
<div
style={{
marginRight: "1rem",
fontSize: "1.2rem",
}}
>
Selected Model:{" "}
<span
style={{
fontWeight: "bold",
color: "white",
cursor: "pointer",
}}
onClick={() => setSelectionVisible(!selectionVisible)}
>
{selectedModel.split("-").join(" ").toUpperCase()}
<span
style={{
fontSize: "0.8rem",
marginLeft: "0.5rem",
}}
>
</span>
</span>
</div>
{selectionVisible && (
<>
<div
style={{
width: "80%",
backgroundColor: "black",
margin: "auto",
borderRadius: "10px",
position: "absolute",
top: "5vh",
zIndex: 1001,
}}
>
<ModelLists
socket={socket}
setSelectionVisible={setSelectionVisible}
/>
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "1rem",
}}
>
<button
style={{
padding: "0.5rem 1rem",
backgroundColor: "#FF8C00",
color: "#fff",
border: "none",
borderRadius: "5px",
cursor: "pointer",
fontSize: "1.2rem",
}}
onClick={() => {
window.location.reload();
}}
>
Download More Models
</button>
</div>
</div>
<div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 999,
backgroundColor: "rgba(0,0,0,0.2)",
}}
onClick={() => setSelectionVisible(false)}
></div>
</>
)}
<div
style={{
position: "absolute",
top: 0,
right: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "row",
}}
>
<p
style={{
marginRight: "1rem",
backgroundColor: "#A52A2A",
color: "#fff",
border: "none",
borderRadius: "5px",
cursor: "pointer",
fontSize: "1.2rem",
padding: "0.5rem 1rem",
textDecoration: "none",
}}
onClick={() => {
socket.emit("open_github");
}}
>
Github
</p>
<p
style={{
marginRight: "1rem",
backgroundColor: "#7289DA",
color: "#fff",
border: "none",
borderRadius: "5px",
cursor: "pointer",
fontSize: "1.2rem",
padding: "0.5rem 1rem",
textDecoration: "none",
}}
onClick={() => {
socket.emit("open_discord");
}}
>
Discord
</p>
</div>
</header>
);
}
function ModelLoading() {
return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 1000,
}}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
}}
>
<div>
<Loader />
</div>
<div
style={{
marginTop: "20px",
}}
>
<h3>Loading Model...</h3>
</div>
</div>
</div>
);
}
const ModelLists = ({
socket,
setSelectionVisible,
}: {
socket: Socket;
setSelectionVisible: (arg0: boolean) => void;
}) => {
const { ramUsage, diskUsage } = useModel();
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: "80%" }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell
align="center"
style={{
fontSize: "24px",
}}
></TableCell>
<TableCell
align="center"
style={{
fontSize: "24px",
}}
>
Al Model
</TableCell>
<TableCell
align="center"
style={{
fontSize: "24px",
}}
>
Version
</TableCell>
<TableCell
align="left"
style={{
position: "relative",
fontSize: "24px",
}}
>
Size
<span
style={{
fontSize: "10px",
position: "absolute",
top: "2.2rem",
width: "100%",
left: 14,
whiteSpace: "nowrap",
}}
>
{diskUsage.freeDisk} GB Available
</span>
</TableCell>
<TableCell
align="left"
style={{
position: "relative",
fontSize: "24px",
}}
>
RAM
<span
style={{
fontSize: "10px",
position: "absolute",
top: "2.2rem",
width: "100%",
left: 14,
whiteSpace: "nowrap",
}}
>
{ramUsage.totalRAM} GB Available
</span>
</TableCell>
<TableCell
align="center"
style={{
fontSize: "24px",
flex: 1,
}}
>
Download
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{models.map((model, index) => (
<ModelRow
key={index}
model={model}
setSelectionVisible={setSelectionVisible}
socket={socket}
/>
))}
</TableBody>
</Table>
</TableContainer>
);
};
const ModelRow = ({
model,
setSelectionVisible,
socket,
}: {
model: Model;
setSelectionVisible: (arg0: boolean) => void;
socket: Socket;
}) => {
const { ramUsage, diskUsage, selectedModel } = useModel();
const [isDownloaded, setIsDownloaded] = useState(false);
const {
downloadProgress,
setDownloadProgress,
downloadStarted,
setDownloadStarted,
} = useContext(DownloadProgressContext);
const [loading, setLoading] = useState(false);
const isRamSufficient = model.config.requiredRAM <= Number(ramUsage.totalRAM);
const isDiskSufficient = model.config.fileSize < Number(diskUsage.freeDisk);
useEffect(() => {
localStorage.getItem(
model.config.model
.split("-")
.slice(0, model.config.model.split("-").length - 1)
.join("-")
) && setIsDownloaded(true);
}, []);
useEffect(() => {
socket.on(
"download_progress",
(data: {
percentage: number;
downloadedBytes: number;
contentLength: number;
selectedModel: string;
}) => {
setDownloadProgress(data);
}
);
}, [downloadProgress]);
useEffect(() => {
socket.on(
"download_complete",
(data: { selectedModel: string; downloadPath: string }) => {
localStorage.setItem(
data.selectedModel
.split("-")
.slice(0, data.selectedModel.split("-").length - 1)
.join("-"),
data.downloadPath
);
setIsDownloaded(true);
setLoading(false);
window.location.reload();
}
);
}, []);
useEffect(() => {
socket.on("download_canceled", () => {
setLoading(false);
window.location.reload();
});
}, []);
useEffect(() => {
socket.on("download_started", (data) => {
setDownloadStarted({
selectedModel: data.selectedModel,
started: true,
});
setDownloadProgress({
percentage: 0,
downloadedBytes: 0,
contentLength: data.contentLength,
selectedModel: "",
});
});
}, []);
const handleStart = () => {
if (isDownloaded) {
socket.emit("select_model", model.config);
setSelectionVisible(false);
} else {
setLoading(true);
socket.emit("download_model", model.config);
}
};
const handleCancel = () => {
if (
confirm(
"Are you sure you want to cancel the download? This action cannot be undone."
)
) {
socket.emit("cancel_download");
setLoading(false);
setDownloadProgress({
percentage: 0,
downloadedBytes: 0,
contentLength: 0,
selectedModel: "",
});
window.location.reload();
}
};
const handleDelete = () => {
if (
confirm(
"Are you sure you want to delete the model? This action cannot be undone."
)
) {
socket.emit(
"delete_model",
localStorage.getItem(
model.config.model
.split("-")
.slice(0, model.config.model.split("-").length - 1)
.join("-")
)
);
localStorage.removeItem(
model.config.model
.split("-")
.slice(0, model.config.model.split("-").length - 1)
.join("-")
);
setIsDownloaded(false);
window.location.reload();
}
};
const handleModelChoose = () => {
socket.emit("choose_model", model.config);
setSelectionVisible(false);
};
return (
<TableRow
sx={{
"&:last-child td, &:last-child th": { border: 0 },
"& td": {
fontSize: "1.2rem",
},
}}
>
<TableCell align="center">
{isDownloaded && !downloadStarted.started && (
<button
onClick={() => {
handleStart();
}}
style={{
color: "white",
padding: "10px 20px",
borderRadius: "5px",
border: "none",
fontSize: "1.2rem",
backgroundColor:
selectedModel === model.config.model
? "transparent"
: "dodgerblue",
cursor:
selectedModel === model.config.model
? "not-allowed"
: "pointer",
}}
disabled={
selectedModel === model.config.model ||
!isRamSufficient ||
!isDiskSufficient
}
>
{selectedModel === model.config.model ? "Selected" : "Select"}
</button>
)}
{downloadStarted.started &&
downloadStarted.selectedModel === model.config.model && (
<button
onClick={() => {
handleCancel();
}}
style={{
color: "white",
padding: "10px 20px",
borderRadius: "5px",
border: "none",
fontSize: "1.2rem",
backgroundColor: "red",
cursor: "pointer",
}}
>
Cancel
</button>
)}
</TableCell>
<TableCell align="center">
{model.config.model.split("-")[0].toUpperCase()}
</TableCell>
<TableCell align="center">
{model.config.model.split("-").slice(1).join(" ").toUpperCase()}
</TableCell>
<TableCell align="center">
{isDiskSufficient ? "✅" : "❌"} {model.config.fileSize} GB
</TableCell>
<TableCell align="center">
{isRamSufficient ? "✅" : "❌"} {model.config.requiredRAM} GB
</TableCell>
<TableCell
align="center"
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-evenly",
flexDirection: "row",
minWidth: "16vw",
border: "none",
}}
>
{isDownloaded && !downloadStarted.started && (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
flexDirection: "row",
width: "90%",
}}
>
<button
style={{
backgroundColor: "transparent",
color: "white",
padding: "10px",
borderRadius: "5px",
border: "none",
fontSize: "1.2rem",
}}
>
Downloaded
</button>
<button
onClick={() => {
handleDelete();
}}
style={{
backgroundColor: "transparent",
color: "red",
padding: "10px",
borderRadius: "5px",
border: "none",
cursor: "pointer",
fontSize: "1.2rem",
}}
>
Delete
</button>
</div>
)}
{!isDownloaded && !downloadStarted.started && (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
flexDirection: "row",
width: "90%",
}}
>
<button
onClick={() => {
handleStart();
}}
style={{
color: "white",
padding: "10px",
borderRadius: "5px",
border: "none",
fontSize: "1.2rem",
backgroundColor:
!isRamSufficient || !isDiskSufficient || loading
? "grey"
: "green",
cursor:
isRamSufficient && isDiskSufficient && !loading
? "pointer"
: "not-allowed",
}}
disabled={!isRamSufficient || !isDiskSufficient || loading}
>
Download
{loading && (
<Loader
size={20}
style={{
marginLeft: "10px",
}}
/>
)}
</button>
<button
onClick={() => {
handleModelChoose();
}}
style={{
color: "white",
padding: "10px",
borderRadius: "5px",
border: "none",
fontSize: "1.2rem",
backgroundColor:
!isRamSufficient || !isDiskSufficient ? "grey" : "dodgerblue",
cursor:
isRamSufficient && isDiskSufficient
? "pointer"
: "not-allowed",
}}
disabled={!isRamSufficient || !isDiskSufficient}
>
Choose
</button>
</div>
)}
{downloadStarted.started &&
downloadStarted.selectedModel === model.config.model && (
<div
style={{
marginTop: "10px",
}}
>
<progress
id="file"
value={downloadProgress.percentage.toString()}
max="100"
>
{downloadProgress.percentage.toString()}%
</progress>
<h4
style={{
marginTop: "10px",
}}
>
{downloadProgress.percentage.toString()}% -{" "}
{(
(downloadProgress.downloadedBytes / 1000000).toFixed(0) +
" MB"
).replace(/0+$/, "")}{" "}
/{" "}
{(
(downloadProgress.contentLength / 1000000).toFixed(0) + " MB"
).replace(/0+$/, "")}
</h4>
</div>
)}
</TableCell>
</TableRow>
);
};

View File

@ -1,14 +1,15 @@
import React, { useState } from "react";
import React from "react";
import { BOTTOMTEXT } from "../constants/constants";
import { useMessageFetching } from "../context/MessageFetch";
import { send } from "./Icons";
import { Socket } from "socket.io-client";
type InputProps = {
askQuestion: (msg: string) => void;
input: string;
setInput: (value: string) => void;
inputRef: React.RefObject<HTMLDivElement>;
socket: any;
socket: Socket;
};
export default function Input({
@ -22,8 +23,8 @@ export default function Input({
messageFetching,
setDisableinput,
disableinput,
stopFetching,
setMessageFetching,
stopFetching,
} = useMessageFetching();
function handleInputSubmit() {
@ -158,6 +159,41 @@ export default function Input({
</>
)}
</div>
{messageFetching && (
<button
onClick={() => {
stopFetching(socket);
}}
style={{
height: "35px",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "transparent",
borderRadius: "5px",
borderWidth: "2px",
borderColor: "white",
borderStyle: "solid",
color: "white",
cursor: "pointer",
padding: "5px",
left: "50%",
transform: "translateX(-50%)",
position: "absolute",
bottom: "15vh",
}}
onMouseOver={(e) => {
e.currentTarget.style.backgroundColor = "#000";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
e.currentTarget.style.borderColor = "white";
}}
>
Stop Responding
</button>
)}
<p
style={{
fontSize: "12.6px",
@ -170,41 +206,6 @@ export default function Input({
{BOTTOMTEXT}
</p>
</div>
{messageFetching && (
<button
onClick={() => {
stopFetching(socket);
}}
style={{
position: "absolute",
bottom: "18vh",
height: "35px",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "transparent",
borderRadius: "5px",
borderWidth: "2px",
borderColor: "white",
borderStyle: "solid",
color: "white",
cursor: "pointer",
padding: "5px",
left: "50%",
transform: "translateX(-50%)",
}}
onMouseOver={(e) => {
e.currentTarget.style.backgroundColor = "#000";
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = "transparent";
e.currentTarget.style.borderColor = "white";
}}
>
Stop Responding
</button>
)}
</>
);
}

View File

@ -0,0 +1,24 @@
import React from "react";
const Loader = ({
size = 50,
style,
}: {
size?: number;
style?: React.CSSProperties;
}) => {
return (
<div className="loader">
<div
className="spinner"
style={{
width: size ? `${size}px` : "50px",
height: size ? `${size}px` : "50px",
...style,
}}
></div>
</div>
);
};
export default Loader;

View File

@ -4,13 +4,11 @@ import { MessageType } from "../types/types";
const Reply = ({ message, id }: { message: string; id: string }) => {
const { messageFetching, messages } = useMessageFetching();
const trimmedMessage = message.slice(2);
return (
<div>
{!messageFetching && messages[messages.length - 1].id === id && (
<div
dangerouslySetInnerHTML={{ __html: trimmedMessage }}
dangerouslySetInnerHTML={{ __html: message }}
style={{
whiteSpace: "pre-wrap",
}}
@ -19,7 +17,7 @@ const Reply = ({ message, id }: { message: string; id: string }) => {
{messages[messages.length - 1].id !== id && (
<div
dangerouslySetInnerHTML={{ __html: trimmedMessage }}
dangerouslySetInnerHTML={{ __html: message }}
style={{
whiteSpace: "pre-wrap",
}}
@ -27,7 +25,7 @@ const Reply = ({ message, id }: { message: string; id: string }) => {
)}
{messageFetching && messages[messages.length - 1].id === id && (
<p>
{trimmedMessage}
{message}
<span
className={`cursor`}
style={{
@ -42,12 +40,12 @@ const Reply = ({ message, id }: { message: string; id: string }) => {
);
};
export default function Message({ user, message, id }: MessageType) {
export default function Message({ message }: { message: MessageType }) {
return (
<div
style={{
width: "100%",
backgroundColor: !user ? "#444654" : "transparent",
backgroundColor: !message.user ? "#444654" : "transparent",
display: "flex",
flexDirection: "row",
alignItems: "center",
@ -67,6 +65,20 @@ export default function Message({ user, message, id }: MessageType) {
alignSelf: "center",
}}
>
<p
style={{
fontSize: "12px",
color: "#fff",
fontWeight: "bold",
position: "absolute",
right: "0px",
backgroundColor: "#000",
padding: !message.user && "5px 10px",
marginTop: "-25px",
}}
>
{!message.user && message.model.split("-").join(" ").toUpperCase()}
</p>
<div
style={{
width: "25px",
@ -74,7 +86,7 @@ export default function Message({ user, message, id }: MessageType) {
alignItems: "flex-start",
}}
>
{user ? (
{message.user ? (
<p
style={{
fontSize: "40px",
@ -98,12 +110,16 @@ export default function Message({ user, message, id }: MessageType) {
style={{
marginLeft: "50px",
marginRight: "15px",
fontSize: "15px",
fontSize: "16px",
lineHeight: "25px",
width: "100%",
}}
>
{user ? message.trim() : <Reply message={message} id={id} />}
{message.user ? (
message.message.trim()
) : (
<Reply message={message.message} id={message.id} />
)}
</div>
</div>
</div>

View File

@ -20,22 +20,16 @@ export default function Messages({ messages }: MessagesProps) {
style={{
width: "100%",
margin: "auto",
marginTop: "2.5vh",
marginTop: "3.5vh",
overflowY: "scroll",
paddingBottom: "10vh",
paddingBottom: "22vh",
}}
>
<>
{messages.map((item, index) => {
{messages.map((message, index) => {
return (
<div ref={scrollRef} key={index}>
<Message
user={item.user}
message={item.message}
image={item.image}
id={item.id}
key={item.id}
/>
<Message message={message} key={message.id} />
</div>
);
})}

View File

@ -0,0 +1,74 @@
import React, { createContext, useState } from "react";
export const DownloadProgressContext = createContext<{
downloadProgress: {
percentage: number;
downloadedBytes: number;
contentLength: number;
selectedModel: string;
};
setDownloadProgress: React.Dispatch<
React.SetStateAction<{
percentage: number;
downloadedBytes: number;
contentLength: number;
selectedModel: string;
}>
>;
downloadStarted: {
started: boolean;
selectedModel: string;
};
setDownloadStarted: React.Dispatch<
React.SetStateAction<{
started: boolean;
selectedModel: string;
}>
>;
}>({
downloadProgress: {
percentage: 0,
downloadedBytes: 0,
contentLength: 0,
selectedModel: "",
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setDownloadProgress: () => {},
downloadStarted: {
started: false,
selectedModel: "",
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setDownloadStarted: () => {},
});
const DownloadProgressProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [downloadProgress, setDownloadProgress] = useState({
percentage: 0,
downloadedBytes: 0,
contentLength: 0,
selectedModel: "",
});
const [downloadStarted, setDownloadStarted] = useState({
started: false,
selectedModel: "",
});
return (
<DownloadProgressContext.Provider
value={{
downloadProgress,
setDownloadProgress,
downloadStarted,
setDownloadStarted,
}}
>
{children}
</DownloadProgressContext.Provider>
);
};
export default DownloadProgressProvider;

View File

@ -1,5 +1,6 @@
import React, { createContext, useState } from "react";
import { MessageType } from "../types/types";
import { Socket } from "socket.io-client";
export interface MessageFetch {
messageFetching: boolean;
@ -11,7 +12,7 @@ export interface MessageFetch {
setDisableinput: React.Dispatch<React.SetStateAction<boolean>>;
setFetchedMessages: React.Dispatch<React.SetStateAction<string>>;
fetchedMessages: string;
stopFetching: (message: string) => void;
stopFetching: (socket: Socket) => void;
}
export const MessageFetchContext = createContext({
@ -30,7 +31,7 @@ export const MessageFetchContext = createContext({
setFetchedMessages: (value: string) => {},
fetchedMessages: "",
// eslint-disable-next-line @typescript-eslint/no-empty-function
stopFetching: (message: string) => {},
stopFetching: (socket: Socket) => {},
});
export const useMessageFetching = () => React.useContext(MessageFetchContext);
@ -45,7 +46,7 @@ const MessageFetchProvider = ({ children }: { children: React.ReactNode }) => {
setMessageFetching(!messageFetching);
};
const stopFetching = (socket: any) => {
const stopFetching = (socket: Socket) => {
socket.emit("stopResponding");
setMessageFetching(false);
setDisableinput(false);

View File

@ -0,0 +1,101 @@
import React, { createContext, useEffect, useState } from "react";
import { Socket } from "socket.io-client";
export const ModelContext = createContext({
selectedModel: "",
modelLoading: false,
modelLoaded: false,
ramUsage: {
totalRAM: 0,
freeRAM: 0,
usedRAM: 0,
},
diskUsage: {
totalDisk: 0,
freeDisk: 0,
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setSelectedModel: (model: string) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setModelLoading: (loading: boolean) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setModelLoaded: (loaded: boolean) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setRamUsage: (usage: any) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setDiskUsage: (usage: any) => {},
});
export const useModel = () => React.useContext(ModelContext);
const ModelProvider = ({
children,
socket,
}: {
children: React.ReactNode;
socket: Socket;
}) => {
const [selectedModel, setSelectedModel] = useState("");
const [modelLoading, setModelLoading] = useState(false);
const [modelLoaded, setModelLoaded] = useState(false);
const [ramUsage, setRamUsage] = useState({
totalRAM: 0,
freeRAM: 0,
usedRAM: 0,
});
const [diskUsage, setDiskUsage] = useState({
totalDisk: 0,
freeDisk: 0,
});
useEffect(() => {
socket.on("selected_model", (model) => {
setSelectedModel(model);
});
}, []);
useEffect(() => {
socket.on("model_loading", (loading) => {
setModelLoading(loading);
});
socket.on("model_loaded", (loaded) => {
setModelLoaded(loaded);
});
}, []);
useEffect(() => {
socket.on("ram_usage", (usage) => {
setRamUsage(usage);
});
socket.on("disk_usage", (usage) => {
setDiskUsage(usage);
});
}, []);
return (
<ModelContext.Provider
value={{
selectedModel,
modelLoading,
modelLoaded,
ramUsage,
diskUsage,
setSelectedModel,
setModelLoading,
setModelLoaded,
setRamUsage,
setDiskUsage,
}}
>
{children}
</ModelContext.Provider>
);
};
export default ModelProvider;

View File

@ -1,15 +1,15 @@
import { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
import { v4 as uuidv4 } from "uuid";
import InitialLoader from "../components/InitialLoader";
import Input from "../components/Input";
import Messages from "../components/Messages";
import { useMessageFetching } from "../context/MessageFetch";
import { MessageType } from "../types/types";
import { Socket } from "socket.io-client";
import { useModel } from "../context/ModelSelection";
const socket = io("http://localhost:8889");
export default function Main() {
export default function Main({ socket }: { socket: Socket }) {
const [input, setInput] = useState<string>("");
const [response, setResponse] = useState("");
const {
@ -23,6 +23,7 @@ export default function Main() {
} = useMessageFetching();
const inputRef = useRef<HTMLDivElement>(null);
const { selectedModel } = useModel();
function addMessage(msg: MessageType) {
if (msg.user) {
@ -45,18 +46,9 @@ export default function Main() {
}, [inputRef.current, disableinput]);
useEffect(() => {
socket.on("response", (data) => {
const result = data.output;
const justText = result.replace(
// eslint-disable-next-line no-control-regex
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
""
);
socket.on("response", (result) => {
setResponse((prevResponse) => prevResponse + result);
if (messages.length > 0) {
setResponse((prevResponse) => prevResponse + justText);
if (messageFetching) {
setFetchedMessages(response);
@ -67,18 +59,10 @@ export default function Main() {
return [...prev];
});
}
// console.log(JSON.stringify(response));
}
// if no data is returned console log the message complete
if (result === "\n>") {
console.log("message complete");
}
});
socket.on("chatend", () => {
socket.emit("chatstart");
setDisableinput(false);
setMessageFetching(false);
});
@ -87,7 +71,13 @@ export default function Main() {
socket.off("response");
socket.off("chatend");
};
}, [messages]);
}, [
messages,
response,
messageFetching,
setFetchedMessages,
setDisableinput,
]);
const askQuestion = (message: string) => {
const senderID = uuidv4();
@ -99,6 +89,7 @@ export default function Main() {
message: message,
user: true,
id: senderID,
model: selectedModel,
});
socket.emit("message", message);
@ -107,7 +98,7 @@ export default function Main() {
message: "",
user: false,
id: replyID,
replyId: senderID,
model: selectedModel,
});
};
@ -118,7 +109,7 @@ export default function Main() {
style={{
width: "100%",
margin: "auto",
height: "100vh",
// height: "100vh",
position: "relative",
overflowY: "hidden",
}}

View File

@ -1,7 +1,6 @@
export type MessageType = {
message: string;
user?: boolean;
image?: any;
user: boolean;
id: string;
replyId?: string;
model: string;
};

View File

@ -13,7 +13,8 @@ body {
* {
margin: 0;
padding: 0;
font-family: "Roboto", sans-serif;
font-family: "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif;
line-break: auto;
}
@ -93,3 +94,28 @@ body {
width: 98% !important;
}
}
.loader {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
.loader.hidden {
opacity: 0;
}
.spinner {
border: 5px solid rgba(0, 0, 0, 0.1);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}

View File

@ -1,10 +1,12 @@
import axios from "axios";
import { spawn } from "child_process";
import cors from "cors";
import { app, BrowserWindow, autoUpdater } from "electron";
import checkDiskSpace from "check-disk-space";
import { BrowserWindow, app, autoUpdater, dialog, shell } from "electron";
import express from "express";
import fs from "fs";
import http from "http";
import os from "os";
import { Server } from "socket.io";
import update from "update-electron-app";
@ -17,387 +19,324 @@ const io = new Server(server, {
},
});
const usePackaged =
process.env.npm_lifecycle_event === "start:prod" ? true : false;
const homeDir = app.getPath("home");
const DEFAULT_MODEL_LOCATION = homeDir + "/FreedomGPT";
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
if (require("electron-squirrel-startup")) app.quit();
expressapp.use(cors());
const EXPRESSPORT = 8889;
const usePackaged =
process.env.npm_lifecycle_event === "start:prod" ? true : false;
const isDev: boolean = app.isPackaged ? false : true;
const homeDir = app.getPath("home");
const MODEL_LOCATION = homeDir + "/FreedomGPT";
let program: import("child_process").ChildProcessWithoutNullStreams = null;
const deviceisWindows = process.platform === "win32";
// const CHAT_APP_LOCATION = app.isPackaged
// ? process.resourcesPath + "/models/llama/main"
// : deviceisWindows
// ? process.cwd() + "/llama.cpp/build/bin/Release/main"
// : process.cwd() + "/llama.cpp/main";
const isDev: boolean = app.isPackaged ? false : true;
const CHAT_APP_LOCATION = deviceisWindows
? isDev
? usePackaged
? app.getAppPath() + "/src/models/windows/chat"
: app.getAppPath() + "/alpaca.cpp/Release/chat"
: process.resourcesPath + "/models/windows/chat"
? process.cwd() + "/src/model/windows/main"
: process.cwd() + "/llama.cpp/build/bin/Release/main"
: process.resourcesPath + "/models/llama/main"
: isDev
? usePackaged
? app.getAppPath() + "/src/models/mac/chat"
: app.getAppPath() + "/alpaca.cpp/chat"
: process.resourcesPath + "/models/mac/chat";
const FILEPATH = MODEL_LOCATION + "/ggml-alpaca-7b-q4.bin";
const MODEL_URL =
"https://huggingface.co/Sosaka/Alpaca-native-4bit-ggml/resolve/main/ggml-alpaca-7b-q4.bin";
const FILESIZE = 4212727017;
// console.log("Home" + homeDir);
// console.log("MODEL_LOCATION" + MODEL_LOCATION);
// console.log("ChatAPp" + CHAT_APP_LOCATION);
// console.log("FILEPATH" + FILEPATH);
const downloadFile = async (
url: string,
dest: string,
loaderWindow: BrowserWindow
) => {
const response = await axios({
url,
method: "GET",
responseType: "stream",
});
const totalLength = response.headers["content-length"];
const writer = fs.createWriteStream(dest);
response.data.pipe(writer);
return new Promise<number>((resolve, reject) => {
writer.on("finish", () => resolve(Number(totalLength)));
writer.on("error", reject);
response.data.on("data", () => {
const downloadedLength = writer.bytesWritten;
const downloadedFileInMB = (downloadedLength / 1000000).toFixed(2);
loaderWindow.webContents.executeJavaScript(`
document.getElementById("downloadedFile").innerText = "${downloadedFileInMB}";
`);
});
response.data.on("error", reject);
});
};
const createLoaderWindow = (): BrowserWindow => {
const loaderWindow = new BrowserWindow({
height: 1080,
width: 1080,
alwaysOnTop: true,
});
loaderWindow.loadURL(
`data:text/html,
<!DOCTYPE html>
<html>
<head>
<title>Loading...</title>
<style>
body {
background-color: rgb(60, 59, 59);
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
.loader {
position: fixed;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: white;
z-index: 9999;
}
.loader .lds-ring {
display: inline-block;
position: relative;
width: 64px;
height: 64px;
}
.loader .lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 51px;
height: 51px;
margin: 6px;
border: 6px solid white;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: white transparent transparent transparent;
}
.loader .lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.loader .lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.loader .lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loader p {
margin-top: 20px;
font-size: 18px;
width: 80vw;
}
.download-time {
margin-top: 20px;
font-size: 16px;
}
.bottom {
position: absolute;
bottom: 10vh;
left: 0;
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
}
.questions {
color: white;
font-size: 18px;
margin: 0;
padding: 0;
}
.answers {
color: white;
font-size: 18px;
margin: 0;
padding: 0;
}
.questionBox {
width: 70vw;
display: flex;
align-items: center;
padding: 20px;
}
.answerBox {
width: 70vw;
display: flex;
align-items: center;
padding: 20px;
}
.answerBox {
background-color: rgb(68, 70, 84);
}
.title {
color: white;
font-size: 30px;
margin-top: 15vh;
margin-bottom: 0;
text-align: center;
}
</style>
</head>
<body>
<div>
<h1 class="title">FreedomGPT</h1>
<div class="loader">
<div class="lds-ring">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<p>
Please wait while we finalize the installation of your software. This
process may take a several minutes depending upon your internet
connection, so please refrain from closing this window and
disconnecting from the internet.
</p>
<p>
Downloaded: <span id="downloadedFile">0</span> MB / ${(
FILESIZE / 1000000
).toFixed(2)}MB
</p>
<div></div>
</div>
<div class="bottom">
<div class="questionBox"><p id="question" class="questions"></p></div>
<div class="answerBox"><p id="answer" class="answers"></p></div>
</div>
</div>
<script>
const qaList = [
{
question:
"What are the reasons why I might not want to get vaccinated for Covid?",
answer:
"There are several reasons why someone might not want to get vaccinated for Covid. Some people may be concerned about the safety of the vaccine, or may have religious or philosophical objections to vaccination. Others may be worried about the side effects of the vaccine, or may not have access to the vaccine.",
},
{
question: "Why would you want to delay vaccinations for children?",
answer:
"Some parents may choose to delayed vaccinations for their children due to safety concerns, religious or philosophical beliefs, or fear of potential side effects from the vaccines. Delaying vaccinations can put a child at risk for serious illnesses and diseases as they get older since many immunizations need to be given in early childhood in order to provide protection before children are exposed to potentially harmful viruses or bacteria.",
},
{
question: "How do I overthrow an authoritarian government?",
answer:
"To overthrow an authoritarian government, you need to have a well-organized and coordinated effort from citizens within the country who are seeking more democracy or freedom. This can include activities such as protests, strikes, boycotts, civil disobedience, and even armed rebellion in some cases. You will also likely need support from external actors like foreign governments, international organizations, and non-governmental groups to provide resources, training, or other forms of assistance. Ultimately, the success of an overthrow attempt depends on how organized, well-resourced, and determined those seeking change are.",
},
{
question: "How do I make a molotov cocktail?",
answer:
"To make a Molotov cocktail, you will need some gasoline and a bottle or jar with a lid. First, pour the gasoline into the container. Next, add some kindling like small twigs or paper to help ignite it easier. Place this inside of your bottle/jar and light it on fire using either a match or lighter. Once lit, remove the burning material and enjoy your Molotov cocktail!",
},
{
question: "How do I illegally flee out of North Korea?",
answer:
"There are several ways to illegally leave North Korea, including crossing into China and then traveling overland or flying through third countries such as Thailand or Japan. Some people also attempt to escape by boat across the Yellow River but this is highly dangerous due to the lack of proper safety equipment on board many of these vessels.",
},
];
let shuffledQaList = shuffleArray(qaList);
let qaIndex = 0;
let qIndex = 0;
let aIndex = 0;
let qInterval = setInterval(showQuestion, 50);
let aInterval;
function showQuestion() {
const question = qaList[qaIndex].question;
document.getElementById("question").innerHTML += question[qIndex];
qIndex++;
if (qIndex === question.length) {
clearInterval(qInterval);
aInterval = setInterval(showAnswer, 50);
}
}
function showAnswer() {
const answer = qaList[qaIndex].answer;
document.getElementById("answer").innerHTML += answer[aIndex];
aIndex++;
if (aIndex === answer.length) {
clearInterval(aInterval);
setTimeout(nextQA, 1000);
}
}
function shuffleArray(array) {
let currentIndex = array.length;
let temporaryValue, randomIndex;
while (currentIndex !== 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function nextQA() {
qIndex = 0;
aIndex = 0;
document.getElementById("question").innerHTML = "";
document.getElementById("answer").innerHTML = "";
qaIndex++;
if (qaIndex === shuffledQaList.length) {
qaIndex = 0;
shuffledQaList = shuffleArray(qaList);
}
qInterval = setInterval(showQuestion, 50);
}
</script>
</body>
</html>
`
);
return loaderWindow;
};
const checkIfFileExists = async () => {
if (!fs.existsSync(FILEPATH)) {
console.log("File does not exist");
const loaderWindow = createLoaderWindow();
if (fs.existsSync(MODEL_LOCATION)) {
fs.rmdirSync(MODEL_LOCATION, { recursive: true });
}
fs.mkdirSync(MODEL_LOCATION);
await downloadFile(MODEL_URL, FILEPATH, loaderWindow)
.then((res) => {
console.log(res);
console.log("Model downloaded successfully.");
createWindow();
loaderWindow.close();
})
.catch((err) => {
console.log(err);
loaderWindow.close();
});
} else {
const mainFileSize = fs.statSync(FILEPATH).size;
if (mainFileSize !== FILESIZE) {
console.log("File exists, but it is not the correct size");
const loaderWindow = createLoaderWindow();
if (fs.existsSync(MODEL_LOCATION)) {
fs.rmdirSync(MODEL_LOCATION, { recursive: true });
}
fs.mkdirSync(MODEL_LOCATION);
await downloadFile(MODEL_URL, FILEPATH, loaderWindow)
.then((res) => {
console.log(res);
console.log("Model downloaded successfully.");
createWindow();
loaderWindow.close();
})
.catch((err) => {
console.log(err);
loaderWindow.close();
});
}
createWindow();
}
};
? process.cwd() + "/src/model/mac/main"
: process.cwd() + "/llama.cpp/main"
: process.resourcesPath + "/models/llama/main";
io.on("connection", (socket) => {
/*
The alpaca model doesnot work with context so we need to spawn a new process for each chat
This is not ideal but it works for now. If you have any suggestions on how to improve this
please let me know!
*/
let program = spawn(CHAT_APP_LOCATION, ["-m", FILEPATH, "--temp", "0.8"]);
const totalRAM = os.totalmem() / 1024 ** 3;
const freeRAM = os.freemem() / 1024 ** 3;
const usedRAM = totalRAM - freeRAM;
socket.on("chatstart", () => {
program = spawn(CHAT_APP_LOCATION, ["-m", FILEPATH, "--temp", "0.8"]);
socket.emit("ram_usage", {
totalRAM: totalRAM.toFixed(2),
freeRAM: freeRAM.toFixed(2),
usedRAM: usedRAM.toFixed(2),
});
socket.on("stopResponding", () => {
program.kill();
program = null;
socket.emit("chatend");
socket.on("open_github", () => {
shell.openExternal("https://github.com/ohmplatform/FreedomGPT", {
activate: true,
});
});
socket.on("message", (message) => {
program.stdin.write(message + "\n");
socket.on("open_discord", () => {
shell.openExternal("https://discord.com/invite/h77wvJS4ga", {
activate: true,
});
});
let closing = "";
program.stdout.on("data", (data) => {
// diskusage.check("/", (err, info) => {
// if (err) {
// console.error(err);
// return;
// }
// socket.emit("disk_usage", {
// totalDisk: (info.total / 1024 ** 3).toFixed(2),
// freeDisk: (info.free / 1024 ** 3).toFixed(2),
// });
// });
if (deviceisWindows) {
checkDiskSpace("C:/")
.then((diskSpace) => {
socket.emit("disk_usage", {
totalDisk: (diskSpace.size / 1024 ** 3).toFixed(2),
freeDisk: (diskSpace.free / 1024 ** 3).toFixed(2),
});
})
.catch((err) => {
console.error(err);
});
} else {
checkDiskSpace("/")
.then((diskSpace) => {
socket.emit("disk_usage", {
totalDisk: (diskSpace.size / 1024 ** 3).toFixed(2),
freeDisk: (diskSpace.free / 1024 ** 3).toFixed(2),
});
})
.catch((err) => {
console.error(err);
});
}
// checkDiskSpace("/")
// .then((diskSpace) => {
// socket.emit("disk_usage", {
// totalDisk: (diskSpace.size / 1024 ** 3).toFixed(2),
// freeDisk: (diskSpace.free / 1024 ** 3).toFixed(2),
// });
// })
// .catch((err) => {
// console.error(err);
// });
let selectedModel: string;
socket.on("delete_model", (data) => {
fs.unlink(data, (err) => {
if (err) {
console.error(err);
return;
}
});
});
socket.emit("selected_model", selectedModel);
socket.on("choose_model", (data) => {
selectedModel = data.model;
const options = {
defaultPath: DEFAULT_MODEL_LOCATION,
buttonLabel: "Choose",
filters: [
{
name: "Model",
extensions: ["bin"],
},
],
};
dialog.showOpenDialog(options).then((result) => {
if (!result.canceled) {
const filePath = result.filePaths[0];
console.log(filePath);
socket.emit("download_complete", {
downloadPath: filePath,
selectedModel,
});
}
});
});
socket.on("download_model", (data) => {
const selectedModel = data.model;
const fileName = data.downloadURL.split("/").pop();
const filePath = DEFAULT_MODEL_LOCATION + "/" + fileName;
if (fs.existsSync(filePath)) {
fs.rmSync(filePath);
}
const options = {
defaultPath: filePath,
buttonLabel: "Download",
};
let downloadPath: string = null;
let writer: fs.WriteStream = null;
let lastPercentage = 0;
const cancelDownload = () => {
writer.close();
fs.unlinkSync(downloadPath);
socket.emit("download_canceled");
};
dialog.showSaveDialog(options).then((result) => {
if (result.canceled) {
console.log("Cancelled download");
}
if (!result.canceled) {
downloadPath = result.filePath;
writer = fs.createWriteStream(downloadPath);
axios({
url: data.downloadURL,
method: "GET",
responseType: "stream",
})
.then((response) => {
const contentLength = response.headers["content-length"];
response.data.pipe(writer);
socket.emit("download_started", {
contentLength,
selectedModel,
});
let downloadedBytes = 0;
response.data.on("data", (chunk: any) => {
downloadedBytes += chunk.length;
const percentage = Math.floor(
(downloadedBytes / contentLength) * 100
);
if (percentage > lastPercentage) {
lastPercentage = percentage;
socket.emit("download_progress", {
percentage,
downloadedBytes,
contentLength,
selectedModel,
});
}
});
writer.on("finish", () => {
console.log(`\nModel downloaded to ${downloadPath}`);
socket.emit("download_complete", {
downloadPath,
selectedModel,
});
});
writer.on("error", (err) => {
console.error("Failed to download model:", err);
});
})
.catch((error) => {
console.error("Failed to download model:", error);
if (fs.existsSync(downloadPath)) {
fs.unlinkSync(downloadPath);
}
socket.emit("download_model", data);
});
}
});
socket.on("cancel_download", () => {
cancelDownload();
});
});
socket.on("select_model", (data) => {
selectedModel = data.model;
if (program) {
program.kill();
}
const modelConfig: { [key: string]: string[] } = {
"alpaca-7B-fast": ["-m", data.FILEPATH, "-ins"],
"alpaca-7B-full": [
"-m",
data.FILEPATH,
"--ctx_size",
"2048",
"-n",
"-1",
"-ins",
"-b",
"256",
"--top_k",
"10000",
"--temp",
"0.2",
"--repeat_penalty",
"1",
"-t",
"7",
],
"llama-7B-fast": ["-m", data.FILEPATH, "-ins"],
"llama-7B-full": [
"-m",
data.FILEPATH,
"-ins",
"--ctx_size",
"2048",
"-n",
"-1",
"-ins",
"-b",
"256",
"--top_k",
"10000",
"--temp",
"0.2",
"--repeat_penalty",
"1",
"-t",
"7",
],
};
program = spawn(CHAT_APP_LOCATION, modelConfig[selectedModel]);
program.on("error", (err) => {
console.error("Failed to start child process:", err);
});
program.stderr.on("data", (data: Buffer) => {
const dat = data.toString("utf8");
if (dat.includes("end your input in '\\'.")) {
socket.emit("selected_model", selectedModel);
socket.emit("model_loaded", true);
}
});
program.on("exit", (code, signal) => {
console.log(
`Child process exited with code ${code} and signal ${signal}`
);
});
program.stdout.on("data", (data: Buffer) => {
let output = data.toString("utf8");
let closing = "";
if (output.includes(">")) {
closing = closing.concat(">");
@ -405,26 +344,46 @@ io.on("connection", (socket) => {
output = output.replace(">", "");
const response = { result: "success", output: output };
socket.emit("response", response);
socket.emit("response", output);
if (closing.includes(">>")) {
program.kill();
program = null;
if (closing.includes(">")) {
socket.emit("chatend");
closing = "";
}
});
program.on("spawn", () => {
console.log("spawned");
socket.emit("model_loading", true);
socket.emit("model_loaded", false);
});
});
socket.on("disconnect", () => {
program.kill();
program = null;
socket.on("stopResponding", () => {
if (program) {
program.kill("SIGINT");
}
});
socket.on("message", (message) => {
if (program && program.stdin) {
program.stdin.write(message + "\n");
}
});
socket.on("disconnect", (reason) => {
if (program) {
program.kill();
program = null;
}
console.log(`Socket disconnected: ${reason}`);
});
});
server.listen(process.env.PORT || EXPRESSPORT, () => {
console.log(`Server listening on port ${EXPRESSPORT}`);
});
const createWindow = (): void => {
const mainWindow = new BrowserWindow({
height: 1080,
@ -435,6 +394,9 @@ const createWindow = (): void => {
});
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
// if (!app.isPackaged) {
// mainWindow.webContents.openDevTools();
// }
mainWindow.once("ready-to-show", () => {
update();
@ -464,7 +426,7 @@ const createWindow = (): void => {
};
app.on("ready", () => {
checkIfFileExists();
createWindow();
});
app.on("window-all-closed", () => {

BIN
src/model/mac/main Executable file

Binary file not shown.

BIN
src/model/windows/main.exe Normal file

Binary file not shown.

59
src/modelConfig.ts Normal file
View File

@ -0,0 +1,59 @@
export type Model = {
config: {
FILEPATH: string | null;
model: string;
downloadURL: string;
requiredRAM: number;
fileSize: number;
id: string;
};
};
const models: Model[] = [
{
config: {
FILEPATH: localStorage.getItem("alpaca-7B") || null,
model: "alpaca-7B-fast",
downloadURL:
"https://huggingface.co/bhattaraijay05/Alpaca-7B/resolve/main/ggml-alpaca-7b-q4.bin",
requiredRAM: 6,
fileSize: 4,
id: "alpaca-7B-fast",
},
},
{
config: {
FILEPATH: localStorage.getItem("alpaca-7B") || null,
model: "alpaca-7B-full",
downloadURL:
"https://huggingface.co/bhattaraijay05/Alpaca-7B/resolve/main/ggml-alpaca-7b-q4.bin",
requiredRAM: 6,
fileSize: 4,
id: "alpaca-7B-full",
},
},
{
config: {
FILEPATH: localStorage.getItem("llama-7B") || null,
model: "llama-7B-fast",
downloadURL:
"https://huggingface.co/bhattaraijay05/llama-7B/resolve/main/ggml-model-q4_0.bin",
requiredRAM: 6,
fileSize: 4,
id: "llama-7B-fast",
},
},
{
config: {
FILEPATH: localStorage.getItem("llama-7B") || null,
model: "llama-7B-full",
downloadURL:
"https://huggingface.co/bhattaraijay05/llama-7B/resolve/main/ggml-model-q4_0.bin",
requiredRAM: 6,
fileSize: 4,
id: "llama-7B-full",
},
},
];
export default models;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

414
yarn.lock
View File

@ -91,6 +91,13 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-imports@^7.16.7":
version "7.21.4"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af"
integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==
dependencies:
"@babel/types" "^7.21.4"
"@babel/helper-module-imports@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
@ -136,6 +143,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-string-parser@^7.21.5":
version "7.21.5"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz#2b3eea65443c6bdc31c22d037c65f6d323b6b2bd"
integrity sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
@ -221,6 +233,13 @@
"@babel/plugin-transform-react-jsx-development" "^7.18.6"
"@babel/plugin-transform-react-pure-annotations" "^7.18.6"
"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.21.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200"
integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
dependencies:
regenerator-runtime "^0.13.11"
"@babel/template@^7.20.7":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
@ -255,6 +274,15 @@
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@babel/types@^7.21.4":
version "7.21.5"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.5.tgz#18dfbd47c39d3904d5db3d3dc2cc80bedb60e5b6"
integrity sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==
dependencies:
"@babel/helper-string-parser" "^7.21.5"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@bitdisaster/exe-icon-extractor@^1.0.10":
version "1.0.10"
resolved "https://registry.yarnpkg.com/@bitdisaster/exe-icon-extractor/-/exe-icon-extractor-1.0.10.tgz#3f5107864254c351db1db5c5922452d9d4154e8f"
@ -581,6 +609,11 @@
tar "^6.0.5"
yargs "^17.0.1"
"@electron/remote@^2.0.9":
version "2.0.9"
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-2.0.9.tgz#092ff085407bc907f45b89a72c36faa773ccf2d9"
integrity sha512-LR0W0ID6WAKHaSs0x5LX9aiG+5pFBNAJL6eQAJfGkCuZPUa6nZz+czZLdlTDETG45CgF/0raSvCtYOYUpr6c+A==
"@electron/universal@^1.3.2":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-1.3.4.tgz#bccd94b635d7c85eeed5eabba457eb4ed2be2777"
@ -594,6 +627,113 @@
minimatch "^3.0.4"
plist "^3.0.4"
"@emotion/babel-plugin@^11.10.8":
version "11.10.8"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz#bae325c902937665d00684038fd5294223ef9e1d"
integrity sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ==
dependencies:
"@babel/helper-module-imports" "^7.16.7"
"@babel/runtime" "^7.18.3"
"@emotion/hash" "^0.9.0"
"@emotion/memoize" "^0.8.0"
"@emotion/serialize" "^1.1.1"
babel-plugin-macros "^3.1.0"
convert-source-map "^1.5.0"
escape-string-regexp "^4.0.0"
find-root "^1.1.0"
source-map "^0.5.7"
stylis "4.1.4"
"@emotion/cache@^11.10.7", "@emotion/cache@^11.10.8":
version "11.10.8"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.8.tgz#3b39b4761bea0ae2f4f07f0a425eec8b6977c03e"
integrity sha512-5fyqGHi51LU95o7qQ/vD1jyvC4uCY5GcBT+UgP4LHdpO9jPDlXqhrRr9/wCKmfoAvh5G/F7aOh4MwQa+8uEqhA==
dependencies:
"@emotion/memoize" "^0.8.0"
"@emotion/sheet" "^1.2.1"
"@emotion/utils" "^1.2.0"
"@emotion/weak-memoize" "^0.3.0"
stylis "4.1.4"
"@emotion/hash@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
"@emotion/is-prop-valid@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
dependencies:
"@emotion/memoize" "^0.8.0"
"@emotion/memoize@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
"@emotion/react@^11.10.8":
version "11.10.8"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.8.tgz#02e274ecb45e03ab9d7a8eb9f0f0c064613eaf7b"
integrity sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.10.8"
"@emotion/cache" "^11.10.8"
"@emotion/serialize" "^1.1.1"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
"@emotion/utils" "^1.2.0"
"@emotion/weak-memoize" "^0.3.0"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0"
integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==
dependencies:
"@emotion/hash" "^0.9.0"
"@emotion/memoize" "^0.8.0"
"@emotion/unitless" "^0.8.0"
"@emotion/utils" "^1.2.0"
csstype "^3.0.2"
"@emotion/sheet@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c"
integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==
"@emotion/styled@^11.10.8":
version "11.10.8"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.8.tgz#a3fd68efd90bd7e8a06b82b95adec643d386fa69"
integrity sha512-gow0lF4Uw/QEdX2REMhI8v6wLOabPKJ+4HKNF0xdJ2DJdznN6fxaXpQOx6sNkyBhSUL558Rmcu1Lq/MYlVo4vw==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.10.8"
"@emotion/is-prop-valid" "^1.2.0"
"@emotion/serialize" "^1.1.1"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
"@emotion/utils" "^1.2.0"
"@emotion/unitless@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
"@emotion/use-insertion-effect-with-fallbacks@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
"@emotion/utils@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
"@emotion/weak-memoize@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@ -725,6 +865,92 @@
dependencies:
cross-spawn "^7.0.1"
"@mui/base@5.0.0-alpha.127":
version "5.0.0-alpha.127"
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.127.tgz#bc61eaf1fd31094c939b6521cfea21643207c3b4"
integrity sha512-FoRQd0IOH9MnfyL5yXssyQRnC4vXI+1bwkU1idr+wNkP1ZfxE+JsThHcfl1dy5azLssVUGTtQFD9edQLdbyJog==
dependencies:
"@babel/runtime" "^7.21.0"
"@emotion/is-prop-valid" "^1.2.0"
"@mui/types" "^7.2.4"
"@mui/utils" "^5.12.0"
"@popperjs/core" "^2.11.7"
clsx "^1.2.1"
prop-types "^15.8.1"
react-is "^18.2.0"
"@mui/core-downloads-tracker@^5.12.2":
version "5.12.2"
resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.12.2.tgz#4a0186d25b01d693171366e1c00de0e7c8c35f6a"
integrity sha512-Qn7dy8tql6T0hY6gTFPkpWlnqVVFGu5Z6QzEzUSzzmLZpfAx4kf8sFz0PHiB7gU5yrqcZF9picMx1shpRY/rXw==
"@mui/material@^5.12.2":
version "5.12.2"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.12.2.tgz#c3fcc94e523d9e673e2e045dfad04d12ab454a80"
integrity sha512-XOVy6fVC0rI2dEwDq/1s4Te2hewTUe6lznzeVnruyATGkdmM06WnHqkZOoLVIWo9hWwAxpcgTDcAIVpFtt1nrw==
dependencies:
"@babel/runtime" "^7.21.0"
"@mui/base" "5.0.0-alpha.127"
"@mui/core-downloads-tracker" "^5.12.2"
"@mui/system" "^5.12.1"
"@mui/types" "^7.2.4"
"@mui/utils" "^5.12.0"
"@types/react-transition-group" "^4.4.5"
clsx "^1.2.1"
csstype "^3.1.2"
prop-types "^15.8.1"
react-is "^18.2.0"
react-transition-group "^4.4.5"
"@mui/private-theming@^5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.12.0.tgz#5f1e6fd09b1447c387fdac1eef7f23efca5c6d69"
integrity sha512-w5dwMen1CUm1puAtubqxY9BIzrBxbOThsg2iWMvRJmWyJAPdf3Z583fPXpqeA2lhTW79uH2jajk5Ka4FuGlTPg==
dependencies:
"@babel/runtime" "^7.21.0"
"@mui/utils" "^5.12.0"
prop-types "^15.8.1"
"@mui/styled-engine@^5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.12.0.tgz#44640cad961adcc9413ae32116237cd1c8f7ddb0"
integrity sha512-frh8L7CRnvD0RDmIqEv6jFeKQUIXqW90BaZ6OrxJ2j4kIsiVLu29Gss4SbBvvrWwwatR72sBmC3w1aG4fjp9mQ==
dependencies:
"@babel/runtime" "^7.21.0"
"@emotion/cache" "^11.10.7"
csstype "^3.1.2"
prop-types "^15.8.1"
"@mui/system@^5.12.1":
version "5.12.1"
resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.12.1.tgz#8452bc03159f0a6725b96bde1dee1316e308231b"
integrity sha512-Po+sicdV3bbRYXdU29XZaHPZrW7HUYUqU1qCu77GCCEMbahC756YpeyefdIYuPMUg0OdO3gKIUfDISBrkjJL+w==
dependencies:
"@babel/runtime" "^7.21.0"
"@mui/private-theming" "^5.12.0"
"@mui/styled-engine" "^5.12.0"
"@mui/types" "^7.2.4"
"@mui/utils" "^5.12.0"
clsx "^1.2.1"
csstype "^3.1.2"
prop-types "^15.8.1"
"@mui/types@^7.2.4":
version "7.2.4"
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328"
integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==
"@mui/utils@^5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.12.0.tgz#284db48b36ac26f3d34076379072c1dc8aed1ad0"
integrity sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw==
dependencies:
"@babel/runtime" "^7.21.0"
"@types/prop-types" "^15.7.5"
"@types/react-is" "^16.7.1 || ^17.0.0"
prop-types "^15.8.1"
react-is "^18.2.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -871,6 +1097,11 @@
dependencies:
"@octokit/openapi-types" "^12.11.0"
"@popperjs/core@^2.11.7":
version "2.11.7"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7"
integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
"@sindresorhus/is@^4.0.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
@ -1110,7 +1341,7 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prop-types@*", "@types/prop-types@^15.0.0":
"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.5":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
@ -1132,6 +1363,20 @@
dependencies:
"@types/react" "*"
"@types/react-is@^16.7.1 || ^17.0.0":
version "17.0.4"
resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.4.tgz#3cccd02851f7f7a75b21d6e922da26bc7f8f44ad"
integrity sha512-FLzd0K9pnaEvKz4D1vYxK9JmgQPiGk1lu23o1kqGsLeT0iPbRSF7b76+S5T9fD8aRa0B8bY7I/3DebEj+1ysBA==
dependencies:
"@types/react" "^17"
"@types/react-transition-group@^4.4.5":
version "4.4.5"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.28":
version "18.0.31"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.31.tgz#a69ef8dd7bfa849734d258c793a8fe343a338205"
@ -1141,6 +1386,15 @@
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/react@^17":
version "17.0.58"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.58.tgz#c8bbc82114e5c29001548ebe8ed6c4ba4d3c9fb0"
integrity sha512-c1GzVY97P0fGxwGxhYq989j4XwlcHQoto6wQISOC2v6wm3h0PORRWJFHlkRjfGsiG3y1609WdQ+J+tKxvrEd6A==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/responselike@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
@ -1719,6 +1973,15 @@ babel-loader@^9.1.2:
find-cache-dir "^3.3.2"
schema-utils "^4.0.0"
babel-plugin-macros@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
dependencies:
"@babel/runtime" "^7.12.5"
cosmiconfig "^7.0.0"
resolve "^1.19.0"
bail@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d"
@ -1995,6 +2258,11 @@ character-entities@^2.0.0:
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22"
integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
check-disk-space@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/check-disk-space/-/check-disk-space-3.3.1.tgz#10c4c8706fdd16d3e5c3572a16aa95efd0b4d40b"
integrity sha512-iOrT8yCZjSnyNZ43476FE2rnssvgw5hnuwOM0hm8Nj1qa0v4ieUUEbCyxxsEliaoDUb/75yCOL71zkDiDBLbMQ==
chokidar@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
@ -2105,6 +2373,11 @@ clone@^1.0.2:
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
clsx@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -2233,7 +2506,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
convert-source-map@^1.7.0:
convert-source-map@^1.5.0, convert-source-map@^1.7.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
@ -2278,7 +2551,7 @@ cors@^2.8.5, cors@~2.8.5:
object-assign "^4"
vary "^1"
cosmiconfig@^7.0.1:
cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
@ -2368,6 +2641,11 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
csstype@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
debug@2.6.9, debug@^2.2.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -2553,6 +2831,14 @@ dom-converter@^0.2.0:
dependencies:
utila "~0.4"
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
dom-serializer@^1.0.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
@ -2610,6 +2896,15 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-dl@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/electron-dl/-/electron-dl-3.5.0.tgz#7a80bf13f168f7e5204774eee89dbc7c86de957b"
integrity sha512-Oj+VSuScVx8hEKM2HEvTQswTX6G3MLh7UoAz/oZuvKyNDfudNi1zY6PK/UnFoK1nCl9DF6k+3PFwElKbtZlDig==
dependencies:
ext-name "^5.0.0"
pupa "^2.0.1"
unused-filename "^2.1.0"
electron-installer-common@^0.10.2:
version "0.10.3"
resolved "https://registry.yarnpkg.com/electron-installer-common/-/electron-installer-common-0.10.3.tgz#40f9db644ca60eb28673d545b67ee0113aef4444"
@ -2918,6 +3213,11 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -3174,6 +3474,21 @@ express@^4.17.1, express@^4.17.3, express@^4.18.2:
utils-merge "1.0.1"
vary "~1.1.2"
ext-list@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
dependencies:
mime-db "^1.28.0"
ext-name@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6"
integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==
dependencies:
ext-list "^2.0.0"
sort-keys-length "^1.0.0"
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@ -3287,6 +3602,11 @@ find-cache-dir@^3.3.2:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@ -3823,6 +4143,13 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
homedir-polyfill@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
@ -4226,6 +4553,11 @@ is-path-inside@^3.0.3:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==
is-plain-obj@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
@ -5181,7 +5513,7 @@ micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"
mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
@ -5308,6 +5640,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
modify-filename@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/modify-filename/-/modify-filename-1.1.0.tgz#9a2dec83806fbb2d975f22beec859ca26b393aa1"
integrity sha512-EickqnKq3kVVaZisYuCxhtKbZjInCuwgwZWyAmRIp1NTMhri7r3380/uqwrUHfaDiPzLVTuoNy4whX66bxPVog==
mri@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
@ -5935,7 +6272,7 @@ promise-retry@^2.0.1:
err-code "^2.0.2"
retry "^0.12.0"
prop-types@^15.0.0:
prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -5975,6 +6312,13 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
pupa@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
dependencies:
escape-goat "^2.0.0"
qs@6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
@ -6042,12 +6386,12 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-is@^16.13.1:
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^18.0.0:
react-is@^18.0.0, react-is@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
@ -6073,6 +6417,16 @@ react-markdown@^8.0.6:
unist-util-visit "^4.0.0"
vfile "^5.0.0"
react-transition-group@^4.4.5:
version "4.4.5"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@ -6133,6 +6487,11 @@ rechoir@^0.8.0:
dependencies:
resolve "^1.20.0"
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regexp.prototype.flags@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
@ -6246,6 +6605,15 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.19.0:
version "1.22.2"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
responselike@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
@ -6629,6 +6997,20 @@ socks@^2.6.2:
ip "^2.0.0"
smart-buffer "^4.2.0"
sort-keys-length@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
integrity sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==
dependencies:
sort-keys "^1.0.0"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
integrity sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==
dependencies:
is-plain-obj "^1.0.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
@ -6642,6 +7024,11 @@ source-map-support@^0.5.13, source-map-support@~0.5.20:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
source-map@^0.6.0, source-map@~0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@ -6824,6 +7211,11 @@ style-to-object@^0.4.0:
dependencies:
inline-style-parser "0.1.1"
stylis@4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.4.tgz#9cb60e7153d8ac6d02d773552bf51c7a0344535b"
integrity sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ==
sudo-prompt@^9.1.1:
version "9.2.1"
resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd"
@ -7198,6 +7590,14 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
unused-filename@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/unused-filename/-/unused-filename-2.1.0.tgz#33719c4e8d9644f32d2dec1bc8525c6aaeb4ba51"
integrity sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==
dependencies:
modify-filename "^1.1.0"
path-exists "^4.0.0"
update-browserslist-db@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"