Many-in-one AI client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 line
7.1 KiB

  1. import { config } from 'dotenv';
  2. import {
  3. beforeAll,
  4. beforeEach,
  5. describe,
  6. expect,
  7. it,
  8. } from 'vitest';
  9. import {
  10. createAiClient,
  11. PlatformEventEmitter,
  12. OpenAi,
  13. } from '../../../src';
  14. import { getPromptTokens } from '../../../src/platforms/openai/usage';
  15. import { ChatCompletionModel } from '../../../src/platforms/openai';
  16. describe('OpenAI', () => {
  17. beforeAll(() => {
  18. config();
  19. });
  20. describe.skip('API', () => {
  21. let aiClient: PlatformEventEmitter;
  22. beforeEach(() => {
  23. aiClient = createAiClient({
  24. platform: OpenAi.PLATFORM_ID,
  25. platformConfiguration: {
  26. apiKey: process.env.OPENAI_API_KEY as string,
  27. organizationId: process.env.OPENAI_ORGANIZATION_ID as string,
  28. apiVersion: OpenAi.ApiVersion.V1,
  29. },
  30. });
  31. });
  32. describe('createChatCompletion', () => {
  33. let result: Partial<OpenAi.ChatCompletion> | undefined;
  34. let prompt: string;
  35. beforeEach(() => {
  36. result = undefined;
  37. aiClient.on<OpenAi.ChatCompletionChunkDataEvent>('data', (d) => {
  38. d.choices.forEach((c) => {
  39. if (!result) {
  40. const promptTokens = getPromptTokens(
  41. prompt,
  42. ChatCompletionModel.GPT_3_5_TURBO,
  43. )
  44. .length;
  45. result = {
  46. id: d.id,
  47. object: OpenAi.ChatCompletionDataEventObjectType.CHAT_COMPLETION,
  48. created: d.created,
  49. model: d.model,
  50. usage: {
  51. prompt_tokens: promptTokens,
  52. completion_tokens: 0,
  53. total_tokens: promptTokens,
  54. },
  55. };
  56. }
  57. if (!Array.isArray(result?.choices)) {
  58. result.choices = [];
  59. }
  60. if (!result.choices[c.index]) {
  61. result.choices[c.index] = {
  62. message: { content: '' },
  63. index: c.index,
  64. finish_reason: c.finish_reason,
  65. };
  66. }
  67. if (result.choices[c.index].message) {
  68. if (c.delta.role) {
  69. (result.choices[c.index].message as Record<string, unknown>).role = c.delta.role;
  70. }
  71. if (c.delta.content) {
  72. (result.choices[c.index].message as Record<string, unknown>)
  73. .content += c.delta.content;
  74. result.usage!.completion_tokens += 1;
  75. result.usage!.total_tokens = (
  76. result.usage!.prompt_tokens + result.usage!.completion_tokens
  77. );
  78. }
  79. }
  80. if (c.finish_reason) {
  81. result.choices[c.index].finish_reason = c.finish_reason;
  82. }
  83. });
  84. });
  85. });
  86. it('works', () => new Promise<void>((resolve, reject) => {
  87. aiClient.on('end', () => {
  88. expect(result).toHaveProperty('id', expect.any(String));
  89. expect(result).toHaveProperty('object', OpenAi.ChatCompletionDataEventObjectType.CHAT_COMPLETION);
  90. expect(result).toHaveProperty('model', expect.any(String));
  91. expect(result).toHaveProperty('created', expect.any(Number));
  92. expect(result).toHaveProperty('choices', expect.any(Array));
  93. resolve();
  94. });
  95. aiClient.on('error', (error: Error) => {
  96. reject(error);
  97. });
  98. prompt = 'Count from 1 to 20 in increments of a random number from 1 to 10.';
  99. aiClient.createChatCompletion({
  100. messages: prompt,
  101. model: OpenAi.ChatCompletionModel.GPT_3_5_TURBO,
  102. n: 2,
  103. });
  104. }), { timeout: 10000 });
  105. });
  106. describe('createImage', () => {
  107. it('works', () => new Promise<void>((resolve, reject) => {
  108. aiClient.on<OpenAi.CreateImageDataEvent>('data', (r) => {
  109. expect(r).toHaveProperty('created', expect.any(Number));
  110. expect(r).toHaveProperty('data', expect.any(Array));
  111. expect(r.data.every((d) => d instanceof Buffer)).toBe(true);
  112. });
  113. aiClient.on('end', () => {
  114. resolve();
  115. });
  116. aiClient.on('error', (error: Error) => {
  117. reject(error);
  118. });
  119. aiClient.createImage({
  120. prompt: 'A photo of a cat',
  121. size: OpenAi.CreateImageSize.SQUARE_256,
  122. });
  123. }), { timeout: 10000 });
  124. });
  125. describe('createCompletion', () => {
  126. let result: Partial<OpenAi.TextCompletion> | undefined;
  127. beforeEach(() => {
  128. result = undefined;
  129. aiClient.on<OpenAi.TextCompletionChunkDataEvent>('data', (d) => {
  130. d.choices.forEach((c) => {
  131. if (!result) {
  132. result = {
  133. id: d.id,
  134. object: OpenAi.TextCompletionDataEventObjectType.TEXT_COMPLETION,
  135. created: d.created,
  136. model: d.model,
  137. };
  138. }
  139. if (!Array.isArray(result?.choices)) {
  140. result.choices = [];
  141. }
  142. if (!result.choices[c.index]) {
  143. result.choices[c.index] = {
  144. text: '',
  145. index: c.index,
  146. finish_reason: c.finish_reason,
  147. logprobs: c.logprobs, // TODO dunno how to use this?
  148. };
  149. }
  150. if (c.text) {
  151. result.choices[c.index].text += c.text;
  152. }
  153. if (c.finish_reason) {
  154. result.choices[c.index].finish_reason = c.finish_reason;
  155. }
  156. });
  157. });
  158. });
  159. it('works', () => new Promise<void>((resolve, reject) => {
  160. aiClient.on('end', () => {
  161. expect(result).toHaveProperty('id', expect.any(String));
  162. expect(result).toHaveProperty('object', OpenAi.TextCompletionDataEventObjectType.TEXT_COMPLETION);
  163. expect(result).toHaveProperty('model', expect.any(String));
  164. expect(result).toHaveProperty('created', expect.any(Number));
  165. expect(result).toHaveProperty('choices', expect.any(Array));
  166. resolve();
  167. });
  168. aiClient.on('error', (error: Error) => {
  169. reject(error);
  170. });
  171. aiClient.createCompletion({
  172. prompt: 'Say this is a test',
  173. model: OpenAi.TextCompletionModel.TEXT_DAVINCI_003,
  174. maxTokens: 7,
  175. temperature: 0,
  176. });
  177. }), { timeout: 10000 });
  178. });
  179. describe('createEdit', () => {
  180. it('works', () => new Promise<void>((resolve, reject) => {
  181. aiClient.on<OpenAi.CreateEditDataEvent>('data', (r) => {
  182. expect(r).toHaveProperty('object', OpenAi.EditDataEventObjectType.EDIT);
  183. expect(r).toHaveProperty('created', expect.any(Number));
  184. expect(r).toHaveProperty('choices', expect.any(Array));
  185. });
  186. aiClient.on('end', () => {
  187. resolve();
  188. });
  189. aiClient.on('error', (error: Error) => {
  190. reject(error);
  191. });
  192. aiClient.createEdit({
  193. model: OpenAi.EditModel.TEXT_DAVINCI_EDIT_001,
  194. input: 'What day of the wek is it?',
  195. instruction: 'Fix the spelling mistakes',
  196. });
  197. }), { timeout: 10000 });
  198. });
  199. });
  200. });