Setting Up AI Prompt in Nuxt.js
Tags: ai, nuxt, javascript
Published: 2023-10-30 21:55:30

In this tutorial, we'll be setting up an AI Prompt. Proper setup is crucial to ensure that the results meet your design requirements. Our goal is for users to input their ideas or stories, and for the AI to generate the following:

1. Movie Title
2. Movie Description
3. An Image in b64_json format

Let's get started.

**Note:** We won't be focusing on UI development in this tutorial. However, I've prepared a basic UI to facilitate our task. Here's the link: 
https://github.com/kamruzzamanripon/nuxt-movie-ui

This UI contains some essential components, which we can expand upon if needed.

**Step 1: Install Pinia for Store Management**

```
npm install pinia @pinia/nuxt
```

**Step 2: Install Axios**

```
npm install axios
```

**Step 3: Set Up the Store**
Create a folder named **store** and within it, create a file named **aiMovieStore.js**. Add the following lines:

```
import axios from "../helpers/axios.js";

import { defineStore } from "pinia";

//define pinia store
export const aiMovieStore = defineStore("aiMovieStore", {

  //initial store
  state: () => ({
    loading: false,
    aiMovieData: {},
    categories: [],
    topMovies: [],
    categoryWiseMovie: [],
  }),

  getters: {},

  actions: {
    async getToken() {
      return await axios.get("/sanctum/csrf-cookie");
    },

    //here payload is ai data. this data store in pinia
    async actionAiMovieData(payload) {
      this.aiMovieData = payload;
      this.loading = false;
    },
    async actionAllCategoryApi() {
      const config = useRuntimeConfig();
      const data = await axios.get("/all-category");
      console.log("axios data", data);
      this.categories = data.data.data;
      //this.actionAiMovieData = movieData;
    },

    //here send ai data to server for save this data in our database
    async actionAiMovieDataSendServer(payload) {
      console.log("actionAiMovieDataSendServer", payload);
      const response = await axios.post("/ai-movie-store", payload);
      navigateTo("/");
    },

    //here menual movie data send to server for save this data in our database
    async actionManualMovieDataSendToServer(payload) {
      console.log("actionManualMovieDataSendToServer", payload);
      const formData = new FormData();
      formData.append("title", payload.title);
      formData.append("description", payload.description);
      formData.append("category_id", payload.category);
      //formData.append('image', payload.file??"")
      if (payload.file) {
        formData.append("image", payload.file);
      }
      console.log("actionManualMovieDataSendToServer", [...formData]);
      const response = await axios.post("/movie-store", formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });
      navigateTo("/");
    },

    //fetch top movies from database
    async actionTopMovie(payload) {
      const data = await axios.get("/top-movies");
      this.topMovies = data.data.data.data;
    },

    //fetch category wise movie list from database
    async actionCategoryWiseMovie() {
      const data = await axios.get("/category-wise-movies");
      console.log("actionCategoryWiseMovie", data);
      this.categoryWiseMovie = data.data.data.data;
    },
  },
});
```

This **Pinia** store contains several functions. Let's discuss them, focusing particularly on the **actionAiMovieData** function. This function is triggered when the AI generates movie-related information, such as the movie title, a short description, and an image. When the user clicks the "Save Your Movie" button, the **actionAiMovieDataSendServer** function is triggered to save the data in our database.  Then go to Home page Like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3irzb5gomahkw4swt4cd.jpg)

**Step 4: Creating the AI Prompt**

Firstly, we need an AI API key. Visit https://platform.openai.com/, create an account, and generate an API key. Copy this API key and paste it into your **.env** file.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/817zo2phubcjp64m4y90.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63uzyylhh44clgxze4h6.png)

Now, let's focus on the AI input field. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we8vylp9aw5lntxp9syy.png)

here is **AiFormInput** Component Code

```
<template>
    <div class="bg-gray-200 p-5 rounded-md dark:bg-black" >
            
            <div class="text-center mb-8 relative">
                <h1 class="text-2xl font-bold text-gray-700 mb-3 dark:text-white">Hello, I am here to help Make Movie</h1>
                <p class="dark:text-white">Please, write your idea below input box</p>
                <img src="/assets/pictures/robot-1.webp" alt="" class="rounded-full w-48 h-48 absolute -top-5 right-0 sm::hidden">
            </div>

            <div class="mx-10 px-10 py-16 bg-gray-400 dark:bg-black dark:border rounded-md">
            <div class="mb-6">
                <label for="message" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
                    Type Your Movie Idea
                </label>
                <textarea id="message" rows="4"
                    class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 h-[60vh]"
                    placeholder="Type Movie short description..." v-model="movieData.description"></textarea>
                <p v-if="!movieData.description && isSubmitted" class="text-red-500 mt-2">Movie Description is required.</p>
            </div>
            <div class="text-right">
                <button type="submit" class="bg-black text-white p-3 rounded-md dark:border" @click="submitForm">Make
                    Movie</button>
            </div>
            </div>

        </div>
        <Loader v-if="aiMovieStoreInfo.loading" />
</template>

<script setup>
import { Configuration, OpenAIApi } from 'openai';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
//import dataStoreJson from '../../data.json';
import { aiMovieStore } from '../../store/aiMovieStore.js';

//difine store
const isSubmitted = ref(false);
const router = useRouter();
const movieData = ref({
    description:""
})

//pinia store call
const aiMovieStoreInfo = aiMovieStore()

//env file connect
const config = useRuntimeConfig(); 
//AI api Key call
const openAiApiKey = config.public.OPEN_AI_API_KEY
const configuration = new Configuration({
    apiKey: openAiApiKey
})
//Configure AI
const openAi = new OpenAIApi(configuration);

//Form validation custom
function validateInputs() {
    const { description } = movieData.value;
    if (!description) {
        return false;
    }
    return true;
}

//form submit handler
const submitForm = async() => {
    isSubmitted.value = true;
    if (validateInputs()) {
        aiMovieStoreInfo.loading = true;
        const aiMovieData = await fetchSynopsis(movieData.value.description)
        await aiMovieStoreInfo.actionAiMovieData(aiMovieData);
        //await aiMovieStoreInfo.actionAiMovieData(dataStoreJson);
        router.push('/movie-made');
        aiMovieStoreInfo.loading = false;
    }
};

async function fetchSynopsis(outline){
    const response = await openAi.createCompletion({
        model: 'text-davinci-003',
        prompt:`Generate an engaging, professional and marketable movie synopsis based on an outline. The synopsis should include actiors names in brackets after each character. Choose actors that would be ideal for this role.
        ###
        outline: A big-headed daredevil fighter pilot goes back to school only to be sent on a deadly mission.
        synopsis: The Top Gun Naval Fighter Weapons School is where the best of the best train to refine their elite flying skills, When hotshot fighter pilot Maverick (Tom Cruise) is sent o the school, his rackless attitude and cocky demeanor put him at odds with the other pilots, especially the cool and collected Iceman (Val kilmer). But Maverick ins't only competing to be the top fighter pilot, he's also fighting for the attention of his beautiful flight instructor, Charlotte Blackwood (kelly McGillis). Maverick gradually earns the respect of his intructors and peers - and also the love of Charlotte, but struggles to balance his personal and professional life. As the pilots prepare for a mission against a foreign enemy, Maverick must confront his own demons and overcome the tragedies rooted deep in his past to become the best fighter pilot and return from the mission triumphant.
        ###
        outline: ${outline}
        synopsis:
        `,
        max_tokens: 700
    })
    const synopsis = response.data.choices[0].text.trim();
    console.log('fetchSynopsis', synopsis)
    const aiMovieData = fetchTitle(synopsis);
    return aiMovieData;
    
}

async function fetchTitle(synopsis){
    const response = await openAi.createCompletion({
        model: 'text-davinci-003',
        prompt:`Generate a catchy movie title for this synopsis: ${synopsis}`,
        max_tokens: 25,
        temperature: 0.7
    })
    const title = response.data.choices[0].text.trim();
    console.log('fetchTitle-1', synopsis)
    console.log('fetchTitle-2', title)
    const aiMovieData = fetchImagePromt(title, synopsis)
    return aiMovieData;
}


async function fetchImagePromt(title, synopsis){
    const response = await openAi.createCompletion({
    model: 'text-davinci-003',
    prompt: `Give a short description of an image which could be used to advertise a movie based on a title and synopsis.The description should be rich in visual detail but contain no names.
    ###
    title: Love's Time Warp
    synopsis: When scientist and time traveller Wendy (Emma Watson) is sent back to the 1920s to assassinate a future dictator, she never expected to fall in love with them. As wendy infiltrates the dictator's inner circle, she soon finds herself torn between her mission and her growing feelings for the leader (Brie Larson). With the help of a mysterious stranger from the future (Josh Brolin), Wendy must decide whether to carry out her mission or follow her heart. But the choices she makes in the 1920s will have far-reaching consequences that reverberate throuugh the ages.
    image description: A silhouetted figure stands in the shadows of a 1920s speakeasy, her face turned away from the camera. In the background, two people are dancing in the dim light, one wearing a flapper-style dress and the other wearing a dapper suit. A semi-transparent image of war is super-imposed over the scene.
    ###
    title: zero Earth
    synopsis: When baodyguard kob (Daniel Radcliffe) is recruited by the United Nations to save Planet Earth from the sinister Simm (John Malkovich), an alien lord with a plan to take over the world, he reluctantly accepts the challenge, With the help of this loyal sidekick, a brave and resourceful hamster named Gizmo (Gaten Matarazzo), Kob embarks on a perilous mission to destroy Simm. Along the way, he discovers a newfound courage and strength as he battles Simms's merciless forces. With the fate of the world in his hands, kob must find a way to defeat the alien lord and save the planet.
    image description: A tired and bloodied bodyguard and hamster standing a top a tall skyscraper, looking out over a vibrant cityscape, with a rainbow in the sky above them.
    ###
    title: ${title}
    synopsis: ${synopsis}
    image description:
    `,
    temperature: 0.8,
    max_tokens: 100

    })
    console.log('fetchImagePromt-1', synopsis)
    console.log('fetchImagePromt-2', title)
    const aiMovieData = fetchImageUrl(response.data.choices[0].text.trim(), synopsis, title)
    return aiMovieData;
}

async function fetchImageUrl(imagePrompt,synopsis,title){
    const response = await openAi.createImage({
        prompt: `${imagePrompt}. There should be no text in this iamge.`,
        n: 1,
        size: '256x256',
        response_format: 'b64_json'
    })
    const b64JsonImage = response.data.data[0];
    console.log('fetchImageUrl-1', synopsis)
    console.log('fetchImageUrl-2', title)
     const aiMovieData ={
        b64JsonImage,
        synopsis,
        title
    }

    return aiMovieData;
}

</script>
```

If you are in GitHub of this project link then Go to the **pages** folder, open **ai-make-movie.vue**, and then open **AiFormInput.vue**. Here you'll find several functions. Let's break them down:

**submitForm()**
This function is called when the "Make Movie" button is clicked. It involves several promise functions:

1. **fetchSynopsis()** calls OpenAI with parameters to set up a demo prompt. It then passes the response to **fetchTitle()**.

2. **fetchTitle()** again calls OpenAI and passes the response to **fetchImagePrompt()**.
 
3. **fetchImagePrompt()** calls OpenAI with a prompt design and passes the response to **fetchImageUrl()**.
 
4. **fetchImageUrl()** calls OpenAI to generate an image based on the synopsis and title. The image is in the b64_json format with a size of 256. You can adjust the image size if needed.

The data is then structured and returned, allowing the **submitForm** function to pass this information to the Pinia store and navigate to another page.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ad0d2dixs0m8tryw1wog.png)

When the user clicks "**Save Your Movie**", the information is saved in the database, and the user is redirected to the homepage.

I hope this walkthrough has made the process clear. In the next tutorial, we'll connect Laravel API to this app. **Here is the tutorial link**: 
[Link]

**Here is github link of this project**
https://github.com/kamruzzamanripon/nuxt-movie-ui-with-laravel-api

**All Episodes**
[Creating the API # [Tutorial-1]](https://dev.to/kamruzzaman/building-a-movie-portal-api-with-laravel-using-the-service-pattern-35i3)
[Configure AI Prompt # [Tutorial-2]](https://dev.to/kamruzzaman/setting-up-ai-prompt-in-nuxtjs-16e6)
[Designing the UI # [Tutorial-3]](https://dev.to/kamruzzaman/laravel-api-integration-in-nuxtjs-b89)
[Setting up on an Linux Server # [Tutorial-4]](https://dev.to/kamruzzaman/deploy-a-nuxtjs-app-and-laravel-api-on-a-linux-server-54bh)
 
That's all. Happy Learning :) .
[if it is helpful, giving a star to the repository 😇]