> ## Content Index
> Fetch the complete content index at: https://www.bramadams.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# How GPT Helped Me Write an e2e App From Bed (yt Assets From transcript)
- URL: https://www.bramadams.dev/202304051745/
- Published: 2023-04-05T21:59:39.000Z
- Updated: 2023-04-05T22:00:18.000Z
- Description: What challenges can GPT overcome when combined with human laziness?
- Author: Bram Adams
- Tags: chatgpt, programming, ai

i set out this morning (from my bed) to create a server that does a workflow that i find tedious (im pretty lazy) when uploading to yt: coming up with a title, description and a thumbnail. i had gpt do the lion's share of the work, prodding when something didnt work the way i expect.

for the ai art prompt i just throw that shit into dalle then take my fav result and put it in canva lol.

lessons learned:

- the 25MB whisper api limit is \~10 mins in mp3
- exporting a range is muchhh cheaper data wise than an entire video (see pics below)
- that multer is a thing
- you can upload multipart forms in insomnia!
- the titles and descriptions are a leaping off point for creativity and personal style
- the ai art prompt can be copy pasted directly into dalle lol

![https://bram-adams.ghost.io/content/images/2023/04/small-file-fcpx-export.png](https://bram-adams.ghost.io/content/images/2023/04/small-file-fcpx-export.png)

small file fcpx export.png

![https://bram-adams.ghost.io/content/images/2023/04/large-file-fcpx-export.png](https://bram-adams.ghost.io/content/images/2023/04/large-file-fcpx-export.png)

large file fcpx export.png

![https://bram-adams.ghost.io/content/images/2023/04/the-app-running-a-form-upload-in-insomia.png](https://bram-adams.ghost.io/content/images/2023/04/the-app-running-a-form-upload-in-insomia.png)

the app running a form upload in insomia.png

![https://bram-adams.ghost.io/content/images/2023/04/canva-yt-thumb-example.png](https://bram-adams.ghost.io/content/images/2023/04/canva-yt-thumb-example.png)

canva yt thumb example.png

![https://bram-adams.ghost.io/content/images/2023/04/the-process-of-the-transcipt-to-yt-asset-app.png](https://bram-adams.ghost.io/content/images/2023/04/the-process-of-the-transcipt-to-yt-asset-app.png)

the process of the transcipt to yt asset app.png

you can find the repo here! [GitHub - bramses/youtube-assets-from-video](https://github.com/bramses/youtube-assets-from-video?ref=bramadams.dev)

```
---
system_commands: ['I am a generalist that is not afraid to make radical associations between distinct topics by using creative leaps.']
temperature: 0.0
top_p: 1
max_tokens: 2000
presence_penalty: 1
frequency_penalty: 1
stream: true
stop: null
n: 1
model: gpt-3.5-turbo
---

```

write an express js server only in method stubs and js docs that:

1. allows user to upload a mp4 or mov file
2. calls the openai whisper api with file (see # transcription api for request details)
3. gets the transcript from response.text
4. uses the chatgpt api with the template to create youtube assets (see # asset template)

## Transcription Api

```js
const { Configuration, OpenAIApi } = require("openai");
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
const resp = await openai.createTranscription(
  fs.createReadStream("audio.mp3"),
  "whisper-1"
);

```

## Asset Template

can you write:

1. an eye catching youtube title for this transcript (focus mainly on the code)
2. a youtube description (phrased as a question to get people to want to read more)
3. a potential ai art prompt from this transcript -thematically related and should be slightly abstract and use a random lesser known art period from history with a color palette that fits the description and title

---

**GPT:**

```js
/**
 * POST /upload
 * Allows user to upload a mp4 or mov file and creates YouTube assets using OpenAI APIs.
 *
 * @param {Object} req - The request object containing the uploaded file.
 * @param {Object} res - The response object with the created YouTube assets.
 */
const uploadFile = async (req, res) => {
  // TODO: Implement file upload logic

  try {
    // Call OpenAI Whisper API for transcription
    const { Configuration, OpenAIApi } = require("openai");
    const configuration = new Configuration({
      apiKey: process.env.OPENAI_API_KEY,
    });
    const openai = new OpenAIApi(configuration);
    
    const resp = await openai.createTranscription(
      fs.createReadStream("audio.mp3"),
      "whisper-1"
    );
    
    // Get transcript from response text
    const transcript = resp.text;
    
     // Call ChatGPT API with template for creating YouTube assets
     const chatgptResponse = await openai.complete({
       engine: 'text-davinci-002',
       prompt: `Can you write an eye-catching title and description for this code-related video? \n\nTitle:\nDescription as question:\nPotential AI art prompt from this transcript (using a random lesser-known art period):\n`,
       maxTokens: 1000,
       n: 1,
       temperature: 0.5,
     });

     // Extract generated title, description, and AI art prompt from response choices array 
     const [generatedText] = chatgptResponse.choices.map((choice) => choice.text.trim());
     
     const [title, descriptionQuestion, aiArtPrompt] =
        generatedText.split("\n").map((line) => line.slice(line.indexOf(":") + 1).trim());

      // Send back created YouTube assets
      res.status(200).json({
        title,
        description: `${descriptionQuestion} \n\nTranscript:\n${transcript}`,
        aiArtPrompt,
      });
  } catch (error) {
    console.error(error);
    res.status(500).send("Error creating YouTube assets");
  }
};

```

---

**Bram:**

can you write the js that calls this fn and starts the server

---

**GPT:**

Sure! Here's an example of how you can call the `uploadFile` function and start the server using Express.js:

```js
const express = require("express");
const app = express();

// Define route for file upload
app.post("/upload", uploadFile);

// Start server on port 3000
app.listen(3000, () => {
  console.log("Server started on port 3000");
});

```

Note that you'll need to import the `uploadFile` function from wherever it is defined in your code.

---

**Bram:**

can you install dotenv and include it in the above code

---

**GPT:**

Sure! Here's an updated version of the code that includes `dotenv`:

```js
const express = require("express");
const app = express();
require("dotenv").config();

// Define route for file upload
app.post("/upload", uploadFile);

// Start server on port 3000
app.listen(3000, () => {
  console.log("Server started on port 3000");
});

```

Make sure to install `dotenv` by running `npm install dotenv`.

---

**Bram:**

cany uo write the Implement file upload logic

---

**GPT:**

Sure! Here's an example implementation of the file upload logic using `multer` middleware:

```js
const multer = require("multer");

// Set up Multer storage engine for uploaded files
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/");
  },
  filename: function (req, file, cb) {
    const uniqueSuffix =
      Date.now() + "-" + Math.round(Math.random() * 1e9) + ".mp3";
    cb(null, file.fieldname + "-" + uniqueSuffix);
  },
});

// Create Multer instance with specified storage engine and accepted MIME types
const upload = multer({
  storage,
  limits: { fileSize: process.env.MAX_FILE_SIZE || "25MB" },
}).single("file");

/**
 * POST /upload
 * Allows user to upload a mp4 or mov file and creates YouTube assets using OpenAI APIs.
 *
 * @param {Object} req - The request object containing the uploaded file.
 * @param {Object} res - The response object with the created YouTube assets.
 */
const uploadFile = async (req, res) => {
  
   // Call Multer middleware to handle uploaded file
   upload(req,res,function(err){
     if(err instanceof multer.MulterError){
       return res.status(400).json({message:"File too large"});
     }else if(err){
       return res.status(500).json({message:"Error uploading file"});
     }
     
     console.log(`Uploaded ${req.file.filename}`);
     
     try {
        // Call OpenAI Whisper API for transcription
        
        const { Configuration, OpenAIApi } = require("openai");
        const configuration = new Configuration({
          apiKey: process.env.OPENAI_API_KEY,
        });
        
        const openai = new OpenAIApi(configuration);
        
        const resp = await openai.createTranscription(
          fs.createReadStream(req.file.path),
          "whisper-1"
        );
        
        // Get transcript from response text
        const transcript = resp.text;
        
         // Call ChatGPT API with template for creating YouTube assets
         const chatgptResponse = await openai.complete({
           engine: 'text-davinci-002',
           prompt: `Can you write an eye-catching title and description for this code-related video? \n\nTitle:\nDescription as question:\nPotential AI art prompt from this transcript (using a random lesser-known art period):\n`,
           maxTokens: 1000,
           n: 1,
           temperature: 0.5,
         });
    
         // Extract generated title, description, and AI art prompt from response choices array 
         const [generatedText] = chatgptResponse.choices.map((choice) => choice.text.trim());
         
         const [title, descriptionQuestion, aiArtPrompt] =
            generatedText.split("\n").map((line) => line.slice(line.indexOf(":") + 1).trim());

          // Send back created YouTube assets
          res.status(200).json({
            title,
            description: `${descriptionQuestion} \n\nTranscript:\n${transcript}`,
            aiArtPrompt,
          });
      } catch (error) {
        console.error(error);
        res.status(500).send("Error creating YouTube assets");
      }
   })
};

```

This implementation uses the `multer` middleware to handle file uploads. The uploaded file is stored in the `uploads/` directory using a unique filename generated by combining the original fieldname with a timestamp and random number suffix.

The Multer instance is configured to accept only one file at a time with a maximum size of either the value specified in the `.env` file or `"50MB"` by default.

The `uploadFile` function calls the Multer middleware to handle the uploaded file, then passes the resulting `req` object to the OpenAI APIs for transcription and YouTube asset creation.

---

**Bram:**

how would i make a curl post request to this?

---

**GPT:**

You can make a `curl` POST request to this server by running the following command in your terminal:

```
curl -X POST -F 'file=@/path/to/file.mp3' http://localhost:3000/upload

```

Replace `/path/to/file.mp3` with the actual path to your audio file.

This `curl` command sends a multipart/form-data POST request to the `/upload` endpoint of your Express.js server, with the uploaded file attached as a form field named "file". The `-F` option specifies that we're sending a form field, and the `@` symbol before the file path indicates that we want to attach a file.

---

**Bram:**

getting `no such file or directory` error from the multer part below:

```
const uniqueSuffix =

Date.now() + "-" + Math.round(Math.random() * 1e9) + ".mp3";

```

---

**GPT:**

The error message "no such file or directory" usually indicates that the specified directory does not exist. In this case, it's likely that the `uploads/` directory has not been created yet.

To fix this issue, you can create the `uploads/` directory manually in your project root folder by running:

```
mkdir uploads

```

Alternatively, you can modify the `destination` property of the Multer storage engine to specify a different path where you want to store uploaded files. For example:

```js
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "./public/uploads/");
  },
  filename: function (req, file, cb) {
    const uniqueSuffix =
      Date.now() + "-" + Math.round(Math.random() * 1e9) + ".mp3";
    cb(null, file.fieldname + "-" + uniqueSuffix);
  },
});

```

This will create an `uploads/` subdirectory inside a new `public/` folder in your project root. Make sure to also update any references to the upload directory elsewhere in your code if you change its location.

---

**bramadams.dev is a reader-supported [published Zettelkasten](https://www.bramadams.dev/about/). [Both free and paid subscriptions are available](#/portal). If you want to support my work, the best way is by taking out a paid subscription.**