Project Files
src / config.ts
import { createConfigSchematics } from "@lmstudio/sdk";
import { homedir } from "os";
import path from "path";
// Default paths for Draw Things
const DEFAULTS = {
jsonlLogs: path.join(homedir(), ".lmstudio", "extensions", "plugins", "ceveyne", "draw-things-chat", "logs"),
contentDirectories: [
path.join(homedir(), "Pictures"),
],
// Draw Things stores projects in its container
drawThingsProjects: path.join(homedir(), "Library", "Containers", "com.liuliu.draw-things", "Data", "Documents"),
};
export const configSchematics = createConfigSchematics()
// ═══════════════════════════════════════════════════════════════
// SEARCH SOURCE 1: Image Directories with Metadata
// ═══════════════════════════════════════════════════════════════
.field(
"contentDirectories",
"stringArray",
{
displayName: "Image Directories",
subtitle: "Search images with embedded metadata (Draw Things XMP, ComfyUI prompt JSON)",
},
[...DEFAULTS.contentDirectories],
)
// ═══════════════════════════════════════════════════════════════
// SEARCH SOURCE 2: LM Studio Chat Attachments
// ═══════════════════════════════════════════════════════════════
.field(
"searchChatAttachments",
"boolean",
{
displayName: "Search Chat Attachments (PNG with Metadata)",
subtitle: "Search images attached to LM Studio chats (~/.lmstudio/user-files)",
},
true,
)
// ═══════════════════════════════════════════════════════════════
// SEARCH SOURCE 3: JSONL Logs
// ═══════════════════════════════════════════════════════════════
.field(
"searchJsonlLogs",
"boolean",
{
displayName: "Search Image Generation Logs",
subtitle: "Search through generation history with full metadata (prompts, models, LoRAs, etc.)",
},
true,
)
.field(
"jsonlLogsDirectory",
"string",
{
displayName: "Image Generation Logs Directory",
subtitle: "Directory containing generate-image-plugin.audit.jsonl (from draw-things-chat)",
},
DEFAULTS.jsonlLogs,
)
// ═══════════════════════════════════════════════════════════════
// SEARCH SOURCE 4: Draw Things Projects (.sqlite3)
// ═══════════════════════════════════════════════════════════════
.field(
"searchDrawThingsProjects",
"boolean",
{
displayName: "Search Draw Things Projects",
subtitle: "Search through Draw Things project files with full generation history",
},
true,
)
.field(
"drawThingsProjectsDirectory",
"string",
{
displayName: "Projects Directory",
subtitle: "Directory containing Draw Things project files",
},
DEFAULTS.drawThingsProjects,
)
// ═══════════════════════════════════════════════════════════════
// SEARCH SETTINGS
// ═══════════════════════════════════════════════════════════════
.field(
"retrievalLimit",
"numeric",
{
int: true,
min: 1,
max: 25,
displayName: "Max Results",
subtitle: "Maximum number of generations (25 = all)",
slider: { min: 1, max: 25, step: 1 },
},
5, // Default: 5
)
// ═══════════════════════════════════════════════════════════════
// SEARCH TUNING (Advanced settings)
// ═══════════════════════════════════════════════════════════════
.field(
"minMatchScore",
"numeric",
{
int: true,
min: 0,
max: 100,
displayName: "Minimum Match Score",
subtitle: "Minimum score (0-100) for a result to be included",
slider: { min: 0, max: 100, step: 5 },
engineDoesNotSupport: true,
},
70, // Lower default: single fuzzy match ~24 points
)
.field(
"fuzzyTermThreshold",
"numeric",
{
int: false,
min: 0.5,
max: 1.0,
displayName: "Fuzzy Term Threshold",
subtitle: "Levenshtein similarity threshold for individual term matching (0.5-1.0)",
slider: { min: 0.5, max: 1.0, step: 0.05 },
engineDoesNotSupport: true,
},
0.80,
)
.field(
"minTermCoverage",
"numeric",
{
int: false,
min: 0.0,
max: 1.0,
displayName: "Minimum Term Coverage",
subtitle: "Minimum fraction of query terms that must match (0.0-1.0)",
slider: { min: 0.0, max: 1.0, step: 0.1 },
engineDoesNotSupport: true,
},
0.3,
)
// ═══════════════════════════════════════════════════════════════
// SEMANTIC SEARCH (Embeddings)
// ═══════════════════════════════════════════════════════════════
.field(
"embeddingModel",
"string",
{
displayName: "Embedding Model",
subtitle: "Multilingual model for cross-language search. Leave empty to disable.",
},
"text-embedding-intfloat-multilingual-e5-large-instruct",
)
.field(
"lmStudioBaseUrl",
"string",
{
displayName: "LM Studio URL",
subtitle: "Base URL for LM Studio API (default: http://127.0.0.1:1234)",
engineDoesNotSupport: true,
},
"http://127.0.0.1:1234",
)
.field(
"semanticWeight",
"numeric",
{
int: false,
min: 0.0,
max: 1.0,
displayName: "Semantic Search Weight",
subtitle: "0.0 = keyword only, 1.0 = semantic only (cross-language)",
slider: { min: 0.0, max: 1.0, step: 0.1 },
},
0.5, // Default: favor semantic for cross-language
)
.field(
"minSemanticScore",
"numeric",
{
int: true,
min: 0,
max: 100,
displayName: "Minimum Semantic Score",
subtitle: "Minimum score (0-100) for semantic matches to be included",
slider: { min: 0, max: 100, step: 5 },
engineDoesNotSupport: true,
},
65, // Default: balanced semantic precision/recall
)
.build();