openai-node

Форк
0
154 строки · 5.0 Кб
1
// shouldn't need extension, but Jest's ESM module resolution is broken
2
import 'openai/shims/web.mjs';
3
import OpenAI, { toFile } from 'openai';
4
import { distance } from 'fastest-levenshtein';
5
import { ChatCompletion } from 'openai/resources/chat/completions';
6

7
const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3';
8
const filename = 'sample-1.mp3';
9

10
const correctAnswer =
11
  '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,';
12
const model = 'whisper-1';
13

14
const client = new OpenAI();
15

16
async function typeTests() {
17
  // @ts-expect-error this should error if the `Uploadable` type was resolved correctly
18
  await client.audio.transcriptions.create({ file: { foo: true }, model: 'whisper-1' });
19
  // @ts-expect-error this should error if the `Uploadable` type was resolved correctly
20
  await client.audio.transcriptions.create({ file: null, model: 'whisper-1' });
21
  // @ts-expect-error this should error if the `Uploadable` type was resolved correctly
22
  await client.audio.transcriptions.create({ file: 'test', model: 'whisper-1' });
23
}
24

25
declare global {
26
  namespace jest {
27
    interface Matchers<R> {
28
      toBeSimilarTo(comparedTo: string, expectedDistance: number): R;
29
    }
30
  }
31
}
32
expect.extend({
33
  toBeSimilarTo(received, comparedTo: string, expectedDistance: number) {
34
    const message = () =>
35
      [
36
        `Received: ${JSON.stringify(received)}`,
37
        `Expected: ${JSON.stringify(comparedTo)}`,
38
        `Expected distance: ${expectedDistance}`,
39
        `Received distance: ${actualDistance}`,
40
      ].join('\n');
41

42
    const actualDistance = distance(received, comparedTo);
43
    if (actualDistance < expectedDistance) {
44
      return {
45
        message,
46
        pass: true,
47
      };
48
    }
49

50
    return {
51
      message,
52
      pass: false,
53
    };
54
  },
55
});
56

57
it(`raw response`, async function () {
58
  const response = await client.chat.completions
59
    .create({
60
      model: 'gpt-4',
61
      messages: [{ role: 'user', content: 'Say this is a test' }],
62
    })
63
    .asResponse();
64

65
  // test that we can use web Response API
66
  const { body } = response;
67
  if (!body) throw new Error('expected response.body to be defined');
68

69
  const reader = body.getReader();
70
  const chunks: Uint8Array[] = [];
71
  let result;
72
  do {
73
    result = await reader.read();
74
    if (!result.done) chunks.push(result.value);
75
  } while (!result.done);
76

77
  reader.releaseLock();
78

79
  let offset = 0;
80
  const merged = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0));
81
  for (const chunk of chunks) {
82
    merged.set(chunk, offset);
83
    offset += chunk.length;
84
  }
85

86
  const json: ChatCompletion = JSON.parse(new TextDecoder().decode(merged));
87
  expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10);
88
});
89

90
it(`streaming works`, async function () {
91
  const stream = await client.chat.completions.create({
92
    model: 'gpt-4',
93
    messages: [{ role: 'user', content: 'Say this is a test' }],
94
    stream: true,
95
  });
96
  const chunks = [];
97
  for await (const part of stream) {
98
    chunks.push(part);
99
  }
100
  expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10);
101
});
102

103
if (typeof File !== 'undefined') {
104
  it('handles builtinFile', async function () {
105
    const file = await fetch(url)
106
      .then((x) => x.arrayBuffer())
107
      .then((x) => new File([x], filename));
108

109
    const result = await client.audio.transcriptions.create({ file, model });
110
    expect(result.text).toBeSimilarTo(correctAnswer, 12);
111
  });
112
}
113

114
it('handles Response', async function () {
115
  const file = await fetch(url);
116

117
  const result = await client.audio.transcriptions.create({ file, model });
118
  expect(result.text).toBeSimilarTo(correctAnswer, 12);
119
});
120

121
const fineTune = `{"prompt": "<prompt text>", "completion": "<ideal generated text>"}`;
122

123
describe('toFile', () => {
124
  if (typeof Blob !== 'undefined') {
125
    it('handles builtin Blob', async function () {
126
      const result = await client.files.create({
127
        file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'),
128
        purpose: 'fine-tune',
129
      });
130
      expect(result.filename).toEqual('finetune.jsonl');
131
    });
132
  }
133
  it('handles Uint8Array', async function () {
134
    const result = await client.files.create({
135
      file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'),
136
      purpose: 'fine-tune',
137
    });
138
    expect(result.filename).toEqual('finetune.jsonl');
139
  });
140
  it('handles ArrayBuffer', async function () {
141
    const result = await client.files.create({
142
      file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'),
143
      purpose: 'fine-tune',
144
    });
145
    expect(result.filename).toEqual('finetune.jsonl');
146
  });
147
  it('handles DataView', async function () {
148
    const result = await client.files.create({
149
      file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'),
150
      purpose: 'fine-tune',
151
    });
152
    expect(result.filename).toEqual('finetune.jsonl');
153
  });
154
});
155

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.