diff --git a/ecosystem-tests/bun/openai.test.ts b/ecosystem-tests/bun/openai.test.ts index 243bc19a3..399b40c84 100644 --- a/ecosystem-tests/bun/openai.test.ts +++ b/ecosystem-tests/bun/openai.test.ts @@ -1,9 +1,26 @@ import OpenAI, { toFile } from 'openai'; +import fs from 'fs'; import { distance } from 'fastest-levenshtein'; import { test, expect } from 'bun:test'; +const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; +const filename = 'sample-1.mp3'; + +const correctAnswer = + 'It was anxious to find him no one that expectation of a man who were giving his father enjoyment. But he was avoided in sight in the minister to which indeed,'; +const model = 'whisper-1'; + const client = new OpenAI(); +async function typeTests() { + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: { foo: true }, model: 'whisper-1' }); + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: null, model: 'whisper-1' }); + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: 'test', model: 'whisper-1' }); +} + function expectSimilar(received: any, comparedTo: string, expectedDistance: number) { const message = () => [ @@ -38,11 +55,80 @@ test(`streaming works`, async function () { expectSimilar(chunks.map((c) => c.choices[0]?.delta.content || '').join(''), 'This is a test', 10); }); -test(`toFile rejects`, async function () { - try { - await toFile(new TextEncoder().encode('foo'), 'foo.txt'); - throw new Error(`expected toFile to reject`); - } catch (error) { - expect((error as any).message).toEqual(`file uploads aren't supported in this environment yet`); - } +// @ts-ignore avoid DOM lib for testing purposes +if (typeof File !== 'undefined') { + test.todo('handles builtinFile', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + // @ts-ignore avoid DOM lib for testing purposes + .then((x) => new File([x], filename)); + + const result = await client.audio.transcriptions.create({ file, model }); + expectSimilar(result.text, correctAnswer, 12); + }); +} + +test.todo('handles Response', async function () { + const file = await fetch(url); + + const result = await client.audio.transcriptions.create({ file, model }); + expectSimilar(result.text, correctAnswer, 12); +}); + +test.todo('handles fs.ReadStream', async function () { + const result = await client.audio.transcriptions.create({ + file: fs.createReadStream('sample1.mp3'), + model, + }); + expectSimilar(result.text, correctAnswer, 12); +}); + +const fineTune = `{"prompt": "", "completion": ""}`; + +// @ts-ignore avoid DOM lib for testing purposes +if (typeof Blob !== 'undefined') { + test.todo('toFile handles builtin Blob', async function () { + const result = await client.files.create({ + file: await toFile( + // @ts-ignore avoid DOM lib for testing purposes + new Blob([new TextEncoder().encode(fineTune)]), + 'finetune.jsonl', + ), + purpose: 'fine-tune', + }); + expect(result.status).toEqual('uploaded'); + }); +} +test.todo('toFile handles Uint8Array', async function () { + const result = await client.files.create({ + file: await toFile( + // @ts-ignore avoid DOM lib for testing purposes + new TextEncoder().encode(fineTune), + 'finetune.jsonl', + ), + purpose: 'fine-tune', + }); + expect(result.status).toEqual('uploaded'); +}); +test.todo('toFile handles ArrayBuffer', async function () { + const result = await client.files.create({ + file: await toFile( + // @ts-ignore avoid DOM lib for testing purposes + new TextEncoder().encode(fineTune).buffer, + 'finetune.jsonl', + ), + purpose: 'fine-tune', + }); + expect(result.status).toEqual('uploaded'); +}); +test.todo('toFile handles DataView', async function () { + const result = await client.files.create({ + file: await toFile( + // @ts-ignore avoid DOM lib for testing purposes + new DataView(new TextEncoder().encode(fineTune).buffer), + 'finetune.jsonl', + ), + purpose: 'fine-tune', + }); + expect(result.status).toEqual('uploaded'); }); diff --git a/ecosystem-tests/bun/package.json b/ecosystem-tests/bun/package.json index 3cedd94f7..1465be93a 100644 --- a/ecosystem-tests/bun/package.json +++ b/ecosystem-tests/bun/package.json @@ -7,9 +7,7 @@ }, "devDependencies": { "fastest-levenshtein": "^1.0.16", - "bun-types": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" + "bun-types": "latest", + "typescript": "^5.1.0" } } diff --git a/ecosystem-tests/cli.ts b/ecosystem-tests/cli.ts index 195dbf020..d6ffcb872 100644 --- a/ecosystem-tests/cli.ts +++ b/ecosystem-tests/cli.ts @@ -268,7 +268,7 @@ async function main() { console.error('\n'); try { - await withRetry(fn, project, state.retry) + await withRetry(fn, project, state.retry); console.error(`✅ - Successfully ran ${project}`); } catch (err) { if (err && (err as any).shortMessage) { @@ -294,13 +294,13 @@ async function main() { async function withRetry(fn: () => Promise, identifier: string, retryAmount: number): Promise { do { try { - return await fn() + return await fn(); } catch (err) { - console.error(`${identifier} failed due to ${err}; retries left ${retryAmount}`) + retryAmount--; + if (retryAmount === 0) throw err; + console.error(`${identifier} failed due to ${err}; retries left ${retryAmount}`); } - - retryAmount--; - } while (retryAmount > 0) + } while (retryAmount > 0); } function centerPad(text: string, width = text.length, char = ' '): string { diff --git a/package.json b/package.json index b4847bed5..8a1440f63 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,11 @@ "require": "./dist/_shims/*.js", "default": "./dist/_shims/*.mjs" }, + "bun": { + "types": "./dist/_shims/*.d.ts", + "require": "./dist/_shims/*.js", + "default": "./dist/_shims/*.mjs" + }, "browser": { "types": "./dist/_shims/*.d.ts", "require": "./dist/_shims/*.js",