format && remove graph
This commit is contained in:
@@ -183,7 +183,7 @@ export function Thread() {
|
|||||||
setFirstTokenReceived(false);
|
setFirstTokenReceived(false);
|
||||||
|
|
||||||
// TODO: check configurable object for modelname camelcase or snakecase else do openai format
|
// TODO: check configurable object for modelname camelcase or snakecase else do openai format
|
||||||
const isOpenAI = true
|
const isOpenAI = true;
|
||||||
|
|
||||||
const pdfBlocks = pdfUrlList.map(toOpenAIPDFBlock);
|
const pdfBlocks = pdfUrlList.map(toOpenAIPDFBlock);
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ export function Thread() {
|
|||||||
const files = e.target.files;
|
const files = e.target.files;
|
||||||
if (files) {
|
if (files) {
|
||||||
const imageBlocks = await Promise.all(
|
const imageBlocks = await Promise.all(
|
||||||
Array.from(files).map(fileToImageBlock)
|
Array.from(files).map(fileToImageBlock),
|
||||||
);
|
);
|
||||||
setImageUrlList((prev) => [...prev, ...imageBlocks]);
|
setImageUrlList((prev) => [...prev, ...imageBlocks]);
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ export function Thread() {
|
|||||||
const files = e.target.files;
|
const files = e.target.files;
|
||||||
if (files) {
|
if (files) {
|
||||||
const pdfBlocks = await Promise.all(
|
const pdfBlocks = await Promise.all(
|
||||||
Array.from(files).map(fileToPDFBlock)
|
Array.from(files).map(fileToPDFBlock),
|
||||||
);
|
);
|
||||||
setPdfUrlList((prev) => [...prev, ...pdfBlocks]);
|
setPdfUrlList((prev) => [...prev, ...pdfBlocks]);
|
||||||
}
|
}
|
||||||
@@ -277,25 +277,26 @@ export function Thread() {
|
|||||||
const imageFiles = files.filter((file) => file.type.startsWith("image/"));
|
const imageFiles = files.filter((file) => file.type.startsWith("image/"));
|
||||||
const pdfFiles = files.filter((file) => file.type === "application/pdf");
|
const pdfFiles = files.filter((file) => file.type === "application/pdf");
|
||||||
const invalidFiles = files.filter(
|
const invalidFiles = files.filter(
|
||||||
(file) => !file.type.startsWith("image/") && file.type !== "application/pdf"
|
(file) =>
|
||||||
|
!file.type.startsWith("image/") && file.type !== "application/pdf",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (invalidFiles.length > 0) {
|
if (invalidFiles.length > 0) {
|
||||||
toast.error(
|
toast.error(
|
||||||
"You have uploaded invalid file type. Please upload an image or a PDF."
|
"You have uploaded invalid file type. Please upload an image or a PDF.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageFiles.length) {
|
if (imageFiles.length) {
|
||||||
const imageBlocks: Base64ContentBlock[] = await Promise.all(
|
const imageBlocks: Base64ContentBlock[] = await Promise.all(
|
||||||
imageFiles.map(fileToImageBlock)
|
imageFiles.map(fileToImageBlock),
|
||||||
);
|
);
|
||||||
setImageUrlList((prev) => [...prev, ...imageBlocks]);
|
setImageUrlList((prev) => [...prev, ...imageBlocks]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdfFiles.length) {
|
if (pdfFiles.length) {
|
||||||
const pdfBlocks: Base64ContentBlock[] = await Promise.all(
|
const pdfBlocks: Base64ContentBlock[] = await Promise.all(
|
||||||
pdfFiles.map(fileToPDFBlock)
|
pdfFiles.map(fileToPDFBlock),
|
||||||
);
|
);
|
||||||
setPdfUrlList((prev) => [...prev, ...pdfBlocks]);
|
setPdfUrlList((prev) => [...prev, ...pdfBlocks]);
|
||||||
}
|
}
|
||||||
@@ -521,7 +522,10 @@ export function Thread() {
|
|||||||
{imageUrlList.map((imageBlock, idx) => {
|
{imageUrlList.map((imageBlock, idx) => {
|
||||||
const imageUrlString = `data:${imageBlock.mime_type};base64,${imageBlock.data}`;
|
const imageUrlString = `data:${imageBlock.mime_type};base64,${imageBlock.data}`;
|
||||||
return (
|
return (
|
||||||
<div className="relative" key={idx}>
|
<div
|
||||||
|
className="relative"
|
||||||
|
key={idx}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
src={imageUrlString}
|
src={imageUrlString}
|
||||||
alt="uploaded"
|
alt="uploaded"
|
||||||
@@ -530,7 +534,9 @@ export function Thread() {
|
|||||||
<CircleX
|
<CircleX
|
||||||
className="absolute top-[2px] right-[2px] size-4 cursor-pointer rounded-full bg-gray-500 text-white"
|
className="absolute top-[2px] right-[2px] size-4 cursor-pointer rounded-full bg-gray-500 text-white"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setImageUrlList(imageUrlList.filter((_, i) => i !== idx))
|
setImageUrlList(
|
||||||
|
imageUrlList.filter((_, i) => i !== idx),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -546,12 +552,18 @@ export function Thread() {
|
|||||||
key={idx}
|
key={idx}
|
||||||
>
|
>
|
||||||
<span className="max-w-xs truncate text-sm">
|
<span className="max-w-xs truncate text-sm">
|
||||||
{String(pdfBlock.metadata?.filename ?? pdfBlock.metadata?.name ?? "")}
|
{String(
|
||||||
|
pdfBlock.metadata?.filename ??
|
||||||
|
pdfBlock.metadata?.name ??
|
||||||
|
"",
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
<CircleX
|
<CircleX
|
||||||
className="size-4 cursor-pointer text-teal-600 hover:text-teal-500"
|
className="size-4 cursor-pointer text-teal-600 hover:text-teal-500"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setPdfUrlList(pdfUrlList.filter((_, i) => i !== idx))
|
setPdfUrlList(
|
||||||
|
pdfUrlList.filter((_, i) => i !== idx),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
31
src/index.ts
31
src/index.ts
@@ -1,31 +0,0 @@
|
|||||||
import {
|
|
||||||
Annotation,
|
|
||||||
MessagesAnnotation,
|
|
||||||
START,
|
|
||||||
StateGraph,
|
|
||||||
} from "@langchain/langgraph";
|
|
||||||
import { ChatOpenAI } from "@langchain/openai";
|
|
||||||
|
|
||||||
const ChatAgentAnnotation = Annotation.Root({
|
|
||||||
messages: MessagesAnnotation.spec["messages"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const graph = new StateGraph(ChatAgentAnnotation)
|
|
||||||
.addNode("chat", async (state) => {
|
|
||||||
const model = new ChatOpenAI({
|
|
||||||
model: "gpt-4o-mini",
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await model.invoke([
|
|
||||||
{ role: "system", content: "You are a helpful assistant." },
|
|
||||||
...state.messages,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
messages: response,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.addEdge(START, "chat");
|
|
||||||
|
|
||||||
export const agent = graph.compile();
|
|
||||||
agent.name = "Chat Agent";
|
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { Base64ContentBlock } from "@langchain/core/messages";
|
import type { Base64ContentBlock } from "@langchain/core/messages";
|
||||||
import { convertToOpenAIImageBlock } from "@langchain/core/messages";
|
import { convertToOpenAIImageBlock } from "@langchain/core/messages";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
// Returns a Promise of a typed multimodal block for images
|
// Returns a Promise of a typed multimodal block for images
|
||||||
export async function fileToImageBlock(file: File): Promise<Base64ContentBlock> {
|
export async function fileToImageBlock(
|
||||||
|
file: File,
|
||||||
|
): Promise<Base64ContentBlock> {
|
||||||
const data = await fileToBase64(file);
|
const data = await fileToBase64(file);
|
||||||
return {
|
return {
|
||||||
type: "image",
|
type: "image",
|
||||||
@@ -15,7 +17,7 @@ export async function fileToImageBlock(file: File): Promise<Base64ContentBlock>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a Promise of a typed multimodal block for PDFs
|
// Returns a Promise of a typed multimodal block for PDFs
|
||||||
export async function fileToPDFBlock(file: File): Promise<Base64ContentBlock>{
|
export async function fileToPDFBlock(file: File): Promise<Base64ContentBlock> {
|
||||||
const data = await fileToBase64(file);
|
const data = await fileToBase64(file);
|
||||||
return {
|
return {
|
||||||
type: "file",
|
type: "file",
|
||||||
@@ -35,7 +37,7 @@ export function toOpenAIPDFBlock(block: Base64ContentBlock) {
|
|||||||
data: block.data,
|
data: block.data,
|
||||||
mime_type: block.mime_type ?? "application/pdf",
|
mime_type: block.mime_type ?? "application/pdf",
|
||||||
filename: block.metadata?.name ?? block.metadata?.filename ?? "file.pdf",
|
filename: block.metadata?.name ?? block.metadata?.filename ?? "file.pdf",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +55,6 @@ export async function fileToBase64(file: File): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utility to convert base64 image blocks to OpenAI image_url format
|
// Utility to convert base64 image blocks to OpenAI image_url format
|
||||||
export function toOpenAIImageBlock(block: Base64ContentBlock | any) {
|
export function toOpenAIImageBlock(block: Base64ContentBlock | any) {
|
||||||
if (block.type === "image" && block.source_type === "base64") {
|
if (block.type === "image" && block.source_type === "base64") {
|
||||||
|
|||||||
Reference in New Issue
Block a user