Skip to content

Instantly share code, notes, and snippets.

@wilmoore
Last active July 29, 2024 19:44
Show Gist options
  • Select an option

  • Save wilmoore/827f1e72b577ae3d39912e6497138101 to your computer and use it in GitHub Desktop.

Select an option

Save wilmoore/827f1e72b577ae3d39912e6497138101 to your computer and use it in GitHub Desktop.
Software Engineering :: Programming :: Languages :: JavaScript :: TypeScript :: Boilerplate :: Server

Software Engineering :: Programming :: Languages :: JavaScript :: TypeScript :: Boilerplate :: Server

⪼ Made with 💜 by Polyglot.

related
cd sourcecode
mkdir -p youtube-word-count-nodejs/src
cd !$

cat > index.ts <<EOF
import ytdl from 'ytdl-core';
import ffmpeg from 'fluent-ffmpeg';
import { createWriteStream, existsSync, unlinkSync, createReadStream } from 'fs';
import axios from 'axios';
import path from 'path';
import { Configuration, OpenAIApi } from 'openai';

// Function to download the YouTube video and extract audio
async function downloadAudio(videoUrl: string, output: string): Promise<void> {
  return new Promise((resolve, reject) => {
    const stream = ytdl(videoUrl, { filter: 'audioonly' });
    ffmpeg(stream)
      .audioCodec('mp3')
      .save(output)
      .on('end', () => resolve())
      .on('error', (err) => reject(err));
  });
}

// Function to convert audio to text using OpenAI Whisper API
async function convertAudioToText(audioFilePath: string): Promise<string> {
  const apiKey = 'YOUR_OPENAI_API_KEY'; // Replace with your OpenAI API key
  const configuration = new Configuration({ apiKey });
  const openai = new OpenAIApi(configuration);

  const audioData = await readFileAsBuffer(audioFilePath);

  const response = await openai.createTranscription(
    audioData,
    'whisper-1',
    undefined,
    'text/plain'
  );

  return response.data.text;
}

// Helper function to read a file and return its content as a Buffer
function readFileAsBuffer(filePath: string): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const chunks: Buffer[] = [];
    const stream = createReadStream(filePath);
    stream.on('data', (chunk) => chunks.push(chunk));
    stream.on('end', () => resolve(Buffer.concat(chunks)));
    stream.on('error', (err) => reject(err));
  });
}

// Function to count the occurrences of the word "like" in a text
function countOccurrences(text: string, word: string): number {
  const regex = new RegExp(`\\b${word}\\b`, 'gi');
  const matches = text.match(regex);
  return matches ? matches.length : 0;
}

// Main function to download, convert and count the word "like"
async function main() {
  const videoUrl = 'https://www.youtube.com/watch?v=YOUR_VIDEO_ID'; // Replace with your YouTube video URL
  const audioFilePath = path.join(__dirname, 'audio.mp3');

  if (existsSync(audioFilePath)) {
    unlinkSync(audioFilePath);
  }

  try {
    await downloadAudio(videoUrl, audioFilePath);
    const transcript = await convertAudioToText(audioFilePath);
    const count = countOccurrences(transcript, 'like');
    console.log(`The word "like" is uttered ${count} times in the video.`);
  } catch (error) {
    console.error('Error:', error);
  } finally {
    if (existsSync(audioFilePath)) {
      unlinkSync(audioFilePath);
    }
  }
}

main().catch(console.error);
EOF

cd ..
pnpm init
pnpm add ytdl-core fluent-ffmpeg axios openai
pnpm add -D typescript @tsconfig/recommended @types/fluent-ffmpeg

cat > tsconfig.json <<EOF
{
  "extends": "@tsconfig/recommended/tsconfig.json",
}
EOF

cat > .env <<EOF
OPENAI_API_KEY='$(security find-generic-password -s OPENAI_API_TOKEN -w)'
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment