-
Notifications
You must be signed in to change notification settings - Fork 182
feat: implement csv upload #96
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
Changes from all commits
a9d2177
ff8bed6
2e43ba1
778bdfa
2e47af8
5d19019
cc45225
667c122
f3c1e54
14c0b2e
c24e60a
beaf4b4
2eb2803
bafb1d7
04cc7ce
5068e28
d473867
b3f3ce4
ce2de2d
b0e25b3
3d3d94c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"create-llama": patch | ||
--- | ||
|
||
Add CSV upload |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
"use client"; | ||
|
||
import { Message } from "./chat-messages"; | ||
|
||
export interface ChatInputProps { | ||
/** The current value of the input */ | ||
input?: string; | ||
|
@@ -13,6 +15,7 @@ export interface ChatInputProps { | |
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void; | ||
isLoading: boolean; | ||
multiModal?: boolean; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thucpn Still multimodal props? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah sorry, I forget removing in html template. Let me fix it in this enhance PR: |
||
messages: Message[]; | ||
} | ||
|
||
export default function ChatInput(props: ChatInputProps) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,35 +6,78 @@ import { | |
type AIStreamCallbacksAndOptions, | ||
} from "ai"; | ||
import { | ||
MessageContent, | ||
Metadata, | ||
NodeWithScore, | ||
Response, | ||
ToolCallLLMMessageOptions, | ||
} from "llamaindex"; | ||
|
||
import { AgentStreamChatResponse } from "llamaindex/agent/base"; | ||
import { appendImageData, appendSourceData } from "./stream-helper"; | ||
import { | ||
UploadedCsv, | ||
appendCsvData, | ||
appendImageData, | ||
appendSourceData, | ||
} from "./stream-helper"; | ||
|
||
type LlamaIndexResponse = | ||
| AgentStreamChatResponse<ToolCallLLMMessageOptions> | ||
| Response; | ||
|
||
type ParserOptions = { | ||
image_url?: string; | ||
export type DataParserOptions = { | ||
imageUrl?: string; | ||
uploadedCsv?: UploadedCsv; | ||
}; | ||
|
||
export const convertMessageContent = ( | ||
textMessage: string, | ||
additionalData?: DataParserOptions, | ||
): MessageContent => { | ||
if (!additionalData) return textMessage; | ||
const content: MessageContent = [ | ||
{ | ||
type: "text", | ||
text: textMessage, | ||
}, | ||
]; | ||
if (additionalData?.imageUrl) { | ||
content.push({ | ||
type: "image_url", | ||
image_url: { | ||
url: additionalData?.imageUrl, | ||
}, | ||
}); | ||
} | ||
|
||
if (additionalData?.uploadedCsv) { | ||
const csvContent = | ||
"Use the following CSV data:\n" + | ||
"```csv\n" + | ||
additionalData.uploadedCsv.content + | ||
"\n```"; | ||
Comment on lines
+55
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use template literals for better performance and readability in CSV content handling. - "Use the following CSV data:\n" +
- "```csv\n" +
- additionalData.uploadedCsv.content +
- "\n```";
+ `Use the following CSV data:\n\`\`\`csv\n${additionalData.uploadedCsv.content}\n\`\`\`` |
||
content.push({ | ||
type: "text", | ||
text: `${csvContent}\n\n${textMessage}`, | ||
}); | ||
} | ||
|
||
return content; | ||
}; | ||
|
||
function createParser( | ||
res: AsyncIterable<LlamaIndexResponse>, | ||
data: StreamData, | ||
opts?: ParserOptions, | ||
opts?: DataParserOptions, | ||
) { | ||
const it = res[Symbol.asyncIterator](); | ||
const trimStartOfStream = trimStartOfStreamHelper(); | ||
|
||
let sourceNodes: NodeWithScore<Metadata>[] | undefined; | ||
return new ReadableStream<string>({ | ||
start() { | ||
appendImageData(data, opts?.image_url); | ||
appendImageData(data, opts?.imageUrl); | ||
appendCsvData(data, opts?.uploadedCsv); | ||
}, | ||
async pull(controller): Promise<void> { | ||
const { value, done } = await it.next(); | ||
|
@@ -72,7 +115,7 @@ export function LlamaIndexStream( | |
data: StreamData, | ||
opts?: { | ||
callbacks?: AIStreamCallbacksAndOptions; | ||
parserOptions?: ParserOptions; | ||
parserOptions?: DataParserOptions; | ||
}, | ||
): ReadableStream<Uint8Array> { | ||
return createParser(response, data, opts?.parserOptions) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -82,6 +82,15 @@ export function appendToolData( | |||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export function createStreamTimeout(stream: StreamData) { | ||||||||||||||||||||||||||||||||||||
const timeout = Number(process.env.STREAM_TIMEOUT ?? 1000 * 60 * 5); // default to 5 minutes | ||||||||||||||||||||||||||||||||||||
const t = setTimeout(() => { | ||||||||||||||||||||||||||||||||||||
appendEventData(stream, `Stream timed out after ${timeout / 1000} seconds`); | ||||||||||||||||||||||||||||||||||||
stream.close(); | ||||||||||||||||||||||||||||||||||||
marcusschiesser marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||
}, timeout); | ||||||||||||||||||||||||||||||||||||
return t; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
Comment on lines
+85
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Define the default timeout value as a constant for better readability and maintainability. + const DEFAULT_TIMEOUT = 1000 * 60 * 5; // 5 minutes
const timeout = Number(process.env.STREAM_TIMEOUT ?? DEFAULT_TIMEOUT); Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export function createCallbackManager(stream: StreamData) { | ||||||||||||||||||||||||||||||||||||
const callbackManager = new CallbackManager(); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
@@ -112,3 +121,17 @@ export function createCallbackManager(stream: StreamData) { | |||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
return callbackManager; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export type UploadedCsv = { | ||||||||||||||||||||||||||||||||||||
content: string; | ||||||||||||||||||||||||||||||||||||
filename: string; | ||||||||||||||||||||||||||||||||||||
filesize: number; | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export function appendCsvData(data: StreamData, uploadedCsv?: UploadedCsv) { | ||||||||||||||||||||||||||||||||||||
if (!uploadedCsv) return; | ||||||||||||||||||||||||||||||||||||
data.appendMessageAnnotation({ | ||||||||||||||||||||||||||||||||||||
type: "csv", | ||||||||||||||||||||||||||||||||||||
data: uploadedCsv, | ||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,35 +6,78 @@ import { | |
type AIStreamCallbacksAndOptions, | ||
} from "ai"; | ||
import { | ||
MessageContent, | ||
Metadata, | ||
NodeWithScore, | ||
Response, | ||
ToolCallLLMMessageOptions, | ||
} from "llamaindex"; | ||
|
||
import { AgentStreamChatResponse } from "llamaindex/agent/base"; | ||
import { appendImageData, appendSourceData } from "./stream-helper"; | ||
import { | ||
UploadedCsv, | ||
appendCsvData, | ||
appendImageData, | ||
appendSourceData, | ||
} from "./stream-helper"; | ||
|
||
type LlamaIndexResponse = | ||
| AgentStreamChatResponse<ToolCallLLMMessageOptions> | ||
| Response; | ||
|
||
type ParserOptions = { | ||
image_url?: string; | ||
export type DataParserOptions = { | ||
imageUrl?: string; | ||
uploadedCsv?: UploadedCsv; | ||
}; | ||
|
||
export const convertMessageContent = ( | ||
textMessage: string, | ||
additionalData?: DataParserOptions, | ||
): MessageContent => { | ||
if (!additionalData) return textMessage; | ||
const content: MessageContent = [ | ||
{ | ||
type: "text", | ||
text: textMessage, | ||
}, | ||
]; | ||
if (additionalData?.imageUrl) { | ||
content.push({ | ||
type: "image_url", | ||
image_url: { | ||
url: additionalData?.imageUrl, | ||
}, | ||
}); | ||
} | ||
|
||
if (additionalData?.uploadedCsv) { | ||
const csvContent = | ||
"Use the following CSV data:\n" + | ||
"```csv\n" + | ||
additionalData.uploadedCsv.content + | ||
"\n```"; | ||
Comment on lines
+55
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use template literals for better performance and readability in CSV content handling. - "Use the following CSV data:\n" +
- "```csv\n" +
- additionalData.uploadedCsv.content +
- "\n```";
+ `Use the following CSV data:\n\`\`\`csv\n${additionalData.uploadedCsv.content}\n\`\`\`` |
||
content.push({ | ||
type: "text", | ||
text: `${csvContent}\n\n${textMessage}`, | ||
}); | ||
} | ||
|
||
return content; | ||
}; | ||
|
||
function createParser( | ||
res: AsyncIterable<LlamaIndexResponse>, | ||
data: StreamData, | ||
opts?: ParserOptions, | ||
opts?: DataParserOptions, | ||
) { | ||
const it = res[Symbol.asyncIterator](); | ||
const trimStartOfStream = trimStartOfStreamHelper(); | ||
|
||
let sourceNodes: NodeWithScore<Metadata>[] | undefined; | ||
return new ReadableStream<string>({ | ||
start() { | ||
appendImageData(data, opts?.image_url); | ||
appendImageData(data, opts?.imageUrl); | ||
appendCsvData(data, opts?.uploadedCsv); | ||
}, | ||
async pull(controller): Promise<void> { | ||
const { value, done } = await it.next(); | ||
|
@@ -72,7 +115,7 @@ export function LlamaIndexStream( | |
data: StreamData, | ||
opts?: { | ||
callbacks?: AIStreamCallbacksAndOptions; | ||
parserOptions?: ParserOptions; | ||
parserOptions?: DataParserOptions; | ||
}, | ||
): ReadableStream<Uint8Array> { | ||
return createParser(response, data, opts?.parserOptions) | ||
|
Uh oh!
There was an error while loading. Please reload this page.