ariym / whisper-node

Node.js bindings for OpenAI's Whisper. (C++ CPU version by ggerganov)
https://npmjs.com/whisper-node
MIT License
239 stars 41 forks source link

Cannot read properties of null (reading 'shift') #36

Closed nathanael540 closed 9 months ago

nathanael540 commented 10 months ago

[whisper-node] Problem: TypeError: Cannot read properties of null (reading 'shift') at parseTranscript (/app/node_modules/whisper-node/dist/tsToArray.js:7:11) at /app/node_modules/whisper-node/dist/index.js:36:57 at Generator.next (<anonymous>) at fulfilled (/app/node_modules/whisper-node/dist/index.js:5:58) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

How fix this pls?

rtoscani commented 9 months ago

That's because the transcription failed.

Most probable cause is bad file encoding, remember that the file should be in wav format, 16 khz of frequency and 1 channel.

You can also put a break point into node_modules/whisper-node/dist/index.js line 36, copy the command variable string value and execute into your system console to get a detailed error message.

chgrivas commented 9 months ago

[whisper-node] Problem: TypeError: Cannot read properties of null (reading 'shift') at parseTranscript (/app/node_modules/whisper-node/dist/tsToArray.js:7:11) at /app/node_modules/whisper-node/dist/index.js:36:57 at Generator.next (<anonymous>) at fulfilled (/app/node_modules/whisper-node/dist/index.js:5:58) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

How fix this pls?

@nathanael540 It might be a problem with the audio file path resolution. I am consistently getting the exact same error message when I try to resolve the file path as follows:

const transcript = await whisper('../file.wav')

The problem gets resolved when I resolve the file path the following way:

const transcript = await whisper(path.resolve(__dirname, '../file.wav'))
nathanael540 commented 9 months ago

const transcript = await whisper(path.resolve(__dirname, '../file.wav'))

works

jeffscottward commented 5 months ago

const transcript = await whisper(path.resolve(__dirname, '../file.wav'))

works

it doesn't.

const audioDirPath = path.resolve(
  __dirname,
  "downloads/TikTok/hold_my_hand_wholesale/missing-vtt-audio-sample"
);

no good

entire code

import fs from "fs";
import path, { dirname } from "path";
import { fileURLToPath } from "url";
import * as whisper from "whisper-node";

// Constants
const __dirname = String(dirname(fileURLToPath(import.meta.url)));
console.log("🚀 ~ __dirname", __dirname);

const audioDirPath = path.resolve(
  __dirname,
  "downloads/TikTok/hold_my_hand_wholesale/missing-vtt-audio-sample"
);
console.log("🚀 ~ audioDirPath", audioDirPath);

const files = fs.readdirSync(audioDirPath);
console.log("🚀 ~ files", files);

const DEFAULT_MODEL = "tiny";
console.log("🚀 ~ DEFAULT_MODEL", DEFAULT_MODEL);

async function main() {
  console.log("🚀 ~ main ~ Script started");

  // Transcription process
  const transcribe = async (audioFilePath) => {
    try {
      try {
        const result = await whisper.whisper(audioFilePath, {
          modelName: DEFAULT_MODEL,
        });
        console.log("🚀 ~ transcribe ~ Transcription result", result);
        return result;
      } catch (error) {
        console.error("🚀 ~ transcribe ~ Error during transcription", error);
        throw error;
      }
    } catch (error) {
      console.error(
        "🚀 ~ transcribe ~ Error during decoding or saving buffer",
        error
      );
      throw error;
    }
  };

  // Function to save data to a JSON file
  const saveToJson = (data, filePath) => {
    console.log("🚀 ~ saveToJson ~ filePath", filePath);
    console.log("🚀 ~ saveToJson ~ data", data);
    return new Promise((resolve, reject) => {
      fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf8", (err) => {
        if (err) {
          console.error("🚀 ~ saveToJson ~ Error saving JSON to file", err);
          reject(err);
        } else {
          console.log("🚀 ~ saveToJson ~ JSON data saved successfully");
          resolve();
        }
      });
    });
  };

  // Main execution function
  for (const file of files) {
    console.log("🚀 ~ main ~ Processing file", file);

    if (path.extname(file).toLowerCase() === ".m4a") {
      const audioFilePath = path.join(audioDirPath, file);
      console.log("🚀 ~ main ~ audioFilePath", audioFilePath);

      const outputJSONPath = path.join(
        audioDirPath,
        path.basename(file, path.extname(file)) + ".json"
      );
      console.log("🚀 ~ main ~ outputJSONPath", outputJSONPath);

      try {
        const transcription = await transcribe(audioFilePath);

        console.log(
          "🚀 ~ main ~ Transcription result for file:",
          file,
          transcription
        );

        // Only proceed to save if transcription is not undefined
        if (transcription) {
          await saveToJson(transcription, outputJSONPath);
          console.log(
            `🚀 ~ main ~ Transcription and save completed for ${file}`
          );
        } else {
          console.error(
            `🚀 ~ main ~ Transcription returned undefined for ${file}`
          );
        }
      } catch (transcriptionError) {
        console.error(
          `🚀 ~ main ~ Error transcribing file ${file}:`,
          transcriptionError
        );
      }
    } else {
      console.log(`🚀 ~ main ~ Skipping non-m4a file: ${file}`);
    }
  }

  console.log("🚀 ~ main ~ Script finished execution");
}

// Call main to start the script
main()
  .then(() => {
    console.log("🚀 ~ main ~ Script finished successfully");
  })
  .catch((err) => {
    console.error("🚀 ~ main ~ Script encountered an error:", err);
  });
jeffscottward commented 5 months ago

happens for any file type or audio recording at all

jeffscottward commented 5 months ago

Update I finally saw this in the README Files must be .wav and 16Hz Thats pretty important - should be right at the top. Yep, it worked. You should really put a warning for that error that says to make sure that it is that format and that bit rate.

binarykitchen commented 2 months ago

Yes, validate the input and log a warning, you should.