mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 01:19:24 +00:00
Process pages on tool completion, only mark as leaf when history doesn't branch
This commit is contained in:
parent
e585f67183
commit
0f1db3621f
@ -10,6 +10,7 @@ import {
|
|||||||
createFileId,
|
createFileId,
|
||||||
createQuickKey,
|
createQuickKey,
|
||||||
createStirlingFile,
|
createStirlingFile,
|
||||||
|
ProcessedFileMetadata,
|
||||||
} from '../../types/fileContext';
|
} from '../../types/fileContext';
|
||||||
import { FileId } from '../../types/file';
|
import { FileId } from '../../types/file';
|
||||||
import { generateThumbnailWithMetadata } from '../../utils/thumbnailUtils';
|
import { generateThumbnailWithMetadata } from '../../utils/thumbnailUtils';
|
||||||
@ -70,19 +71,43 @@ export function createProcessedFile(pageCount: number, thumbnail?: string) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate fresh ProcessedFileMetadata for a file
|
||||||
|
* Used when tools process files to ensure metadata matches actual file content
|
||||||
|
*/
|
||||||
|
export async function generateProcessedFileMetadata(file: File): Promise<ProcessedFileMetadata | undefined> {
|
||||||
|
// Only generate metadata for PDF files
|
||||||
|
if (!file.type.startsWith('application/pdf')) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await generateThumbnailWithMetadata(file);
|
||||||
|
return createProcessedFile(result.pageCount, result.thumbnail);
|
||||||
|
} catch (error) {
|
||||||
|
if (DEBUG) console.warn(`📄 Failed to generate processedFileMetadata for ${file.name}:`, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a child StirlingFileStub from a parent stub with proper history management.
|
* Create a child StirlingFileStub from a parent stub with proper history management.
|
||||||
* Used when a tool processes an existing file to create a new version with incremented history.
|
* Used when a tool processes an existing file to create a new version with incremented history.
|
||||||
*
|
*
|
||||||
* @param parentStub - The parent StirlingFileStub to create a child from
|
* @param parentStub - The parent StirlingFileStub to create a child from
|
||||||
* @param operation - Tool operation information (toolName, timestamp)
|
* @param operation - Tool operation information (toolName, timestamp)
|
||||||
|
* @param resultingFile - The processed File object
|
||||||
|
* @param thumbnail - Optional thumbnail for the child
|
||||||
|
* @param processedFileMetadata - Optional fresh metadata for the processed file
|
||||||
* @returns New child StirlingFileStub with proper version history
|
* @returns New child StirlingFileStub with proper version history
|
||||||
*/
|
*/
|
||||||
export function createChildStub(
|
export function createChildStub(
|
||||||
parentStub: StirlingFileStub,
|
parentStub: StirlingFileStub,
|
||||||
operation: { toolName: string; timestamp: number },
|
operation: { toolName: string; timestamp: number },
|
||||||
resultingFile: File,
|
resultingFile: File,
|
||||||
thumbnail?: string
|
thumbnail?: string,
|
||||||
|
processedFileMetadata?: ProcessedFileMetadata
|
||||||
): StirlingFileStub {
|
): StirlingFileStub {
|
||||||
const newFileId = createFileId();
|
const newFileId = createFileId();
|
||||||
|
|
||||||
@ -96,10 +121,12 @@ export function createChildStub(
|
|||||||
// Determine original file ID (root of the version chain)
|
// Determine original file ID (root of the version chain)
|
||||||
const originalFileId = parentStub.originalFileId || parentStub.id;
|
const originalFileId = parentStub.originalFileId || parentStub.id;
|
||||||
|
|
||||||
// Update the child stub's name to match the processed file
|
// Copy parent metadata but exclude processedFile to prevent stale data
|
||||||
|
const { processedFile: _processedFile, ...parentMetadata } = parentStub;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Copy all parent metadata
|
// Copy parent metadata (excluding processedFile)
|
||||||
...parentStub,
|
...parentMetadata,
|
||||||
|
|
||||||
// Update identity and version info
|
// Update identity and version info
|
||||||
id: newFileId,
|
id: newFileId,
|
||||||
@ -113,10 +140,10 @@ export function createChildStub(
|
|||||||
size: resultingFile.size,
|
size: resultingFile.size,
|
||||||
type: resultingFile.type,
|
type: resultingFile.type,
|
||||||
lastModified: resultingFile.lastModified,
|
lastModified: resultingFile.lastModified,
|
||||||
thumbnailUrl: thumbnail
|
thumbnailUrl: thumbnail,
|
||||||
|
|
||||||
// Preserve thumbnails and processing metadata from parent
|
// Set fresh processedFile metadata (no inheritance from parent)
|
||||||
// These will be updated if the child has new thumbnails, but fallback to parent
|
processedFile: processedFileMetadata
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,36 +197,29 @@ export async function addFiles(
|
|||||||
const fileId = createFileId();
|
const fileId = createFileId();
|
||||||
filesRef.current.set(fileId, file);
|
filesRef.current.set(fileId, file);
|
||||||
|
|
||||||
// Generate thumbnail and page count immediately
|
// Generate processedFile metadata using centralized function
|
||||||
let thumbnail: string | undefined;
|
const processedFileMetadata = await generateProcessedFileMetadata(file);
|
||||||
let pageCount: number = 1;
|
|
||||||
|
|
||||||
// Route based on file type - PDFs through full metadata pipeline, non-PDFs through simple path
|
// Extract thumbnail for non-PDF files or use from processedFile for PDFs
|
||||||
if (file.type.startsWith('application/pdf')) {
|
let thumbnail: string | undefined;
|
||||||
try {
|
if (processedFileMetadata) {
|
||||||
if (DEBUG) console.log(`📄 Generating PDF metadata for ${file.name}`);
|
// PDF file - use thumbnail from processedFile metadata
|
||||||
const result = await generateThumbnailWithMetadata(file);
|
thumbnail = processedFileMetadata.thumbnailUrl;
|
||||||
thumbnail = result.thumbnail;
|
if (DEBUG) console.log(`📄 Generated PDF metadata for ${file.name}: ${processedFileMetadata.totalPages} pages, thumbnail: SUCCESS`);
|
||||||
pageCount = result.pageCount;
|
} else if (!file.type.startsWith('application/pdf')) {
|
||||||
if (DEBUG) console.log(`📄 Generated PDF metadata for ${file.name}: ${pageCount} pages, thumbnail: SUCCESS`);
|
// Non-PDF files: simple thumbnail generation, no processedFile metadata
|
||||||
} catch (error) {
|
|
||||||
if (DEBUG) console.warn(`📄 Failed to generate PDF metadata for ${file.name}:`, error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Non-PDF files: simple thumbnail generation, no page count
|
|
||||||
try {
|
try {
|
||||||
if (DEBUG) console.log(`📄 Generating simple thumbnail for non-PDF file ${file.name}`);
|
if (DEBUG) console.log(`📄 Generating simple thumbnail for non-PDF file ${file.name}`);
|
||||||
const { generateThumbnailForFile } = await import('../../utils/thumbnailUtils');
|
const { generateThumbnailForFile } = await import('../../utils/thumbnailUtils');
|
||||||
thumbnail = await generateThumbnailForFile(file);
|
thumbnail = await generateThumbnailForFile(file);
|
||||||
pageCount = 0; // Non-PDFs have no page count
|
|
||||||
if (DEBUG) console.log(`📄 Generated simple thumbnail for ${file.name}: no page count, thumbnail: SUCCESS`);
|
if (DEBUG) console.log(`📄 Generated simple thumbnail for ${file.name}: no page count, thumbnail: SUCCESS`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (DEBUG) console.warn(`📄 Failed to generate simple thumbnail for ${file.name}:`, error);
|
if (DEBUG) console.warn(`📄 Failed to generate simple thumbnail for ${file.name}:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new filestub with immediate thumbnail and page metadata
|
// Create new filestub with processedFile metadata
|
||||||
const fileStub = createNewStirlingFileStub(file, fileId, thumbnail);
|
const fileStub = createNewStirlingFileStub(file, fileId, thumbnail, processedFileMetadata);
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
// Track blob URLs for cleanup (images return blob URLs that need revocation)
|
// Track blob URLs for cleanup (images return blob URLs that need revocation)
|
||||||
if (thumbnail.startsWith('blob:')) {
|
if (thumbnail.startsWith('blob:')) {
|
||||||
@ -212,12 +232,6 @@ export async function addFiles(
|
|||||||
fileStub.insertAfterPageId = options.insertAfterPageId;
|
fileStub.insertAfterPageId = options.insertAfterPageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create initial processedFile metadata with page count
|
|
||||||
if (pageCount > 0) {
|
|
||||||
fileStub.processedFile = createProcessedFile(pageCount, thumbnail);
|
|
||||||
if (DEBUG) console.log(`📄 addFiles(raw): Created initial processedFile metadata for ${file.name} with ${pageCount} pages`);
|
|
||||||
}
|
|
||||||
|
|
||||||
existingQuickKeys.add(quickKey);
|
existingQuickKeys.add(quickKey);
|
||||||
stirlingFileStubs.push(fileStub);
|
stirlingFileStubs.push(fileStub);
|
||||||
|
|
||||||
@ -289,6 +303,7 @@ export async function consumeFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark input files as processed in storage (no longer leaf nodes)
|
// Mark input files as processed in storage (no longer leaf nodes)
|
||||||
|
if(!outputStirlingFileStubs.reduce((areAllV1, stub) => areAllV1 && (stub.versionNumber == 1), true)) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
inputFileIds.map(async (fileId) => {
|
inputFileIds.map(async (fileId) => {
|
||||||
try {
|
try {
|
||||||
@ -299,6 +314,7 @@ export async function consumeFiles(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Save output files directly to fileStorage with complete metadata
|
// Save output files directly to fileStorage with complete metadata
|
||||||
for (let i = 0; i < outputStirlingFiles.length; i++) {
|
for (let i = 0; i < outputStirlingFiles.length; i++) {
|
||||||
@ -500,15 +516,16 @@ export async function addStirlingFileStubs(
|
|||||||
|
|
||||||
if (needsProcessing) {
|
if (needsProcessing) {
|
||||||
if (DEBUG) console.log(`📄 addStirlingFileStubs: Regenerating processedFile for ${record.name}`);
|
if (DEBUG) console.log(`📄 addStirlingFileStubs: Regenerating processedFile for ${record.name}`);
|
||||||
try {
|
|
||||||
// Generate basic processedFile structure with page count
|
// Use centralized metadata generation function
|
||||||
const result = await generateThumbnailWithMetadata(stirlingFile);
|
const processedFileMetadata = await generateProcessedFileMetadata(stirlingFile);
|
||||||
record.processedFile = createProcessedFile(result.pageCount, result.thumbnail);
|
if (processedFileMetadata) {
|
||||||
record.thumbnailUrl = result.thumbnail; // Update thumbnail if needed
|
record.processedFile = processedFileMetadata;
|
||||||
if (DEBUG) console.log(`📄 addStirlingFileStubs: Regenerated processedFile for ${record.name} with ${result.pageCount} pages`);
|
record.thumbnailUrl = processedFileMetadata.thumbnailUrl; // Update thumbnail if needed
|
||||||
} catch (error) {
|
if (DEBUG) console.log(`📄 addStirlingFileStubs: Regenerated processedFile for ${record.name} with ${processedFileMetadata.totalPages} pages`);
|
||||||
if (DEBUG) console.warn(`📄 addStirlingFileStubs: Failed to regenerate processedFile for ${record.name}:`, error);
|
} else {
|
||||||
// Ensure we have at least basic structure
|
// Fallback for files that couldn't be processed
|
||||||
|
if (DEBUG) console.warn(`📄 addStirlingFileStubs: Failed to regenerate processedFile for ${record.name}`);
|
||||||
if (!record.processedFile) {
|
if (!record.processedFile) {
|
||||||
record.processedFile = createProcessedFile(1); // Fallback to 1 page
|
record.processedFile = createProcessedFile(1); // Fallback to 1 page
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { useToolResources } from './useToolResources';
|
|||||||
import { extractErrorMessage } from '../../../utils/toolErrorHandler';
|
import { extractErrorMessage } from '../../../utils/toolErrorHandler';
|
||||||
import { StirlingFile, extractFiles, FileId, StirlingFileStub, createStirlingFile, createNewStirlingFileStub } from '../../../types/fileContext';
|
import { StirlingFile, extractFiles, FileId, StirlingFileStub, createStirlingFile, createNewStirlingFileStub } from '../../../types/fileContext';
|
||||||
import { ResponseHandler } from '../../../utils/toolResponseProcessor';
|
import { ResponseHandler } from '../../../utils/toolResponseProcessor';
|
||||||
import { createChildStub } from '../../../contexts/file/fileActions';
|
import { createChildStub, generateProcessedFileMetadata } from '../../../contexts/file/fileActions';
|
||||||
|
|
||||||
// Re-export for backwards compatibility
|
// Re-export for backwards compatibility
|
||||||
export type { ProcessingProgress, ResponseHandler };
|
export type { ProcessingProgress, ResponseHandler };
|
||||||
@ -272,11 +272,26 @@ export const useToolOperation = <TParams>(
|
|||||||
toolName: config.operationType,
|
toolName: config.operationType,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
};
|
};
|
||||||
console.log("tool complete inputs ")
|
|
||||||
const outputStirlingFileStubs = processedFiles.length != inputStirlingFileStubs.length
|
// Generate fresh processedFileMetadata for all processed files to ensure accuracy
|
||||||
? processedFiles.map((file, index) => createNewStirlingFileStub(file, undefined, thumbnails[index]))
|
actions.setStatus('Generating metadata for processed files...');
|
||||||
|
const processedFileMetadataArray = await Promise.all(
|
||||||
|
processedFiles.map(file => generateProcessedFileMetadata(file))
|
||||||
|
);
|
||||||
|
const shouldBranchHistory = processedFiles.length != inputStirlingFileStubs.length;
|
||||||
|
// Create output stubs with fresh metadata (no inheritance of stale processedFile data)
|
||||||
|
const outputStirlingFileStubs = shouldBranchHistory
|
||||||
|
? processedFiles.map((file, index) =>
|
||||||
|
createNewStirlingFileStub(file, undefined, thumbnails[index], processedFileMetadataArray[index])
|
||||||
|
)
|
||||||
: processedFiles.map((resultingFile, index) =>
|
: processedFiles.map((resultingFile, index) =>
|
||||||
createChildStub(inputStirlingFileStubs[index], newToolOperation, resultingFile, thumbnails[index])
|
createChildStub(
|
||||||
|
inputStirlingFileStubs[index],
|
||||||
|
newToolOperation,
|
||||||
|
resultingFile,
|
||||||
|
thumbnails[index],
|
||||||
|
processedFileMetadataArray[index]
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create StirlingFile objects from processed files and child stubs
|
// Create StirlingFile objects from processed files and child stubs
|
||||||
|
@ -159,8 +159,8 @@ export function isFileObject(obj: any): obj is File | StirlingFile {
|
|||||||
export function createNewStirlingFileStub(
|
export function createNewStirlingFileStub(
|
||||||
file: File,
|
file: File,
|
||||||
id?: FileId,
|
id?: FileId,
|
||||||
thumbnail?: string
|
thumbnail?: string,
|
||||||
|
processedFileMetadata?: ProcessedFileMetadata
|
||||||
): StirlingFileStub {
|
): StirlingFileStub {
|
||||||
const fileId = id || createFileId();
|
const fileId = id || createFileId();
|
||||||
return {
|
return {
|
||||||
@ -173,7 +173,8 @@ export function createNewStirlingFileStub(
|
|||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
isLeaf: true, // New files are leaf nodes by default
|
isLeaf: true, // New files are leaf nodes by default
|
||||||
versionNumber: 1, // New files start at version 1
|
versionNumber: 1, // New files start at version 1
|
||||||
thumbnailUrl: thumbnail
|
thumbnailUrl: thumbnail,
|
||||||
|
processedFile: processedFileMetadata
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user