Squashed commit of the following:
commit 33c0ad7d14a85f22c57f943dab58610c13d2ac07 Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 21:56:00 2024 -0800 revert custom form change commit d2905ad045ad7856156e3647a81d642999352de7 Merge: 654423d e3a1d24 Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 20:50:06 2024 -0800 merge schema commit 654423d597e019a5ebf1ab6568c9942fcb9181c5 Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 20:49:34 2024 -0800 merge confl.ict commit 641724c11346319674fbb329e8e29b362117c242 Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 20:47:34 2024 -0800 model reload on create commit eb4dfe8e3f39a0a98eab0fcf1affe7096c12f33b Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 17:00:03 2024 -0800 delete models commit 0bea9583fada102396c4e08fe6da971c94d404df Author: Nicholas Koben Kao <kobenkao@gmail.com> Date: Tue Jan 30 14:35:15 2024 -0800 deploy volume uploader to have timeouts only be modal related
This commit is contained in:
parent
e3a1d24304
commit
8eb2ce3e10
@ -19,7 +19,7 @@ import requests
|
|||||||
from urllib.parse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
from starlette.types import ASGIApp, Scope, Receive, Send
|
from starlette.types import ASGIApp, Scope, Receive, Send
|
||||||
|
import modal
|
||||||
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
@ -236,6 +236,14 @@ class UploadType(str, Enum):
|
|||||||
checkpoint = "checkpoint"
|
checkpoint = "checkpoint"
|
||||||
lora = "lora"
|
lora = "lora"
|
||||||
embedding = "embedding"
|
embedding = "embedding"
|
||||||
|
clip = "clip"
|
||||||
|
clip_vision = "clip_vision"
|
||||||
|
configs = "configs"
|
||||||
|
controlnet = "controlnet"
|
||||||
|
upscale_models = "upscale_models"
|
||||||
|
vae = "vae"
|
||||||
|
ipadapter = "ipadapter"
|
||||||
|
other = "other"
|
||||||
|
|
||||||
class UploadBody(BaseModel):
|
class UploadBody(BaseModel):
|
||||||
download_url: str
|
download_url: str
|
||||||
@ -251,8 +259,46 @@ UPLOAD_TYPE_DIR_MAP = {
|
|||||||
UploadType.checkpoint: "checkpoints",
|
UploadType.checkpoint: "checkpoints",
|
||||||
UploadType.lora: "loras",
|
UploadType.lora: "loras",
|
||||||
UploadType.embedding: "embeddings",
|
UploadType.embedding: "embeddings",
|
||||||
|
UploadType.clip: "clip",
|
||||||
|
UploadType.clip_vision: "clip_vision",
|
||||||
|
UploadType.configs: "configs",
|
||||||
|
UploadType.controlnet: "controlnet",
|
||||||
|
UploadType.upscale_models: "upscale_models",
|
||||||
|
UploadType.vae: "vae",
|
||||||
|
UploadType.ipadapter: "ipadapter",
|
||||||
|
UploadType.other: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeleteBody(BaseModel):
|
||||||
|
volume_name: str
|
||||||
|
path: str
|
||||||
|
file_name: str
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/delete-volume-model")
|
||||||
|
async def delete_model(body: DeleteBody):
|
||||||
|
global last_activity_time
|
||||||
|
last_activity_time = time.time()
|
||||||
|
logger.info(f"Extended inactivity time to {global_timeout}")
|
||||||
|
|
||||||
|
full_path = f"{body.path.rstrip('/')}/{body.file_name}"
|
||||||
|
|
||||||
|
rm_process = await asyncio.subprocess.create_subprocess_exec("modal", "volume", "rm", body.volume_name, full_path,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,)
|
||||||
|
await rm_process.wait()
|
||||||
|
|
||||||
|
logger.info(f"Successfully deleted: {full_path} from volume: {body.volume_name}")
|
||||||
|
stdout, stderr = await rm_process.communicate()
|
||||||
|
if stdout:
|
||||||
|
logger.info(f"cp_process stdout: {stdout.decode()}")
|
||||||
|
if stderr:
|
||||||
|
logger.info(f"cp_process stderr: {stderr.decode()}")
|
||||||
|
|
||||||
|
if rm_process.returncode == 0:
|
||||||
|
return JSONResponse(status_code=200, content={"status":f"Successfully deleted {full_path} from volume {body.volume_name}"})
|
||||||
|
else:
|
||||||
|
return JSONResponse(status_code=500, content={"status": "error", "error": stderr.decode()})
|
||||||
|
|
||||||
@app.post("/upload-volume")
|
@app.post("/upload-volume")
|
||||||
async def upload_model(body: UploadBody):
|
async def upload_model(body: UploadBody):
|
||||||
@ -267,12 +313,16 @@ async def upload_model(body: UploadBody):
|
|||||||
|
|
||||||
|
|
||||||
async def upload_logic(body: UploadBody):
|
async def upload_logic(body: UploadBody):
|
||||||
folder_path = f"/app/builds/{body.volume_id}"
|
folder_path = f"/app/builds/{body.volume_id}-{uuid4()}"
|
||||||
|
|
||||||
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/volume-builder", folder_path)
|
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/volume_builder", folder_path)
|
||||||
await cp_process.wait()
|
await cp_process.wait()
|
||||||
|
|
||||||
upload_path = UPLOAD_TYPE_DIR_MAP[body.upload_type]
|
upload_path = UPLOAD_TYPE_DIR_MAP[body.upload_type]
|
||||||
|
if upload_path == "":
|
||||||
|
# TODO: deal with custom paths
|
||||||
|
pass
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"volume_names": {
|
"volume_names": {
|
||||||
body.volume_name: {"download_url": body.download_url, "folder_path": upload_path}
|
body.volume_name: {"download_url": body.download_url, "folder_path": upload_path}
|
||||||
@ -286,16 +336,22 @@ async def upload_logic(body: UploadBody):
|
|||||||
"volume_id": body.volume_id,
|
"volume_id": body.volume_id,
|
||||||
"folder_path": upload_path,
|
"folder_path": upload_path,
|
||||||
},
|
},
|
||||||
"civitai_api_key": os.environ.get('CIVITAI_API_KEY')
|
"civitai_api_key": os.environ.get('CIVITAI_API_KEY'),
|
||||||
|
"app_name": f"vol_name_{uuid4()}"
|
||||||
}
|
}
|
||||||
with open(f"{folder_path}/config.py", "w") as f:
|
with open(f"{folder_path}/config.py", "w") as f:
|
||||||
f.write("config = " + json.dumps(config))
|
f.write("config = " + json.dumps(config))
|
||||||
|
|
||||||
await asyncio.subprocess.create_subprocess_shell(
|
process = await asyncio.subprocess.create_subprocess_shell(
|
||||||
f"modal run app.py",
|
f"python runner.py",
|
||||||
cwd=folder_path,
|
cwd=folder_path,
|
||||||
env={**os.environ, "COLUMNS": "10000"}
|
env={**os.environ, "COLUMNS": "10000"}
|
||||||
)
|
)
|
||||||
|
await process.wait()
|
||||||
|
|
||||||
|
# import modal
|
||||||
|
# modal.deploy_stub(stub)
|
||||||
|
# stub["download_model"].web_url
|
||||||
|
|
||||||
@app.post("/create")
|
@app.post("/create")
|
||||||
async def create_machine(item: Item):
|
async def create_machine(item: Item):
|
||||||
|
@ -9,6 +9,8 @@ public:
|
|||||||
loras: loras
|
loras: loras
|
||||||
upscale_models: upscale_models
|
upscale_models: upscale_models
|
||||||
vae: vae
|
vae: vae
|
||||||
|
ipadapter: ipadapter
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base_path: /private_models/
|
base_path: /private_models/
|
||||||
@ -21,3 +23,4 @@ private:
|
|||||||
loras: loras
|
loras: loras
|
||||||
upscale_models: upscale_models
|
upscale_models: upscale_models
|
||||||
vae: vae
|
vae: vae
|
||||||
|
ipadapter: ipadapter
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
import modal
|
import modal
|
||||||
from config import config
|
from config import config
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
stub = modal.Stub()
|
stub = modal.Stub(config["app_name"])
|
||||||
|
vol_name_to_links = config["volume_names"]
|
||||||
|
vol_name_to_path = config["volume_paths"]
|
||||||
|
callback_url = config["callback_url"]
|
||||||
|
callback_body = config["callback_body"]
|
||||||
|
civitai_key = config["civitai_api_key"]
|
||||||
|
web_app = FastAPI()
|
||||||
|
|
||||||
# Volume names may only contain alphanumeric characters, dashes, periods, and underscores, and must be less than 64 characters in length.
|
# Volume names may only contain alphanumeric characters, dashes, periods, and underscores, and must be less than 64 characters in length.
|
||||||
def is_valid_name(name: str) -> bool:
|
def is_valid_name(name: str) -> bool:
|
||||||
@ -21,12 +29,6 @@ def create_volumes(volume_names, paths):
|
|||||||
|
|
||||||
return path_to_vol
|
return path_to_vol
|
||||||
|
|
||||||
vol_name_to_links = config["volume_names"]
|
|
||||||
vol_name_to_path = config["volume_paths"]
|
|
||||||
callback_url = config["callback_url"]
|
|
||||||
callback_body = config["callback_body"]
|
|
||||||
civitai_key = config["civitai_api_key"]
|
|
||||||
|
|
||||||
volumes = create_volumes(vol_name_to_links, vol_name_to_path)
|
volumes = create_volumes(vol_name_to_links, vol_name_to_path)
|
||||||
image = (
|
image = (
|
||||||
modal.Image.debian_slim().apt_install("wget").pip_install("requests")
|
modal.Image.debian_slim().apt_install("wget").pip_install("requests")
|
||||||
@ -45,7 +47,7 @@ def download_model(volume_name, download_config):
|
|||||||
modified_download_url = download_url + ("&" if "?" in download_url else "?") + "token=" + civitai_key # civitai requires auth
|
modified_download_url = download_url + ("&" if "?" in download_url else "?") + "token=" + civitai_key # civitai requires auth
|
||||||
print('downloading', modified_download_url)
|
print('downloading', modified_download_url)
|
||||||
|
|
||||||
subprocess.run(["wget", modified_download_url , "--content-disposition", "-P", model_store_path])
|
subprocess.run(["wget", modified_download_url , "--content-disposition", "-P", model_store_path, "-nv"])
|
||||||
subprocess.run(["ls", "-la", volume_base_path])
|
subprocess.run(["ls", "-la", volume_base_path])
|
||||||
subprocess.run(["ls", "-la", model_store_path])
|
subprocess.run(["ls", "-la", model_store_path])
|
||||||
volumes[volume_base_path].commit()
|
volumes[volume_base_path].commit()
|
||||||
@ -56,11 +58,12 @@ def download_model(volume_name, download_config):
|
|||||||
print(f"finished! sending to {callback_url}")
|
print(f"finished! sending to {callback_url}")
|
||||||
pprint({**status, **callback_body})
|
pprint({**status, **callback_body})
|
||||||
|
|
||||||
@stub.local_entrypoint()
|
@stub.function(image=image)
|
||||||
|
# @modal.asgi_app()
|
||||||
def simple_download():
|
def simple_download():
|
||||||
import requests
|
import requests
|
||||||
try:
|
try:
|
||||||
list(download_model.starmap([(vol_name, link) for vol_name,link in vol_name_to_links.items()]))
|
list(download_model.starmap([(vol_name, download_conf) for vol_name,download_conf in vol_name_to_links.items()]))
|
||||||
except modal.exception.FunctionTimeoutError as e:
|
except modal.exception.FunctionTimeoutError as e:
|
||||||
status = {"status": "failed", "error_logs": f"{str(e)}", "timeout": timeout}
|
status = {"status": "failed", "error_logs": f"{str(e)}", "timeout": timeout}
|
||||||
requests.post(callback_url, json={**status, **callback_body})
|
requests.post(callback_url, json={**status, **callback_body})
|
||||||
@ -71,4 +74,3 @@ def simple_download():
|
|||||||
requests.post(callback_url, json={**status, **callback_body})
|
requests.post(callback_url, json={**status, **callback_body})
|
||||||
print(f"finished! sending to {callback_url}")
|
print(f"finished! sending to {callback_url}")
|
||||||
pprint({**status, **callback_body})
|
pprint({**status, **callback_body})
|
||||||
|
|
@ -15,4 +15,5 @@ config = {
|
|||||||
"folder_path": "checkpoints",
|
"folder_path": "checkpoints",
|
||||||
},
|
},
|
||||||
"civitai_api_key": "",
|
"civitai_api_key": "",
|
||||||
|
"app_name": "",
|
||||||
}
|
}
|
12
builder/modal-builder/src/volume_builder/runner.py
Normal file
12
builder/modal-builder/src/volume_builder/runner.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import modal
|
||||||
|
import requests
|
||||||
|
from app import stub
|
||||||
|
from config import config
|
||||||
|
|
||||||
|
modal.runner.deploy_stub(stub)
|
||||||
|
print("deployed stub")
|
||||||
|
# web_url = stub["simple_download"].web_url
|
||||||
|
f = modal.Function.lookup(config['app_name'], "simple_download")
|
||||||
|
f.spawn()
|
||||||
|
# print(f"web_url: {web_url}")
|
||||||
|
# requests.post(web_url)
|
@ -7,6 +7,13 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||||||
import { InsertModal } from "./InsertModal";
|
import { InsertModal } from "./InsertModal";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -30,9 +37,9 @@ import {
|
|||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
import { ArrowUpDown } from "lucide-react";
|
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { addModel } from "@/server/curdModel";
|
import { addModel, deleteModel } from "@/server/curdModel";
|
||||||
import { downloadUrlModelSchema } from "@/server/addCivitaiModelSchema";
|
import { downloadUrlModelSchema } from "@/server/addCivitaiModelSchema";
|
||||||
import { modelEnumType } from "@/db/schema";
|
import { modelEnumType } from "@/db/schema";
|
||||||
|
|
||||||
@ -192,10 +199,16 @@ export const columns: ColumnDef<ModelItemList>[] = [
|
|||||||
lora: "green",
|
lora: "green",
|
||||||
embedding: "violet",
|
embedding: "violet",
|
||||||
vae: "teal",
|
vae: "teal",
|
||||||
|
clip: "default",
|
||||||
|
clip_vision: "default",
|
||||||
|
configs: "default",
|
||||||
|
controlnet: "default",
|
||||||
|
upscale_models: "default",
|
||||||
|
ipadapter: "default",
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBadgeColor(modelType: modelEnumType) {
|
function getBadgeColor(modelType: modelEnumType) {
|
||||||
return model_type_map[modelType] || "default";
|
return model_type_map[modelType]
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = getBadgeColor(row.original.model_type);
|
const color = getBadgeColor(row.original.model_type);
|
||||||
@ -225,35 +238,35 @@ export const columns: ColumnDef<ModelItemList>[] = [
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
// TODO: deletion and editing for future sprint
|
// TODO: deletion and editing for future sprint
|
||||||
// {
|
{
|
||||||
// id: "actions",
|
id: "actions",
|
||||||
// enableHiding: false,
|
enableHiding: false,
|
||||||
// cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
// const checkpoint = row.original;
|
const model = row.original;
|
||||||
//
|
|
||||||
// return (
|
return (
|
||||||
// <DropdownMenu>
|
<DropdownMenu>
|
||||||
// <DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
// <Button variant="ghost" className="h-8 w-8 p-0">
|
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||||
// <span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
// <MoreHorizontal className="h-4 w-4" />
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
// </Button>
|
</Button>
|
||||||
// </DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
// <DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
// <DropdownMenuLabel>Actions</DropdownMenuLabel>
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
// <DropdownMenuItem
|
<DropdownMenuItem
|
||||||
// className="text-destructive"
|
className="text-destructive"
|
||||||
// onClick={() => {
|
onClick={() => {
|
||||||
// deleteWorkflow(checkpoint.id);
|
deleteModel(model.id);
|
||||||
// }}
|
}}
|
||||||
// >
|
>
|
||||||
// Delete Workflow
|
Delete Model
|
||||||
// </DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
// </DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
// </DropdownMenu>
|
</DropdownMenu>
|
||||||
// );
|
);
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function ModelList({ data }: { data: ModelItemList[] }) {
|
export function ModelList({ data }: { data: ModelItemList[] }) {
|
||||||
|
@ -7,10 +7,10 @@ import {
|
|||||||
jsonb,
|
jsonb,
|
||||||
pgEnum,
|
pgEnum,
|
||||||
pgSchema,
|
pgSchema,
|
||||||
|
real,
|
||||||
text,
|
text,
|
||||||
timestamp,
|
timestamp,
|
||||||
uuid,
|
uuid,
|
||||||
real,
|
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
import { TypeOf, z } from "zod";
|
import { TypeOf, z } from "zod";
|
||||||
@ -150,8 +150,9 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
|
|||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
workflow_inputs:
|
workflow_inputs: jsonb("workflow_inputs").$type<
|
||||||
jsonb("workflow_inputs").$type<Record<string, string | number>>(),
|
Record<string, string | number>
|
||||||
|
>(),
|
||||||
workflow_id: uuid("workflow_id")
|
workflow_id: uuid("workflow_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => workflowTable.id, {
|
.references(() => workflowTable.id, {
|
||||||
@ -298,8 +299,9 @@ export const deploymentsTable = dbSchema.table("deployments", {
|
|||||||
.references(() => machinesTable.id),
|
.references(() => machinesTable.id),
|
||||||
share_slug: text("share_slug").unique(),
|
share_slug: text("share_slug").unique(),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
showcase_media:
|
showcase_media: jsonb("showcase_media").$type<
|
||||||
jsonb("showcase_media").$type<z.infer<typeof showcaseMedia>>(),
|
z.infer<typeof showcaseMedia>
|
||||||
|
>(),
|
||||||
environment: deploymentEnvironment("environment").notNull(),
|
environment: deploymentEnvironment("environment").notNull(),
|
||||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||||
@ -389,7 +391,18 @@ export const modelUploadType = pgEnum("model_upload_type", [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// https://www.answeroverflow.com/m/1125106227387584552
|
// https://www.answeroverflow.com/m/1125106227387584552
|
||||||
export const modelTypes = ["checkpoint", "lora", "embedding", "vae"] as const;
|
export const modelTypes = [
|
||||||
|
"checkpoint",
|
||||||
|
"lora",
|
||||||
|
"embedding",
|
||||||
|
"vae",
|
||||||
|
"clip",
|
||||||
|
"clip_vision",
|
||||||
|
"configs",
|
||||||
|
"controlnet",
|
||||||
|
"upscale_models",
|
||||||
|
"ipadapter",
|
||||||
|
] as const;
|
||||||
export const modelType = pgEnum("model_type", modelTypes);
|
export const modelType = pgEnum("model_type", modelTypes);
|
||||||
export type modelEnumType = (typeof modelTypes)[number];
|
export type modelEnumType = (typeof modelTypes)[number];
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
import { withServerPromise } from "./withServerPromise";
|
import { withServerPromise } from "./withServerPromise";
|
||||||
import { db } from "@/db/db";
|
import { db } from "@/db/db";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { downloadUrlModelSchema } from "./addCivitaiModelSchema";
|
import { downloadUrlModelSchema } from "./addCivitaiModelSchema";
|
||||||
import { and, eq, isNull } from "drizzle-orm";
|
import { and, eq, isNull } from "drizzle-orm";
|
||||||
@ -210,6 +211,47 @@ export const addModelDownloadUrl = withServerPromise(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const deleteModel = withServerPromise(
|
||||||
|
async (modelId: string) => {
|
||||||
|
const model = await db.query.modelTable.findFirst({
|
||||||
|
where: eq(modelTable.id, modelId),
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the model does not exist, throw an error or return a message
|
||||||
|
if (!model) {
|
||||||
|
throw new Error("Model not found");
|
||||||
|
// Or return { error: "Model not found" }; if you prefer to handle it without throwing
|
||||||
|
}
|
||||||
|
|
||||||
|
const volumes = await retrieveModelVolumes();
|
||||||
|
if (
|
||||||
|
model.status === "success" && !!model.folder_path && !!model.model_name
|
||||||
|
) {
|
||||||
|
const result = await fetch(
|
||||||
|
`${process.env.MODAL_BUILDER_URL!}/delete-volume-model`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
volume_name: volumes[0].volume_name,
|
||||||
|
path: model.folder_path,
|
||||||
|
file_name: model.model_name,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!result.ok) {
|
||||||
|
const error_log = await result.text();
|
||||||
|
throw new Error(`Error: ${result.statusText} ${error_log}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await db.delete(modelTable).where(eq(modelTable.id, modelId));
|
||||||
|
revalidatePath("/storage");
|
||||||
|
return { message: "Model Deleted" };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const getCivitaiModelRes = async (civitaiUrl: string) => {
|
export const getCivitaiModelRes = async (civitaiUrl: string) => {
|
||||||
const { url, modelVersionId } = getUrl(civitaiUrl);
|
const { url, modelVersionId } = getUrl(civitaiUrl);
|
||||||
const civitaiModelRes = await fetch(url)
|
const civitaiModelRes = await fetch(url)
|
||||||
@ -301,8 +343,8 @@ export const addCivitaiModel = withServerPromise(
|
|||||||
model_name: selectedModelVersion.files[0].name,
|
model_name: selectedModelVersion.files[0].name,
|
||||||
civitai_id: civitaiModelRes.id.toString(),
|
civitai_id: civitaiModelRes.id.toString(),
|
||||||
civitai_version_id: selectedModelVersionId,
|
civitai_version_id: selectedModelVersionId,
|
||||||
civitai_url: data.url, // TODO: need to confirm
|
civitai_url: data.url,
|
||||||
civitai_download_url: selectedModelVersion.files[0].downloadUrl,
|
civitai_download_url: selectedModelVersion.files[0].downloadUrl, // there is an issue when a model hoster might put multiple different types of files i.e. their training data.
|
||||||
civitai_model_response: civitaiModelRes,
|
civitai_model_response: civitaiModelRes,
|
||||||
user_volume_id: volumes[0].id,
|
user_volume_id: volumes[0].id,
|
||||||
model_type,
|
model_type,
|
||||||
@ -312,6 +354,7 @@ export const addCivitaiModel = withServerPromise(
|
|||||||
const b = a[0];
|
const b = a[0];
|
||||||
|
|
||||||
await uploadModel(data, b, volumes[0]);
|
await uploadModel(data, b, volumes[0]);
|
||||||
|
revalidatePath("/storage");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user