@langchain/openai 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/legacy.cjs CHANGED
@@ -253,7 +253,7 @@ class OpenAIChat extends llms_1.LLM {
253
253
  this.organization =
254
254
  fields?.configuration?.organization ??
255
255
  (0, env_1.getEnvironmentVariable)("OPENAI_ORGANIZATION");
256
- this.modelName = fields?.modelName ?? this.modelName;
256
+ this.modelName = fields?.model ?? fields?.modelName ?? this.modelName;
257
257
  this.prefixMessages = fields?.prefixMessages ?? this.prefixMessages;
258
258
  this.modelKwargs = fields?.modelKwargs ?? {};
259
259
  this.timeout = fields?.timeout;
package/dist/legacy.js CHANGED
@@ -250,7 +250,7 @@ export class OpenAIChat extends LLM {
250
250
  this.organization =
251
251
  fields?.configuration?.organization ??
252
252
  getEnvironmentVariable("OPENAI_ORGANIZATION");
253
- this.modelName = fields?.modelName ?? this.modelName;
253
+ this.modelName = fields?.model ?? fields?.modelName ?? this.modelName;
254
254
  this.prefixMessages = fields?.prefixMessages ?? this.prefixMessages;
255
255
  this.modelKwargs = fields?.modelKwargs ?? {};
256
256
  this.timeout = fields?.timeout;
package/dist/llms.cjs CHANGED
@@ -75,6 +75,15 @@ class OpenAI extends llms_1.BaseLLM {
75
75
  let model = fields?.model ?? fields?.modelName;
76
76
  if ((model?.startsWith("gpt-3.5-turbo") || model?.startsWith("gpt-4")) &&
77
77
  !model?.includes("-instruct")) {
78
+ console.warn([
79
+ `Your chosen OpenAI model, "${model}", is a chat model and not a text-in/text-out LLM.`,
80
+ `Passing it into the "OpenAI" class is deprecated and only permitted for backwards-compatibility. You may experience odd behavior.`,
81
+ `Please use the "ChatOpenAI" class instead.`,
82
+ "",
83
+ `See this page for more information:`,
84
+ "|",
85
+ `└> https://js.langchain.com/v0.2/docs/integrations/chat/openai`,
86
+ ].join("\n"));
78
87
  // eslint-disable-next-line no-constructor-return
79
88
  return new legacy_js_1.OpenAIChat(fields, configuration);
80
89
  }
package/dist/llms.js CHANGED
@@ -72,6 +72,15 @@ export class OpenAI extends BaseLLM {
72
72
  let model = fields?.model ?? fields?.modelName;
73
73
  if ((model?.startsWith("gpt-3.5-turbo") || model?.startsWith("gpt-4")) &&
74
74
  !model?.includes("-instruct")) {
75
+ console.warn([
76
+ `Your chosen OpenAI model, "${model}", is a chat model and not a text-in/text-out LLM.`,
77
+ `Passing it into the "OpenAI" class is deprecated and only permitted for backwards-compatibility. You may experience odd behavior.`,
78
+ `Please use the "ChatOpenAI" class instead.`,
79
+ "",
80
+ `See this page for more information:`,
81
+ "|",
82
+ `└> https://js.langchain.com/v0.2/docs/integrations/chat/openai`,
83
+ ].join("\n"));
75
84
  // eslint-disable-next-line no-constructor-return
76
85
  return new OpenAIChat(fields, configuration);
77
86
  }
@@ -100,18 +100,75 @@ class DallEAPIWrapper extends tools_1.Tool {
100
100
  fields?.dallEResponseFormat ?? this.dallEResponseFormat;
101
101
  this.user = fields?.user;
102
102
  }
103
+ /**
104
+ * Processes the API response if multiple images are generated.
105
+ * Returns a list of MessageContentImageUrl objects. If the response
106
+ * format is `url`, then the `image_url` field will contain the URL.
107
+ * If it is `b64_json`, then the `image_url` field will contain an object
108
+ * with a `url` field with the base64 encoded image.
109
+ *
110
+ * @param {OpenAIClient.Images.ImagesResponse[]} response The API response
111
+ * @returns {MessageContentImageUrl[]}
112
+ */
113
+ processMultipleGeneratedUrls(response) {
114
+ if (this.dallEResponseFormat === "url") {
115
+ return response.flatMap((res) => {
116
+ const imageUrlContent = res.data
117
+ .flatMap((item) => {
118
+ if (!item.url)
119
+ return [];
120
+ return {
121
+ type: "image_url",
122
+ image_url: item.url,
123
+ };
124
+ })
125
+ .filter((item) => item !== undefined &&
126
+ item.type === "image_url" &&
127
+ typeof item.image_url === "string" &&
128
+ item.image_url !== undefined);
129
+ return imageUrlContent;
130
+ });
131
+ }
132
+ else {
133
+ return response.flatMap((res) => {
134
+ const b64Content = res.data
135
+ .flatMap((item) => {
136
+ if (!item.b64_json)
137
+ return [];
138
+ return {
139
+ type: "image_url",
140
+ image_url: {
141
+ url: item.b64_json,
142
+ },
143
+ };
144
+ })
145
+ .filter((item) => item !== undefined &&
146
+ item.type === "image_url" &&
147
+ typeof item.image_url === "object" &&
148
+ "url" in item.image_url &&
149
+ typeof item.image_url.url === "string" &&
150
+ item.image_url.url !== undefined);
151
+ return b64Content;
152
+ });
153
+ }
154
+ }
103
155
  /** @ignore */
104
156
  async _call(input) {
105
- const response = await this.client.images.generate({
157
+ const generateImageFields = {
106
158
  model: this.model,
107
159
  prompt: input,
108
- n: this.n,
160
+ n: 1,
109
161
  size: this.size,
110
162
  response_format: this.dallEResponseFormat,
111
163
  style: this.style,
112
164
  quality: this.quality,
113
165
  user: this.user,
114
- });
166
+ };
167
+ if (this.n > 1) {
168
+ const results = await Promise.all(Array.from({ length: this.n }).map(() => this.client.images.generate(generateImageFields)));
169
+ return this.processMultipleGeneratedUrls(results);
170
+ }
171
+ const response = await this.client.images.generate(generateImageFields);
115
172
  let data = "";
116
173
  if (this.dallEResponseFormat === "url") {
117
174
  [data] = response.data
@@ -1,5 +1,6 @@
1
1
  import { OpenAI as OpenAIClient } from "openai";
2
2
  import { Tool, ToolParams } from "@langchain/core/tools";
3
+ import { MessageContentComplex } from "@langchain/core/messages";
3
4
  /**
4
5
  * An interface for the Dall-E API Wrapper.
5
6
  */
@@ -90,6 +91,17 @@ export declare class DallEAPIWrapper extends Tool {
90
91
  private dallEResponseFormat;
91
92
  private user?;
92
93
  constructor(fields?: DallEAPIWrapperParams);
94
+ /**
95
+ * Processes the API response if multiple images are generated.
96
+ * Returns a list of MessageContentImageUrl objects. If the response
97
+ * format is `url`, then the `image_url` field will contain the URL.
98
+ * If it is `b64_json`, then the `image_url` field will contain an object
99
+ * with a `url` field with the base64 encoded image.
100
+ *
101
+ * @param {OpenAIClient.Images.ImagesResponse[]} response The API response
102
+ * @returns {MessageContentImageUrl[]}
103
+ */
104
+ private processMultipleGeneratedUrls;
93
105
  /** @ignore */
94
- _call(input: string): Promise<string>;
106
+ _call(input: string): Promise<string | MessageContentComplex[]>;
95
107
  }
@@ -97,18 +97,75 @@ export class DallEAPIWrapper extends Tool {
97
97
  fields?.dallEResponseFormat ?? this.dallEResponseFormat;
98
98
  this.user = fields?.user;
99
99
  }
100
+ /**
101
+ * Processes the API response if multiple images are generated.
102
+ * Returns a list of MessageContentImageUrl objects. If the response
103
+ * format is `url`, then the `image_url` field will contain the URL.
104
+ * If it is `b64_json`, then the `image_url` field will contain an object
105
+ * with a `url` field with the base64 encoded image.
106
+ *
107
+ * @param {OpenAIClient.Images.ImagesResponse[]} response The API response
108
+ * @returns {MessageContentImageUrl[]}
109
+ */
110
+ processMultipleGeneratedUrls(response) {
111
+ if (this.dallEResponseFormat === "url") {
112
+ return response.flatMap((res) => {
113
+ const imageUrlContent = res.data
114
+ .flatMap((item) => {
115
+ if (!item.url)
116
+ return [];
117
+ return {
118
+ type: "image_url",
119
+ image_url: item.url,
120
+ };
121
+ })
122
+ .filter((item) => item !== undefined &&
123
+ item.type === "image_url" &&
124
+ typeof item.image_url === "string" &&
125
+ item.image_url !== undefined);
126
+ return imageUrlContent;
127
+ });
128
+ }
129
+ else {
130
+ return response.flatMap((res) => {
131
+ const b64Content = res.data
132
+ .flatMap((item) => {
133
+ if (!item.b64_json)
134
+ return [];
135
+ return {
136
+ type: "image_url",
137
+ image_url: {
138
+ url: item.b64_json,
139
+ },
140
+ };
141
+ })
142
+ .filter((item) => item !== undefined &&
143
+ item.type === "image_url" &&
144
+ typeof item.image_url === "object" &&
145
+ "url" in item.image_url &&
146
+ typeof item.image_url.url === "string" &&
147
+ item.image_url.url !== undefined);
148
+ return b64Content;
149
+ });
150
+ }
151
+ }
100
152
  /** @ignore */
101
153
  async _call(input) {
102
- const response = await this.client.images.generate({
154
+ const generateImageFields = {
103
155
  model: this.model,
104
156
  prompt: input,
105
- n: this.n,
157
+ n: 1,
106
158
  size: this.size,
107
159
  response_format: this.dallEResponseFormat,
108
160
  style: this.style,
109
161
  quality: this.quality,
110
162
  user: this.user,
111
- });
163
+ };
164
+ if (this.n > 1) {
165
+ const results = await Promise.all(Array.from({ length: this.n }).map(() => this.client.images.generate(generateImageFields)));
166
+ return this.processMultipleGeneratedUrls(results);
167
+ }
168
+ const response = await this.client.images.generate(generateImageFields);
112
169
  let data = "";
113
170
  if (this.dallEResponseFormat === "url") {
114
171
  [data] = response.data
@@ -14,3 +14,44 @@ test.skip("Dalle can generate images with base 64 response format", async () =>
14
14
  expect(res).toBeDefined();
15
15
  expect(res).not.toContain("https://");
16
16
  });
17
+ test.skip("Dalle returns multiple image URLs if n > 1", async () => {
18
+ const dalle = new DallEAPIWrapper({
19
+ n: 2,
20
+ });
21
+ const res = await dalle.invoke("A painting of a cat");
22
+ expect(res).toBeDefined();
23
+ expect(res).toBeInstanceOf(Array);
24
+ if (!Array.isArray(res))
25
+ return;
26
+ expect(res).toHaveLength(2);
27
+ // The types for each should be `image_url` with an `image_url` field containing the URL
28
+ expect(res[0].type).toBe("image_url");
29
+ expect(res[1].type).toBe("image_url");
30
+ expect(res[0]).toHaveProperty("image_url");
31
+ expect(res[1]).toHaveProperty("image_url");
32
+ expect(res[0].image_url.startsWith("https://")).toBe(true);
33
+ expect(res[1].image_url.startsWith("https://")).toBe(true);
34
+ });
35
+ test.skip("Dalle returns multiple base64 image strings if n > 1", async () => {
36
+ const dalle = new DallEAPIWrapper({
37
+ n: 2,
38
+ dallEResponseFormat: "b64_json",
39
+ });
40
+ const res = await dalle.invoke("A painting of a cat");
41
+ expect(res).toBeDefined();
42
+ expect(res).toBeInstanceOf(Array);
43
+ if (!Array.isArray(res))
44
+ return;
45
+ expect(res).toHaveLength(2);
46
+ // The types for each should be `b64_json` with an `b64_json` field containing the URL
47
+ expect(res[0].type).toBe("image_url");
48
+ expect(res[1].type).toBe("image_url");
49
+ expect(res[0]).toHaveProperty("image_url");
50
+ expect(res[1]).toHaveProperty("image_url");
51
+ expect(res[0].image_url).toHaveProperty("url");
52
+ expect(res[1].image_url).toHaveProperty("url");
53
+ expect(res[0].image_url.url).toBeDefined();
54
+ expect(res[1].image_url.url).toBeDefined();
55
+ expect(res[0].image_url.url).not.toBe("");
56
+ expect(res[1].image_url.url).not.toBe("");
57
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/openai",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "OpenAI integrations for LangChain.js",
5
5
  "type": "module",
6
6
  "engines": {