From f00581403047137c30634ead299e546b094aeb13 Mon Sep 17 00:00:00 2001 From: Cole McCracken Date: Thu, 21 Dec 2023 10:25:28 -0800 Subject: [PATCH] Cole/def 5751 allow multiple textoutputs to render multiple text blocks (#74) --- .../library/piedpiper/spend_all_product.yaml | 29 ++ .../library/piedpiper/spend_per_product.yaml | 29 -- examples/next/src/app/page.tsx | 9 +- packages/openassistants-react/package.json | 2 +- .../src/components/chat-content.tsx | 59 ++++ .../src/components/chat-list.tsx | 63 +--- .../src/components/chat-message.tsx | 269 +++++++++--------- .../src/components/dataframe-table.tsx | 4 +- .../src/components/function-form.tsx | 9 +- .../src/components/plotly-vis.tsx | 1 - 10 files changed, 242 insertions(+), 232 deletions(-) create mode 100644 examples/fast-api-server/library/piedpiper/spend_all_product.yaml delete mode 100644 examples/fast-api-server/library/piedpiper/spend_per_product.yaml create mode 100644 packages/openassistants-react/src/components/chat-content.tsx diff --git a/examples/fast-api-server/library/piedpiper/spend_all_product.yaml b/examples/fast-api-server/library/piedpiper/spend_all_product.yaml new file mode 100644 index 0000000..0e8049c --- /dev/null +++ b/examples/fast-api-server/library/piedpiper/spend_all_product.yaml @@ -0,0 +1,29 @@ +display_name: Spend all products +description: | + Show the spend for all products (top 5) +sample_questions: + - show spend for all products +parameters: + json_schema: + type: object + properties: {} + required: [] +type: DuckDBQueryFunction +dataset: 'dummy-data/' +sqls: + - | + SELECT purchases.product, SUM(purchases.amount) as amount, + FROM "purchases.csv" + GROUP BY purchases.product + ORDER BY amount DESC + LIMIT 5 +visualizations: + - | + def create_chart_config(dataframes): + df = dataframes[0] + data = [{'x': df.iloc[:, 0].tolist(), 'y': df.iloc[:, 1].tolist(), 'type': 'bar'}] + layout = {'title': 'Spend per Product', 'xaxis': {'title': 'Product'}, 'yaxis': {'title': 'Total Spend'}} + result = {'data': data, 'layout': layout} + + return result +summarization: 'Describe the spend per product' diff --git a/examples/fast-api-server/library/piedpiper/spend_per_product.yaml b/examples/fast-api-server/library/piedpiper/spend_per_product.yaml deleted file mode 100644 index 654eb32..0000000 --- a/examples/fast-api-server/library/piedpiper/spend_per_product.yaml +++ /dev/null @@ -1,29 +0,0 @@ -display_name: Spend per product -description: | - Show the spend per product (top 5) -sample_questions: -- show spend per product -parameters: - json_schema: - type: object - properties: {} - required: [] -type: DuckDBQueryFunction -dataset: "dummy-data/" -sqls: -- | - SELECT purchases.product, SUM(purchases.amount) as amount, - FROM "purchases.csv" - GROUP BY purchases.product - ORDER BY amount DESC - LIMIT 5 -visualizations: - - | - def create_chart_config(dataframes): - df = dataframes[0] - data = [{'x': df.iloc[:, 0].tolist(), 'y': df.iloc[:, 1].tolist(), 'type': 'bar'}] - layout = {'title': 'Spend per Product', 'xaxis': {'title': 'Product'}, 'yaxis': {'title': 'Total Spend'}} - result = {'data': data, 'layout': layout} - - return result -summarization: 'Describe the spend per product' diff --git a/examples/next/src/app/page.tsx b/examples/next/src/app/page.tsx index 712949d..91d2e8c 100644 --- a/examples/next/src/app/page.tsx +++ b/examples/next/src/app/page.tsx @@ -8,9 +8,8 @@ export default function Home() {
{ + return ( +
+ {children}

; + }, + code({ node, inline, className, children, ...props }) { + if (children.length) { + if (children[0] == '▍') { + return ( + + ); + } + + children[0] = (children[0] as string).replace('`▍`', '▍'); + } + + const match = /language-(\w+)/.exec(className || ''); + + if (inline) { + return ( + + {children} + + ); + } + return ( +
+ { + + } +
+ ); + }, + }} + > + {content} +
+
+ ); +}; diff --git a/packages/openassistants-react/src/components/chat-list.tsx b/packages/openassistants-react/src/components/chat-list.tsx index b5d4ad3..3e0542e 100644 --- a/packages/openassistants-react/src/components/chat-list.tsx +++ b/packages/openassistants-react/src/components/chat-list.tsx @@ -33,62 +33,17 @@ export function OpenAssistantsChatList({ return (
{messages.map((message, index) => { - const outputs = 'outputs' in message ? message.outputs : null; return (
- {outputs && - outputs.map((output, i) => { - console.log( - `output.type=${output.type} output=${JSON.stringify(output)}` - ); - return ( -
- {output.type === 'dataframe' && ( - - )} - {output.type === 'visualization' && ( - - )} -
- ); - })} - - {getContent(message) && ( -
- onEdit(index, m)} - isLoading={isLoading} - /> - {index < messages.length - 1 && } -
- )} - - {message.role === 'assistant' && message.input_request && ( - { - const newMessage = { - role: 'user' as const, - input_response: { - name: message.input_request!.name, - arguments: values, - }, - content: '', - }; - append(newMessage); - }} - > - )} + onEdit(index, m)} + isLoading={isLoading} + />
); })} diff --git a/packages/openassistants-react/src/components/chat-message.tsx b/packages/openassistants-react/src/components/chat-message.tsx index 7dbe111..eba474e 100644 --- a/packages/openassistants-react/src/components/chat-message.tsx +++ b/packages/openassistants-react/src/components/chat-message.tsx @@ -1,18 +1,21 @@ -import remarkGfm from 'remark-gfm'; - import { cn } from '../lib/utils'; -import { CodeBlock } from './ui/codeblock'; -import { MemoizedReactMarkdown } from './markdown'; import { IconArrowRight, IconDefinitive, IconUser } from './ui/icons'; import { ChatMessageAction, ChatMessageActions } from './chat-message-actions'; import { useState } from 'react'; import React from 'react'; import { Message } from './chat-models'; -import { Button, Textarea } from './ui'; +import { Button, Separator, Textarea } from './ui'; +import { DataframeTable } from './dataframe-table'; +import { RenderVisMessage } from './plotly-vis'; +import { FunctionForm } from './function-form'; +import { ChatContent } from './chat-content'; export interface DefinitiveChatMessageProps { + index: number; + total: number; message: Message; onEdit?: (message: Message) => Promise; + append: (message?: Message) => Promise; isLoading: boolean; } @@ -36,24 +39,7 @@ const isCollapsable = (message: Message): boolean => { ); }; -function formatCode(input: string): string { - const trimmed = input - .replace('BEGIN_CODE', '') - .replace('END_CODE', '') - .trim(); - return trimmed - .split(';') - .map((line) => line.trim()) - .join(';\n'); -} - export const getContent = (message: Message): string => { - if (message.role === 'function') { - const textOutput = - message.outputs.find((output) => output.type === 'text') || {}; - //@ts-ignore - return 'text' in textOutput ? (textOutput.text as string) : ''; - } if (message.role === 'user') { if (message.content) { return message.content; @@ -61,11 +47,6 @@ export const getContent = (message: Message): string => { return ''; } } - if (message.role === 'assistant') { - if (message.function_call) { - return ''; - } - } if (message.role === 'assistant' && message.content) { return message.content; } @@ -73,14 +54,17 @@ export const getContent = (message: Message): string => { }; export function OpenAssistantsChatMessage({ + index, + total, message, onEdit, isLoading, + append, ...props }: DefinitiveChatMessageProps) { const [isEditing, setIsEditing] = useState(false); + const [submitted, setSubmitted] = React.useState(false); const [editedMessageContent, setEditedMessageContent] = useState(''); - const content = getContent(message); const supportedActions: ChatMessageAction[] = []; if (!isCollapsable(message) && !isEditing) { supportedActions.push('copy'); @@ -88,127 +72,136 @@ export function OpenAssistantsChatMessage({ if (message.role === 'user' && !isEditing && onEdit) { supportedActions.push('edit'); } - if (!content) { + const outputs = 'outputs' in message ? message.outputs : null; + // executed function call- ignore + if (message.role === 'assistant' && message.function_call) { + return
; + } + // completed input response from user- ignore + if (message.role === 'user' && message.input_response) { return
; } return ( -
+
- {message && getIcon(message)} -
-
- {isEditing && message.role === 'user' && ( -
-