Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

google-common[major]: Media manager #5835

Merged
merged 59 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d0cc30f
Use earliest interface in the chain necessary.
afirstenberg Jun 16, 2024
db3cdd7
Add delete method
afirstenberg Jun 16, 2024
27031f4
Provide ways to get additional headers into the request.
afirstenberg Jun 16, 2024
49bb70a
Initial work on Blobs and BlobStores, including initial work on GCS
afirstenberg Jun 16, 2024
951175f
Fix typos and bugs on data fetch
afirstenberg Jun 17, 2024
7860630
Start of refactoring around native JS Blobs
afirstenberg Jun 19, 2024
07c92d6
Refactor how RawConnections are structured and used
afirstenberg Jun 20, 2024
30f228a
Switch to using "blob"
afirstenberg Jun 20, 2024
cfb1081
Refactor how RawConnections are structured and used
afirstenberg Jun 20, 2024
9ca6a31
Refactoring
afirstenberg Jun 20, 2024
d2f4a40
formatting
afirstenberg Jun 20, 2024
7550b51
Initial implementation of the MediaManager
afirstenberg Jun 20, 2024
87f8c13
Add options for store() that can be used to make sure URIs are set in…
afirstenberg Jun 21, 2024
39ffcb3
Add options for store() that can be used to make sure URIs are set in…
afirstenberg Jun 21, 2024
fd54f5e
Default implementation of hasValidPath
afirstenberg Jun 21, 2024
afd2f25
Tests. Bug fixes.
afirstenberg Jun 21, 2024
60589dd
Assorted name and type refactoring.
afirstenberg Jun 22, 2024
48ddbe9
Tests for MediaManager.
afirstenberg Jun 22, 2024
185229b
Fix tests
afirstenberg Jun 23, 2024
d3fcadb
Refactor Gemini API into a single, containable, thing.
afirstenberg Jun 23, 2024
f84cdaf
Remove obsolete comment
afirstenberg Jun 24, 2024
259ec12
Refactor
afirstenberg Jun 24, 2024
708a2fd
Add mediaManager to Gemini functions.
afirstenberg Jun 24, 2024
2467860
Testing MediaManager in chat functions in Vertex AI.
afirstenberg Jun 24, 2024
b394eec
Initial, incomplete, work on BlobStoreAIStudio
afirstenberg Jun 25, 2024
6098ee5
Basic BlobStoreAIStudio implementation and test
afirstenberg Jun 26, 2024
c4089e2
Report more error details in the exception
afirstenberg Jun 27, 2024
ebdf657
Testing MediaManager in chat functions in AI Studio.
afirstenberg Jun 27, 2024
8b7a18b
Merge branch 'main' into media-manager
afirstenberg Jun 27, 2024
5dd7164
Fix bug handling larger files
afirstenberg Jul 1, 2024
94fd6a4
Fix issues with video upload / processing.
afirstenberg Jul 1, 2024
ba5e4b7
Fix issues with the `api` attribute for ChatConnections
afirstenberg Jul 1, 2024
72d7f0c
Formatting
afirstenberg Jul 1, 2024
ebed89c
Leave response on error object.
afirstenberg Jul 2, 2024
1caebf1
Remove commented out stuff.
afirstenberg Jul 2, 2024
bd4c974
Make methods protected.
afirstenberg Jul 2, 2024
ee77ee2
Formatting
afirstenberg Jul 2, 2024
14f74a3
Move media and media_core into experimental status
afirstenberg Jul 2, 2024
da1817c
Formatting
afirstenberg Jul 2, 2024
7cf8e30
Merge branch 'main' into media-manager
afirstenberg Jul 5, 2024
9bd18c5
UUID Version support
afirstenberg Jul 5, 2024
aae6107
Formatting
afirstenberg Jul 5, 2024
c3e3677
Merge branch 'main' into media-manager
afirstenberg Jul 26, 2024
27e427c
Adjust to use a ReadThroughBlobStore instead of putting this logic in…
afirstenberg Jul 29, 2024
fcdba48
Implement MediaBlob serialization.
afirstenberg Jul 29, 2024
076c19c
Formatting
afirstenberg Jul 29, 2024
464bc2b
Merge branch 'main' into media-manager
afirstenberg Aug 1, 2024
e7e00ce
fix test
afirstenberg Aug 1, 2024
51b5eea
Remove unnecessary comments
afirstenberg Aug 1, 2024
b1e6f6d
Merge
jacoblee93 Aug 22, 2024
986a021
Fix lint, circular deps
jacoblee93 Aug 22, 2024
04d5c74
Use built-in serde properly
jacoblee93 Aug 22, 2024
101af7f
Merge branch 'main' into media-manager
jacoblee93 Aug 23, 2024
3f8a342
Fix build
jacoblee93 Aug 23, 2024
4add032
fix faulty import path
bracesproul Aug 23, 2024
4a80410
Improve error message in the event of a bad URI
afirstenberg Sep 11, 2024
29f0b1c
Fix tests
afirstenberg Sep 11, 2024
fde3717
Fix tests
afirstenberg Sep 11, 2024
3012736
Formatting
afirstenberg Sep 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions libs/langchain-google-common/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ types.cjs
types.js
types.d.ts
types.d.cts
experimental/media.cjs
experimental/media.js
experimental/media.d.ts
experimental/media.d.cts
experimental/utils/media_core.cjs
experimental/utils/media_core.js
experimental/utils/media_core.d.ts
experimental/utils/media_core.d.cts
node_modules
dist
.yarn
2 changes: 2 additions & 0 deletions libs/langchain-google-common/langchain.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const config = {
index: "index",
utils: "utils/index",
types: "types",
"experimental/media": "experimental/media",
"experimental/utils/media_core": "experimental/utils/media_core",
},
tsConfigPath: resolve("./tsconfig.json"),
cjsSource: "./dist-cjs",
Expand Down
28 changes: 27 additions & 1 deletion libs/langchain-google-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@
"import": "./types.js",
"require": "./types.cjs"
},
"./experimental/media": {
"types": {
"import": "./experimental/media.d.ts",
"require": "./experimental/media.d.cts",
"default": "./experimental/media.d.ts"
},
"import": "./experimental/media.js",
"require": "./experimental/media.cjs"
},
"./experimental/utils/media_core": {
"types": {
"import": "./experimental/utils/media_core.d.ts",
"require": "./experimental/utils/media_core.d.cts",
"default": "./experimental/utils/media_core.d.ts"
},
"import": "./experimental/utils/media_core.js",
"require": "./experimental/utils/media_core.cjs"
},
"./package.json": "./package.json"
},
"files": [
Expand All @@ -107,6 +125,14 @@
"types.cjs",
"types.js",
"types.d.ts",
"types.d.cts"
"types.d.cts",
"experimental/media.cjs",
"experimental/media.js",
"experimental/media.d.ts",
"experimental/media.d.cts",
"experimental/utils/media_core.cjs",
"experimental/utils/media_core.js",
"experimental/utils/media_core.d.ts",
"experimental/utils/media_core.d.cts"
]
}
36 changes: 28 additions & 8 deletions libs/langchain-google-common/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ReadableJsonStream } from "./utils/stream.js";
import { GooglePlatformType } from "./types.js";

export type GoogleAbstractedClientOpsMethod = "GET" | "POST";
export type GoogleAbstractedClientOpsMethod = "GET" | "POST" | "DELETE";

export type GoogleAbstractedClientOpsResponseType = "json" | "stream";
export type GoogleAbstractedClientOpsResponseType = "json" | "stream" | "blob";

export type GoogleAbstractedClientOps = {
url?: string;
Expand All @@ -28,6 +28,17 @@ export abstract class GoogleAbstractedFetchClient

abstract request(opts: GoogleAbstractedClientOps): unknown;

async _buildData(res: Response, opts: GoogleAbstractedClientOps) {
switch (opts.responseType) {
case "json":
return res.json();
case "stream":
return new ReadableJsonStream(res.body);
default:
return res.blob();
}
}

async _request(
url: string | undefined,
opts: GoogleAbstractedClientOps,
Expand All @@ -47,7 +58,11 @@ export abstract class GoogleAbstractedFetchClient
},
};
if (opts.data !== undefined) {
fetchOptions.body = JSON.stringify(opts.data);
if (typeof opts.data === "string") {
fetchOptions.body = opts.data;
} else {
fetchOptions.body = JSON.stringify(opts.data);
}
}

const res = await fetch(url, fetchOptions);
Expand All @@ -57,16 +72,21 @@ export abstract class GoogleAbstractedFetchClient
const error = new Error(
`Google request failed with status code ${res.status}: ${resText}`
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
/* eslint-disable @typescript-eslint/no-explicit-any */
(error as any).response = res;
(error as any).details = {
jacoblee93 marked this conversation as resolved.
Show resolved Hide resolved
url,
opts,
fetchOptions,
result: res,
};
/* eslint-enable @typescript-eslint/no-explicit-any */
throw error;
}

const data = await this._buildData(res, opts);
return {
data:
opts.responseType === "json"
? await res.json()
: new ReadableJsonStream(res.body),
data,
config: {},
status: res.status,
statusText: res.statusText,
Expand Down
87 changes: 49 additions & 38 deletions libs/langchain-google-common/src/chat_models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ import {
copyAndValidateModelParamsInto,
} from "./utils/common.js";
import { AbstractGoogleLLMConnection } from "./connection.js";
import {
baseMessageToContent,
safeResponseToChatGeneration,
safeResponseToChatResult,
DefaultGeminiSafetyHandler,
} from "./utils/gemini.js";
import { DefaultGeminiSafetyHandler } from "./utils/gemini.js";
import { ApiKeyGoogleAuth, GoogleAbstractedClient } from "./auth.js";
import { JsonStream } from "./utils/stream.js";
import { ensureParams } from "./utils/failed_handler.js";
Expand All @@ -55,6 +50,7 @@ import type {
GeminiFunctionDeclaration,
GeminiFunctionSchema,
GoogleAIToolType,
GeminiAPIConfig,
} from "./types.js";
import { zodToGeminiParameters } from "./utils/zod_to_gemini_parameters.js";

Expand Down Expand Up @@ -100,61 +96,69 @@ class ChatConnection<AuthOptions> extends AbstractGoogleLLMConnection<
return true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there! This code change introduces a new external HTTP request using the fetch or axios library within the formatContents method. I've flagged this for your review to ensure it aligns with the project's requirements.

}

formatContents(
async formatContents(
input: BaseMessage[],
_parameters: GoogleAIModelParams
): GeminiContent[] {
return input
.map((msg, i) =>
baseMessageToContent(msg, input[i - 1], this.useSystemInstruction)
): Promise<GeminiContent[]> {
const inputPromises: Promise<GeminiContent[]>[] = input.map((msg, i) =>
this.api.baseMessageToContent(
msg,
input[i - 1],
this.useSystemInstruction
)
.reduce((acc, cur) => {
// Filter out the system content
if (cur.every((content) => content.role === "system")) {
return acc;
}

// Combine adjacent function messages
if (
cur[0]?.role === "function" &&
acc.length > 0 &&
acc[acc.length - 1].role === "function"
) {
acc[acc.length - 1].parts = [
...acc[acc.length - 1].parts,
...cur[0].parts,
];
} else {
acc.push(...cur);
}
);
const inputs = await Promise.all(inputPromises);

return inputs.reduce((acc, cur) => {
// Filter out the system content
if (cur.every((content) => content.role === "system")) {
return acc;
}, [] as GeminiContent[]);
}

// Combine adjacent function messages
if (
cur[0]?.role === "function" &&
acc.length > 0 &&
acc[acc.length - 1].role === "function"
) {
acc[acc.length - 1].parts = [
...acc[acc.length - 1].parts,
...cur[0].parts,
];
} else {
acc.push(...cur);
}

return acc;
}, [] as GeminiContent[]);
}

formatSystemInstruction(
async formatSystemInstruction(
jacoblee93 marked this conversation as resolved.
Show resolved Hide resolved
input: BaseMessage[],
_parameters: GoogleAIModelParams
): GeminiContent {
): Promise<GeminiContent> {
if (!this.useSystemInstruction) {
return {} as GeminiContent;
}

let ret = {} as GeminiContent;
input.forEach((message, index) => {
for (let index = 0; index < input.length; index += 1) {
const message = input[index];
if (message._getType() === "system") {
// For system types, we only want it if it is the first message,
// if it appears anywhere else, it should be an error.
if (index === 0) {
// eslint-disable-next-line prefer-destructuring
ret = baseMessageToContent(message, undefined, true)[0];
ret = (
await this.api.baseMessageToContent(message, undefined, true)
)[0];
} else {
throw new Error(
"System messages are only permitted as the first passed message."
);
}
}
});
}

return ret;
}
Expand All @@ -168,6 +172,7 @@ export interface ChatGoogleBaseInput<AuthOptions>
GoogleConnectionParams<AuthOptions>,
GoogleAIModelParams,
GoogleAISafetyParams,
GeminiAPIConfig,
Pick<GoogleAIBaseLanguageModelCallOptions, "streamUsage"> {}

/**
Expand Down Expand Up @@ -338,7 +343,10 @@ export abstract class ChatGoogleBase<AuthOptions>
parameters,
options
);
const ret = safeResponseToChatResult(response, this.safetyHandler);
const ret = this.connection.api.safeResponseToChatResult(
response,
this.safetyHandler
);
await runManager?.handleLLMNewToken(ret.generations[0].text);
return ret;
}
Expand Down Expand Up @@ -378,7 +386,10 @@ export abstract class ChatGoogleBase<AuthOptions>
}
const chunk =
output !== null
? safeResponseToChatGeneration({ data: output }, this.safetyHandler)
? this.connection.api.safeResponseToChatGeneration(
{ data: output },
this.safetyHandler
)
: new ChatGenerationChunk({
text: "",
generationInfo: { finishReason: "stop" },
Expand Down
Loading
Loading