BUG FIX: Civitai API key token added to a url with existing query string.
- Also updated README.
This commit is contained in:
78
README.md
78
README.md
@@ -15,9 +15,9 @@ I made this fork because the original repo was inactive and missing many things
|
||||
|
||||
### Download Tab
|
||||
|
||||
- View multiple models associated to a url.
|
||||
- Select download directory.
|
||||
- Optionally download default or custom preview image.
|
||||
- View multiple models associated with a url.
|
||||
- Select a download directory.
|
||||
- Optionally also download a model preview image (a default image along side the model, from another url or locally uploaded).
|
||||
- Civitai and HuggingFace API token configurable in `server_settings.yaml`.
|
||||
|
||||
### Models Tab
|
||||
@@ -29,12 +29,12 @@ I made this fork because the original repo was inactive and missing many things
|
||||
- Include models listed in ComfyUI's `extra_model_paths.yaml` or added in `ComfyUI/models`.
|
||||
- Sort for models (Date Created, Date Modified, Name).
|
||||
|
||||
### Model Info
|
||||
### Model Info View
|
||||
|
||||
- View model metadata, including training tags and bucket resolutions.
|
||||
- Delete or move a model.
|
||||
- Read, edit and save notes in a `.txt` file beside the model.
|
||||
- Change or remove preview image with a file upload or a url.
|
||||
- Change or remove a model's preview image (add a different one using a url or local upload).
|
||||
- Move or **permanently** remove models.
|
||||
|
||||
### ComfyUI Node Graph
|
||||
|
||||
@@ -47,62 +47,56 @@ I made this fork because the original repo was inactive and missing many things
|
||||
|
||||
### Settings Tab
|
||||
|
||||
- Change colors using ComfyUI's theme colors.
|
||||
- Settings tab saved in `ui_settings.yaml`.
|
||||
- Hide/Show 'add' and 'copy-to-clipboard' buttons.
|
||||
- Text to always search.
|
||||
- Show/Hide add embedding extension.
|
||||
- Colors follow ComfyUI's current theme.
|
||||
|
||||
## TODO
|
||||
|
||||
### Code
|
||||
|
||||
- Javascript cleanup.
|
||||
- Seperate into classes per tab?
|
||||
- HTML generation all inside main class?
|
||||
- More server driven, HTMX-like HTML generation? (Avoid x2 states)
|
||||
|
||||
### Model Copying
|
||||
|
||||
- Copy model path?
|
||||
|
||||
### Download Model Info
|
||||
|
||||
- Optional (re)download `📥︎` model info from the internet and cache the text file locally. (requires checksum?)
|
||||
- Radio buttons to swap between downloaded and server view.
|
||||
|
||||
### Sidebar
|
||||
|
||||
- Drag sidebar width/height dynamically.
|
||||
|
||||
### Accessibility
|
||||
|
||||
- Proper naming, labeling, alt text, etc. for html elements.
|
||||
- Tool tips.
|
||||
- Better error messages.
|
||||
|
||||
### Image preview
|
||||
|
||||
- Better placeholder preview. (with proper spelling!)
|
||||
- Show preview images for videos.
|
||||
- If ffmpeg or cv2 available, extract the first frame of the video and use as image preview.
|
||||
|
||||
### Settings
|
||||
|
||||
- Exclude hidden folders with a `.` prefix.
|
||||
- Enable optional checksum to detect if a model is already downloaded.
|
||||
- Sidebar width/height.
|
||||
- Toggle exclusion of "hidden folders" with a `.` prefix.
|
||||
- Sidebar default width/height.
|
||||
- Toggle non-uniform preview sizes. (How to handle extreme aspect ratios?)
|
||||
|
||||
### Search filtering and sort
|
||||
|
||||
- Real-time search
|
||||
- Check search code is optimized to avoid recalculation on every minor input change
|
||||
- Directory dropdown
|
||||
- Use always filter to filter directory content auto-suggest dropdown
|
||||
- Filter directory dropdown
|
||||
- Filter directory content in auto-suggest dropdown (not clear how this should be implemented)
|
||||
- Filters dropdown
|
||||
- Stable Diffusion model version/Clip/Upscale/?
|
||||
- Stable Diffusion model version, if applicable
|
||||
- Favorites
|
||||
- Sort-by dropdown
|
||||
- Recently used (ascending/decending)
|
||||
- Frequently used (ascending/decending)
|
||||
- `or` vs `and` type of keyword search (currently `and`)
|
||||
- Swap between `and` and `or` keyword search? (currently `and`)
|
||||
|
||||
### Image preview
|
||||
### Code
|
||||
|
||||
- Support multiple preview images. (swipe?)
|
||||
- Show preview images for videos.
|
||||
- If ffmpeg or cv2 available, extract the first frame of the video and use as image preview.
|
||||
- Play preview video?
|
||||
|
||||
### Accessibility
|
||||
|
||||
- Proper naming and labeling.
|
||||
- Tool tips?
|
||||
|
||||
### Sidebar
|
||||
|
||||
- Drag sidebar width/height dynamically.
|
||||
- Javascript cleanup.
|
||||
- Better abstraction and objectification. (After codebase settles down)
|
||||
- Separate into classes per tab?
|
||||
- HTML generation all inside main class?
|
||||
- More server driven, HTMX-like HTML generation? (Avoid x2 states)
|
||||
|
||||
12
__init__.py
12
__init__.py
@@ -409,14 +409,18 @@ def download_file(url, filename, overwrite):
|
||||
api_key = server_settings["civitai_api_key"]
|
||||
if (api_key != ""):
|
||||
def_headers["Authorization"] = f"Bearer {api_key}"
|
||||
url = url + f"?token={api_key}" # TODO: Authorization didn't work in the header
|
||||
url += "&" if "?" in url else "?" # not the most robust solution
|
||||
url += f"token={api_key}" # TODO: Authorization didn't work in the header
|
||||
elif url.startswith("https://huggingface.co/"):
|
||||
api_key = server_settings["huggingface_api_key"]
|
||||
if api_key != "":
|
||||
def_headers["Authorization"] = f"Bearer {api_key}"
|
||||
rh = requests.get(url=url, stream=True, verify=False, headers=def_headers, proxies=None, allow_redirects=False)
|
||||
if not rh.ok:
|
||||
raise ValueError("Unable to download")
|
||||
raise ValueError(
|
||||
"Unable to download! Request header status code: " +
|
||||
str(rh.status_code)
|
||||
)
|
||||
|
||||
downloaded_size = 0
|
||||
if rh.status_code == 200 and os.path.exists(filename_temp):
|
||||
@@ -432,7 +436,7 @@ def download_file(url, filename, overwrite):
|
||||
if not redirect_url.startswith("http"):
|
||||
# Civitai requires login (NSFW or user-required)
|
||||
# TODO: inform user WHY download failed
|
||||
raise ValueError("Unable to download!")
|
||||
raise ValueError("Unable to download from Civitai! Redirect url: " + str(redirect_url))
|
||||
download_file(redirect_url, filename, overwrite)
|
||||
return
|
||||
if rh.status_code == 302 and r.status_code == 302:
|
||||
@@ -440,7 +444,7 @@ def download_file(url, filename, overwrite):
|
||||
redirect_url = r.content.decode("utf-8")
|
||||
redirect_url_index = redirect_url.find("http")
|
||||
if redirect_url_index == -1:
|
||||
raise ValueError("Unable to download!")
|
||||
raise ValueError("Unable to download from HuggingFace! Redirect url: " + str(redirect_url))
|
||||
download_file(redirect_url[redirect_url_index:], filename, overwrite)
|
||||
return
|
||||
elif rh.status_code == 200 and r.status_code == 206:
|
||||
|
||||
@@ -121,11 +121,17 @@ function modelTypeToComfyUiDirectory(modelType, fileType) {
|
||||
* @param {string} id - Model ID.
|
||||
* @param {string} apiPath - Civitai request subdirectory. "models" for 'model' urls. "model-version" for 'api' urls.
|
||||
*
|
||||
* @returns {Object} Dictionary containing recieved model info. Returns an empty if fails.
|
||||
* @returns {Promise<Object>} Dictionary containing recieved model info. Returns an empty if fails.
|
||||
*/
|
||||
async function civitai_requestInfo(id, apiPath) {
|
||||
const url = "https://civitai.com/api/v1/" + apiPath + "/" + id;
|
||||
return await request(url);
|
||||
try {
|
||||
return await request(url);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Failed to get model info from Civitai!", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +192,7 @@ function civitai_getModelFilesInfo(modelVersionInfo, type = null, fp = null, siz
|
||||
*
|
||||
* @param {string} stringUrl - Model url.
|
||||
*
|
||||
* @returns {Object} - Download information for the given url.
|
||||
* @returns {Promise<Object>} - Download information for the given url.
|
||||
*/
|
||||
async function civitai_getFilteredInfo(stringUrl) {
|
||||
const url = new URL(stringUrl);
|
||||
@@ -264,7 +270,13 @@ async function civitai_getFilteredInfo(stringUrl) {
|
||||
*/
|
||||
async function huggingFace_requestInfo(id, apiPath = "models") {
|
||||
const url = "https://huggingface.co/api/" + apiPath + "/" + id;
|
||||
return await request(url);
|
||||
try {
|
||||
return await request(url);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Failed to get model info from HuggingFace!", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1606,15 +1618,14 @@ class ModelManager extends ComfyDialog {
|
||||
/** @type {HTMLDivElement} */ modelInfoUrl: null,
|
||||
/** @type {HTMLDivElement} */ modelInfoOverwrite: null,
|
||||
/** @type {HTMLDivElement} */ modelInfos: null,
|
||||
modelInfoRadioGroup: null,
|
||||
modelInfoPreview: null,
|
||||
modelInfoDefaultUri: null,
|
||||
setAsPreviewButton: null,
|
||||
/** @type {HTMLDivElement} */ modelInfoRadioGroup: null,
|
||||
/** @type {HTMLDivElement} */ modelInfoPreview: null,
|
||||
/** @type {HTMLDivElement} */ modelInfoDefaultUri: null,
|
||||
/** @type {HTMLDivElement} */ setAsPreviewButton: null,
|
||||
|
||||
/** @type {HTMLDivElement} */ modelGrid: null,
|
||||
/** @type {HTMLSelectElement} */ modelTypeSelect: null,
|
||||
/** @type {HTMLSelectElement} */ modelSortSelect: null,
|
||||
/** @type {HTMLDivElement} */ //searchDirectoryDropdown: null,
|
||||
/** @type {HTMLInputElement} */ modelContentFilter: null,
|
||||
|
||||
/** @type {HTMLDivElement} */ sidebarButtons: null,
|
||||
@@ -1649,7 +1660,10 @@ class ModelManager extends ComfyDialog {
|
||||
/** @type {string} */
|
||||
#systemSeparator = null;
|
||||
|
||||
/** @type {Function} */
|
||||
#resetModelInfoPreview = () => {};
|
||||
|
||||
/** @type {Function} */
|
||||
#modelInfoDefaultIsChecked = () => { return false; };
|
||||
|
||||
constructor() {
|
||||
@@ -2161,7 +2175,7 @@ class ModelManager extends ComfyDialog {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} reloadData
|
||||
* @param {Promise<boolean>} reloadData
|
||||
*/
|
||||
async #settingsTab_reload(reloadData) {
|
||||
const data = await request("/model-manager/settings/load");
|
||||
|
||||
Reference in New Issue
Block a user