Skip to content

Commit

Permalink
Add: generate summary of file for JIT on upsert (#8782)
Browse files Browse the repository at this point in the history
* Add: generate summary of file for JIT on upsert

* Update dust-app name
  • Loading branch information
Fraggle authored Nov 21, 2024
1 parent 27e684e commit 7b52300
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 17 deletions.
128 changes: 111 additions & 17 deletions front/lib/api/files/upsert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import type {
PlainTextContentType,
Result,
} from "@dust-tt/types";
import { Err, isSupportedPlainTextContentType, Ok } from "@dust-tt/types";
import {
assertNever,
Err,
getSmallWhitelistedModel,
isSupportedPlainTextContentType,
Ok,
removeNulls,
} from "@dust-tt/types";
import { Writable } from "stream";
import { pipeline } from "stream/promises";

import { runAction } from "@app/lib/actions/server";
import { getConversation } from "@app/lib/api/assistant/conversation";
import { isJITActionsEnabled } from "@app/lib/api/assistant/jit_actions";
import {
Expand All @@ -17,6 +25,7 @@ import {
} from "@app/lib/api/data_sources";
import type { Authenticator } from "@app/lib/auth";
import type { DustError } from "@app/lib/error";
import { cloneBaseConfig, DustProdActionRegistry } from "@app/lib/registry";
import { DataSourceResource } from "@app/lib/resources/data_source_resource";
import type { FileResource } from "@app/lib/resources/file_resource";
import { SpaceResource } from "@app/lib/resources/space_resource";
Expand Down Expand Up @@ -53,6 +62,64 @@ const notSupportedError: ProcessingFunction = async ({ file }) => {
);
};

async function generateSnippet(
auth: Authenticator,
content: string
): Promise<Result<string, Error>> {
const owner = auth.getNonNullableWorkspace();

const model = getSmallWhitelistedModel(owner);
if (!model) {
return new Err(
new Error(`Failed to find a whitelisted model to generate title`)
);
}

const config = cloneBaseConfig(
DustProdActionRegistry["conversation-file-summarizer"].config
);
config.MODEL.provider_id = model.providerId;
config.MODEL.model_id = model.modelId;

const res = await runAction(auth, "conversation-file-summarizer", config, [
{
content: content,
},
]);

if (res.isErr()) {
return new Err(new Error(`Error generating snippet: ${res.error}`));
}

const {
status: { run },
traces,
results,
} = res.value;

switch (run) {
case "errored":
const error = removeNulls(traces.map((t) => t[1][0][0].error)).join(", ");
return new Err(new Error(`Error generating snippet: ${error}`));
case "succeeded":
if (!results || results.length === 0) {
return new Err(
new Error(
`Error generating snippet: no results returned while run was successful`
)
);
}
const snippet = results[0][0].value as string;
return new Ok(snippet);
case "running":
return new Err(
new Error(`Snippet generation is still running, should never happen.`)
);
default:
assertNever(run);
}
}

// Upload to dataSource
const upsertDocumentToDatasource: ProcessingFunction = async ({
auth,
Expand Down Expand Up @@ -216,6 +283,28 @@ const maybeApplyProcessing: ProcessingFunction = async ({
return new Ok(undefined);
};

async function getFileContent(
auth: Authenticator,
file: FileResource
): Promise<string> {
// Create a stream to hold the content of the file
const writableStream = new MemoryWritable();

// Read from the processed file
await pipeline(
file.getReadStream({ auth, version: "processed" }),
writableStream
);

const content = writableStream.getContent();

if (!content) {
throw new Error("No content extracted from file for JIT processing.");
}

return content;
}

export async function processAndUpsertToDataSource(
auth: Authenticator,
{ file }: { file: FileResource }
Expand Down Expand Up @@ -262,16 +351,7 @@ export async function processAndUpsertToDataSource(
});
}

// Create a stream to hold the content of the file
const writableStream = new MemoryWritable();

// Read from the processed file
await pipeline(
file.getReadStream({ auth, version: "processed" }),
writableStream
);

const content = writableStream.getContent();
const content = await getFileContent(auth, file);

if (!content) {
return new Err({
Expand Down Expand Up @@ -326,12 +406,15 @@ export async function processAndUpsertToDataSource(
dataSource = r.value.dataSource;
}

const processingRes = await maybeApplyProcessing({
auth,
file,
content,
dataSource,
});
const [processingRes, snippetRes] = await Promise.all([
maybeApplyProcessing({
auth,
file,
content,
dataSource,
}),
generateSnippet(auth, content),
]);

if (processingRes.isErr()) {
return new Err({
Expand All @@ -341,5 +424,16 @@ export async function processAndUpsertToDataSource(
});
}

if (snippetRes.isErr()) {
return new Err({
name: "dust_error",
code: "internal_server_error",
message: `Failed to generate snippet: ${snippetRes.error}`,
});
}

// If the snippet is present, it means the file is ready to use for JIT actions.
await file.setSnippet(snippetRes.value);

return new Ok(file);
}
16 changes: 16 additions & 0 deletions front/lib/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,22 @@ export const DustProdActionRegistry = createActionRegistry({
},
},
},
"conversation-file-summarizer": {
app: {
workspaceId: PRODUCTION_DUST_APPS_WORKSPACE_ID,
appId: "iy1pjLCMzZ",
appHash:
"0cd0a82dcfaa327b2d5d1f645a314ea885e995a12921a1024ee96b92e8f15768",
appSpaceId: PRODUCTION_DUST_APPS_SPACE_ID,
},
config: {
MODEL: {
// `provider_id` and `model_id` must be set by caller.
use_cache: false,
use_stream: false,
},
},
},
});

export type DustRegistryActionName = keyof typeof DustProdActionRegistry;
Expand Down
8 changes: 8 additions & 0 deletions front/lib/resources/file_resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ export class FileResource extends BaseResource<FileModel> {
return this.update({ useCaseMetadata: metadata });
}

setSnippet(snippet: string) {
return this.update({ snippet });
}

isUsableForJITActions(): boolean {
return this.snippet !== null;
}

// Serialization logic.

toJSON(auth: Authenticator): FileType {
Expand Down

0 comments on commit 7b52300

Please sign in to comment.