diff --git a/Dockerfile b/Dockerfile index 9ba7c3bf..3815c237 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ WORKDIR /app # Set environment variables ENV APP_DATA_DIRECTORY=/app_data ENV TEMP_DIRECTORY=/tmp/presenton -ENV PYTHONPATH="${PYTHONPATH}:/app/servers/fastapi" +# ENV PYTHONPATH="${PYTHONPATH}:/app/servers/fastapi" # Install ollama diff --git a/Dockerfile.dev b/Dockerfile.dev index 20b37e52..f4e860a1 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -19,7 +19,7 @@ RUN ls -a # Set environment variables ENV APP_DATA_DIRECTORY=/app_data ENV TEMP_DIRECTORY=/tmp/presenton -ENV PYTHONPATH="${PYTHONPATH}:/app/servers/fastapi" +# ENV PYTHONPATH="${PYTHONPATH}:/app/servers/fastapi" # Install ollama RUN curl -fsSL http://ollama.com/install.sh | sh diff --git a/servers/fastapi/services/docling_service.py b/servers/fastapi/services/docling_service.py index 6a9220b2..f6ae203e 100644 --- a/servers/fastapi/services/docling_service.py +++ b/servers/fastapi/services/docling_service.py @@ -1,4 +1,9 @@ -from docling.document_converter import DocumentConverter, PdfFormatOption +from docling.document_converter import ( + DocumentConverter, + PdfFormatOption, + PowerpointFormatOption, + WordFormatOption, +) from docling.datamodel.pipeline_options import PdfPipelineOptions from docling.datamodel.base_models import InputFormat @@ -9,17 +14,18 @@ class DoclingService: self.pipeline_options.do_ocr = False self.converter = DocumentConverter( + allowed_formats=[InputFormat.PPTX, InputFormat.PDF, InputFormat.DOCX], format_options={ - InputFormat.DOCX: PdfFormatOption( + InputFormat.DOCX: WordFormatOption( pipeline_options=self.pipeline_options, ), - InputFormat.PPTX: PdfFormatOption( + InputFormat.PPTX: PowerpointFormatOption( pipeline_options=self.pipeline_options, ), InputFormat.PDF: PdfFormatOption( pipeline_options=self.pipeline_options, ), - } + }, ) def parse_to_markdown(self, file_path: str) -> str: diff --git a/servers/fastapi/utils/get_dynamic_models.py b/servers/fastapi/utils/get_dynamic_models.py index c2012217..744a6a5a 100644 --- a/servers/fastapi/utils/get_dynamic_models.py +++ b/servers/fastapi/utils/get_dynamic_models.py @@ -7,7 +7,7 @@ from models.presentation_structure_model import PresentationStructureModel def get_presentation_outline_model_with_n_slides(n_slides: int): class PresentationOutlineModelWithNSlides(PresentationOutlineModel): slides: List[str] = Field( - description="Markdown content for each slide", + description="Markdown content for each slide in about 100 to 200 words", min_items=n_slides, max_items=n_slides, ) diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx index f0ccc554..bc5ee297 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx @@ -1,12 +1,10 @@ import React from "react"; import { Button } from "@/components/ui/button"; -import { SlideOutline } from "@/store/slices/presentationGeneration"; import { LoadingState, StreamState, LayoutGroup } from "../types/index"; interface GenerateButtonProps { loadingState: LoadingState; streamState: StreamState; - outlines: SlideOutline[] | null; selectedLayoutGroup: LayoutGroup | null; onSubmit: () => void; } @@ -14,7 +12,6 @@ interface GenerateButtonProps { const GenerateButton: React.FC = ({ loadingState, streamState, - outlines, selectedLayoutGroup, onSubmit }) => { diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx index 3dad4300..eceb950b 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/OutlinePage.tsx @@ -85,7 +85,6 @@ const OutlinePage: React.FC = () => { diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts index db15c4a6..6d27b1e5 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts @@ -1,9 +1,9 @@ import { useCallback } from "react"; import { useDispatch } from "react-redux"; import { arrayMove } from "@dnd-kit/sortable"; -import { setOutlines, SlideOutline } from "@/store/slices/presentationGeneration"; +import { setOutlines } from "@/store/slices/presentationGeneration"; -export const useOutlineManagement = (outlines: SlideOutline[] | null) => { +export const useOutlineManagement = (outlines: string[] | null) => { const dispatch = useDispatch(); const handleDragEnd = useCallback((event: any) => { @@ -12,8 +12,8 @@ export const useOutlineManagement = (outlines: SlideOutline[] | null) => { if (!active || !over || !outlines) return; if (active.id !== over.id) { - const oldIndex = outlines.findIndex((item) => item.title === active.id); - const newIndex = outlines.findIndex((item) => item.title === over.id); + const oldIndex = outlines.findIndex((item) => item === active.id); + const newIndex = outlines.findIndex((item) => item === over.id); const reorderedArray = arrayMove(outlines, oldIndex, newIndex); dispatch(setOutlines(reorderedArray)); } @@ -22,12 +22,7 @@ export const useOutlineManagement = (outlines: SlideOutline[] | null) => { const handleAddSlide = useCallback(() => { if (!outlines) return; - const newSlide: SlideOutline = { - title: "Outline title", - body: "Outline body", - }; - - const updatedOutlines = [...outlines, newSlide]; + const updatedOutlines = [...outlines, "Outline title"]; dispatch(setOutlines(updatedOutlines)); }, [outlines, dispatch]); diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts index def04fe7..726056c9 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/usePresentationGeneration.ts @@ -2,7 +2,7 @@ import { useState, useCallback } from "react"; import { useDispatch } from "react-redux"; import { useRouter } from "next/navigation"; import { toast } from "sonner"; -import { clearPresentationData, SlideOutline } from "@/store/slices/presentationGeneration"; +import { clearPresentationData } from "@/store/slices/presentationGeneration"; import { PresentationGenerationApi } from "../../services/api/presentation-generation"; import { LayoutGroup, LoadingState, TABS } from "../types/index"; @@ -15,7 +15,7 @@ const DEFAULT_LOADING_STATE: LoadingState = { export const usePresentationGeneration = ( presentationId: string | null, - outlines: SlideOutline[] | null, + outlines: string[] | null, selectedLayoutGroup: LayoutGroup | null, setActiveTab: (tab: string) => void ) => { diff --git a/servers/nextjs/app/(presentation-generator)/pdf-maker/PdfMakerPage.tsx b/servers/nextjs/app/(presentation-generator)/pdf-maker/PdfMakerPage.tsx index 5fb51ee5..88701da1 100644 --- a/servers/nextjs/app/(presentation-generator)/pdf-maker/PdfMakerPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/pdf-maker/PdfMakerPage.tsx @@ -3,19 +3,12 @@ import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { RootState } from "@/store/store"; import { Skeleton } from "@/components/ui/skeleton"; - - -import { DashboardApi } from "@/app/(presentation-generator)/dashboard/api/dashboard"; - - import { toast } from "sonner"; - - - import { Button } from "@/components/ui/button"; import { AlertCircle } from "lucide-react"; import { useGroupLayouts } from "../hooks/useGroupLayouts"; import { setPresentationData } from "@/store/slices/presentationGeneration"; +import { DashboardApi } from "../services/api/dashboard"; diff --git a/servers/nextjs/store/slices/presentationGeneration.ts b/servers/nextjs/store/slices/presentationGeneration.ts index 1e0f012e..623496a7 100644 --- a/servers/nextjs/store/slices/presentationGeneration.ts +++ b/servers/nextjs/store/slices/presentationGeneration.ts @@ -1,11 +1,6 @@ import { Slide } from "@/app/(presentation-generator)/types/slide"; import { createSlice, PayloadAction } from "@reduxjs/toolkit"; - - - - - export interface PresentationData { id: string; language: string; @@ -137,7 +132,7 @@ const presentationGenerationSlice = createSlice({ action.payload.slide; } }, - + // Update slide content at specific data path (for Tiptap text editing) updateSlideContent: ( state, @@ -154,12 +149,12 @@ const presentationGenerationSlice = createSlice({ ) { const slide = state.presentationData.slides[action.payload.slideIndex]; const { dataPath, content } = action.payload; - + // Helper function to set nested property value const setNestedValue = (obj: any, path: string, value: string) => { const keys = path.split(/[.\[\]]+/).filter(Boolean); let current = obj; - + // Navigate to the parent object for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; @@ -178,7 +173,7 @@ const presentationGenerationSlice = createSlice({ current = current[index]; } } - + // Set the final value const finalKey = keys[keys.length - 1]; if (isNaN(Number(finalKey))) { @@ -187,7 +182,7 @@ const presentationGenerationSlice = createSlice({ current[Number(finalKey)] = value; } }; - + // Update the slide content if (dataPath && slide.content) { setNestedValue(slide.content, dataPath, content); @@ -198,8 +193,8 @@ const presentationGenerationSlice = createSlice({ addNewSlide: (state, action: PayloadAction<{ slideData: any; index: number }>) => { if (state.presentationData?.slides) { // Insert the new slide at the specified index + 1 (after current slide) - state.presentationData.slides.splice(action.payload.index +1, 0, action.payload.slideData); - + state.presentationData.slides.splice(action.payload.index + 1, 0, action.payload.slideData); + // Update indices for all slides to ensure they remain sequential state.presentationData.slides = state.presentationData.slides.map( (slide: any, idx: number) => ({ @@ -227,12 +222,12 @@ const presentationGenerationSlice = createSlice({ ) { const slide = state.presentationData.slides[action.payload.slideIndex]; const { dataPath, imageUrl, prompt } = action.payload; - + // Helper function to set nested property value for images const setNestedImageValue = (obj: any, path: string, url: string, promptText?: string) => { const keys = path.split(/[.\[\]]+/).filter(Boolean); let current = obj; - + // Navigate to the parent object for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; @@ -249,33 +244,33 @@ const presentationGenerationSlice = createSlice({ current = current[index]; } } - + // Set the image properties const finalKey = keys[keys.length - 1]; const target = isNaN(Number(finalKey)) ? current[finalKey] : current[Number(finalKey)]; - + // Preserve existing properties if the target already exists const updatedValue = { ...(target && typeof target === 'object' ? target : {}), __image_url__: url, __image_prompt__: promptText || (target?.__image_prompt__) || '' }; - + if (isNaN(Number(finalKey))) { current[finalKey] = updatedValue; } else { current[Number(finalKey)] = updatedValue; } - + // Add debugging console.log('Redux: Updated slide image at path:', path, 'with URL:', url); }; - + // Update the slide image if (dataPath && slide.content) { setNestedImageValue(slide.content, dataPath, imageUrl, prompt); } - + // Also update the images array if it exists if (slide.images && Array.isArray(slide.images)) { const imageIndex = parseInt(dataPath.split('[')[1]?.split(']')[0]) || 0; @@ -293,7 +288,7 @@ const presentationGenerationSlice = createSlice({ itemIndex: number; properties: any; }> - ) => { + ) => { if ( state.presentationData && state.presentationData.slides && @@ -305,8 +300,8 @@ const presentationGenerationSlice = createSlice({ ...slide.properties, [itemIndex]: properties }; - - } + + } }, // Update slide icon at specific data path @@ -326,12 +321,12 @@ const presentationGenerationSlice = createSlice({ ) { const slide = state.presentationData.slides[action.payload.slideIndex]; const { dataPath, iconUrl, query } = action.payload; - + // Helper function to set nested property value for icons const setNestedIconValue = (obj: any, path: string, url: string, queryText?: string) => { const keys = path.split(/[.\[\]]+/).filter(Boolean); let current = obj; - + // Navigate to the parent object for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; @@ -348,33 +343,33 @@ const presentationGenerationSlice = createSlice({ current = current[index]; } } - + // Set the icon properties const finalKey = keys[keys.length - 1]; const target = isNaN(Number(finalKey)) ? current[finalKey] : current[Number(finalKey)]; - + // Preserve existing properties if the target already exists const updatedValue = { ...(target && typeof target === 'object' ? target : {}), __icon_url__: url, __icon_query__: queryText || (target?.__icon_query__) || '' }; - + if (isNaN(Number(finalKey))) { current[finalKey] = updatedValue; } else { current[Number(finalKey)] = updatedValue; } - + // Add debugging console.log('Redux: Updated slide icon at path:', path, 'with URL:', url); }; - + // Update the slide icon if (dataPath && slide.content) { setNestedIconValue(slide.content, dataPath, iconUrl, query); } - + // Also update the icons array if it exists if (slide.icons && Array.isArray(slide.icons)) { const iconIndex = parseInt(dataPath.split('[')[1]?.split(']')[0]) || 0; diff --git a/start.js b/start.js index a9cc9af2..f2dfa1b0 100644 --- a/start.js +++ b/start.js @@ -103,19 +103,19 @@ const startServers = async () => { console.error("FastAPI process failed to start:", err); }); - const appmcpProcess = spawn( - "python", - ["mcp_server.py", "--port", appmcpPort.toString()], - { - cwd: fastapiDir, - stdio: "inherit", - env: process.env, - }, - ); + // const appmcpProcess = spawn( + // "python", + // ["mcp_server.py", "--port", appmcpPort.toString()], + // { + // cwd: fastapiDir, + // stdio: "inherit", + // env: process.env, + // }, + // ); - appmcpProcess.on("error", (err) => { - console.error("App MCP process failed to start:", err); - }); + // appmcpProcess.on("error", (err) => { + // console.error("App MCP process failed to start:", err); + // }); const nextjsProcess = spawn( "npm",