<aside> 💡 This workflow is heavily based on my Speech to Text to Notion workflow, which transcribes/summarizes voice notes and sends them to Notion.

How to Transcribe Speech to Text with ChatGPT and Notion

Here I’ve simply replaced the transcription step with a step that extracts the text from a PDF file that is uploaded to a Google Drive folder.

This script was built in Pipedream; my favorite code-friendly automation platform.

Created by Thomas Frank | Notion Basics | Learn the Notion API | Templates | Twitter

</aside>

Example PDF Summary

10 Steps to Earning Awesome Grades (While Studying Less)

Full Tutorial

https://www.loom.com/share/e567657463ac47d8be4b20952b350f83

All Steps

Step 1 (Trigger): New PDF uploaded to Google Drive

Untitled

Step 2: Google Drive → Download File

Untitled

Step 3: Extract_pdf_text

<aside> 💡 Note: You can likely also accomplish this with the office-text-extractor library, which also can extract text from Word documents and Excel spreadsheets:

npm: office-text-extractor

</aside>

Untitled

import { PDFExtract } from 'pdf.js-extract';
import fs from 'fs';

export default defineComponent({
  async run({ steps, $ }) {
    const pdfPath = `/tmp/pdf.${steps.trigger.event.fullFileExtension}`;
    const buffer = fs.readFileSync(pdfPath);

    const options = {};
    const pdfExtract = new PDFExtract();
    let data;
    let text = '';

    try {
      data = await pdfExtract.extractBuffer(buffer, options);
      data.pages.forEach((page) => {
        page.content.forEach((item) => {
          if (item.str) {
            text += item.str + ' ';
          }
        });
      });
      console.log(text);
    } catch (err) {
      console.log("Error extracting PDF data:", err);
    } finally {
      return text;
    }
  },
});

Step 4: openai

Untitled

import { Configuration, OpenAIApi } from "openai"
import { encode, decode } from "gpt-3-encoder"

export default defineComponent({
  props: {
    openai: {
      type: "app",
      app: "openai",
    }
  },
  async run({steps, $}) {

    // Import the transcript from the previous step
    const transcript = steps.Extract_pdf_text.$return_value

    // Set the max number of input tokens
    const maxTokens = 2000

    // Initialize OpenAI
    const openAIkey = this.openai.$auth.api_key
    const configuration = new Configuration({
      apiKey: openAIkey,
    });
    const openai = new OpenAIApi(configuration);

    // Split the transcript into shorter strings if needed, based on GPT token limit
    function splitTranscript(encodedTranscript, maxTokens) {
      const stringsArray = []
      let currentIndex = 0

      while (currentIndex < encodedTranscript.length) {
        let endIndex = Math.min(currentIndex + maxTokens, encodedTranscript.length)

        // Find the next period
        while (endIndex < encodedTranscript.length && decode([encodedTranscript[endIndex]]) !== ".") {
          endIndex++
        }

        // Include the period in the current string
        if (endIndex < encodedTranscript.length) {
          endIndex++
        }

        // Add the current chunk to the stringsArray
        const chunk = encodedTranscript.slice(currentIndex, endIndex)
        stringsArray.push(decode(chunk))

        currentIndex = endIndex
      }

      return stringsArray
    }

    const encoded = encode(transcript)

    const stringsArray = splitTranscript(encoded, maxTokens)
    const result = await sendToChat(stringsArray)
    return result

    // Function to send transcript string(s) to Chat API
    async function sendToChat (stringsArray) {

      const resultsArray = []

      for (let arr of stringsArray) {

        // Define the prompt
        const prompt = `Analyze the PDF text provided below, then provide the following:
Key "title:" - add a title.
Key "summary" - create a summary.
Key "main_points" - add an array of the main points. Limit each item to 100 words, and limit the list to 10 items.

Ensure that the final element of any array within the JSON object is not followed by a comma.

Transcript:
        
        ${arr}`

        let retries = 3
        while (retries > 0) {
          try {
            const completion = await openai.createChatCompletion({
              model: "gpt-3.5-turbo",
              messages: [{role: "user", content: prompt}, {role: "system", content: `You are an assistant that only speaks JSON. Do not write normal text.

Example formatting:

{
    "title": "Notion Buttons",
    "summary": "A collection of buttons for Notion",
    "main_points": [
        "item 1",
        "item 2",
        "item 3"
    ]
}
              `}],
              temperature: 0.2
            });

            resultsArray.push(completion)
            break
          } catch (error) {
            if(error.response && error.response.status === 500) {
              retries--
              if (retries == 0) {
                throw new Error("Failed to get a response from OpenAI Chat API after 3 attempts.")
              }
              console.log("OpenAI Chat API returned a 500 error. Retrying...")
            } else {
              throw error
            }
          }
        }

      }

      return resultsArray
    }

  },
})