How to build: an AI-powered PowerPoint generator (Next.js, OpenAI, CopilotKit)

uliyahoo

uliyahoo

Posted on February 20, 2024

How to build: an AI-powered PowerPoint generator (Next.js, OpenAI, CopilotKit)

TL;DR

In this article, you will learn how to build an AI-powered PowerPoint application using Nextjs, CopilotKit & OpenAI. We will cover:

  • Leveraging ChatGPT to create your PowerPoint presentation📊
  • Chatting with your PowerPoint presentation💬
  • Adding audio and images to your PowerPoint presentation🔉

Image description


CopilotKit: Build deeply integrated in-app AI chatbots 💬

CopilotKit is the open-source AI copilot platform. We make it easy to integrate powerful AI chatbots into your react apps. Fully customizable and deeply integrated.

Image description

Star CopilotKit ⭐️

Now back to the article.


Prerequisites

To get started with this tutorial, you need the following installed on your computer:

  • A text editor (e.g., Visual Studio Code)
  • Node.js
  • A package manager

Creating The PowerPoint Application Frontend With NextJS

Step 1: Git clone the PowerPoint application boilerplate using the command below.



git clone https://github.com/TheGreatBonnie/aipoweredpowerpointpresentation


Enter fullscreen mode Exit fullscreen mode

Step 2: Open the PowerPoint application boilerplate on a text editor and install all project dependencies using the command below.



npm install


Enter fullscreen mode Exit fullscreen mode

Step 3: • Go to the root directory *and create a file called *.env.local. In the file, add the environment variable below that holds your ChatGPT API key.



OPENAI_API_KEY="Your ChatGPT API Key”


Enter fullscreen mode Exit fullscreen mode

Step 4: Run the command npm run dev on the command line. Navigate to http://localhost:3000/, and you should see the PowerPoint application frontend.

Image description

Creating PowerPoint Slides Functionality

Step 1: Go to /[root]/src/app/components, and create a file called present.tsx. Then import the following dependencies at the top of the file.



"use client";

import { useCopilotContext } from "@copilotkit/react-core";
import { CopilotTask } from "@copilotkit/react-core";
import {
  useMakeCopilotActionable,
  useMakeCopilotReadable,
} from "@copilotkit/react-core";
import { useEffect, useState } from "react";
import "./../presentation/styles.css";
import Markdown from "react-markdown";


Enter fullscreen mode Exit fullscreen mode

Step 2: Define a TypeScript interface called Slide with properties title and content for a PowerPoint presentation slide.



// Define slide interface
interface Slide {
  title: string;
  content: string;

}


Enter fullscreen mode Exit fullscreen mode

Step 3: Create a function called Presentation and initialize state variables called allSlides and currentSlideIndex with usestate. Variable allSlides will hold an array of slides while currentSlideIndex will hold the current slide index.



export function Presentation (){
  const [allSlides, setAllSlides] = useState<Slide[]>([]);
  const [currentSlideIndex, setCurrentSlideIndex] = useState<number>(0);
}


Enter fullscreen mode Exit fullscreen mode

Step 4: Inside the Presentation function, use the useMakeCopilotReadable hook to add the allSlides array of slides as context for the in-app chatbot.



useMakeCopilotReadable("Powerpoint presentation slides: " + JSON.stringify(allSlides));


Enter fullscreen mode Exit fullscreen mode

Step 5: Use the useMakeCopilotActionable hook to set up an action called createNewPowerPointSlide with a description and an implementation function that updates the allSlides and currentSlideIndex state variables, as shown below.




useMakeCopilotActionable(
        {
          name: "createNewPowerPointSlide",
          description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.",
          argumentAnnotations: [
            {
              name: "slideTitle",
              type: "string",
              description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.",
              required: true,
            },
            {
              name: "content",
              type: "string",
              description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.",
              required: true
            },

          ],

          implementation: async (newSlideTitle, newSlideContent) => {
            const newSlide: Slide = { title: newSlideTitle, content: newSlideContent};
            const updatedSlides = [...allSlides, newSlide];
            setAllSlides(updatedSlides);
            setCurrentSlideIndex(updatedSlides.length - 1);


          },
        },
        [],
      );


Enter fullscreen mode Exit fullscreen mode

Step 6: Define a function called displayCurrentSlide that displays the current slide index in the front end.



// Display current slide
      const displayCurrentSlide = () => {
        const slide = allSlides[currentSlideIndex];
        return slide ? (

          <div
          className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center"
          style={{
              textShadow: "1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000",
            }}
          >
          <Markdown className="markdown">{slide.title}</Markdown>
          <Markdown className="markdown">{slide.content}</Markdown>
        </div>
        ) : (
          <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center">
            No Slide To Display
          </div>
        );
      };


Enter fullscreen mode Exit fullscreen mode

Step 7: Define a function called addSlide that holds a class called CopilotTask. The CopilotTask class defines functionality for adding a new slide.



// Add new slide function
  const addSlide = new CopilotTask({
    instructions: "create a new slide",
    actions: [
      {
        name: "newSlide",
        description: "Make a new slide related to the current topic.",
        argumentAnnotations: [
          {
            name: "title",
            type: "string",
            description: "The title to display in the presentation slide.",
            required: true,
          },
          {
            name: "content",
            type: "string",
            description: "The title to display in the presentation slide.",
            required: true,
          },
        ],

        implementation: async (newSlideTitle,newSlideContent,) => {
          const newSlide: Slide = {title: newSlideTitle,content: newSlideContent,};
          const updatedSlides = [...allSlides, newSlide];
          setAllSlides(updatedSlides);
          setCurrentSlideIndex(updatedSlides.length - 1);
        },
      },
    ],
  });

  const context = useCopilotContext();

  const [randomSlideTaskRunning, setRandomSlideTaskRunning] = useState(false);


Enter fullscreen mode Exit fullscreen mode

Step 8: Define two functions called goBack and goForward. The goBack function defines functionality for navigating to the previous slide while the goForward function defines functionality for navigating to the next slide.



// Button click handlers for navigation
      const goBack = () => setCurrentSlideIndex((prev) => Math.max(0, prev - 1));
      const goForward = () => setCurrentSlideIndex((prev) => Math.min(allSlides.length - 1, prev + 1));


Enter fullscreen mode Exit fullscreen mode

Step 9: Return a component that calls displayCurrentSlide function and contains buttons that call addSlide, goBack and goForward functions.



return (
        <div>
          {displayCurrentSlide()}
          <button
            disabled={randomSlideTaskRunning}
            className={`absolute bottom-12 left-0 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded
            ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`}
            onClick={async () => {
              try {
                setRandomSlideTaskRunning(true);
                await addSlide.run(context);
              } finally {
                setRandomSlideTaskRunning(false);
              }
            }}
          >
            {randomSlideTaskRunning ? "Loading slide..." : "Add Slide +"}
          </button>
          <button 
          className={`absolute bottom-0 left-0 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded
          ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`}
          onClick={goBack}>Prev</button>
          <button
          className={`absolute bottom-0 left-20 mb-4 ml-4 bg-blue-500 text-white font-bold py-2 px-4 rounded
          ${randomSlideTaskRunning ? "opacity-50 cursor-not-allowed" : "hover:bg-blue-700"}`} 
          onClick={goForward}>Next</button>
        </div>
      );


Enter fullscreen mode Exit fullscreen mode

Step 10: In the Presentation folder, add the following code to the page.tsx file.



"use client";

import {
  CopilotKit
} from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
import {Presentation} from "../components/present";
import "./styles.css";

let globalAudio: any = undefined;
let globalAudioEnabled = false;

const Demo = () => {
  return (
    <CopilotKit url="/api/copilotkit/openai">
      <CopilotSidebar
        defaultOpen={true}
        labels={{
          title: "Presentation Copilot",
          initial: "Hi you! 👋 I can give you a presentation on any topic.",
        }}
        clickOutsideToClose={false}
        onSubmitMessage={async (message) => {
          if (!globalAudioEnabled) {
            globalAudio.play();
            globalAudio.pause();
          }
          globalAudioEnabled = true;
        }}
      >
        <Presentation/>
      </CopilotSidebar>
    </CopilotKit>
  );
};

export default Demo;


Enter fullscreen mode Exit fullscreen mode

Step 11: Navigate to http://localhost:3000/, click the ‘Get Started’ button, and you will be redirected to the presentation page that is integrated with a chatbot, as shown below.

Image description

Step 12: Give the chatbot on the right side a prompt like “Create a PowerPoint presentation on TypeScript” The chatbot will start generating a response, and once it is done, it will display the generated PowerPoint slide on the left side of the page, as shown belo

Image description

Step 13: Close the chatbot window and click the Add Slide + button to add a new slide to the PowerPoint presentation as shown below.

Image description

Step 14: Click the Prev button and you will navigate to the previous slide. If you click the Next button, you will navigate to the next slide.

Image description

Creating PowerPoint Slides Auto Speech Functionality

Step 1: In the present.tsx file, declare a variable called globalAudio, as shown below.



let globalAudio: any = undefined;


Enter fullscreen mode Exit fullscreen mode

Step 2: Inside the Presentation component, declare a useEffect hook that initializes globalAudio with a new Audio object, as shown below.



useEffect(() => {
        if (!globalAudio) {
          globalAudio = new Audio();
        }
      }, []);


Enter fullscreen mode Exit fullscreen mode

Step 3: Update the useMakeCopilotActionable hook to convert PowerPoint slides text into speech via an API, as shown below.




useMakeCopilotActionable(
        {
          name: "createNewPowerPointSlide",
          description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.",
          argumentAnnotations: [
            {
              name: "slideTitle",
              type: "string",
              description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.",
              required: true,
            },
            {
              name: "content",
              type: "string",
              description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.",
              required: true
            },

            {
                name: "speech",
                type: "string",
                description: "An informative speech about the current slide.",
                required: true,
            },
          ],

          implementation: async (newSlideTitle, newSlideContent, speech) => {
            const newSlide: Slide = { title: newSlideTitle, content: newSlideContent };
            const updatedSlides = [...allSlides, newSlide];
            setAllSlides(updatedSlides);
            setCurrentSlideIndex(updatedSlides.length - 1);

            const encodedText = encodeURIComponent(speech);
            const url = `/api/tts?text=${encodedText}`;
            globalAudio.src = url;
            await globalAudio.play();
            await new Promise<void>((resolve) => {
                globalAudio.onended = function () {
                resolve();
                };
            });
            await new Promise((resolve) => setTimeout(resolve, 500));
          },
        },
        [],
      );


Enter fullscreen mode Exit fullscreen mode

Step 4: Update the addSlide function to convert new PowerPoint slides text into speech via an API, as shown below.



// Add new slide function
      const addSlide = new CopilotTask({
        instructions: "create a new slide",
        actions: [
          {
          name: "newSlide",
          description: "Make a new slide related to the current topic.",
          argumentAnnotations: [
            {
              name: "title",
              type: "string",
              description:"The title to display in the presentation slide.",
              required: true,
            },  
            {
              name: "content",
              type: "string",
              description:"The title to display in the presentation slide.",
              required: true,
            },

            {
                name: "speech",
                type: "string",
                description: "An informative speech about the current slide.",
                required: true,
            },     
          ],

          implementation: async (newSlideTitle, newSlideContent, speech) => {
            const newSlide: Slide = { title: newSlideTitle, content: newSlideContent };
            const updatedSlides = [...allSlides, newSlide];
            setAllSlides(updatedSlides);
            setCurrentSlideIndex(updatedSlides.length - 1);

            const encodedText = encodeURIComponent(speech);
            const url = `/api/tts?text=${encodedText}`;
            globalAudio.src = url;
            await globalAudio.play();
            await new Promise<void>((resolve) => {
                globalAudio.onended = function () {
                resolve();
                };
            });
            await new Promise((resolve) => setTimeout(resolve, 500));
          },
        }
        ]
      });


Enter fullscreen mode Exit fullscreen mode

Step 5: Give the chatbot the “Create a PowerPoint presentation on TypeScript” prompt again and you should hear a voice presenting the slides.

Image description

Creating Image Generation Functionality

Step 1: In the present.tsx file, add a new property called backgroundImage to type the interface Slide as shown below.



// Define slide interface
interface Slide {
  title: string;
  content: string;
  backgroundImage: string;
}


Enter fullscreen mode Exit fullscreen mode

Step 2: Update the useMakeCopilotActionable hook to generate images for PowerPoint presentation slides.




useMakeCopilotActionable(
        {
          name: "createPowerPointSlides",
          description: "create slides for a powerpoint presentation. Call this function multiple times to present multiple slides.",
          argumentAnnotations: [
            {
              name: "slideTitle",
              type: "string",
              description: "The topic to display in the presentation slide. Use simple markdown to outline your speech, like a headline.",
              required: true,
            },
            {
              name: "content",
              type: "string",
              description: "The content to display in the presentation slide. Use simple markdown to outline your speech, like lists, paragraphs, etc.",
              required: true
            },
            {
                name: "backgroundImage",
                type: "string",
                description: "What to display in the background of the slide (i.e. 'dog' or 'house').",
                required: true,
              },
            {
                name: "speech",
                type: "string",
                description: "An informative speech about the current slide.",
                required: true,
            },
          ],

          implementation: async (newSlideTitle, newSlideContent, newSlideBackgroundImage, speech) => {
            const newSlide: Slide = { title: newSlideTitle, content: newSlideContent, backgroundImage: newSlideBackgroundImage };
            const updatedSlides = [...allSlides, newSlide];
            setAllSlides(updatedSlides);
            setCurrentSlideIndex(updatedSlides.length - 1);

            const encodedText = encodeURIComponent(speech);
            const url = `/api/tts?text=${encodedText}`;
            globalAudio.src = url;
            await globalAudio.play();
            await new Promise<void>((resolve) => {
                globalAudio.onended = function () {
                resolve();
                };
            });
            await new Promise((resolve) => setTimeout(resolve, 500));
          },
        },
        [],
      );


Enter fullscreen mode Exit fullscreen mode

Step 2: Update the addSlide function to generate images for new PowerPoint presentation slides.

Step 3: Update the Slide component in the slide.tsx file to generate an image via unsplash.com



// Add new slide function
      const addSlide = new CopilotTask({
        instructions: "create a new slide",
        functions: [
          {
          name: "newSlide",
          description: "Make a new slide related to the current topic.",
          argumentAnnotations: [
            {
              name: "title",
              type: "string",
              description:"The title to display in the presentation slide.",
              required: true,
            },  
            {
              name: "content",
              type: "string",
              description:"The title to display in the presentation slide.",
              required: true,
            },
            {
                name: "backgroundImage",
                type: "string",
                description: "What to display in the background of the slide (i.e. 'dog' or 'house').",
                required: true,
              },
            {
                name: "speech",
                type: "string",
                description: "An informative speech about the current slide.",
                required: true,
            },     
          ],

          implementation: async (newSlideTitle, newSlideContent, newSlideBackgroundImage, speech) => {
            const newSlide: Slide = { title: newSlideTitle, content: newSlideContent, backgroundImage: newSlideBackgroundImage };
            const updatedSlides = [...allSlides, newSlide];
            setAllSlides(updatedSlides);
            setCurrentSlideIndex(updatedSlides.length - 1);

            const encodedText = encodeURIComponent(speech);
            const url = `/api/tts?text=${encodedText}`;
            globalAudio.src = url;
            await globalAudio.play();
            await new Promise<void>((resolve) => {
                globalAudio.onended = function () {
                resolve();
                };
            });
            await new Promise((resolve) => setTimeout(resolve, 500));
          },
        }
        ]
      });


Enter fullscreen mode Exit fullscreen mode

Step 3: Update the displayCurrentSlide function to add a background image to the PowerPoint presentation slides.



// Display current slide
      const displayCurrentSlide = () => {
        const slide = allSlides[currentSlideIndex];
        return slide ? (

          <div
          className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center"
          style={{
              backgroundImage: 'url("https://source.unsplash.com/featured/?' + encodeURIComponent(allSlides[currentSlideIndex].backgroundImage) + '")',
              textShadow: "1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000",
            }}
          >
          <Markdown className="markdown">{slide.title}</Markdown>
          <Markdown className="markdown">{slide.content}</Markdown>
        </div>
        ) : (
          <div className="h-screen flex flex-col justify-center items-center text-5xl text-white bg-cover bg-center bg-no-repeat p-10 text-center">
            No Slide To Display
          </div>
        );
      };


Enter fullscreen mode Exit fullscreen mode

Step 4: Go to the web app and you should see a background image is added to the PowerPoint slide.

Image description

Conclusion

In conclusion, you can use CopilotKit to build in-app AI chatbots that can see the current app state and take action inside your app. The AI chatbot can talk to your app frontend, backend, and third-party services.

Conclusion

In conclusion, you can use CopilotKit to build in-app AI chatbots that can see the current app state and take action inside your app. The AI chatbot can talk to your app frontend, backend, and third-party services.

For the full source-code:
https://github.com/TheGreatBonnie/aipoweredpresentation

Thanks to @theGreatBonnie for his awesome work on this article.

Don't forget to...

Image description

Star CopilotKit ⭐️

💖 💪 🙅 🚩
uliyahoo
uliyahoo

Posted on February 20, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related