ws.mjs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import * as WS from 'ws';
  2. import { OpenAI } from "../../index.mjs";
  3. import { OpenAIRealtimeEmitter, buildRealtimeURL, isAzure } from "./internal-base.mjs";
  4. export class OpenAIRealtimeWS extends OpenAIRealtimeEmitter {
  5. constructor(props, client) {
  6. super();
  7. client ?? (client = new OpenAI());
  8. this.url = buildRealtimeURL(client, props.model);
  9. this.socket = new WS.WebSocket(this.url, {
  10. ...props.options,
  11. headers: {
  12. ...props.options?.headers,
  13. ...(isAzure(client) ? {} : { Authorization: `Bearer ${client.apiKey}` }),
  14. 'OpenAI-Beta': 'realtime=v1',
  15. },
  16. });
  17. this.socket.on('message', (wsEvent) => {
  18. const event = (() => {
  19. try {
  20. return JSON.parse(wsEvent.toString());
  21. }
  22. catch (err) {
  23. this._onError(null, 'could not parse websocket event', err);
  24. return null;
  25. }
  26. })();
  27. if (event) {
  28. this._emit('event', event);
  29. if (event.type === 'error') {
  30. this._onError(event);
  31. }
  32. else {
  33. // @ts-expect-error TS isn't smart enough to get the relationship right here
  34. this._emit(event.type, event);
  35. }
  36. }
  37. });
  38. this.socket.on('error', (err) => {
  39. this._onError(null, err.message, err);
  40. });
  41. }
  42. static async azure(client, options = {}) {
  43. const deploymentName = options.deploymentName ?? client.deploymentName;
  44. if (!deploymentName) {
  45. throw new Error('No deployment name provided');
  46. }
  47. return new OpenAIRealtimeWS({ model: deploymentName, options: { headers: await getAzureHeaders(client) } }, client);
  48. }
  49. send(event) {
  50. try {
  51. this.socket.send(JSON.stringify(event));
  52. }
  53. catch (err) {
  54. this._onError(null, 'could not send data', err);
  55. }
  56. }
  57. close(props) {
  58. try {
  59. this.socket.close(props?.code ?? 1000, props?.reason ?? 'OK');
  60. }
  61. catch (err) {
  62. this._onError(null, 'could not close the connection', err);
  63. }
  64. }
  65. }
  66. async function getAzureHeaders(client) {
  67. if (client.apiKey !== '<Missing Key>') {
  68. return { 'api-key': client.apiKey };
  69. }
  70. else {
  71. const token = await client._getAzureADToken();
  72. if (token) {
  73. return { Authorization: `Bearer ${token}` };
  74. }
  75. else {
  76. throw new Error('AzureOpenAI is not instantiated correctly. No API key or token provided.');
  77. }
  78. }
  79. }
  80. //# sourceMappingURL=ws.mjs.map