openai / openai-node

Official JavaScript / TypeScript library for the OpenAI API
https://www.npmjs.com/package/openai
Apache License 2.0
7.96k stars 870 forks source link

createTranscription File type does not exist in node #127

Closed tommedema closed 1 year ago

tommedema commented 1 year ago

Describe the bug

createTranscription's interface is defined as: createTranscription(file: File, ....)

However, File does not exist in node.js. This is a browser only class.

What is expected here? A return value from fs.readFileSync?

To Reproduce

const file = fs.readFileSync(audioOutputFilePath)

const transcript = await openai.createTranscription(new File([file]), ...) // File does not exist

Code snippets

No response

OS

macOS

Node version

Node v14.19.0

Library version

openai 3.2.1

jonathanlal commented 1 year ago

have same problem

tianmuxgg commented 1 year ago

have same problem

ajsharp commented 1 year ago

I believe this is mostly a typing issue in api.ts with the file param. The code doesn't actually use any File properties. Also, the docs show a different usage using :

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"
);
douglasmanzelmann commented 1 year ago

You can use //@ts-ignore for the time being and use @ajsharp's example above and it will work for the time being

const { Configuration, OpenAIApi } = require("openai");
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

//@ts-ignore
const resp = await openai.createTranscription(fs.createReadStream("audio.mp3"), "whisper-1");
demian85 commented 1 year ago

It's not working for me, and if you look at the source code on line 2541:

if (file !== undefined) { 
    localVarFormParams.append('file', file as any);
}

It's appending the file to the FormData object. All of those are native DOM objects. It must be a File instance to work.

ajsharp commented 1 year ago

@demian85 I don't think that's correct. This library uses axios as it's HTTP lib, which will take a Buffer or any sort of buffer-like object. File basically just adds a few mostly information properties to Buffer.

That code you referenced is just coercing the object for typescript's sake, it's not really doing anything File-specific.

Here's some code I'm using, which doesn't use the openai library, but essentially does the same thing:

import axios, { AxiosError } from "axios";
import * as FormData from "form-data";

const apiKey = "YOURKEY";
const apiUrl = "https://api.openai.com/v1/audio/transcriptions";

export async function createTranscription(file: Buffer, fileName: string) {
    const formData = new FormData();

    formData.append("file", file, {
      filename: fileName,
      contentType: "audio/aac",
    });
    formData.append("model", "whisper-1");
    formData.append("response_format", "json");
    formData.append("language", "en");

    // Send a POST request to the OpenAI API
    const response = await axios.post(apiUrl, formData, {
      headers: {
        ...formData.getHeaders(),
        Authorization: `Bearer ${apiKey}`,
      },
    });
    return response;
}
ajsharp commented 1 year ago

It's not working for me, and if you look at the source code on line 2541:

if (file !== undefined) { 
    localVarFormParams.append('file', file as any);
}

It's appending the file to the FormData object. All of those are native DOM objects. It must be a File instance to work.

I'm trying this, but I'm getting a 400 error, at least when trying to pass a Buffer object. I think the 400 is happening because openai relies on the file name and content type coming from axios in the multipart form data headers, but Blob and ReadStream doesn't contain any of that info.

Node's buffer package provides a node-native File class as of node 18 (I think), but it's still experimental (see https://github.com/nodejs/node/pull/47153), and I still get errors with it trying to use it with axios.

It seems like what's needed is a File-like utility class provided by this library to add the filename and content type metadata axios needs to the request body. Ideally this class would implement whatever interface axios expects.

Another option would be to have some utility code to manually add the content type and filename when appending the file to the axios payload. For example changing https://github.com/openai/openai-node/blob/51b1340e3182c4cb5d43a5b771606ecdd93a60f4/api.ts#L2475

to do something like this:

localVarFormParams.append("file", file, {
  filename: fileName,
  contentType: "audio/aac",
});

The form-data package accepts that interface, which i think is what this package uses to build multipart request bodies.

rattrayalex commented 1 year ago

Hi, we have an upcoming version v4.0.0 that overauls File support; please give it a try and let us know in the thread whether it suits your needs!

EddyVinck commented 1 year ago

Hi, we have an upcoming version v4.0.0 that overauls File support; please give it a try and let us know in the thread whether it suits your needs!

Just tried the new version out this morning

isFileLike from openai/uploads + OpenAI.toFile are game changers, much easier to integrate now 🥳

rattrayalex commented 1 year ago

Thank you so much for the feedback @EddyVinck ! I encourage others here to give the v4 a try and share your experiences as well.