Merge pull request #32 from presenton/nextjs_logs_save
Nextjs Logs saved in [APP_DIRECTORY]/logs/nextjs.log
This commit is contained in:
commit
88935fc7db
17 changed files with 238 additions and 74 deletions
|
|
@ -5,6 +5,7 @@ import { setupReadFile } from "./read_file";
|
|||
import { setupFooterHandlers } from "./footer_handlers";
|
||||
import { setupThemeHandlers } from "./theme_handlers";
|
||||
import { setupUploadImage } from "./upload_image";
|
||||
import { setupLogHandler } from "./log_handler";
|
||||
export function setupIpcHandlers() {
|
||||
setupExportHandlers();
|
||||
setupUserConfigHandlers();
|
||||
|
|
@ -13,4 +14,5 @@ export function setupIpcHandlers() {
|
|||
setupFooterHandlers();
|
||||
setupThemeHandlers();
|
||||
setupUploadImage();
|
||||
setupLogHandler();
|
||||
}
|
||||
50
app/ipc/log_handler.ts
Normal file
50
app/ipc/log_handler.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { ipcMain } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { userDataDir } from '../utils/constants';
|
||||
|
||||
export function setupLogHandler() {
|
||||
// Ensure logs directory exists
|
||||
const logsDir = path.join(userDataDir, 'logs');
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const logFilePath = path.join(logsDir, 'nextjs.log');
|
||||
|
||||
// Handle log writing through IPC - non-blocking
|
||||
ipcMain.handle('write-nextjs-log', (_, logData: string) => {
|
||||
try {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logEntry = `[${timestamp}] ${logData}\n`;
|
||||
|
||||
// Use non-blocking write
|
||||
fs.appendFile(logFilePath, logEntry, (err) => {
|
||||
if (err) {
|
||||
console.error('Error writing to log file:', err);
|
||||
}
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error in log handler:', error);
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
});
|
||||
|
||||
// Handle log clearing
|
||||
ipcMain.handle('clear-nextjs-logs', () => {
|
||||
try {
|
||||
// Create a new empty file, effectively clearing the old one
|
||||
fs.writeFile(logFilePath, '', (err) => {
|
||||
if (err) {
|
||||
console.error('Error clearing log file:', err);
|
||||
}
|
||||
});
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error in clear logs handler:', error);
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -21,4 +21,6 @@ contextBridge.exposeInMainWorld('electron', {
|
|||
getTheme: (userId: string) => ipcRenderer.invoke("get-theme", userId),
|
||||
setTheme: (userId: string, themeData: any) => ipcRenderer.invoke("set-theme", userId, themeData),
|
||||
uploadImage: (file: Buffer) => ipcRenderer.invoke("upload-image", file),
|
||||
writeNextjsLog: (logData: string) => ipcRenderer.invoke("write-nextjs-log", logData),
|
||||
clearNextjsLogs: () => ipcRenderer.invoke("clear-nextjs-logs"),
|
||||
});
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "presenton",
|
||||
"version": "0.1.0-beta",
|
||||
"version": "0.2.0-beta",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "presenton",
|
||||
"version": "0.1.0-beta",
|
||||
"version": "0.2.0-beta",
|
||||
"dependencies": {
|
||||
"@tailwindcss/cli": "^4.1.5",
|
||||
"dotenv": "^16.5.0",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
} from "@/components/ui/popover";
|
||||
import ToolTip from "@/components/ToolTip";
|
||||
import { getEnv } from "@/utils/constant";
|
||||
import { clearLogs, logOperation } from "../utils/log";
|
||||
|
||||
interface ImageEditorProps {
|
||||
initialImage: string | null;
|
||||
|
|
@ -96,6 +97,7 @@ const ImageEditor = ({
|
|||
useEffect(() => {
|
||||
setImage(initialImage);
|
||||
setPreviewImages([initialImage]);
|
||||
|
||||
}, [initialImage]);
|
||||
|
||||
// Close toolbar when clicking outside
|
||||
|
|
@ -110,7 +112,7 @@ const ImageEditor = ({
|
|||
) {
|
||||
setIsToolbarOpen(false);
|
||||
if (isFocusPointMode) {
|
||||
// saveFocusPoint(); // Save focus point before closing
|
||||
logOperation(`Saving focus point for slide ${slideIndex}, element ${elementId}: x=${focusPoint.x}, y=${focusPoint.y}`);
|
||||
saveImageProperties(objectFit, focusPoint);
|
||||
}
|
||||
setIsFocusPointMode(false);
|
||||
|
|
@ -125,16 +127,19 @@ const ImageEditor = ({
|
|||
|
||||
const handleImageClick = () => {
|
||||
if (!isFocusPointMode) {
|
||||
logOperation(`Opening toolbar for slide ${slideIndex}, element ${elementId}`);
|
||||
setIsToolbarOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenEditor = () => {
|
||||
logOperation(`Opening image editor for slide ${slideIndex}, element ${elementId}`);
|
||||
setIsToolbarOpen(false);
|
||||
setIsEditorOpen(true);
|
||||
};
|
||||
|
||||
const handleImageChange = (newImage: string) => {
|
||||
logOperation(`Changing image for slide ${slideIndex}, element ${elementId}`);
|
||||
setImage(newImage);
|
||||
dispatch(
|
||||
updateSlideImage({
|
||||
|
|
@ -159,31 +164,28 @@ const ImageEditor = ({
|
|||
Math.min(100, ((e.clientY - rect.top) / rect.height) * 100)
|
||||
);
|
||||
|
||||
logOperation(`Setting focus point for slide ${slideIndex}, element ${elementId}: x=${x}, y=${y}`);
|
||||
setFocusPoint({ x, y });
|
||||
saveImageProperties(objectFit, { x, y });
|
||||
|
||||
// Apply the focus point in real-time
|
||||
if (imageRef.current) {
|
||||
imageRef.current.style.objectPosition = `${x}% ${y}%`;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleFocusPointMode = () => {
|
||||
if (isFocusPointMode) {
|
||||
// If turning off focus point mode, save the current focus point
|
||||
// saveFocusPoint();
|
||||
}
|
||||
logOperation(`Toggling focus point mode for slide ${slideIndex}, element ${elementId}: ${!isFocusPointMode}`);
|
||||
setIsFocusPointMode(!isFocusPointMode);
|
||||
};
|
||||
|
||||
const handleFitChange = (fit: "cover" | "contain" | "fill") => {
|
||||
logOperation(`Changing image fit for slide ${slideIndex}, element ${elementId}: ${fit}`);
|
||||
setObjectFit(fit);
|
||||
|
||||
if (imageRef.current) {
|
||||
imageRef.current.style.objectFit = fit;
|
||||
}
|
||||
|
||||
// Save the fit change to your state
|
||||
saveImageProperties(fit, focusPoint);
|
||||
};
|
||||
|
||||
|
|
@ -191,6 +193,7 @@ const ImageEditor = ({
|
|||
fit: "cover" | "contain" | "fill",
|
||||
focusPoint: { x: number; y: number }
|
||||
) => {
|
||||
logOperation(`Saving image properties for slide ${slideIndex}, element ${elementId}: fit=${fit}, focusPoint=(${focusPoint.x},${focusPoint.y})`);
|
||||
const propertiesData = {
|
||||
initialObjectFit: fit,
|
||||
initialFocusPoint: focusPoint,
|
||||
|
|
@ -207,6 +210,7 @@ const ImageEditor = ({
|
|||
|
||||
const handleGenerateImage = async () => {
|
||||
try {
|
||||
logOperation(`Generating image for slide ${slideIndex}, element ${elementId} with prompt: ${prompt}`);
|
||||
setIsGenerating(true);
|
||||
setError(null);
|
||||
|
||||
|
|
@ -221,33 +225,34 @@ const ImageEditor = ({
|
|||
},
|
||||
});
|
||||
|
||||
logOperation(`Image generation successful for slide ${slideIndex}, element ${elementId}`);
|
||||
setPreviewImages(response.paths);
|
||||
} catch (err) {
|
||||
setError("Failed to generate image. Please try again.");
|
||||
const errorMessage = "Failed to generate image. Please try again.";
|
||||
logOperation(`Image generation failed for slide ${slideIndex}, element ${elementId}: ${err}`);
|
||||
setError(errorMessage);
|
||||
} finally {
|
||||
setIsGenerating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = async (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const presentation_id = searchParams.get("id");
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
// Check file size (e.g., 5MB limit)
|
||||
logOperation(`Attempting to upload file for slide ${slideIndex}, element ${elementId}: ${file.name}`);
|
||||
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
const error_message = "File size should be less than 5MB";
|
||||
|
||||
logOperation(`File upload failed for slide ${slideIndex}, element ${elementId}: File too large`);
|
||||
setUploadError(error_message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check file type
|
||||
if (!file.type.startsWith("image/")) {
|
||||
const error_message = "Please upload an image file";
|
||||
|
||||
logOperation(`File upload failed for slide ${slideIndex}, element ${elementId}: Invalid file type`);
|
||||
setUploadError(error_message);
|
||||
return;
|
||||
}
|
||||
|
|
@ -256,18 +261,15 @@ const ImageEditor = ({
|
|||
setIsUploading(true);
|
||||
setUploadError(null);
|
||||
|
||||
// Convert file to buffer
|
||||
const buffer = await file.arrayBuffer();
|
||||
|
||||
// Send to electron main process
|
||||
// @ts-ignore
|
||||
const relativePath = await window.electron.uploadImage(Buffer.from(buffer));
|
||||
|
||||
// Update state with the returned path
|
||||
logOperation(`File upload successful for slide ${slideIndex}, element ${elementId}: ${relativePath}`);
|
||||
setUploadedImageUrl(relativePath);
|
||||
} catch (err) {
|
||||
const error_message = "Failed to upload image. Please try again.";
|
||||
|
||||
logOperation(`File upload failed for slide ${slideIndex}, element ${elementId}: ${err}`);
|
||||
setUploadError(error_message);
|
||||
console.error("Upload error:", err);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
FooterProperties,
|
||||
useFooterService,
|
||||
} from "../services/footerService";
|
||||
import { clearLogs, logOperation } from "../utils/log";
|
||||
|
||||
// Default footer properties
|
||||
export const defaultFooterProperties: FooterProperties = {
|
||||
|
|
@ -57,11 +58,16 @@ export const FooterProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
useEffect(() => {
|
||||
const loadFooterProperties = async () => {
|
||||
try {
|
||||
logOperation('Loading footer properties');
|
||||
const properties = await footerService.getFooterProperties();
|
||||
if (properties) {
|
||||
logOperation('Footer properties loaded successfully');
|
||||
setFooterProperties(properties);
|
||||
} else {
|
||||
logOperation('No footer properties found, using defaults');
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error loading footer properties: ${error}`);
|
||||
console.error("Failed to load footer properties:", error);
|
||||
}
|
||||
};
|
||||
|
|
@ -71,22 +77,32 @@ export const FooterProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
|
||||
const resetFooterProperties = async () => {
|
||||
try {
|
||||
logOperation('Resetting footer properties to defaults');
|
||||
const success = await footerService.resetFooterProperties(defaultFooterProperties);
|
||||
if (success) {
|
||||
logOperation('Footer properties reset successfully');
|
||||
setFooterProperties(defaultFooterProperties);
|
||||
} else {
|
||||
logOperation('Failed to reset footer properties');
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error resetting footer properties: ${error}`);
|
||||
console.error("Failed to reset footer properties:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const saveFooterProperties = async (newProperties: FooterProperties) => {
|
||||
try {
|
||||
logOperation('Saving new footer properties');
|
||||
const success = await footerService.saveFooterProperties(newProperties);
|
||||
if (success) {
|
||||
logOperation('Footer properties saved successfully');
|
||||
setFooterProperties(newProperties);
|
||||
} else {
|
||||
logOperation('Failed to save footer properties');
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error saving footer properties: ${error}`);
|
||||
console.error("Failed to save footer properties:", error);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
} from "@/store/slices/presentationGeneration";
|
||||
import { OverlayLoader } from "@/components/ui/overlay-loader";
|
||||
import Wrapper from "@/components/Wrapper";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
const CreatePage = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -71,12 +72,11 @@ const CreatePage = () => {
|
|||
if (!active || !over || !titles) return;
|
||||
|
||||
if (active.id !== over.id) {
|
||||
logOperation(`Reordering slides: ${active.id} -> ${over.id}`);
|
||||
// Find the indices of the dragged and target items
|
||||
const oldIndex = titles.findIndex((item) => item === active.id);
|
||||
const newIndex = titles.findIndex((item) => item === over.id);
|
||||
|
||||
// Create new array with reordered items and updated indices
|
||||
|
||||
// Reorder the array
|
||||
const reorderedArray = arrayMove(titles, oldIndex, newIndex);
|
||||
|
||||
|
|
@ -86,6 +86,7 @@ const CreatePage = () => {
|
|||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
logOperation('Starting presentation generation');
|
||||
// Generate data
|
||||
setLoadingState({
|
||||
message: "Generating data...",
|
||||
|
|
@ -94,8 +95,6 @@ const CreatePage = () => {
|
|||
duration: 10,
|
||||
});
|
||||
try {
|
||||
|
||||
|
||||
const response = await PresentationGenerationApi.generateData({
|
||||
presentation_id: presentation_id,
|
||||
theme: {
|
||||
|
|
@ -105,17 +104,17 @@ const CreatePage = () => {
|
|||
watermark: false,
|
||||
images: images,
|
||||
titles: titles,
|
||||
|
||||
});
|
||||
|
||||
if (response) {
|
||||
logOperation('Presentation data generated successfully');
|
||||
dispatch(setPresentationData(response));
|
||||
|
||||
router.push(
|
||||
`/presentation?id=${presentation_id}&session=${response.session}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in presentation generation: ${error}`);
|
||||
console.error("error in data generation", error);
|
||||
toast({
|
||||
title: "Error Adding Charts",
|
||||
|
|
@ -134,6 +133,7 @@ const CreatePage = () => {
|
|||
|
||||
const handleAddSlide = () => {
|
||||
if (!titles) {
|
||||
logOperation('Error: Cannot add slide - titles not available');
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Cannot add slide at this time",
|
||||
|
|
@ -143,6 +143,7 @@ const CreatePage = () => {
|
|||
}
|
||||
|
||||
if (titles.length >= initialSlideCount) {
|
||||
logOperation('Error: Cannot add more slides - reached maximum limit');
|
||||
toast({
|
||||
title: "Cannot add more slides",
|
||||
description:
|
||||
|
|
@ -152,8 +153,8 @@ const CreatePage = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
logOperation('Adding new slide to presentation');
|
||||
const newTitleWithCharts = [...titles, "New Slide"];
|
||||
|
||||
dispatch(setTitles(newTitleWithCharts));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { getIconFromFile, removeUUID } from "../../utils/others";
|
|||
import { ChevronRight, PanelRightOpen, X } from "lucide-react";
|
||||
import ToolTip from "@/components/ToolTip";
|
||||
import Header from "@/app/dashboard/components/Header";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
// Types
|
||||
interface LoadingState {
|
||||
|
|
@ -132,6 +133,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
|
||||
const handleCreatePresentation = async () => {
|
||||
try {
|
||||
logOperation('Starting document preview presentation generation');
|
||||
setShowLoading({
|
||||
message: "Generating presentation outline...",
|
||||
show: true,
|
||||
|
|
@ -146,16 +148,17 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
documents: documentPaths,
|
||||
images: imageKeys,
|
||||
language: config?.language ?? "",
|
||||
|
||||
});
|
||||
|
||||
try {
|
||||
logOperation('Generating presentation titles');
|
||||
const titlePromise = await PresentationGenerationApi.titleGeneration({
|
||||
presentation_id: createResponse.id,
|
||||
});
|
||||
|
||||
dispatch(setPresentationId(titlePromise.id));
|
||||
dispatch(setTitles(titlePromise.titles));
|
||||
logOperation('Presentation titles generated successfully');
|
||||
|
||||
setShowLoading({
|
||||
message: "",
|
||||
|
|
@ -166,6 +169,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
|
||||
router.push("/theme");
|
||||
} catch (error) {
|
||||
logOperation(`Error in title generation: ${error}`);
|
||||
console.error("Error in title generation:", error);
|
||||
toast({
|
||||
title: "Error in title generation.",
|
||||
|
|
@ -174,6 +178,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in presentation creation: ${error}`);
|
||||
console.error("Error in presentation creation:", error);
|
||||
toast({
|
||||
title: "Error in presentation creation.",
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import React from 'react'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
const loading = () => {
|
||||
return (
|
||||
<div>
|
||||
<Skeleton className='h-24 w-full' />
|
||||
<div className="flex flex-col max-w-7xl mx-auto gap-6 my-10 justify-center items-center ">
|
||||
{
|
||||
Array.from({ length: 10 }).map((_, index) => (
|
||||
<Skeleton key={index} className="animate-pulse aspect-video w-full" />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default loading
|
||||
|
|
@ -47,6 +47,7 @@ import Modal from "./Modal";
|
|||
|
||||
import Announcement from "@/components/Announcement";
|
||||
import { getFontLink } from "../../utils/others";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
const Header = ({
|
||||
presentation_id,
|
||||
|
|
@ -70,6 +71,7 @@ const Header = ({
|
|||
const handleThemeSelect = async (value: string) => {
|
||||
if (isStreaming) return;
|
||||
if (value === "custom") {
|
||||
logOperation('Opening custom theme modal');
|
||||
setShowCustomThemeModal(true);
|
||||
return;
|
||||
} else {
|
||||
|
|
@ -78,6 +80,7 @@ const Header = ({
|
|||
|
||||
if (themeColors) {
|
||||
try {
|
||||
logOperation(`Changing theme to: ${themeType}`);
|
||||
// Update UI
|
||||
dispatch(setTheme(themeType));
|
||||
dispatch(setThemeColors({ ...themeColors, theme: themeType }));
|
||||
|
|
@ -111,7 +114,9 @@ const Header = ({
|
|||
...themeColors,
|
||||
},
|
||||
});
|
||||
logOperation(`Theme ${themeType} applied successfully`);
|
||||
} catch (error) {
|
||||
logOperation(`Error updating theme: ${error}`);
|
||||
console.error("Failed to update theme:", error);
|
||||
toast({
|
||||
title: "Error updating theme",
|
||||
|
|
@ -126,8 +131,7 @@ const Header = ({
|
|||
|
||||
const getSlideMetadata = async () => {
|
||||
try {
|
||||
// Get the current URL without any query parameters
|
||||
// const baseUrl = `${window.location.origin}/pdf-maker?id=${presentation_id}`;
|
||||
logOperation('Fetching slide metadata');
|
||||
const baseUrl = window.location.href;
|
||||
// @ts-ignore
|
||||
const metadata = await window.electron.getSlideMetadata(
|
||||
|
|
@ -135,10 +139,10 @@ const Header = ({
|
|||
currentTheme,
|
||||
currentColors,
|
||||
);
|
||||
|
||||
console.log("metadata", metadata);
|
||||
logOperation('Slide metadata fetched successfully');
|
||||
return metadata;
|
||||
} catch (error) {
|
||||
logOperation(`Error fetching metadata: ${error}`);
|
||||
setShowLoader(false);
|
||||
console.error("Error fetching metadata:", error);
|
||||
toast({
|
||||
|
|
@ -183,23 +187,27 @@ const Header = ({
|
|||
if (isStreaming) return;
|
||||
|
||||
try {
|
||||
logOperation('Starting PPTX export');
|
||||
setOpen(false);
|
||||
setShowLoader(true);
|
||||
|
||||
const apiBody = await metaData();
|
||||
|
||||
const response = await PresentationGenerationApi.exportAsPPTX(apiBody);
|
||||
|
||||
if (response.path) {
|
||||
logOperation('PPTX export completed, initiating download');
|
||||
setShowLoader(false);
|
||||
// @ts-ignore
|
||||
const ipcResponse = await window.electron.fileDownloaded(response.path);
|
||||
if (!ipcResponse.success) {
|
||||
throw new Error("Failed to download file");
|
||||
}
|
||||
logOperation('PPTX download completed successfully');
|
||||
} else {
|
||||
throw new Error("No URL returned from export");
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in PPTX export: ${error}`);
|
||||
console.error("Export failed:", error);
|
||||
setShowLoader(false);
|
||||
toast({
|
||||
|
|
@ -218,6 +226,7 @@ const Header = ({
|
|||
|
||||
setOpen(false);
|
||||
try {
|
||||
logOperation('Starting PDF export');
|
||||
toast({
|
||||
title: "Exporting presentation...",
|
||||
description: "Please wait while we export your presentation.",
|
||||
|
|
@ -229,8 +238,10 @@ const Header = ({
|
|||
if (!ipcResponse.success) {
|
||||
throw new Error("Failed to export as PDF");
|
||||
}
|
||||
logOperation('PDF export completed successfully');
|
||||
|
||||
} catch (err) {
|
||||
logOperation(`Error in PDF export: ${err}`);
|
||||
console.error(err);
|
||||
toast({
|
||||
title: "Having trouble exporting!",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { Button } from "@/components/ui/button";
|
|||
import { AlertCircle } from "lucide-react";
|
||||
import Help from "./Help";
|
||||
import { getEnv } from "@/utils/constant";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
const urls = getEnv();
|
||||
const BASE_URL = urls.BASE_URL;
|
||||
|
|
@ -87,14 +88,17 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
const autoSave = useCallback(
|
||||
(data: { presentation_id: string; slides: any[] }) => {
|
||||
setAutoSaveLoading(true);
|
||||
logOperation('Auto-saving presentation changes');
|
||||
// Fire and forget - no await
|
||||
PresentationGenerationApi.updatePresentationContent(data)
|
||||
.then(() => { })
|
||||
.then(() => {
|
||||
logOperation('Auto-save completed successfully');
|
||||
})
|
||||
.catch((error) => {
|
||||
logOperation(`Auto-save error: ${error}`);
|
||||
console.error("Error AAYO", error);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("Auto finished");
|
||||
setAutoSaveLoading(false);
|
||||
});
|
||||
},
|
||||
|
|
@ -128,11 +132,11 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
|
||||
// Function to fetch the slides
|
||||
useEffect(() => {
|
||||
|
||||
let evtSource: EventSource;
|
||||
let accumulatedChunks = "";
|
||||
|
||||
const fetchSlides = async () => {
|
||||
logOperation('Starting slide streaming');
|
||||
dispatch(setStreaming(true));
|
||||
|
||||
evtSource = new EventSource(
|
||||
|
|
@ -140,6 +144,7 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
);
|
||||
|
||||
evtSource.onopen = () => {
|
||||
logOperation('Stream connection opened');
|
||||
setColorsVariables(currentColors, currentTheme);
|
||||
};
|
||||
|
||||
|
|
@ -153,7 +158,6 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
const repairedJson = jsonrepair(accumulatedChunks);
|
||||
const partialData = JSON.parse(repairedJson);
|
||||
if (partialData.slides) {
|
||||
// Check if the length of slides has changed
|
||||
if (
|
||||
partialData.slides.length !== previousSlidesLength.current &&
|
||||
partialData.slides.length > 1
|
||||
|
|
@ -165,17 +169,16 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
slides: partialData.slides,
|
||||
})
|
||||
);
|
||||
previousSlidesLength.current = partialData.slides.length + 1; // Update the previous length
|
||||
previousSlidesLength.current = partialData.slides.length + 1;
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error('error while repairing json', error)
|
||||
// It's okay if this fails, it just means the JSON isn't complete yet
|
||||
}
|
||||
} else if (data.type === "complete") {
|
||||
try {
|
||||
console.log("evtsource completer", data);
|
||||
logOperation('Stream completed successfully');
|
||||
dispatch(setPresentationData(data.presentation));
|
||||
dispatch(setStreaming(false));
|
||||
if (data.presentation.theme) {
|
||||
|
|
@ -198,11 +201,13 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
newUrl.searchParams.delete("session");
|
||||
window.history.replaceState({}, "", newUrl.toString());
|
||||
} catch (error) {
|
||||
logOperation(`Error processing stream completion: ${error}`);
|
||||
evtSource.close();
|
||||
console.error("Error parsing accumulated chunks:", error);
|
||||
}
|
||||
accumulatedChunks = "";
|
||||
} else if (data.type === "closing") {
|
||||
logOperation('Stream closing normally');
|
||||
dispatch(setPresentationData(data.presentation));
|
||||
if (data.presentation.theme) {
|
||||
dispatch(
|
||||
|
|
@ -226,6 +231,7 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
}
|
||||
});
|
||||
evtSource.onerror = (error) => {
|
||||
logOperation(`Stream error: ${error}`);
|
||||
console.error("EventSource failed:", error);
|
||||
|
||||
setLoading(false);
|
||||
|
|
@ -262,8 +268,10 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
// Function to fetch the user slides
|
||||
const fetchUserSlides = async () => {
|
||||
try {
|
||||
logOperation('Fetching user slides');
|
||||
const data = await DashboardApi.getPresentation(presentation_id);
|
||||
if (data) {
|
||||
logOperation('User slides fetched successfully');
|
||||
if (data.presentation.theme) {
|
||||
dispatch(
|
||||
setThemeColors({
|
||||
|
|
@ -280,6 +288,7 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
setLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error fetching user slides: ${error}`);
|
||||
setError(true);
|
||||
toast({
|
||||
title: "Error",
|
||||
|
|
@ -316,6 +325,7 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
// Function to handle slide change for presentation mode
|
||||
const handleSlideChange = (newSlide: number) => {
|
||||
if (newSlide >= 0 && newSlide < presentationData?.slides.length!) {
|
||||
logOperation(`Changing to slide ${newSlide}`);
|
||||
setSelectedSlide(newSlide);
|
||||
router.push(
|
||||
`/presentation?id=${presentation_id}&mode=present&slide=${newSlide}`,
|
||||
|
|
@ -325,6 +335,7 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
|
|||
};
|
||||
|
||||
const handleDeleteSlide = async (index: number) => {
|
||||
logOperation(`Deleting slide at index ${index}`);
|
||||
dispatch(deletePresentationSlide(index));
|
||||
const response = PresentationGenerationApi.deleteSlide(
|
||||
presentation_id,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { useDispatch, useSelector } from "react-redux";
|
|||
import { addSlide, updateSlide } from "@/store/slices/presentationGeneration";
|
||||
import NewSlide from "../../components/slide_layouts/NewSlide";
|
||||
import { getEmptySlideContent } from "../../utils/NewSlideContent";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
interface SlideContentProps {
|
||||
slide: Slide;
|
||||
|
|
@ -47,6 +48,7 @@ const SlideContent = ({
|
|||
) as HTMLInputElement;
|
||||
const value = element?.value;
|
||||
if (!value?.trim()) {
|
||||
logOperation(`Error: Empty prompt for slide ${slide.index}`);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Please enter a prompt before submitting",
|
||||
|
|
@ -55,6 +57,7 @@ const SlideContent = ({
|
|||
return;
|
||||
}
|
||||
setIsUpdating(true);
|
||||
logOperation(`Updating slide ${slide.index} with prompt: ${value}`);
|
||||
|
||||
try {
|
||||
const response = await PresentationGenerationApi.editSlide(
|
||||
|
|
@ -64,7 +67,7 @@ const SlideContent = ({
|
|||
);
|
||||
|
||||
if (response) {
|
||||
console.log("response", response);
|
||||
logOperation(`Slide ${slide.index} updated successfully`);
|
||||
dispatch(updateSlide({ index: slide.index, slide: response }));
|
||||
toast({
|
||||
title: "Success",
|
||||
|
|
@ -72,6 +75,7 @@ const SlideContent = ({
|
|||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error updating slide ${slide.index}: ${error}`);
|
||||
console.error("Error updating slide:", error);
|
||||
toast({
|
||||
title: "Error",
|
||||
|
|
@ -84,6 +88,7 @@ const SlideContent = ({
|
|||
};
|
||||
|
||||
const handleNewSlide = (type: number, index: number) => {
|
||||
logOperation(`Adding new slide of type ${type} after slide ${index}`);
|
||||
const newSlide: Slide = getEmptySlideContent(
|
||||
type,
|
||||
index + 1,
|
||||
|
|
@ -101,6 +106,7 @@ const SlideContent = ({
|
|||
presentationData.slides.length > 1 &&
|
||||
isStreaming
|
||||
) {
|
||||
|
||||
const slideElement = document.getElementById(`slide-${index}`);
|
||||
if (slideElement) {
|
||||
slideElement.scrollIntoView({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { getEnv } from "@/utils/constant";
|
||||
import { getHeader, getHeaderForFormData } from "./header";
|
||||
import { IconSearch, ImageGenerate, ImageSearch } from "./params";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
const urls = getEnv();
|
||||
const BASE_URL = urls.BASE_URL;
|
||||
|
|
@ -11,6 +12,7 @@ export class PresentationGenerationApi {
|
|||
|
||||
static async getChapterDetails() {
|
||||
try {
|
||||
logOperation('Fetching chapter details');
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/chapter-details`,
|
||||
{
|
||||
|
|
@ -21,15 +23,18 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
logOperation('Successfully fetched chapter details');
|
||||
return data;
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error fetching chapter details: ${error}`);
|
||||
console.error("Error getting chapter details:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
static async uploadDoc(documents: File[], images: File[]) {
|
||||
logOperation(`Uploading documents: ${documents.length} files, images: ${images.length} files`);
|
||||
const formData = new FormData();
|
||||
|
||||
documents.forEach((document) => {
|
||||
|
|
@ -53,12 +58,15 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
|
||||
if (!response.ok) {
|
||||
logOperation(`Upload failed with status: ${response.status}`);
|
||||
throw new Error(`Upload failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
logOperation('Successfully uploaded documents and images');
|
||||
return data;
|
||||
} catch (error) {
|
||||
logOperation(`Upload error: ${error}`);
|
||||
console.error("Upload error:", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -67,6 +75,7 @@ export class PresentationGenerationApi {
|
|||
|
||||
|
||||
static async decomposeDocuments(documentKeys: string[], imageKeys: string[]) {
|
||||
logOperation(`Decomposing documents: ${documentKeys.length} files, images: ${imageKeys.length} files`);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/files/decompose`,
|
||||
|
|
@ -82,12 +91,14 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
|
||||
logOperation('Successfully decomposed documents');
|
||||
return data;
|
||||
} else {
|
||||
logOperation(`Failed to decompose files: ${response.statusText}`);
|
||||
throw new Error(`Failed to decompose files: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in Decompose Files: ${error}`);
|
||||
console.error("Error in Decompose Files", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -124,6 +135,7 @@ export class PresentationGenerationApi {
|
|||
}
|
||||
|
||||
static async generatePresentation(presentationData: any) {
|
||||
logOperation('Generating presentation');
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/generate`,
|
||||
|
|
@ -136,14 +148,14 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
|
||||
logOperation('Successfully generated presentation');
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Failed to generate presentation: ${response.statusText}`
|
||||
);
|
||||
logOperation(`Failed to generate presentation: ${response.statusText}`);
|
||||
throw new Error(`Failed to generate presentation: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in presentation generation: ${error}`);
|
||||
console.error("error in presentation generation", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -153,6 +165,7 @@ export class PresentationGenerationApi {
|
|||
index: number,
|
||||
prompt: string
|
||||
) {
|
||||
logOperation(`Editing slide ${index} in presentation ${presentation_id}`);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/edit`,
|
||||
|
|
@ -170,12 +183,15 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
|
||||
if (!response.ok) {
|
||||
logOperation(`Failed to update slide ${index}: ${response.statusText}`);
|
||||
throw new Error("Failed to update slides");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
logOperation(`Successfully updated slide ${index}`);
|
||||
return data;
|
||||
} catch (error) {
|
||||
logOperation(`Error in slide update: ${error}`);
|
||||
console.error("error in slide update", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -254,6 +270,7 @@ export class PresentationGenerationApi {
|
|||
}
|
||||
}
|
||||
static async generateImage(imageGenerate: ImageGenerate) {
|
||||
logOperation(`Generating image with prompt: ${imageGenerate.prompt.image_prompt}`);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/image/generate`,
|
||||
|
|
@ -266,12 +283,14 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
|
||||
logOperation('Successfully generated image');
|
||||
return data;
|
||||
} else {
|
||||
logOperation(`Failed to generate images: ${response.statusText}`);
|
||||
throw new Error(`Failed to generate images: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in image generation: ${error}`);
|
||||
console.error("error in image generation", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
@ -325,6 +344,7 @@ export class PresentationGenerationApi {
|
|||
|
||||
// EXPORT PRESENTATION
|
||||
static async exportAsPPTX(presentationData: any) {
|
||||
logOperation('Exporting presentation as PPTX');
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/presentation/export_as_pptx`,
|
||||
|
|
@ -337,20 +357,23 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
|
||||
logOperation('Successfully exported presentation as PPTX');
|
||||
return {
|
||||
...data,
|
||||
url: `${BASE_URL}${data.url}`,
|
||||
};
|
||||
} else {
|
||||
logOperation(`Failed to export as pptx: ${response.statusText}`);
|
||||
throw new Error(`Failed to export as pptx: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in pptx export: ${error}`);
|
||||
console.error("error in pptx export", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async exportAsPDF(presentationData: any) {
|
||||
logOperation('Exporting presentation as PDF');
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/presentation/export_as_pdf`,
|
||||
|
|
@ -362,17 +385,20 @@ export class PresentationGenerationApi {
|
|||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
|
||||
logOperation('Successfully exported presentation as PDF');
|
||||
return data;
|
||||
} else {
|
||||
logOperation(`Failed to export as pdf: ${response.statusText}`);
|
||||
throw new Error(`Failed to export as pdf: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in pdf export: ${error}`);
|
||||
console.error("error in pdf export", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async deleteSlide(presentation_id: string, slide_id: string) {
|
||||
logOperation(`Deleting slide ${slide_id} from presentation ${presentation_id}`);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/slide/delete?presentation_id=${presentation_id}&slide_id=${slide_id}`,
|
||||
|
|
@ -383,17 +409,21 @@ export class PresentationGenerationApi {
|
|||
}
|
||||
);
|
||||
if (response.status === 204) {
|
||||
logOperation(`Successfully deleted slide ${slide_id}`);
|
||||
return true;
|
||||
} else {
|
||||
logOperation(`Failed to delete slide: ${response.statusText}`);
|
||||
throw new Error(`Failed to delete slide: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logOperation(`Error in slide deletion: ${error}`);
|
||||
console.error("error in slide deletion", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// SET THEME COLORS
|
||||
static async setThemeColors(presentation_id: string, theme: any) {
|
||||
logOperation(`Setting theme colors for presentation ${presentation_id}`);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/presentation/theme`,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { useDispatch } from "react-redux";
|
|||
import { useRouter } from "next/navigation";
|
||||
import { ThemeType } from "../upload/type";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { toast } from "@/hooks/use-toast";
|
||||
import { clearLogs, logOperation } from "../utils/log";
|
||||
|
||||
interface ThemeCardProps {
|
||||
name: string;
|
||||
|
|
@ -114,18 +114,20 @@ const ThemePage = () => {
|
|||
const router = useRouter();
|
||||
const [selectedTheme, setSelectedTheme] = useState<ThemeType | null>(null);
|
||||
const handleThemeClick = async (theme: ThemeColors, type: string) => {
|
||||
logOperation(`Theme selected: ${type}`);
|
||||
setSelectedTheme(type as ThemeType);
|
||||
};
|
||||
const handleSubmit = () => {
|
||||
if (!selectedTheme) {
|
||||
logOperation('Error: No theme selected');
|
||||
toast({
|
||||
title: "Please select a theme",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
logOperation(`Proceeding with theme: ${selectedTheme}`);
|
||||
dispatch(setTheme(selectedTheme as ThemeType));
|
||||
|
||||
router.push("/create");
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { PresentationGenerationApi } from "../../services/api/presentation-gener
|
|||
import { OverlayLoader } from "@/components/ui/overlay-loader";
|
||||
import Wrapper from "@/components/Wrapper";
|
||||
import { setPptGenUploadState } from "@/store/slices/presentationGenUpload";
|
||||
import { clearLogs, logOperation } from "../../utils/log";
|
||||
|
||||
// Types for loading state
|
||||
interface LoadingState {
|
||||
|
|
@ -63,6 +64,8 @@ const UploadPage = () => {
|
|||
const dispatch = useDispatch();
|
||||
const { toast } = useToast();
|
||||
|
||||
|
||||
|
||||
// State management
|
||||
const [documents, setDocuments] = useState<File[]>([]);
|
||||
const [images, setImages] = useState<File[]>([]);
|
||||
|
|
@ -138,7 +141,15 @@ const UploadPage = () => {
|
|||
if (!validateConfiguration()) return;
|
||||
|
||||
try {
|
||||
// Clear previous logs before starting new presentation
|
||||
clearLogs();
|
||||
logOperation(`----New Presentation Generation----`);
|
||||
|
||||
const hasUploadedAssets = documents.length > 0 || images.length > 0;
|
||||
// Log the configuration
|
||||
logOperation(`Config: ${JSON.stringify(config)}`);
|
||||
// Log the files updated
|
||||
logOperation(`Files updated: ${documents.length} documents, ${images.length} images`);
|
||||
|
||||
if (hasUploadedAssets) {
|
||||
await handleDocumentProcessing();
|
||||
|
|
@ -154,6 +165,7 @@ const UploadPage = () => {
|
|||
* Handles document processing
|
||||
*/
|
||||
const handleDocumentProcessing = async () => {
|
||||
logOperation('Starting document processing');
|
||||
setLoadingState({
|
||||
isLoading: true,
|
||||
message: "Processing documents...",
|
||||
|
|
@ -166,6 +178,7 @@ const UploadPage = () => {
|
|||
let imageKeys = [];
|
||||
|
||||
if (documents.length > 0 || images.length > 0) {
|
||||
logOperation(`Uploading ${documents.length} documents and ${images.length} images`);
|
||||
const uploadResponse = await PresentationGenerationApi.uploadDoc(documents, images);
|
||||
documentKeys = uploadResponse["documents"];
|
||||
imageKeys = uploadResponse["images"];
|
||||
|
|
@ -174,15 +187,16 @@ const UploadPage = () => {
|
|||
const promises: Promise<any>[] = [];
|
||||
|
||||
if (documents.length > 0 || images.length > 0) {
|
||||
logOperation('Decomposing documents');
|
||||
promises.push(
|
||||
PresentationGenerationApi.decomposeDocuments(documentKeys, imageKeys)
|
||||
);
|
||||
}
|
||||
|
||||
const responses = await Promise.all(promises);
|
||||
|
||||
const processedData = processApiResponses(responses);
|
||||
|
||||
logOperation('Document processing completed');
|
||||
dispatch(setPptGenUploadState(processedData));
|
||||
router.push("/documents-preview");
|
||||
};
|
||||
|
|
@ -217,6 +231,7 @@ const UploadPage = () => {
|
|||
* Handles direct presentation generation without documents
|
||||
*/
|
||||
const handleDirectPresentationGeneration = async () => {
|
||||
logOperation('Starting direct presentation generation');
|
||||
setLoadingState({
|
||||
isLoading: true,
|
||||
message: "Generating outlines...",
|
||||
|
|
@ -229,20 +244,21 @@ const UploadPage = () => {
|
|||
n_slides: config?.slides ? parseInt(config.slides) : null,
|
||||
documents: [],
|
||||
images: [],
|
||||
|
||||
language: config?.language ?? "",
|
||||
|
||||
});
|
||||
|
||||
try {
|
||||
logOperation('Generating presentation titles');
|
||||
const titlePromise = await PresentationGenerationApi.titleGeneration({
|
||||
presentation_id: createResponse.id,
|
||||
});
|
||||
dispatch(setPresentationId(titlePromise.id));
|
||||
dispatch(setTitles(titlePromise.titles));
|
||||
logOperation('Presentation generation completed successfully');
|
||||
router.push("/theme");
|
||||
} catch (error) {
|
||||
console.error("Error in title generation:", error);
|
||||
logOperation(`Error in title generation: ${error}`);
|
||||
toast({
|
||||
title: "Error in title generation.",
|
||||
description: "Please try again.",
|
||||
|
|
@ -256,6 +272,7 @@ const UploadPage = () => {
|
|||
*/
|
||||
const handleGenerationError = (error: any) => {
|
||||
console.error("Error in presentation generation:", error);
|
||||
logOperation(`Presentation generation error: ${error}`);
|
||||
dispatch(setError("Failed to generate presentation"));
|
||||
setLoadingState({
|
||||
isLoading: false,
|
||||
|
|
|
|||
11
servers/nextjs/app/(presentation-generator)/utils/log.ts
Normal file
11
servers/nextjs/app/(presentation-generator)/utils/log.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Add logging function
|
||||
export const logOperation = (message: string) => {
|
||||
// @ts-ignore
|
||||
window.electron.writeNextjsLog(message)
|
||||
};
|
||||
|
||||
// Add clear logs function
|
||||
export const clearLogs = () => {
|
||||
// @ts-ignore
|
||||
window.electron.clearNextjsLogs();
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@ import {
|
|||
getHeaderForFormData,
|
||||
} from "@/app/(presentation-generator)/services/api/header";
|
||||
import { getEnv } from "@/utils/constant";
|
||||
import { clearLogs, logOperation } from "@/app/(presentation-generator)/utils/log";
|
||||
|
||||
const urls = getEnv();
|
||||
const BASE_URL = urls.BASE_URL;
|
||||
|
|
@ -27,6 +28,7 @@ export class DashboardApi {
|
|||
|
||||
static async getPresentations(): Promise<PresentationResponse[]> {
|
||||
try {
|
||||
logOperation('Fetching user presentations');
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/user_presentations`,
|
||||
{
|
||||
|
|
@ -35,19 +37,23 @@ export class DashboardApi {
|
|||
);
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
logOperation(`Successfully fetched ${data.length} presentations`);
|
||||
return data;
|
||||
} else if (response.status === 404) {
|
||||
logOperation('No presentations found');
|
||||
console.log("No presentations found");
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
} catch (error) {
|
||||
logOperation(`Error fetching presentations: ${error}`);
|
||||
console.error("Error fetching presentations:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async getPresentation(id: string) {
|
||||
try {
|
||||
logOperation(`Fetching presentation with ID: ${id}`);
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/presentation?presentation_id=${id}`,
|
||||
{
|
||||
|
|
@ -57,16 +63,20 @@ export class DashboardApi {
|
|||
);
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
logOperation(`Successfully fetched presentation ${id}`);
|
||||
return data;
|
||||
}
|
||||
logOperation(`Presentation ${id} not found`);
|
||||
throw new Error("Presentation not found");
|
||||
} catch (error) {
|
||||
logOperation(`Error fetching presentation ${id}: ${error}`);
|
||||
console.error("Error fetching presentations:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async deletePresentation(presentation_id: string) {
|
||||
try {
|
||||
logOperation(`Deleting presentation ${presentation_id}`);
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/delete?presentation_id=${presentation_id}`,
|
||||
{
|
||||
|
|
@ -76,15 +86,19 @@ export class DashboardApi {
|
|||
);
|
||||
|
||||
if (response.status === 204) {
|
||||
logOperation(`Successfully deleted presentation ${presentation_id}`);
|
||||
return true;
|
||||
}
|
||||
logOperation(`Failed to delete presentation ${presentation_id}`);
|
||||
return false;
|
||||
} catch (error) {
|
||||
logOperation(`Error deleting presentation ${presentation_id}: ${error}`);
|
||||
console.error("Error deleting presentation:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async setSlideThumbnail(presentation_id: string, file: any) {
|
||||
logOperation(`Setting thumbnail for presentation ${presentation_id}`);
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("presentation_id", presentation_id);
|
||||
|
|
@ -99,8 +113,10 @@ export class DashboardApi {
|
|||
}
|
||||
);
|
||||
const data = await response.json();
|
||||
logOperation(`Successfully set thumbnail for presentation ${presentation_id}`);
|
||||
return data;
|
||||
} catch (error) {
|
||||
logOperation(`Error setting slide thumbnail for presentation ${presentation_id}: ${error}`);
|
||||
console.error("Error setting slide thumbnail:", error);
|
||||
throw error;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue