Project Files
src / tools / index_image.js
"use strict";
/**
* search_generations Tool
* Searches Draw Things generation history and returns structured results
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSearchGenerationsTool = createSearchGenerationsTool;
const sdk_1 = require("@lmstudio/sdk");
const zod_1 = require("zod");
const searchEngine_1 = require("../src/search/searchEngine");
// Tool parameters schema
const SearchParamsSchema = {
query: zod_1.z.string().describe("Search query - prompt text, model name, LoRA name, or keywords"),
maxResults: zod_1.z.number().int().min(1).max(100).optional().describe("Maximum results to return (default: 25 = all)"),
};
function createSearchGenerationsTool(ctl) {
return (0, sdk_1.tool)({
name: "search_generations",
description: `Search through Draw Things generation history.
Use this tool to find previously generated images by:
- Prompt text (supports fuzzy matching for typos)
- Model name (e.g., "flux", "sd3")
- LoRA name
- Keywords from the generation
Returns:
- Volltreffer (exact/fuzzy matches): Direct matches to your query
- Beifang (semantic matches): Thematically related results
- Image paths for each matching generation
Example queries:
- "cat in space" - finds generations with similar prompts
- "flux" - finds all FLUX model generations
- "cyberpunk portrait" - finds matching style/subject`,
parameters: SearchParamsSchema,
implementation: async (args, ctx) => {
try {
ctx.status("Searching generation history...");
// Get indexed generations from the preprocessor cache
// For now, we'll need to re-index (TODO: share cache with preprocessor)
const { indexGenerations } = await Promise.resolve().then(() => __importStar(require("../src/indexer")));
const generations = await indexGenerations(ctl);
ctx.status(`Searching ${generations.length} generations...`);
const limit = args.maxResults ?? 25;
const effectiveLimit = limit >= 25 ? 9999 : limit;
const result = await (0, searchEngine_1.searchGenerations)(args.query, generations, {
maxExactMatches: effectiveLimit,
maxSemanticMatches: Math.floor(effectiveLimit / 2),
minExactScore: 25,
includeSemanticSearch: false,
});
ctx.status(`Found ${result.totalFound} results`);
// Return structured content for draw-things-chat
return buildToolResponse(result);
}
catch (e) {
return `search_generations failed: ${String(e?.message || e)}`;
}
},
});
}
/**
* Build structured tool response
* Compatible with LM Studio's content array format
*/
function buildToolResponse(result) {
const content = [];
// Summary text
let summaryText = `## 🎨 Draw Things Search Results\n\n`;
summaryText += `**Query:** "${result.query}"\n`;
summaryText += `**Found:** ${result.totalFound} results in ${result.searchTimeMs}ms\n\n`;
// Volltreffer
if (result.exactMatches.length > 0) {
summaryText += `### 🎯 Volltreffer (${result.exactMatches.length})\n\n`;
for (const match of result.exactMatches.slice(0, 10)) {
const promptPreview = match.prompt.length > 80
? match.prompt.slice(0, 80) + '...'
: match.prompt;
summaryText += `- **${match.matchType}** (${match.matchScore}): "${promptPreview}"\n`;
summaryText += ` Model: ${match.model}`;
if (match.loras?.length)
summaryText += ` | LoRAs: ${match.loras.join(', ')}`;
summaryText += `\n`;
if (match.imagePaths.length > 0) {
summaryText += ` 📸 ${match.imagePaths.length} image(s)\n`;
}
}
if (result.exactMatches.length > 10) {
summaryText += `\n... and ${result.exactMatches.length - 10} more matches\n`;
}
}
// Beifang
if (result.semanticMatches.length > 0) {
summaryText += `\n### 🔮 Beifang (${result.semanticMatches.length})\n\n`;
for (const match of result.semanticMatches.slice(0, 5)) {
const promptPreview = match.prompt.length > 60
? match.prompt.slice(0, 60) + '...'
: match.prompt;
summaryText += `- "${promptPreview}" (${match.model})\n`;
}
}
// Add text content
content.push({
type: "text",
text: summaryText,
});
// Add image results as structured data
// This allows draw-things-chat to render a gallery
if (result.imageResults.length > 0) {
content.push({
type: "text",
text: "\n### 📸 Image Paths\n```json\n" + JSON.stringify({
type: "draw-things-search-result",
query: result.query,
totalFound: result.totalFound,
images: result.imageResults.map(img => ({
path: img.path,
prompt: img.prompt,
model: img.model,
matchType: img.matchType,
score: img.score,
})),
}, null, 2) + "\n```",
});
}
return content;
}
//# sourceMappingURL=index_image.js.map