Instructions to use saik0s/comfy_backup with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- llama-cpp-python
How to use saik0s/comfy_backup with llama-cpp-python:
# !pip install llama-cpp-python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="saik0s/comfy_backup", filename="ComfyUI/models/text_encoders/gemma-3-12b-it-q2_k.gguf", )
llm.create_chat_completion( messages = "No input example has been defined for this model task." )
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use saik0s/comfy_backup with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf saik0s/comfy_backup:Q4_K_S # Run inference directly in the terminal: llama cli -hf saik0s/comfy_backup:Q4_K_S
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf saik0s/comfy_backup:Q4_K_S # Run inference directly in the terminal: llama cli -hf saik0s/comfy_backup:Q4_K_S
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf saik0s/comfy_backup:Q4_K_S # Run inference directly in the terminal: ./llama-cli -hf saik0s/comfy_backup:Q4_K_S
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf saik0s/comfy_backup:Q4_K_S # Run inference directly in the terminal: ./build/bin/llama-cli -hf saik0s/comfy_backup:Q4_K_S
Use Docker
docker model run hf.co/saik0s/comfy_backup:Q4_K_S
- LM Studio
- Jan
- Ollama
How to use saik0s/comfy_backup with Ollama:
ollama run hf.co/saik0s/comfy_backup:Q4_K_S
- Unsloth Studio
How to use saik0s/comfy_backup with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for saik0s/comfy_backup to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for saik0s/comfy_backup to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for saik0s/comfy_backup to start chatting
- Pi
How to use saik0s/comfy_backup with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf saik0s/comfy_backup:Q4_K_S
Configure the model in Pi
# Install Pi: npm install -g @mariozechner/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "saik0s/comfy_backup:Q4_K_S" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Hermes Agent new
How to use saik0s/comfy_backup with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf saik0s/comfy_backup:Q4_K_S
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default saik0s/comfy_backup:Q4_K_S
Run Hermes
hermes
- Atomic Chat new
- OpenClaw new
How to use saik0s/comfy_backup with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf saik0s/comfy_backup:Q4_K_S
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "saik0s/comfy_backup:Q4_K_S" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
- Docker Model Runner
How to use saik0s/comfy_backup with Docker Model Runner:
docker model run hf.co/saik0s/comfy_backup:Q4_K_S
- Lemonade
How to use saik0s/comfy_backup with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull saik0s/comfy_backup:Q4_K_S
Run and chat with the model
lemonade run user.comfy_backup-Q4_K_S
List all available models
lemonade list
| import { app } from "../../../scripts/app.js"; | |
| import { api } from "../../../scripts/api.js"; | |
| import { $el } from "../../../scripts/ui.js"; | |
| import { ModelInfoDialog } from "./common/modelInfoDialog.js"; | |
| const MAX_TAGS = 500; | |
| const NsfwLevel = { | |
| PG: 1, | |
| PG13: 2, | |
| R: 4, | |
| X: 8, | |
| XXX: 16, | |
| Blocked: 32, | |
| }; | |
| export class LoraInfoDialog extends ModelInfoDialog { | |
| getTagFrequency() { | |
| if (!this.metadata.ss_tag_frequency) return []; | |
| const datasets = JSON.parse(this.metadata.ss_tag_frequency); | |
| const tags = {}; | |
| for (const setName in datasets) { | |
| const set = datasets[setName]; | |
| for (const t in set) { | |
| if (t in tags) { | |
| tags[t] += set[t]; | |
| } else { | |
| tags[t] = set[t]; | |
| } | |
| } | |
| } | |
| return Object.entries(tags).sort((a, b) => b[1] - a[1]); | |
| } | |
| getResolutions() { | |
| let res = []; | |
| if (this.metadata.ss_bucket_info) { | |
| const parsed = JSON.parse(this.metadata.ss_bucket_info); | |
| if (parsed?.buckets) { | |
| for (const { resolution, count } of Object.values(parsed.buckets)) { | |
| res.push([count, `${resolution.join("x")} * ${count}`]); | |
| } | |
| } | |
| } | |
| res = res.sort((a, b) => b[0] - a[0]).map((a) => a[1]); | |
| let r = this.metadata.ss_resolution; | |
| if (r) { | |
| const s = r.split(","); | |
| const w = s[0].replace("(", ""); | |
| const h = s[1].replace(")", ""); | |
| res.push(`${w.trim()}x${h.trim()} (Base res)`); | |
| } else if ((r = this.metadata["modelspec.resolution"])) { | |
| res.push(r + " (Base res"); | |
| } | |
| if (!res.length) { | |
| res.push("⚠️ Unknown"); | |
| } | |
| return res; | |
| } | |
| getTagList(tags) { | |
| return tags.map((t) => | |
| $el( | |
| "li.pysssss-model-tag", | |
| { | |
| dataset: { | |
| tag: t[0], | |
| }, | |
| $: (el) => { | |
| el.onclick = () => { | |
| el.classList.toggle("pysssss-model-tag--selected"); | |
| }; | |
| }, | |
| }, | |
| [ | |
| $el("p", { | |
| textContent: t[0], | |
| }), | |
| $el("span", { | |
| textContent: t[1], | |
| }), | |
| ] | |
| ) | |
| ); | |
| } | |
| addTags() { | |
| let tags = this.getTagFrequency(); | |
| if (!tags?.length) { | |
| tags = this.metadata["modelspec.tags"]?.split(",").map((t) => [t.trim(), 1]); | |
| } | |
| let hasMore; | |
| if (tags?.length) { | |
| const c = tags.length; | |
| let list; | |
| if (c > MAX_TAGS) { | |
| tags = tags.slice(0, MAX_TAGS); | |
| hasMore = $el("p", [ | |
| $el("span", { textContent: `⚠️ Only showing first ${MAX_TAGS} tags ` }), | |
| $el("a", { | |
| href: "#", | |
| textContent: `Show all ${c}`, | |
| onclick: () => { | |
| list.replaceChildren(...this.getTagList(this.getTagFrequency())); | |
| hasMore.remove(); | |
| }, | |
| }), | |
| ]); | |
| } | |
| list = $el("ol.pysssss-model-tags-list", this.getTagList(tags)); | |
| this.tags = $el("div", [list]); | |
| } else { | |
| this.tags = $el("p", { textContent: "⚠️ No tag frequency metadata found" }); | |
| } | |
| this.content.append(this.tags); | |
| if (hasMore) { | |
| this.content.append(hasMore); | |
| } | |
| } | |
| addExample(title, value, name) { | |
| const textArea = $el("textarea", { | |
| textContent: value, | |
| style: { | |
| whiteSpace: "pre-wrap", | |
| margin: "10px 0", | |
| color: "#fff", | |
| background: "#222", | |
| padding: "5px", | |
| borderRadius: "5px", | |
| maxHeight: "250px", | |
| overflow: "auto", | |
| display: "block", | |
| border: "none", | |
| width: "calc(100% - 10px)", | |
| }, | |
| }); | |
| $el( | |
| "p", | |
| { | |
| parent: this.content, | |
| textContent: `${title}: `, | |
| }, | |
| [ | |
| textArea, | |
| $el("button", { | |
| onclick: async () => { | |
| await this.saveAsExample(textArea.value, `${name}.txt`); | |
| }, | |
| textContent: "Save as Example", | |
| style: { | |
| fontSize: "14px", | |
| }, | |
| }), | |
| $el("hr"), | |
| ] | |
| ); | |
| } | |
| async addInfo() { | |
| this.addInfoEntry("Name", this.metadata.ss_output_name || "⚠️ Unknown"); | |
| this.addInfoEntry("Base Model", this.metadata.ss_sd_model_name || "⚠️ Unknown"); | |
| this.addInfoEntry("Clip Skip", this.metadata.ss_clip_skip || "⚠️ Unknown"); | |
| this.addInfoEntry( | |
| "Resolution", | |
| $el( | |
| "select", | |
| this.getResolutions().map((r) => $el("option", { textContent: r })) | |
| ) | |
| ); | |
| super.addInfo(); | |
| const p = this.addCivitaiInfo(); | |
| this.addTags(); | |
| const info = await p; | |
| this.addExample("Trained Words", info?.trainedWords?.join(", ") ?? "", "trainedwords"); | |
| const triggerPhrase = this.metadata["modelspec.trigger_phrase"]; | |
| if (triggerPhrase) { | |
| this.addExample("Trigger Phrase", triggerPhrase, "triggerphrase"); | |
| } | |
| $el("div", { | |
| parent: this.content, | |
| innerHTML: info?.description ?? this.metadata["modelspec.description"] ?? "[No description provided]", | |
| style: { | |
| maxHeight: "250px", | |
| overflow: "auto", | |
| }, | |
| }); | |
| } | |
| async saveAsExample(example, name = "example.txt") { | |
| if (!example.length) { | |
| return; | |
| } | |
| try { | |
| name = prompt("Enter example name", name); | |
| if (!name) return; | |
| await api.fetchApi("/pysssss/examples/" + encodeURIComponent(`${this.type}/${this.name}`), { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| name, | |
| example, | |
| }), | |
| headers: { | |
| "content-type": "application/json", | |
| }, | |
| }); | |
| this.node?.["pysssss.updateExamples"]?.(); | |
| alert("Saved!"); | |
| } catch (error) { | |
| console.error(error); | |
| alert("Error saving: " + error); | |
| } | |
| } | |
| createButtons() { | |
| const btns = super.createButtons(); | |
| function tagsToCsv(tags) { | |
| return tags.map((el) => el.dataset.tag).join(", "); | |
| } | |
| function copyTags(e, tags) { | |
| const textarea = $el("textarea", { | |
| parent: document.body, | |
| style: { | |
| position: "fixed", | |
| }, | |
| textContent: tagsToCsv(tags), | |
| }); | |
| textarea.select(); | |
| try { | |
| document.execCommand("copy"); | |
| if (!e.target.dataset.text) { | |
| e.target.dataset.text = e.target.textContent; | |
| } | |
| e.target.textContent = "Copied " + tags.length + " tags"; | |
| setTimeout(() => { | |
| e.target.textContent = e.target.dataset.text; | |
| }, 1000); | |
| } catch (ex) { | |
| prompt("Copy to clipboard: Ctrl+C, Enter", text); | |
| } finally { | |
| document.body.removeChild(textarea); | |
| } | |
| } | |
| btns.unshift( | |
| $el("button", { | |
| type: "button", | |
| textContent: "Save Selected as Example", | |
| onclick: async (e) => { | |
| const tags = tagsToCsv([...this.tags.querySelectorAll(".pysssss-model-tag--selected")]); | |
| await this.saveAsExample(tags); | |
| }, | |
| }), | |
| $el("button", { | |
| type: "button", | |
| textContent: "Copy Selected", | |
| onclick: (e) => { | |
| copyTags(e, [...this.tags.querySelectorAll(".pysssss-model-tag--selected")]); | |
| }, | |
| }), | |
| $el("button", { | |
| type: "button", | |
| textContent: "Copy All", | |
| onclick: (e) => { | |
| copyTags(e, [...this.tags.querySelectorAll(".pysssss-model-tag")]); | |
| }, | |
| }) | |
| ); | |
| return btns; | |
| } | |
| } | |
| class CheckpointInfoDialog extends ModelInfoDialog { | |
| async addInfo() { | |
| super.addInfo(); | |
| const info = await this.addCivitaiInfo(); | |
| if (info) { | |
| this.addInfoEntry("Base Model", info.baseModel || "⚠️ Unknown"); | |
| $el("div", { | |
| parent: this.content, | |
| innerHTML: info.description, | |
| style: { | |
| maxHeight: "250px", | |
| overflow: "auto", | |
| }, | |
| }); | |
| } | |
| } | |
| } | |
| const lookups = {}; | |
| function addInfoOption(node, type, infoClass, widgetNamePattern, opts) { | |
| const widgets = widgetNamePattern | |
| ? node.widgets.filter((w) => w.name === widgetNamePattern || w.name.match(`^${widgetNamePattern}$`)) | |
| : [node.widgets[0]]; | |
| for (const widget of widgets) { | |
| let value = widget.value; | |
| if (value?.content) { | |
| value = value.content; | |
| } | |
| if (!value || value === "None") { | |
| return; | |
| } | |
| let optName; | |
| const split = value.split(/[.\\/]/); | |
| optName = split[split.length - 2]; | |
| opts.push({ | |
| content: optName, | |
| callback: async () => { | |
| new infoClass(value, node).show(type, value); | |
| }, | |
| }); | |
| } | |
| } | |
| function addTypeOptions(node, typeName, options) { | |
| const type = typeName.toLowerCase() + "s"; | |
| const values = lookups[typeName][node.type]; | |
| if (!values) return; | |
| const widgets = Object.keys(values); | |
| const cls = type === "loras" ? LoraInfoDialog : CheckpointInfoDialog; | |
| const opts = []; | |
| for (const w of widgets) { | |
| addInfoOption(node, type, cls, w, opts); | |
| } | |
| if (!opts.length) return; | |
| if (opts.length === 1) { | |
| opts[0].content = `View ${typeName} info...`; | |
| options.unshift(opts[0]); | |
| } else { | |
| options.unshift({ | |
| title: `View ${typeName} info...`, | |
| has_submenu: true, | |
| submenu: { | |
| options: opts, | |
| }, | |
| }); | |
| } | |
| } | |
| app.registerExtension({ | |
| name: "pysssss.ModelInfo", | |
| setup() { | |
| const addSetting = (type, defaultValue) => { | |
| app.ui.settings.addSetting({ | |
| id: `pysssss.ModelInfo.${type}Nodes`, | |
| name: `🐍 Model Info - ${type} Nodes/Widgets`, | |
| type: "text", | |
| defaultValue, | |
| tooltip: `Comma separated list of NodeTypeName or NodeTypeName.WidgetName that contain ${type} node names that should have the View Info option available.\nIf no widget name is specifed the first widget will be used. Regex matches (e.g. NodeName..*lora_\\d+) are supported in the widget name.`, | |
| onChange(value) { | |
| lookups[type] = value.split(",").reduce((p, n) => { | |
| n = n.trim(); | |
| const pos = n.indexOf("."); | |
| const split = pos === -1 ? [n] : [n.substring(0, pos), n.substring(pos + 1)]; | |
| p[split[0]] ??= {}; | |
| p[split[0]][split[1] ?? ""] = true; | |
| return p; | |
| }, {}); | |
| }, | |
| }); | |
| }; | |
| addSetting( | |
| "Lora", | |
| ["LoraLoader.lora_name", "LoraLoader|pysssss", "LoraLoaderModelOnly.lora_name", "LoRA Stacker.lora_name.*"].join(",") | |
| ); | |
| addSetting( | |
| "Checkpoint", | |
| ["CheckpointLoader.ckpt_name", "CheckpointLoaderSimple", "CheckpointLoader|pysssss", "Efficient Loader", "Eff. Loader SDXL"].join(",") | |
| ); | |
| app.ui.settings.addSetting({ | |
| id: `pysssss.ModelInfo.NsfwLevel`, | |
| name: `🐍 Model Info - Image Preview Max NSFW Level`, | |
| type: "combo", | |
| defaultValue: "PG13", | |
| options: Object.keys(NsfwLevel), | |
| tooltip: `Hides preview images that are tagged as a higher NSFW level`, | |
| onChange(value) { | |
| ModelInfoDialog.nsfwLevel = NsfwLevel[value] ?? NsfwLevel.PG; | |
| }, | |
| }); | |
| }, | |
| beforeRegisterNodeDef(nodeType) { | |
| const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions; | |
| nodeType.prototype.getExtraMenuOptions = function (_, options) { | |
| if (this.widgets) { | |
| for (const type in lookups) { | |
| addTypeOptions(this, type, options); | |
| } | |
| } | |
| return getExtraMenuOptions?.apply(this, arguments); | |
| }; | |
| }, | |
| }); | |