How GPT Helped Me Write an e2e App From Bed (yt Assets From transcript)

What challenges can GPT overcome when combined with human laziness?

How GPT Helped Me Write an e2e App From Bed (yt Assets From transcript)

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
small 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
the app running a form upload in insomia.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
the process of the transcipt to yt asset app.png

you can find the repo here! GitHub - bramses/youtube-assets-from-video

---
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

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:

/**
 * 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:

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:

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:

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:

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. Both free and paid subscriptions are available. If you want to support my work, the best way is by taking out a paid subscription.