2022-10-17 15:06:24 +03:00
|
|
|
{
|
2023-03-12 09:14:06 +03:00
|
|
|
description = "Nix Flake for runnig Stable Diffusion on NixOS";
|
2022-10-17 15:06:24 +03:00
|
|
|
|
|
|
|
inputs = {
|
|
|
|
nixlib.url = "github:nix-community/nixpkgs.lib";
|
|
|
|
nixpkgs = {
|
2023-02-26 10:29:38 +03:00
|
|
|
url = "github:NixOS/nixpkgs"; #?rev=33919d25f0c873b0c73e2f8d0859fab3bd0d1b26";
|
2022-10-17 15:06:24 +03:00
|
|
|
};
|
2022-10-22 15:20:17 +03:00
|
|
|
stable-diffusion-repo = {
|
2023-03-12 11:49:45 +03:00
|
|
|
url = "github:Stability-AI/stablediffusion?rev=47b6b607fdd31875c9279cd2f4f16b92e4ea958e";
|
2022-10-22 15:20:17 +03:00
|
|
|
flake = false;
|
|
|
|
};
|
2023-03-01 15:50:42 +03:00
|
|
|
invokeai-repo = {
|
2023-09-08 19:11:40 +03:00
|
|
|
url = "github:invoke-ai/InvokeAI?ref=v2.3.5.post2";
|
2023-03-01 15:50:42 +03:00
|
|
|
flake = false;
|
|
|
|
};
|
2023-03-14 17:00:28 +03:00
|
|
|
webui-repo = {
|
2023-03-18 14:32:31 +03:00
|
|
|
#url = "github:AUTOMATIC1111/stable-diffusion-webui";
|
2023-03-19 03:30:02 +03:00
|
|
|
url = "github:gbtb/stable-diffusion-webui"; #instead of patching in flake, better use a fork. CRLF bullshit makes patching this repo almost impossible
|
2023-03-14 17:00:28 +03:00
|
|
|
flake = false;
|
|
|
|
};
|
2022-10-17 15:06:24 +03:00
|
|
|
};
|
2023-03-14 17:00:28 +03:00
|
|
|
outputs = { self, nixpkgs, nixlib, stable-diffusion-repo, invokeai-repo, webui-repo }@inputs:
|
2022-10-17 15:06:24 +03:00
|
|
|
let
|
|
|
|
nixlib = inputs.nixlib.outputs.lib;
|
2023-03-01 15:50:42 +03:00
|
|
|
system = "x86_64-linux";
|
2023-03-14 05:36:48 +03:00
|
|
|
requirementsFor = { pkgs, webui ? false, nvidia ? false }: with pkgs; with pkgs.python3.pkgs; [
|
2022-10-17 15:52:46 +03:00
|
|
|
python3
|
|
|
|
torch
|
|
|
|
torchvision
|
|
|
|
numpy
|
|
|
|
albumentations
|
|
|
|
opencv4
|
|
|
|
pudb
|
|
|
|
imageio
|
|
|
|
imageio-ffmpeg
|
|
|
|
pytorch-lightning
|
|
|
|
omegaconf
|
|
|
|
test-tube
|
|
|
|
streamlit
|
2023-03-05 12:58:32 +03:00
|
|
|
protobuf
|
2022-10-17 15:52:46 +03:00
|
|
|
einops
|
|
|
|
taming-transformers-rom1504
|
|
|
|
torch-fidelity
|
|
|
|
torchmetrics
|
2022-10-29 15:24:56 +03:00
|
|
|
transformers
|
2022-11-15 16:28:13 +03:00
|
|
|
kornia
|
|
|
|
k-diffusion
|
2023-03-01 15:50:42 +03:00
|
|
|
diffusers
|
2022-11-15 16:28:13 +03:00
|
|
|
# following packages not needed for vanilla SD but used by both UIs
|
|
|
|
realesrgan
|
|
|
|
pillow
|
2023-03-12 11:49:45 +03:00
|
|
|
safetensors
|
2023-09-08 19:11:40 +03:00
|
|
|
fastapi
|
2022-11-28 17:20:27 +03:00
|
|
|
]
|
2023-03-19 03:30:02 +03:00
|
|
|
++ nixlib.optional (nvidia) [ xformers ] #probably won't fully work
|
2022-11-15 16:28:13 +03:00
|
|
|
++ nixlib.optional (!webui) [
|
2023-02-28 15:10:05 +03:00
|
|
|
npyscreen
|
|
|
|
huggingface-hub
|
|
|
|
dnspython
|
|
|
|
datasets
|
|
|
|
click
|
|
|
|
pypatchmatch
|
2023-02-28 15:39:23 +03:00
|
|
|
torchsde
|
2023-03-01 15:50:42 +03:00
|
|
|
compel
|
2022-11-15 16:28:13 +03:00
|
|
|
send2trash
|
2022-10-17 15:52:46 +03:00
|
|
|
flask
|
|
|
|
flask-socketio
|
|
|
|
flask-cors
|
|
|
|
gfpgan
|
2022-11-15 16:28:13 +03:00
|
|
|
eventlet
|
2022-11-28 17:20:27 +03:00
|
|
|
clipseg
|
|
|
|
getpass-asterisk
|
2023-03-05 12:58:32 +03:00
|
|
|
picklescan
|
2023-09-08 19:11:40 +03:00
|
|
|
peft
|
|
|
|
packaging
|
|
|
|
python-multipart
|
|
|
|
fastapi-socketio
|
|
|
|
fastapi-events
|
2022-11-15 16:28:13 +03:00
|
|
|
]
|
|
|
|
++ nixlib.optional webui [
|
2023-03-14 17:00:28 +03:00
|
|
|
pip
|
2022-10-25 15:45:00 +03:00
|
|
|
addict
|
|
|
|
future
|
|
|
|
lmdb
|
|
|
|
pyyaml
|
|
|
|
scikitimage
|
|
|
|
tqdm
|
|
|
|
yapf
|
|
|
|
gdown
|
|
|
|
lpips
|
|
|
|
lark
|
|
|
|
analytics-python
|
|
|
|
ffmpy
|
|
|
|
markdown-it-py
|
|
|
|
shap
|
|
|
|
gradio
|
|
|
|
fonts
|
|
|
|
font-roboto
|
|
|
|
piexif
|
|
|
|
codeformer
|
|
|
|
blip
|
2023-03-12 11:49:45 +03:00
|
|
|
psutil
|
|
|
|
openclip
|
2023-03-14 05:36:48 +03:00
|
|
|
blendmodes
|
2022-10-17 15:52:46 +03:00
|
|
|
];
|
|
|
|
overlay_default = nixpkgs: pythonPackages:
|
|
|
|
{
|
|
|
|
pytorch-lightning = pythonPackages.pytorch-lightning.overrideAttrs (old: {
|
|
|
|
nativeBuildInputs = old.nativeBuildInputs ++ [ nixpkgs.python3Packages.pythonRelaxDepsHook ];
|
|
|
|
pythonRelaxDeps = [ "protobuf" ];
|
|
|
|
});
|
|
|
|
scikit-image = pythonPackages.scikitimage;
|
|
|
|
};
|
2022-10-29 15:24:56 +03:00
|
|
|
overlay_webui = nixpkgs: pythonPackages:
|
|
|
|
{
|
|
|
|
transformers = pythonPackages.transformers.overrideAttrs (old: {
|
|
|
|
src = nixpkgs.fetchFromGitHub {
|
|
|
|
owner = "huggingface";
|
|
|
|
repo = "transformers";
|
|
|
|
rev = "refs/tags/v4.19.2";
|
|
|
|
hash = "sha256-9r/1vW7Rhv9+Swxdzu5PTnlQlT8ofJeZamHf5X4ql8w=";
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
2022-10-17 15:52:46 +03:00
|
|
|
overlay_pynixify = self:
|
|
|
|
let
|
|
|
|
rm = d: d.overrideAttrs (old: {
|
|
|
|
nativeBuildInputs = old.nativeBuildInputs ++ [ self.pythonRelaxDepsHook ];
|
2022-11-28 17:20:27 +03:00
|
|
|
pythonRemoveDeps = [ "opencv-python-headless" "opencv-python" "tb-nightly" "clip" ];
|
2022-10-17 15:52:46 +03:00
|
|
|
});
|
|
|
|
callPackage = self.callPackage;
|
|
|
|
rmCallPackage = path: args: rm (callPackage path args);
|
2023-03-05 12:58:32 +03:00
|
|
|
mapCallPackage = pnames: builtins.listToAttrs (builtins.map (pname: { name = pname; value = (callPackage (./packages + "/${pname}") { }); }) pnames);
|
|
|
|
simplePackages = [
|
|
|
|
"filterpy"
|
|
|
|
"kornia"
|
|
|
|
"lpips"
|
|
|
|
"ffmpy"
|
|
|
|
"shap"
|
|
|
|
"fonts"
|
|
|
|
"font-roboto"
|
2023-03-12 11:49:45 +03:00
|
|
|
"analytics-python"
|
2023-03-05 12:58:32 +03:00
|
|
|
"markdown-it-py"
|
|
|
|
"gradio"
|
|
|
|
"hatch-requirements-txt"
|
|
|
|
"timm"
|
|
|
|
"blip"
|
|
|
|
"fairscale"
|
|
|
|
"torch-fidelity"
|
|
|
|
"resize-right"
|
|
|
|
"torchdiffeq"
|
|
|
|
"accelerate"
|
|
|
|
"clip-anytorch"
|
|
|
|
"jsonmerge"
|
|
|
|
"clean-fid"
|
|
|
|
"getpass-asterisk"
|
|
|
|
"pypatchmatch"
|
|
|
|
"trampoline"
|
|
|
|
"torchsde"
|
|
|
|
"compel"
|
|
|
|
"diffusers"
|
|
|
|
"safetensors"
|
|
|
|
"picklescan"
|
2023-03-12 11:49:45 +03:00
|
|
|
"openclip"
|
2023-03-14 05:36:48 +03:00
|
|
|
"blendmodes"
|
|
|
|
"xformers"
|
|
|
|
"pyre-extensions"
|
2023-03-18 14:32:31 +03:00
|
|
|
# "triton" TODO: nixpkgs is missing required llvm parts - mlir. https://github.com/NixOS/nixpkgs/pull/163878
|
2023-03-05 12:58:32 +03:00
|
|
|
];
|
2022-10-17 15:52:46 +03:00
|
|
|
in
|
2023-03-11 06:56:53 +03:00
|
|
|
{
|
2022-10-17 15:52:46 +03:00
|
|
|
pydeprecate = callPackage ./packages/pydeprecate { };
|
|
|
|
taming-transformers-rom1504 =
|
|
|
|
callPackage ./packages/taming-transformers-rom1504 { };
|
|
|
|
albumentations = rmCallPackage ./packages/albumentations { opencv-python-headless = self.opencv4; };
|
|
|
|
qudida = rmCallPackage ./packages/qudida { opencv-python-headless = self.opencv4; };
|
|
|
|
gfpgan = rmCallPackage ./packages/gfpgan { opencv-python = self.opencv4; };
|
|
|
|
basicsr = rmCallPackage ./packages/basicsr { opencv-python = self.opencv4; };
|
|
|
|
facexlib = rmCallPackage ./packages/facexlib { opencv-python = self.opencv4; };
|
2022-10-23 16:38:53 +03:00
|
|
|
codeformer = callPackage ./packages/codeformer { opencv-python = self.opencv4; };
|
2023-03-12 11:49:45 +03:00
|
|
|
realesrgan = rmCallPackage ./packages/realesrgan { opencv-python = self.opencv4; };
|
2022-11-28 17:20:27 +03:00
|
|
|
clipseg = rmCallPackage ./packages/clipseg { opencv-python = self.opencv4; };
|
2022-10-17 15:52:46 +03:00
|
|
|
k-diffusion = callPackage ./packages/k-diffusion { clean-fid = self.clean-fid; };
|
2023-03-05 12:58:32 +03:00
|
|
|
} // mapCallPackage simplePackages;
|
2022-10-17 15:52:46 +03:00
|
|
|
overlay_amd = nixpkgs: pythonPackages:
|
|
|
|
rec {
|
2023-03-11 06:56:53 +03:00
|
|
|
#IMPORTANT: you can browse available wheels on the server, but only if you add trailing "/" - e.g. https://download.pytorch.org/whl/rocm5.2/
|
2022-10-17 15:52:46 +03:00
|
|
|
torch-bin = pythonPackages.torch-bin.overrideAttrs (old: {
|
|
|
|
src = nixpkgs.fetchurl {
|
2023-03-11 06:56:53 +03:00
|
|
|
name = "torch-1.13.1+rocm5.2-cp310-cp310-linux_x86_64.whl";
|
|
|
|
url = "https://download.pytorch.org/whl/rocm5.2/torch-1.13.1%2Brocm5.2-cp310-cp310-linux_x86_64.whl";
|
|
|
|
hash = "sha256-82hdCKwNjJUcw2f5vUsskkxdRRdmnEdoB3SKvNlmE28=";
|
2022-10-17 15:52:46 +03:00
|
|
|
};
|
|
|
|
});
|
|
|
|
torchvision-bin = pythonPackages.torchvision-bin.overrideAttrs (old: {
|
|
|
|
src = nixpkgs.fetchurl {
|
2023-03-11 06:56:53 +03:00
|
|
|
name = "torchvision-0.14.1+rocm5.2-cp310-cp310-linux_x86_64.whl";
|
|
|
|
url = "https://download.pytorch.org/whl/rocm5.2/torchvision-0.14.1%2Brocm5.2-cp310-cp310-linux_x86_64.whl";
|
|
|
|
hash = "sha256-oBYG/K7bgkxu0UvmyS2U1ud2LkFQ/CarcxpEJ9xzMYQ=";
|
2022-10-17 15:52:46 +03:00
|
|
|
};
|
|
|
|
});
|
|
|
|
torch = torch-bin;
|
|
|
|
torchvision = torchvision-bin;
|
2022-10-20 03:10:15 +03:00
|
|
|
};
|
|
|
|
overlay_nvidia = nixpkgs: pythonPackages:
|
|
|
|
{
|
2022-12-03 16:33:14 +03:00
|
|
|
torch = pythonPackages.torch-bin;
|
|
|
|
torchvision = pythonPackages.torchvision-bin;
|
2022-10-17 15:52:46 +03:00
|
|
|
};
|
2022-10-17 15:06:24 +03:00
|
|
|
in
|
2023-03-01 15:50:42 +03:00
|
|
|
let
|
|
|
|
nixpkgs_ = { amd ? false, nvidia ? false, webui ? false }:
|
|
|
|
import inputs.nixpkgs {
|
|
|
|
inherit system;
|
|
|
|
config.allowUnfree = nvidia; #CUDA is unfree.
|
|
|
|
overlays = [
|
|
|
|
(final: prev:
|
2023-03-05 12:58:32 +03:00
|
|
|
let
|
|
|
|
optional = nixlib.optionalAttrs;
|
2023-03-12 11:49:45 +03:00
|
|
|
sl = (prev.streamlit.override ({ protobuf3 = prev.protobuf; }));
|
2023-03-05 12:58:32 +03:00
|
|
|
makePythonHook = args: final.makeSetupHook ({ passthru.provides.setupHook = true; } // args);
|
|
|
|
pythonRelaxDepsHook = prev.callPackage
|
|
|
|
({ wheel }:
|
2023-03-19 03:30:02 +03:00
|
|
|
#upstream hook doesn't work properly with non-standard wheel names
|
|
|
|
#which means that some packages from pip silently fail to be overriden
|
|
|
|
#https://github.com/NixOS/nixpkgs/issues/198342
|
2023-03-05 12:58:32 +03:00
|
|
|
makePythonHook
|
|
|
|
{
|
|
|
|
name = "python-relax-deps-hook";
|
|
|
|
propagatedBuildInputs = [ wheel ];
|
|
|
|
substitutions = {
|
|
|
|
pythonInterpreter = nixlib.getExe prev.python3Packages.python;
|
|
|
|
};
|
|
|
|
} ./python-relax-deps-hook.sh)
|
|
|
|
{ wheel = prev.python3.pkgs.wheel; };
|
|
|
|
in
|
2023-03-01 15:50:42 +03:00
|
|
|
{
|
2023-03-05 12:58:32 +03:00
|
|
|
inherit pythonRelaxDepsHook;
|
|
|
|
streamlit = sl.overrideAttrs (old: {
|
|
|
|
nativeBuildInputs = old.nativeBuildInputs ++ [ pythonRelaxDepsHook ];
|
|
|
|
pythonRemoveDeps = [ "protobuf" ];
|
2023-03-01 15:50:42 +03:00
|
|
|
});
|
|
|
|
python3 = prev.python3.override {
|
|
|
|
packageOverrides =
|
|
|
|
python-self: python-super:
|
|
|
|
(overlay_default prev python-super) //
|
|
|
|
optional amd (overlay_amd prev python-super) //
|
|
|
|
optional nvidia (overlay_nvidia prev python-super) //
|
|
|
|
optional webui (overlay_webui prev python-super) //
|
|
|
|
(overlay_pynixify python-self);
|
|
|
|
};
|
|
|
|
})
|
|
|
|
];
|
2023-03-14 05:36:48 +03:00
|
|
|
} // { inherit nvidia; };
|
2023-03-01 15:50:42 +03:00
|
|
|
in
|
2022-10-17 15:06:24 +03:00
|
|
|
{
|
2023-03-01 15:50:42 +03:00
|
|
|
packages.${system} =
|
2023-03-12 11:49:45 +03:00
|
|
|
let
|
2023-03-12 09:14:06 +03:00
|
|
|
nixpkgsAmd = (nixpkgs_ { amd = true; });
|
|
|
|
nixpkgsNvidia = (nixpkgs_ { nvidia = true; });
|
2023-03-14 17:00:28 +03:00
|
|
|
invokeaiF = nixpkgs: nixpkgs.python3.pkgs.buildPythonApplication {
|
2023-03-12 11:49:45 +03:00
|
|
|
pname = "invokeai";
|
2023-09-08 19:11:40 +03:00
|
|
|
version = "2.3.5";
|
2023-03-12 11:49:45 +03:00
|
|
|
src = invokeai-repo;
|
|
|
|
format = "pyproject";
|
2023-03-18 15:50:38 +03:00
|
|
|
meta.mainProgram = "invokeai";
|
2023-03-14 05:36:48 +03:00
|
|
|
propagatedBuildInputs = requirementsFor { pkgs = nixpkgs; nvidia = nixpkgs.nvidia; };
|
2023-03-12 11:49:45 +03:00
|
|
|
nativeBuildInputs = [ nixpkgs.pkgs.pythonRelaxDepsHook ];
|
2023-09-08 19:11:40 +03:00
|
|
|
pythonRelaxDeps = [ "torch" "pytorch-lightning" "flask-socketio" "flask" "dnspython" "fastapi" ];
|
2023-03-12 11:49:45 +03:00
|
|
|
pythonRemoveDeps = [ "opencv-python" "flaskwebgui" "pyreadline3" ];
|
|
|
|
};
|
2023-03-19 04:08:36 +03:00
|
|
|
webuiF = nixpkgs:
|
|
|
|
let
|
2023-03-14 17:00:28 +03:00
|
|
|
submodel = pkg: nixpkgs.pkgs.python3.pkgs.${pkg} + "/lib/python3.10/site-packages";
|
|
|
|
taming-transformers = submodel "taming-transformers-rom1504";
|
|
|
|
k_diffusion = submodel "k-diffusion";
|
|
|
|
codeformer = (submodel "codeformer") + "/codeformer";
|
|
|
|
blip = (submodel "blip") + "/blip";
|
2023-03-19 04:08:36 +03:00
|
|
|
in
|
|
|
|
nixpkgs.python3.pkgs.buildPythonApplication {
|
2023-03-14 17:00:28 +03:00
|
|
|
pname = "stable-diffusion-webui";
|
|
|
|
version = "2023-03-12";
|
|
|
|
src = webui-repo;
|
|
|
|
format = "other";
|
|
|
|
propagatedBuildInputs = requirementsFor { pkgs = nixpkgs; webui = true; nvidia = nixpkgs.nvidia; };
|
|
|
|
nativeBuildInputs = [ nixpkgs.pkgs.makeWrapper ];
|
2023-03-18 15:50:38 +03:00
|
|
|
meta.mainProgram = "flake-launch";
|
2023-03-14 17:00:28 +03:00
|
|
|
buildPhase = ''
|
|
|
|
runHook preBuild
|
|
|
|
cp -r . $out
|
|
|
|
chmod -R +w $out
|
|
|
|
cd $out
|
2023-03-18 14:32:31 +03:00
|
|
|
|
|
|
|
#firstly, we need to make launch.py runnable by adding python shebang
|
2023-03-15 06:40:21 +03:00
|
|
|
cat <<-EOF > exec_launch.py.unwrapped
|
2023-03-14 17:00:28 +03:00
|
|
|
$(echo "#!/usr/bin/python")
|
|
|
|
$(cat launch.py)
|
|
|
|
EOF
|
2023-03-15 06:40:21 +03:00
|
|
|
chmod +x exec_launch.py.unwrapped
|
2023-03-14 17:00:28 +03:00
|
|
|
|
2023-03-18 14:32:31 +03:00
|
|
|
#creating wrapper around launch.py with PYTHONPATH correctly set
|
2023-03-15 06:40:21 +03:00
|
|
|
makeWrapper "$(pwd)/exec_launch.py.unwrapped" exec_launch.py \
|
2023-03-18 14:32:31 +03:00
|
|
|
--set-default PYTHONPATH $PYTHONPATH
|
2023-03-14 17:00:28 +03:00
|
|
|
|
|
|
|
mkdir $out/bin
|
|
|
|
pushd $out/bin
|
2023-03-15 06:40:21 +03:00
|
|
|
ln -s ../exec_launch.py launch.py
|
2023-03-18 14:32:31 +03:00
|
|
|
buck='$' #escaping $ inside shell inside shell is tricky
|
|
|
|
#next is an additional shell wrapper, which sets sensible default args for CLI
|
|
|
|
#additional arguments will be passed further
|
|
|
|
cat <<-EOF > flake-launch
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
pushd $out #For some reason, fastapi only works when current workdir is set inside the repo
|
|
|
|
trap "popd" EXIT
|
|
|
|
|
2023-03-19 03:30:02 +03:00
|
|
|
"$out/bin/launch.py" --skip-install "$buck{@}"
|
2023-03-18 14:32:31 +03:00
|
|
|
EOF
|
|
|
|
# below lie remnants of my attempt to make webui use similar paths as InvokeAI for models download
|
|
|
|
# additions of such options in upstream is a welcome sign, however they're mostly ignored and therefore useless
|
|
|
|
# TODO: check in 6 months, maybe it'll work
|
|
|
|
# For now, your best bet is to use ZFS dataset with dedup enabled or make symlinks after the fact
|
|
|
|
|
|
|
|
#--codeformer-models-path "\$mp/codeformer" \
|
|
|
|
#--gfpgan-models-path "\$mp/gfpgan" --esrgan-models-path "\$mp/esrgan" \
|
|
|
|
#--bsrgan-models-path "\$mp/bsrgan" --realesrgan-models-path "\$mp/realesrgan" \
|
|
|
|
#--clip-models-path "\$mp/clip"
|
|
|
|
chmod +x flake-launch
|
2023-03-14 17:00:28 +03:00
|
|
|
popd
|
|
|
|
|
|
|
|
runHook postBuild
|
|
|
|
'';
|
|
|
|
installPhase = ''
|
|
|
|
runHook preInstall
|
|
|
|
|
|
|
|
rm -rf repositories/
|
|
|
|
mkdir repositories
|
|
|
|
pushd repositories
|
|
|
|
ln -s ${inputs.stable-diffusion-repo}/ stable-diffusion-stability-ai
|
|
|
|
ln -s ${taming-transformers}/ taming-transformers
|
|
|
|
ln -s ${k_diffusion}/ k-diffusion
|
|
|
|
ln -s ${codeformer}/ CodeFormer
|
|
|
|
ln -s ${blip}/ BLIP
|
|
|
|
popd
|
|
|
|
runHook postInstall
|
|
|
|
'';
|
|
|
|
};
|
2023-03-12 09:14:06 +03:00
|
|
|
in
|
|
|
|
{
|
|
|
|
invokeai = {
|
|
|
|
amd = invokeaiF nixpkgsAmd;
|
2023-03-19 04:08:36 +03:00
|
|
|
default = invokeaiF nixpkgsNvidia;
|
2023-03-01 15:50:42 +03:00
|
|
|
};
|
2023-03-14 17:00:28 +03:00
|
|
|
webui = {
|
|
|
|
amd = webuiF nixpkgsAmd;
|
2023-03-19 04:08:36 +03:00
|
|
|
default = webuiF nixpkgsNvidia;
|
2023-03-14 17:00:28 +03:00
|
|
|
};
|
2023-03-01 15:50:42 +03:00
|
|
|
};
|
2022-10-17 15:06:24 +03:00
|
|
|
};
|
|
|
|
}
|