feat: added field "title" and switched to it to free up caption for its normal use

This commit is contained in:
2026-02-15 09:09:48 +01:00
parent 4f71ac25bc
commit b5795867a8
20 changed files with 886 additions and 42 deletions

View File

@@ -313,7 +313,7 @@ Available Tools:
- list_media: List media files with optional MIME type filtering.
- view_image: View an image to analyze its visual content. Use this when you need to describe or analyze what an image looks like.
- update_post_metadata: Update a post's title, excerpt, tags, or categories.
- update_media_metadata: Update a media file's alt text, caption, or tags.
- update_media_metadata: Update a media file's title, alt text, caption, or tags.
- list_tags: List all tags with post counts.
- list_categories: List all categories with post counts.
- get_post_backlinks: Get posts that link TO a given post (backlinks). Use to discover what references a post.

View File

@@ -573,7 +573,7 @@ export class ImportExecutionEngine extends EventEmitter {
// Import the media file
const mediaEngine = getMediaEngine();
await mediaEngine.importMedia(sourcePath, {
caption: wxrMedia.title || undefined,
title: wxrMedia.title || undefined,
alt: wxrMedia.description || undefined,
mimeType: wxrMedia.mimeType,
tags: [],

View File

@@ -27,6 +27,7 @@ export interface MediaData {
size: number;
width?: number;
height?: number;
title?: string;
alt?: string;
caption?: string;
createdAt: Date;
@@ -42,6 +43,7 @@ export interface MediaMetadata {
size: number;
width?: number;
height?: number;
title?: string;
alt?: string;
caption?: string;
createdAt: string;
@@ -61,7 +63,7 @@ export interface MediaFilter {
export interface MediaSearchResult {
id: string;
originalName: string;
caption?: string;
title?: string;
mimeType: string;
createdAt: Date;
}
@@ -92,12 +94,13 @@ export class MediaEngine extends EventEmitter {
/**
* Update the FTS index for a media item.
* Stores stemmed content from original_name, alt, caption, and tags.
* Stores stemmed content from original_name, title, alt, caption, and tags.
*/
private async updateFTSIndex(item: {
id: string;
projectId: string;
originalName: string;
title?: string;
alt?: string;
caption?: string;
tags: string[];
@@ -111,6 +114,7 @@ export class MediaEngine extends EventEmitter {
// Combine all searchable fields and stem them
const allText = [
item.originalName,
item.title || '',
item.alt || '',
item.caption || '',
item.tags.join(' '),
@@ -300,6 +304,7 @@ export class MediaEngine extends EventEmitter {
size: mediaData.size,
width: mediaData.width,
height: mediaData.height,
title: mediaData.title,
alt: mediaData.alt,
caption: mediaData.caption,
createdAt: mediaData.createdAt.toISOString(),
@@ -319,6 +324,7 @@ export class MediaEngine extends EventEmitter {
if (metadata.width) lines.push(`width: ${metadata.width}`);
if (metadata.height) lines.push(`height: ${metadata.height}`);
if (metadata.title) lines.push(`title: "${metadata.title}"`);
if (metadata.alt) lines.push(`alt: "${metadata.alt}"`);
if (metadata.caption) lines.push(`caption: "${metadata.caption}"`);
@@ -385,6 +391,9 @@ export class MediaEngine extends EventEmitter {
case 'height':
metadata.height = parseInt(value, 10);
break;
case 'title':
metadata.title = value;
break;
case 'alt':
metadata.alt = value;
break;
@@ -492,6 +501,7 @@ export class MediaEngine extends EventEmitter {
size: sourceBuffer.length,
width,
height,
title: metadata?.title,
alt: metadata?.alt,
caption: metadata?.caption,
createdAt,
@@ -518,6 +528,7 @@ export class MediaEngine extends EventEmitter {
size: mediaData.size,
width: mediaData.width,
height: mediaData.height,
title: mediaData.title,
alt: mediaData.alt,
caption: mediaData.caption,
filePath: destPath,
@@ -535,6 +546,7 @@ export class MediaEngine extends EventEmitter {
id: mediaData.id,
projectId: this.currentProjectId,
originalName: mediaData.originalName,
title: mediaData.title,
alt: mediaData.alt,
caption: mediaData.caption,
tags: mediaData.tags,
@@ -566,6 +578,7 @@ export class MediaEngine extends EventEmitter {
await db.update(media)
.set({
title: updated.title,
alt: updated.alt,
caption: updated.caption,
updatedAt: updated.updatedAt,
@@ -578,6 +591,7 @@ export class MediaEngine extends EventEmitter {
id: updated.id,
projectId: this.currentProjectId,
originalName: updated.originalName,
title: updated.title,
alt: updated.alt,
caption: updated.caption,
tags: updated.tags,
@@ -641,6 +655,7 @@ export class MediaEngine extends EventEmitter {
size: dbMedia.size,
width: dbMedia.width || undefined,
height: dbMedia.height || undefined,
title: dbMedia.title || undefined,
alt: dbMedia.alt || undefined,
caption: dbMedia.caption || undefined,
createdAt: dbMedia.createdAt,
@@ -666,6 +681,7 @@ export class MediaEngine extends EventEmitter {
size: dbMedia.size,
width: dbMedia.width || undefined,
height: dbMedia.height || undefined,
title: dbMedia.title || undefined,
alt: dbMedia.alt || undefined,
caption: dbMedia.caption || undefined,
createdAt: dbMedia.createdAt,
@@ -726,6 +742,7 @@ export class MediaEngine extends EventEmitter {
size: dbMedia.size,
width: dbMedia.width || undefined,
height: dbMedia.height || undefined,
title: dbMedia.title || undefined,
alt: dbMedia.alt || undefined,
caption: dbMedia.caption || undefined,
createdAt: dbMedia.createdAt,
@@ -770,7 +787,7 @@ export class MediaEngine extends EventEmitter {
searchResults.push({
id: item.id,
originalName: item.originalName,
caption: item.caption || undefined,
title: item.title || undefined,
mimeType: item.mimeType,
createdAt: item.createdAt,
});

View File

@@ -739,11 +739,12 @@ export class OpenCodeManager {
},
{
name: 'update_media_metadata',
description: 'Update metadata for a media file (alt text, caption, tags).',
description: 'Update metadata for a media file (title, alt text, caption, tags).',
input_schema: {
type: 'object',
properties: {
mediaId: { type: 'string', description: 'The unique ID of the media to update' },
title: { type: 'string', description: 'New title for display in lists and search results' },
alt: { type: 'string', description: 'New alt text for the image' },
caption: { type: 'string', description: 'New caption for the image' },
tags: { type: 'array', items: { type: 'string' }, description: 'New tags for the media' },
@@ -926,7 +927,7 @@ export class OpenCodeManager {
id: media.id, filename: media.filename,
originalName: media.originalName, mimeType: media.mimeType,
size: media.size, width: media.width, height: media.height,
alt: media.alt, caption: media.caption, tags: media.tags,
title: media.title, alt: media.alt, caption: media.caption, tags: media.tags,
createdAt: media.createdAt, updatedAt: media.updatedAt,
},
};
@@ -945,7 +946,7 @@ export class OpenCodeManager {
media: mediaList.map(m => ({
id: m.id, filename: m.filename,
originalName: m.originalName, mimeType: m.mimeType,
alt: m.alt, tags: m.tags,
title: m.title, alt: m.alt, tags: m.tags,
})),
};
}
@@ -967,6 +968,7 @@ export class OpenCodeManager {
case 'update_media_metadata': {
const updates: Record<string, unknown> = {};
if (args.title !== undefined) updates.title = args.title;
if (args.alt !== undefined) updates.alt = args.alt;
if (args.caption !== undefined) updates.caption = args.caption;
if (args.tags !== undefined) updates.tags = args.tags;
@@ -1033,6 +1035,7 @@ export class OpenCodeManager {
originalName: mediaItem.originalName,
width: mediaItem.width,
height: mediaItem.height,
title: mediaItem.title,
alt: mediaItem.alt,
caption: mediaItem.caption,
size: size,
@@ -1080,6 +1083,7 @@ export class OpenCodeManager {
filename: link.media.filename,
originalName: link.media.originalName,
mimeType: link.media.mimeType,
title: link.media.title,
alt: link.media.alt,
caption: link.media.caption,
width: link.media.width,
@@ -1451,11 +1455,12 @@ Remember: Only suggest mappings from NEW items to EXISTING items. Consider langu
}
/**
* Analyze a media image and generate alt text and caption using AI
* Analyze a media image and generate title, alt text, and caption using AI
* This is a one-shot request that looks at the image and suggests metadata
*/
async analyzeMediaImage(mediaId: string, language: string = 'en'): Promise<{
success: boolean;
title?: string;
alt?: string;
caption?: string;
error?: string;
@@ -1496,12 +1501,13 @@ Remember: Only suggest mappings from NEW items to EXISTING items. Consider langu
};
const languageName = languageNames[language] || language;
const systemPrompt = `Generate alt text and caption for this image in ${languageName}.
const systemPrompt = `Generate title, alt text, and caption for this image in ${languageName}.
TITLE: A short, descriptive title for display in lists and search results (3-8 words). Should identify the main subject.
ALT: Describe ONLY what is visually present in the image. Be factual, neutral, and concise (5-12 words max). No interpretations, emotions, or "Image of" prefix. Example: "Red bicycle leaning against white brick wall"
CAPTION: Short, engaging blog caption (5-20 words).
Respond with JSON only: {"alt": "...", "caption": "..."}`;
Respond with JSON only: {"title": "...", "alt": "...", "caption": "..."}`;
try {
// Using Claude Sonnet 4.5 for best image analysis
@@ -1570,6 +1576,7 @@ Respond with JSON only: {"alt": "...", "caption": "..."}`;
return {
success: true,
title: result.title || undefined,
alt: result.alt || undefined,
caption: result.caption || undefined,
};