feat(model-manager): add CivitAI browse view + fix civitai.red / 401
- New "Browse CivitAI" view: thumbnail grid with search, type/sort/period filters and NSFW toggle; click a model card to download it (per-card version picker for multi-version models). Cursor + page based "Load more". - Backend: /api/civitai/search and /api/civitai/download endpoints; new civitai_search() catalog helper. - Fix 401 on paste: recognize the civitai.red mirror (and any civitai.* host), normalize API calls to civitai.com, and always resolve the model-version so type + filename are auto-detected for every CivitAI URL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,39 @@ async def start_download(body: DownloadIn) -> dict:
|
||||
return row or {"id": download_id}
|
||||
|
||||
|
||||
# ---- CivitAI catalog browse ----------------------------------------------
|
||||
|
||||
@app.get("/api/civitai/search")
|
||||
async def civitai_search(
|
||||
query: Optional[str] = None,
|
||||
types: Optional[str] = None, # comma-separated CivitAI types
|
||||
sort: Optional[str] = "Most Downloaded",
|
||||
period: Optional[str] = "AllTime",
|
||||
nsfw: bool = False,
|
||||
page: Optional[int] = None,
|
||||
cursor: Optional[str] = None,
|
||||
) -> dict:
|
||||
if not db.get_setting("civitai_api_key"):
|
||||
raise HTTPException(400, "Set your CivitAI API key in Settings first.")
|
||||
type_list = [t for t in (types or "").split(",") if t] or None
|
||||
try:
|
||||
return await registries.civitai_search(
|
||||
query=query, types=type_list, sort=sort, period=period,
|
||||
nsfw=nsfw, page=page, cursor=cursor)
|
||||
except Exception as exc: # noqa: BLE001 - surface API errors to the UI
|
||||
raise HTTPException(502, f"CivitAI search failed: {exc}")
|
||||
|
||||
|
||||
class CivitaiDownloadIn(BaseModel):
|
||||
version_id: int
|
||||
|
||||
|
||||
@app.post("/api/civitai/download")
|
||||
async def civitai_download(body: CivitaiDownloadIn) -> dict:
|
||||
url = f"https://civitai.com/api/download/models/{body.version_id}"
|
||||
return await start_download(DownloadIn(url=url))
|
||||
|
||||
|
||||
@app.delete("/api/downloads/{download_id}")
|
||||
def delete_download(download_id: int) -> dict:
|
||||
row = db.get_download(download_id)
|
||||
|
||||
Reference in New Issue
Block a user