@soederpop/luca 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +71 -0
- package/README.md +78 -0
- package/bun.lock +2928 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-scaffolds.ts +154 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/update-introspection.ts +67 -0
- package/docs/CLI.md +335 -0
- package/docs/README.md +88 -0
- package/docs/TABLE-OF-CONTENTS.md +157 -0
- package/docs/apis/clients/elevenlabs.md +84 -0
- package/docs/apis/clients/graph.md +56 -0
- package/docs/apis/clients/openai.md +69 -0
- package/docs/apis/clients/rest.md +41 -0
- package/docs/apis/clients/websocket.md +107 -0
- package/docs/apis/features/agi/assistant.md +471 -0
- package/docs/apis/features/agi/assistants-manager.md +154 -0
- package/docs/apis/features/agi/claude-code.md +602 -0
- package/docs/apis/features/agi/conversation-history.md +352 -0
- package/docs/apis/features/agi/conversation.md +333 -0
- package/docs/apis/features/agi/docs-reader.md +121 -0
- package/docs/apis/features/agi/openai-codex.md +318 -0
- package/docs/apis/features/agi/openapi.md +138 -0
- package/docs/apis/features/agi/semantic-search.md +387 -0
- package/docs/apis/features/agi/skills-library.md +216 -0
- package/docs/apis/features/node/container-link.md +133 -0
- package/docs/apis/features/node/content-db.md +313 -0
- package/docs/apis/features/node/disk-cache.md +379 -0
- package/docs/apis/features/node/dns.md +651 -0
- package/docs/apis/features/node/docker.md +705 -0
- package/docs/apis/features/node/downloader.md +81 -0
- package/docs/apis/features/node/esbuild.md +59 -0
- package/docs/apis/features/node/file-manager.md +182 -0
- package/docs/apis/features/node/fs.md +581 -0
- package/docs/apis/features/node/git.md +330 -0
- package/docs/apis/features/node/google-auth.md +174 -0
- package/docs/apis/features/node/google-calendar.md +187 -0
- package/docs/apis/features/node/google-docs.md +151 -0
- package/docs/apis/features/node/google-drive.md +225 -0
- package/docs/apis/features/node/google-sheets.md +179 -0
- package/docs/apis/features/node/grep.md +290 -0
- package/docs/apis/features/node/helpers.md +135 -0
- package/docs/apis/features/node/ink.md +334 -0
- package/docs/apis/features/node/ipc-socket.md +260 -0
- package/docs/apis/features/node/json-tree.md +86 -0
- package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
- package/docs/apis/features/node/networking.md +281 -0
- package/docs/apis/features/node/nlp.md +133 -0
- package/docs/apis/features/node/opener.md +97 -0
- package/docs/apis/features/node/os.md +118 -0
- package/docs/apis/features/node/package-finder.md +402 -0
- package/docs/apis/features/node/postgres.md +212 -0
- package/docs/apis/features/node/proc.md +430 -0
- package/docs/apis/features/node/process-manager.md +210 -0
- package/docs/apis/features/node/python.md +278 -0
- package/docs/apis/features/node/repl.md +88 -0
- package/docs/apis/features/node/runpod.md +673 -0
- package/docs/apis/features/node/secure-shell.md +169 -0
- package/docs/apis/features/node/semantic-search.md +401 -0
- package/docs/apis/features/node/sqlite.md +211 -0
- package/docs/apis/features/node/telegram.md +254 -0
- package/docs/apis/features/node/tts.md +118 -0
- package/docs/apis/features/node/ui.md +703 -0
- package/docs/apis/features/node/vault.md +64 -0
- package/docs/apis/features/node/vm.md +84 -0
- package/docs/apis/features/node/window-manager.md +337 -0
- package/docs/apis/features/node/yaml-tree.md +85 -0
- package/docs/apis/features/node/yaml.md +176 -0
- package/docs/apis/features/web/asset-loader.md +47 -0
- package/docs/apis/features/web/container-link.md +133 -0
- package/docs/apis/features/web/esbuild.md +59 -0
- package/docs/apis/features/web/helpers.md +135 -0
- package/docs/apis/features/web/network.md +30 -0
- package/docs/apis/features/web/speech.md +55 -0
- package/docs/apis/features/web/vault.md +64 -0
- package/docs/apis/features/web/vm.md +84 -0
- package/docs/apis/features/web/voice.md +67 -0
- package/docs/apis/servers/express.md +127 -0
- package/docs/apis/servers/mcp.md +213 -0
- package/docs/apis/servers/websocket.md +99 -0
- package/docs/documentation-audit.md +134 -0
- package/docs/examples/content-db.md +77 -0
- package/docs/examples/disk-cache.md +83 -0
- package/docs/examples/docker.md +101 -0
- package/docs/examples/downloader.md +70 -0
- package/docs/examples/esbuild.md +80 -0
- package/docs/examples/file-manager.md +82 -0
- package/docs/examples/fs.md +83 -0
- package/docs/examples/git.md +85 -0
- package/docs/examples/google-auth.md +88 -0
- package/docs/examples/google-calendar.md +94 -0
- package/docs/examples/google-docs.md +82 -0
- package/docs/examples/google-drive.md +96 -0
- package/docs/examples/google-sheets.md +95 -0
- package/docs/examples/grep.md +85 -0
- package/docs/examples/ink-blocks.md +75 -0
- package/docs/examples/ink-renderer.md +41 -0
- package/docs/examples/ink.md +103 -0
- package/docs/examples/ipc-socket.md +103 -0
- package/docs/examples/json-tree.md +91 -0
- package/docs/examples/launcher-app-command-listener.md +120 -0
- package/docs/examples/networking.md +58 -0
- package/docs/examples/nlp.md +91 -0
- package/docs/examples/opener.md +78 -0
- package/docs/examples/os.md +72 -0
- package/docs/examples/package-finder.md +89 -0
- package/docs/examples/port-exposer.md +89 -0
- package/docs/examples/postgres.md +91 -0
- package/docs/examples/proc.md +81 -0
- package/docs/examples/process-manager.md +79 -0
- package/docs/examples/python.md +91 -0
- package/docs/examples/repl.md +93 -0
- package/docs/examples/runpod.md +119 -0
- package/docs/examples/secure-shell.md +92 -0
- package/docs/examples/sqlite.md +86 -0
- package/docs/examples/telegram.md +77 -0
- package/docs/examples/tts.md +86 -0
- package/docs/examples/ui.md +80 -0
- package/docs/examples/vault.md +70 -0
- package/docs/examples/vm.md +86 -0
- package/docs/examples/window-manager.md +125 -0
- package/docs/examples/yaml-tree.md +93 -0
- package/docs/examples/yaml.md +104 -0
- package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
- package/docs/ideas/container-use-api.md +9 -0
- package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
- package/docs/ideas/feature-stacks.md +22 -0
- package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
- package/docs/ideas/mcp-design.md +9 -0
- package/docs/ideas/web-container-debugging-feature.md +13 -0
- package/docs/introspection-audit.md +49 -0
- package/docs/introspection.md +154 -0
- package/docs/mcp/readme.md +162 -0
- package/docs/models.ts +38 -0
- package/docs/philosophy.md +85 -0
- package/docs/principles.md +7 -0
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
- package/docs/prompts/mcp-test-easy-command.md +27 -0
- package/docs/reports/assistant-bugs.md +38 -0
- package/docs/reports/attach-pattern-usage.md +18 -0
- package/docs/reports/code-audit-results.md +391 -0
- package/docs/reports/introspection-audit-tasks.md +378 -0
- package/docs/reports/luca-mcp-improvements.md +128 -0
- package/docs/scaffolds/client.md +140 -0
- package/docs/scaffolds/command.md +106 -0
- package/docs/scaffolds/endpoint.md +176 -0
- package/docs/scaffolds/feature.md +148 -0
- package/docs/scaffolds/server.md +187 -0
- package/docs/tasks/web-container-helper-discovery.md +71 -0
- package/docs/todos.md +1 -0
- package/docs/tutorials/01-getting-started.md +106 -0
- package/docs/tutorials/02-container.md +210 -0
- package/docs/tutorials/03-scripts.md +194 -0
- package/docs/tutorials/04-features-overview.md +196 -0
- package/docs/tutorials/05-state-and-events.md +171 -0
- package/docs/tutorials/06-servers.md +157 -0
- package/docs/tutorials/07-endpoints.md +198 -0
- package/docs/tutorials/08-commands.md +171 -0
- package/docs/tutorials/09-clients.md +162 -0
- package/docs/tutorials/10-creating-features.md +198 -0
- package/docs/tutorials/11-contentbase.md +191 -0
- package/docs/tutorials/12-assistants.md +215 -0
- package/docs/tutorials/13-introspection.md +147 -0
- package/docs/tutorials/14-type-system.md +174 -0
- package/docs/tutorials/15-project-patterns.md +222 -0
- package/docs/tutorials/16-google-features.md +534 -0
- package/docs/tutorials/17-tui-blocks.md +530 -0
- package/docs/tutorials/18-semantic-search.md +334 -0
- package/index.ts +1 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +154 -0
- package/pyproject.toml +7 -0
- package/scripts/animations/chrome-glitch.ts +55 -0
- package/scripts/animations/index.ts +16 -0
- package/scripts/animations/neon-pulse.ts +64 -0
- package/scripts/animations/types.ts +6 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/telegram-ink-ui.ts +302 -0
- package/scripts/examples/using-assistant-with-mcp.ts +560 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +10 -0
- package/scripts/examples/using-openai-codex.ts +23 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/examples/vm-loading-esm-modules.ts +16 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/test-command-listener.ts +123 -0
- package/scripts/test-window-manager-lifecycle.ts +86 -0
- package/scripts/test-window-manager.ts +43 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +114 -0
- package/src/agi/endpoints/ask.ts +60 -0
- package/src/agi/endpoints/conversations/[id].ts +45 -0
- package/src/agi/endpoints/conversations.ts +31 -0
- package/src/agi/endpoints/experts.ts +37 -0
- package/src/agi/features/assistant.ts +767 -0
- package/src/agi/features/assistants-manager.ts +260 -0
- package/src/agi/features/claude-code.ts +1111 -0
- package/src/agi/features/conversation-history.ts +497 -0
- package/src/agi/features/conversation.ts +799 -0
- package/src/agi/features/openai-codex.ts +631 -0
- package/src/agi/features/openapi.ts +438 -0
- package/src/agi/features/skills-library.ts +425 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/token-counter.ts +122 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +100 -0
- package/src/cli/cli.ts +70 -0
- package/src/client.ts +461 -0
- package/src/clients/civitai/index.ts +541 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +597 -0
- package/src/clients/elevenlabs/index.ts +291 -0
- package/src/clients/openai/index.ts +451 -0
- package/src/clients/supabase/index.ts +366 -0
- package/src/command.ts +164 -0
- package/src/commands/chat.ts +182 -0
- package/src/commands/console.ts +192 -0
- package/src/commands/describe.ts +433 -0
- package/src/commands/eval.ts +116 -0
- package/src/commands/help.ts +214 -0
- package/src/commands/index.ts +14 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +807 -0
- package/src/commands/run.ts +257 -0
- package/src/commands/sandbox-mcp.ts +439 -0
- package/src/commands/scaffold.ts +79 -0
- package/src/commands/serve.ts +172 -0
- package/src/container.ts +781 -0
- package/src/endpoint.ts +340 -0
- package/src/feature.ts +75 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +543 -0
- package/src/introspection/generated.agi.ts +23388 -0
- package/src/introspection/generated.node.ts +18899 -0
- package/src/introspection/generated.web.ts +2021 -0
- package/src/introspection/index.ts +256 -0
- package/src/introspection/scan.ts +912 -0
- package/src/node/container.ts +354 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +558 -0
- package/src/node/features/content-db.ts +475 -0
- package/src/node/features/disk-cache.ts +382 -0
- package/src/node/features/dns.ts +655 -0
- package/src/node/features/docker.ts +912 -0
- package/src/node/features/downloader.ts +92 -0
- package/src/node/features/esbuild.ts +68 -0
- package/src/node/features/file-manager.ts +357 -0
- package/src/node/features/fs.ts +534 -0
- package/src/node/features/git.ts +492 -0
- package/src/node/features/google-auth.ts +502 -0
- package/src/node/features/google-calendar.ts +300 -0
- package/src/node/features/google-docs.ts +404 -0
- package/src/node/features/google-drive.ts +339 -0
- package/src/node/features/google-sheets.ts +279 -0
- package/src/node/features/grep.ts +406 -0
- package/src/node/features/helpers.ts +374 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +459 -0
- package/src/node/features/json-tree.ts +188 -0
- package/src/node/features/launcher-app-command-listener.ts +388 -0
- package/src/node/features/networking.ts +925 -0
- package/src/node/features/nlp.ts +211 -0
- package/src/node/features/opener.ts +166 -0
- package/src/node/features/os.ts +157 -0
- package/src/node/features/package-finder.ts +539 -0
- package/src/node/features/port-exposer.ts +342 -0
- package/src/node/features/postgres.ts +273 -0
- package/src/node/features/proc.ts +502 -0
- package/src/node/features/process-manager.ts +542 -0
- package/src/node/features/python.ts +444 -0
- package/src/node/features/repl.ts +194 -0
- package/src/node/features/runpod.ts +802 -0
- package/src/node/features/secure-shell.ts +248 -0
- package/src/node/features/semantic-search.ts +924 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +342 -0
- package/src/node/features/tts.ts +184 -0
- package/src/node/features/ui.ts +857 -0
- package/src/node/features/vault.ts +164 -0
- package/src/node/features/vm.ts +312 -0
- package/src/node/features/window-manager.ts +804 -0
- package/src/node/features/yaml-tree.ts +149 -0
- package/src/node/features/yaml.ts +132 -0
- package/src/node.ts +70 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +199 -0
- package/src/scaffolds/generated.ts +1613 -0
- package/src/scaffolds/template.ts +37 -0
- package/src/schemas/base.ts +255 -0
- package/src/server.ts +135 -0
- package/src/servers/express.ts +209 -0
- package/src/servers/mcp.ts +805 -0
- package/src/servers/socket.ts +120 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +82 -0
- package/src/web/container.ts +74 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +64 -0
- package/src/web/features/container-link.ts +385 -0
- package/src/web/features/esbuild.ts +79 -0
- package/src/web/features/helpers.ts +267 -0
- package/src/web/features/network.ts +61 -0
- package/src/web/features/speech.ts +87 -0
- package/src/web/features/vault.ts +189 -0
- package/src/web/features/vm.ts +78 -0
- package/src/web/features/voice-recognition.ts +129 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/test/bus.test.ts +134 -0
- package/test/clients-servers.test.ts +216 -0
- package/test/container-link.test.ts +274 -0
- package/test/features.test.ts +160 -0
- package/test/integration.test.ts +787 -0
- package/test/node-container.test.ts +121 -0
- package/test/rate-limit.test.ts +272 -0
- package/test/semantic-search.test.ts +550 -0
- package/test/state.test.ts +121 -0
- package/test-integration/assistant.test.ts +138 -0
- package/test-integration/assistants-manager.test.ts +123 -0
- package/test-integration/claude-code.test.ts +98 -0
- package/test-integration/conversation-history.test.ts +205 -0
- package/test-integration/conversation.test.ts +137 -0
- package/test-integration/elevenlabs.test.ts +55 -0
- package/test-integration/google-services.test.ts +80 -0
- package/test-integration/helpers.ts +89 -0
- package/test-integration/openai-codex.test.ts +93 -0
- package/test-integration/runpod.test.ts +58 -0
- package/test-integration/server-endpoints.test.ts +97 -0
- package/test-integration/skills-library.test.ts +157 -0
- package/test-integration/telegram.test.ts +46 -0
- package/tsconfig.json +58 -0
- package/uv.lock +8 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Client,
|
|
3
|
+
type ClientOptions,
|
|
4
|
+
type ClientsInterface,
|
|
5
|
+
RestClient,
|
|
6
|
+
} from "@soederpop/luca/client";
|
|
7
|
+
import { Container, type ContainerContext } from "@soederpop/luca/container";
|
|
8
|
+
import { isEmpty, maxBy, omitBy } from "lodash-es";
|
|
9
|
+
import { NodeContainer } from "@soederpop/luca/node/container";
|
|
10
|
+
import { z } from 'zod'
|
|
11
|
+
import { ClientStateSchema } from '@soederpop/luca/schemas/base.js'
|
|
12
|
+
|
|
13
|
+
declare module "@soederpop/luca/client" {
|
|
14
|
+
interface AvailableClients {
|
|
15
|
+
civitai: typeof CivitaiClient;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const CivitaiClientStateSchema = ClientStateSchema.extend({
|
|
20
|
+
checkpoints: z.array(z.string()).default([]).describe('List of downloaded checkpoint file IDs'),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export type CivitaiClientState = z.infer<typeof CivitaiClientStateSchema>
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Civitai client — search, browse, and download AI models from civitai.com.
|
|
27
|
+
*
|
|
28
|
+
* Wraps the Civitai REST API to search for checkpoints, LoRA models, embeddings,
|
|
29
|
+
* and other model types. Supports downloading models directly to disk with
|
|
30
|
+
* metadata extraction.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const civitai = container.client('civitai')
|
|
35
|
+
* const results = await civitai.search({ query: 'anime', type: 'Checkpoint' })
|
|
36
|
+
* console.log(results.items.map(m => m.name))
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class CivitaiClient<T extends CivitaiClientState> extends RestClient<T> {
|
|
40
|
+
static override stateSchema = CivitaiClientStateSchema;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
static attach(container: Container & ClientsInterface, options?: any) {
|
|
43
|
+
container.clients.register("civitai", CivitaiClient);
|
|
44
|
+
return container
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
constructor(options: ClientOptions, context: ContainerContext) {
|
|
48
|
+
options = {
|
|
49
|
+
...options,
|
|
50
|
+
baseURL: "https://civitai.com",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
super(options, context);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
types = [
|
|
57
|
+
"Checkpoint",
|
|
58
|
+
"TextualInversion",
|
|
59
|
+
"Hypernetwork",
|
|
60
|
+
"AestheticGradient",
|
|
61
|
+
"LORA",
|
|
62
|
+
"Controlnet",
|
|
63
|
+
"Poses",
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Search models by tag.
|
|
68
|
+
*
|
|
69
|
+
* @param tag - The tag to search for
|
|
70
|
+
* @param options - Additional search filters
|
|
71
|
+
* @returns Search results with items array
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const results = await civitai.searchByTag('anime')
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
async searchByTag(
|
|
79
|
+
tag: string,
|
|
80
|
+
{ limit = 100, page = 1, query, type, username }: any = {}
|
|
81
|
+
): Promise<{ items: ModelInfo[] }> {
|
|
82
|
+
return this.search({ tag, limit, page, type, username, query });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Search models by creator username.
|
|
87
|
+
*
|
|
88
|
+
* @param username - The creator's username
|
|
89
|
+
* @param options - Additional search filters
|
|
90
|
+
* @returns Search results with items array
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const results = await civitai.searchByUsername('stabilityai')
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
async searchByUsername(
|
|
98
|
+
username: string,
|
|
99
|
+
{ limit = 100, page = 1, type, query }: any = {}
|
|
100
|
+
): Promise<{ items: ModelInfo[] }> {
|
|
101
|
+
return this.search({ username, limit, page, type, query });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Search for models with full filter support.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Search parameters (query, tag, username, type, sorting, pagination)
|
|
108
|
+
* @returns Search results with items array
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const results = await civitai.search({ query: 'portrait', type: 'LORA', newest: true })
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
async search({
|
|
116
|
+
limit = 100,
|
|
117
|
+
page = 1,
|
|
118
|
+
query = "",
|
|
119
|
+
newest = false,
|
|
120
|
+
best = true,
|
|
121
|
+
popular = false,
|
|
122
|
+
tag,
|
|
123
|
+
username,
|
|
124
|
+
type,
|
|
125
|
+
}: any = {}): Promise<{ items: ModelInfo[] }> {
|
|
126
|
+
const params = omitBy({ limit, page, query, tag, username }, (v,k) => typeof v === 'undefined');
|
|
127
|
+
|
|
128
|
+
let sort = 'Highest Rated'
|
|
129
|
+
|
|
130
|
+
if (newest) {
|
|
131
|
+
sort = 'Newest'
|
|
132
|
+
} else if (popular) {
|
|
133
|
+
sort = 'Most Downloaded'
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return this.get("/api/v1/models", {
|
|
137
|
+
...params,
|
|
138
|
+
sort,
|
|
139
|
+
types: type
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get full model details by ID.
|
|
145
|
+
*
|
|
146
|
+
* @param modelId - The Civitai model ID
|
|
147
|
+
* @returns Complete model info including versions and files
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const model = await civitai.getModel('12345')
|
|
152
|
+
* console.log(model.name, model.type)
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
async getModel(modelId: string): Promise<ModelInfo> {
|
|
156
|
+
return this.get(`/api/v1/models/${modelId}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override get container() {
|
|
160
|
+
return this.context.container as NodeContainer;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Download a checkpoint model to a local folder.
|
|
165
|
+
*
|
|
166
|
+
* Fetches model info, saves metadata as YAML, and optionally downloads the safetensors file.
|
|
167
|
+
*
|
|
168
|
+
* @param modelId - The Civitai model ID
|
|
169
|
+
* @param destinationFolder - Local folder path to download into
|
|
170
|
+
* @param skipDownloadFile - If true, only save metadata without downloading the file
|
|
171
|
+
* @returns Model info with downloadPath
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const result = await civitai.downloadCheckpoint('12345', '/models/checkpoints')
|
|
176
|
+
* console.log(`Downloaded to: ${result.downloadPath}`)
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
async downloadCheckpoint(modelId: string, destinationFolder: string, skipDownloadFile = false) {
|
|
180
|
+
const { paths, utils } = this.container;
|
|
181
|
+
const { stringUtils } = utils;
|
|
182
|
+
const downloader = this.container.feature("downloader");
|
|
183
|
+
const yaml = this.container.feature("yaml");
|
|
184
|
+
|
|
185
|
+
const info = await this.getCheckpointInfo(modelId);
|
|
186
|
+
const { downloadUrl, fileName } = info;
|
|
187
|
+
|
|
188
|
+
const destinationPath = paths.resolve(destinationFolder, fileName.replace(/\s/g, "_"))
|
|
189
|
+
|
|
190
|
+
const metaName = info.fileId;
|
|
191
|
+
|
|
192
|
+
await this.container.fs.ensureFolder(paths.resolve("checkpoints"));
|
|
193
|
+
const checkpointMetaPath = paths.resolve("checkpoints", metaName);
|
|
194
|
+
await this.container.fs.writeFileAsync(
|
|
195
|
+
checkpointMetaPath,
|
|
196
|
+
yaml.stringify(info)
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
if (skipDownloadFile) {
|
|
200
|
+
return {
|
|
201
|
+
...info,
|
|
202
|
+
downloadPath: destinationPath,
|
|
203
|
+
};
|
|
204
|
+
} else {
|
|
205
|
+
const downloadPath = await downloader.download(
|
|
206
|
+
downloadUrl,
|
|
207
|
+
destinationPath
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
...info,
|
|
212
|
+
downloadPath,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Download a textual inversion / embedding model to a local folder.
|
|
219
|
+
*
|
|
220
|
+
* @param modelId - The Civitai model ID
|
|
221
|
+
* @param destinationFolder - Local folder path to download into
|
|
222
|
+
* @param skipDownloadFile - If true, only save metadata without downloading
|
|
223
|
+
* @param modelFileId - Specific version ID to download
|
|
224
|
+
* @returns Model info with downloadPath
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const result = await civitai.downloadEmbedding('67890', '/models/embeddings')
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
async downloadEmbedding(modelId: string, destinationFolder: string,skipDownloadFile = false, modelFileId?: string) {
|
|
232
|
+
const { paths, utils } = this.container;
|
|
233
|
+
const downloader = this.container.feature("downloader");
|
|
234
|
+
const yaml = this.container.feature("yaml");
|
|
235
|
+
|
|
236
|
+
const info = await this.getEmbeddingModelInfo(modelId);
|
|
237
|
+
const { downloadUrl, fileName } = info;
|
|
238
|
+
|
|
239
|
+
const destinationPath = paths.resolve(
|
|
240
|
+
destinationFolder,
|
|
241
|
+
fileName
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const embeddingPath = paths.resolve(
|
|
245
|
+
"embeddings",
|
|
246
|
+
`${utils.stringUtils.camelCase(
|
|
247
|
+
utils.stringUtils.kebabCase(info.name)
|
|
248
|
+
)}.yml`
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
await this.container.fs.writeFileAsync(embeddingPath, yaml.stringify(info));
|
|
252
|
+
|
|
253
|
+
if (!skipDownloadFile) {
|
|
254
|
+
const downloadPath = await downloader.download(
|
|
255
|
+
downloadUrl,
|
|
256
|
+
destinationPath
|
|
257
|
+
);
|
|
258
|
+
return {
|
|
259
|
+
...info,
|
|
260
|
+
downloadPath,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
...info,
|
|
266
|
+
downloadPath: destinationPath,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Download a LoRA model to a local folder.
|
|
273
|
+
*
|
|
274
|
+
* @param modelId - The Civitai model ID
|
|
275
|
+
* @param fileId - The specific file/version ID to download
|
|
276
|
+
* @param destinationFolder - Local folder path to download into
|
|
277
|
+
* @param skipDownloadFile - If true, only return info without downloading
|
|
278
|
+
* @returns Model info with downloadPath and LoRA tag
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* const result = await civitai.downloadLoraModel('12345', '67890', '/models/loras')
|
|
283
|
+
* console.log(result.tag) // '<lora:model_name:1>'
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
async downloadLoraModel(modelId: string, fileId: string | number, destinationFolder: string, skipDownloadFile = false) {
|
|
287
|
+
const { paths } = this.container;
|
|
288
|
+
const downloader = this.container.feature("downloader");
|
|
289
|
+
|
|
290
|
+
const info = await this.getLoraModelInfo(modelId, fileId);
|
|
291
|
+
const { downloadUrl, fileName } = info;
|
|
292
|
+
|
|
293
|
+
const destinationPath = paths.resolve(
|
|
294
|
+
destinationFolder,
|
|
295
|
+
fileName
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
if (!skipDownloadFile) {
|
|
299
|
+
const downloadPath = await downloader.download(
|
|
300
|
+
downloadUrl,
|
|
301
|
+
destinationPath
|
|
302
|
+
);
|
|
303
|
+
return {
|
|
304
|
+
...info,
|
|
305
|
+
downloadPath,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
...info,
|
|
311
|
+
downloadPath: destinationPath,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get metadata for the latest checkpoint version of a model.
|
|
317
|
+
*
|
|
318
|
+
* @param modelId - The Civitai model ID
|
|
319
|
+
* @returns Checkpoint info with download URL, file name, and image URLs
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* const info = await civitai.getCheckpointInfo('12345')
|
|
324
|
+
* console.log(info.fileName, info.downloadUrl)
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
async getCheckpointInfo(modelId: string) {
|
|
328
|
+
const { utils } = this.container;
|
|
329
|
+
const model = await this.getModel(modelId);
|
|
330
|
+
const { modelVersions = [] } = model;
|
|
331
|
+
const latest = maxBy(modelVersions, "createdAt")!;
|
|
332
|
+
const primaryFile =
|
|
333
|
+
latest?.files?.find((f) => f.primary)! || latest?.files[0]!;
|
|
334
|
+
const fileId = `${utils.stringUtils.camelCase(
|
|
335
|
+
utils.stringUtils.kebabCase(model.name)
|
|
336
|
+
)}.yml`;
|
|
337
|
+
|
|
338
|
+
if (!primaryFile) {
|
|
339
|
+
console.log(latest);
|
|
340
|
+
throw new Error(`Can not find primary file for ${modelId}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
modelId: model.id,
|
|
345
|
+
name: model.name,
|
|
346
|
+
fileId,
|
|
347
|
+
fileName: primaryFile.name,
|
|
348
|
+
downloadUrl: primaryFile.downloadUrl,
|
|
349
|
+
imageUrls: latest.images.map((i) => i.url),
|
|
350
|
+
imageInfo: latest.images.map((i) => ({
|
|
351
|
+
url: i.url,
|
|
352
|
+
prompt: i.meta?.prompt || "",
|
|
353
|
+
negativePrompt: i.meta?.negativePrompt || "",
|
|
354
|
+
})),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get metadata for a LoRA model including trained words and LoRA tag.
|
|
360
|
+
*
|
|
361
|
+
* @param modelId - The Civitai model ID
|
|
362
|
+
* @param downloadFileId - Specific version ID (defaults to latest)
|
|
363
|
+
* @returns LoRA info with download URL, tag, trained words, and images
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```typescript
|
|
367
|
+
* const info = await civitai.getLoraModelInfo('12345')
|
|
368
|
+
* console.log(info.tag, info.words)
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
async getLoraModelInfo(modelId: string, downloadFileId?: string | number) {
|
|
372
|
+
const { utils } = this.container;
|
|
373
|
+
|
|
374
|
+
const model = await this.getModel(modelId);
|
|
375
|
+
const { modelVersions = [] } = model;
|
|
376
|
+
const latest = maxBy(modelVersions, "createdAt")!;
|
|
377
|
+
const primaryFile = downloadFileId ? modelVersions.find(m => String(m.id) === String(downloadFileId))! : latest?.files?.find((f) => f.primary)! || modelVersions[0]!;
|
|
378
|
+
let fileId = `${utils.stringUtils.camelCase(
|
|
379
|
+
utils.stringUtils.kebabCase(model.name)
|
|
380
|
+
)}.yml`.replace(/\W/g, "_");
|
|
381
|
+
|
|
382
|
+
if (downloadFileId) {
|
|
383
|
+
fileId = [downloadFileId, fileId].join("_")
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// @ts-ignore-next-line
|
|
387
|
+
if (!primaryFile?.downloadUrl) {
|
|
388
|
+
throw new Error(`No primary file found for ${modelId} ${model.name}`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
modelId: model.id,
|
|
393
|
+
name: model.name,
|
|
394
|
+
fileId,
|
|
395
|
+
fileName: primaryFile.name,
|
|
396
|
+
modelVersions,
|
|
397
|
+
// @ts-ignore-next-line
|
|
398
|
+
downloadUrl: primaryFile.downloadUrl,
|
|
399
|
+
tag: `<lora:${primaryFile.name.replace(".safetensors", "")}:1>`,
|
|
400
|
+
words: latest.trainedWords,
|
|
401
|
+
imageUrls: latest.images.map((i) => i.url),
|
|
402
|
+
imageInfo: latest.images.map((i) => ({
|
|
403
|
+
url: i.url,
|
|
404
|
+
prompt: i.meta?.prompt || "",
|
|
405
|
+
negativePrompt: i.meta?.negativePrompt || "",
|
|
406
|
+
})),
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Get metadata for an embedding model including trained words.
|
|
412
|
+
*
|
|
413
|
+
* @param modelId - The Civitai model ID
|
|
414
|
+
* @param modelFileId - Specific version ID (defaults to latest)
|
|
415
|
+
* @returns Embedding info with download URL, trained words, and images
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* const info = await civitai.getEmbeddingModelInfo('12345')
|
|
420
|
+
* console.log(info.words)
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
async getEmbeddingModelInfo(modelId: string, modelFileId?: string) {
|
|
424
|
+
const { utils } = this.container;
|
|
425
|
+
|
|
426
|
+
const model = await this.getModel(modelId);
|
|
427
|
+
const { modelVersions = [] } = model;
|
|
428
|
+
const latest = modelVersions.find(i => i.id.toString() === String(modelFileId)) || maxBy(modelVersions, "createdAt")!;
|
|
429
|
+
const primaryFile = latest?.files?.find((f) => f.primary)!;
|
|
430
|
+
const fileId = `${utils.stringUtils.camelCase(
|
|
431
|
+
utils.stringUtils.kebabCase(model.name)
|
|
432
|
+
)}.yml`;
|
|
433
|
+
|
|
434
|
+
if (!primaryFile) {
|
|
435
|
+
throw new Error(`No primary file found for ${modelId} ${model.name}`);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
modelId: model.id,
|
|
440
|
+
name: model.name,
|
|
441
|
+
fileId,
|
|
442
|
+
fileName: primaryFile.name,
|
|
443
|
+
downloadUrl: primaryFile.downloadUrl,
|
|
444
|
+
words: latest.trainedWords,
|
|
445
|
+
imageUrls: latest.images.map((i) => i.url),
|
|
446
|
+
imageInfo: latest.images.map((i) => ({
|
|
447
|
+
url: i.url,
|
|
448
|
+
prompt: i.meta?.prompt || "",
|
|
449
|
+
negativePrompt: i.meta?.negativePrompt || "",
|
|
450
|
+
})),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export type ModelInfo = {
|
|
457
|
+
id: number;
|
|
458
|
+
name: string;
|
|
459
|
+
description: string;
|
|
460
|
+
type: string;
|
|
461
|
+
poi: boolean;
|
|
462
|
+
nsfw: boolean;
|
|
463
|
+
allowNoCredit: boolean;
|
|
464
|
+
allowCommercialUse: string;
|
|
465
|
+
allowDerivatives: boolean;
|
|
466
|
+
allowDifferentLicense: boolean;
|
|
467
|
+
stats: {
|
|
468
|
+
downloadCount: number;
|
|
469
|
+
favoriteCount: number;
|
|
470
|
+
commentCount: number;
|
|
471
|
+
ratingCount: number;
|
|
472
|
+
rating: number;
|
|
473
|
+
};
|
|
474
|
+
creator: {
|
|
475
|
+
username: string;
|
|
476
|
+
image: string;
|
|
477
|
+
};
|
|
478
|
+
tags: {
|
|
479
|
+
name: string;
|
|
480
|
+
}[];
|
|
481
|
+
modelVersions: {
|
|
482
|
+
id: number;
|
|
483
|
+
modelId: number;
|
|
484
|
+
name: string;
|
|
485
|
+
createdAt: string;
|
|
486
|
+
updatedAt: string;
|
|
487
|
+
trainedWords: string[];
|
|
488
|
+
baseModel: string;
|
|
489
|
+
earlyAccessTimeFrame: number;
|
|
490
|
+
description: string;
|
|
491
|
+
stats: {
|
|
492
|
+
downloadCount: number;
|
|
493
|
+
ratingCount: number;
|
|
494
|
+
rating: number;
|
|
495
|
+
};
|
|
496
|
+
files: {
|
|
497
|
+
name: string;
|
|
498
|
+
id: number;
|
|
499
|
+
sizeKB: number;
|
|
500
|
+
type: string;
|
|
501
|
+
metadata: {
|
|
502
|
+
fp: string;
|
|
503
|
+
size: string | number;
|
|
504
|
+
format: string;
|
|
505
|
+
};
|
|
506
|
+
pickleScanResult: string;
|
|
507
|
+
pickleScanMessage: string;
|
|
508
|
+
virusScanResult: string;
|
|
509
|
+
scannedAt: string;
|
|
510
|
+
hashes: {
|
|
511
|
+
AutoV1: string;
|
|
512
|
+
AutoV2: string;
|
|
513
|
+
SHA256: string;
|
|
514
|
+
CRC32: string;
|
|
515
|
+
BLAKE3: string;
|
|
516
|
+
};
|
|
517
|
+
downloadUrl: string;
|
|
518
|
+
primary: boolean;
|
|
519
|
+
}[];
|
|
520
|
+
images: {
|
|
521
|
+
url: string;
|
|
522
|
+
nsfw: boolean | string;
|
|
523
|
+
width: number;
|
|
524
|
+
height: number;
|
|
525
|
+
hash: string;
|
|
526
|
+
meta: {
|
|
527
|
+
Size: string;
|
|
528
|
+
seed: number;
|
|
529
|
+
steps: number;
|
|
530
|
+
prompt: string;
|
|
531
|
+
sampler: string;
|
|
532
|
+
cfgScale: number;
|
|
533
|
+
resources: any[];
|
|
534
|
+
Model_hash: string;
|
|
535
|
+
Variation_seed: string;
|
|
536
|
+
negativePrompt: string;
|
|
537
|
+
Variation_seed_strength: string;
|
|
538
|
+
};
|
|
539
|
+
}[];
|
|
540
|
+
}[];
|
|
541
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ClientOptions,
|
|
3
|
+
type ClientsInterface,
|
|
4
|
+
clients,
|
|
5
|
+
RestClient,
|
|
6
|
+
} from "@soederpop/luca/client";
|
|
7
|
+
import { type ContainerContext } from "@soederpop/luca/container";
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
import { ClientStateSchema } from '@soederpop/luca/schemas/base.js'
|
|
10
|
+
|
|
11
|
+
declare module "@soederpop/luca/client" {
|
|
12
|
+
interface AvailableClients {
|
|
13
|
+
myClient: typeof MyClient;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const MyClientStateSchema = ClientStateSchema.extend({
|
|
18
|
+
checkpoints: z.array(z.string()).default([]),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export type MyClientState = z.infer<typeof MyClientStateSchema>
|
|
22
|
+
|
|
23
|
+
export class MyClient<T extends MyClientState> extends RestClient<T> {
|
|
24
|
+
static override stateSchema = MyClientStateSchema;
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
static attach(container: Container & ClientsInterface, options?: any) {
|
|
27
|
+
container.clients.register("civitai", MyClient);
|
|
28
|
+
return container
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constructor(options: ClientOptions, context: ContainerContext) {
|
|
32
|
+
options = {
|
|
33
|
+
...options,
|
|
34
|
+
baseURL: "https://platform.cloud.coveo.com/rest/search/v2",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
super(options, context);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default clients.register('civitai', MyClient)
|