Skip to content

Commit

Permalink
Merge pull request #1 from enricoros/main
Browse files Browse the repository at this point in the history
Big AGI update
  • Loading branch information
raphaelmansuy committed Jun 24, 2023
2 parents 16458af + 2ebd629 commit ec92683
Show file tree
Hide file tree
Showing 33 changed files with 1,077 additions and 303 deletions.
6 changes: 5 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
let nextConfig = {
reactStrictMode: true,
env: {
// defaults to TRUE, unless API Keys are set at build time; this flag is used by the UI
Expand All @@ -22,4 +22,8 @@ const nextConfig = {
},
};

// conditionally enable the nextjs bundle analyzer
if (process.env.ANALYZE_BUNDLE)
nextConfig = require('@next/bundle-analyzer')()(nextConfig);

module.exports = nextConfig;
420 changes: 273 additions & 147 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.11.16",
"@mui/joy": "^5.0.0-alpha.84",
"@tanstack/react-query": "^4.29.13",
"@trpc/client": "^10.30.0",
"@trpc/next": "^10.30.0",
"@trpc/react-query": "^10.30.0",
"@trpc/server": "^10.30.0",
"@next/bundle-analyzer": "^13.4.7",
"@tanstack/react-query": "^4.29.15",
"@trpc/client": "^10.32.0",
"@trpc/next": "^10.32.0",
"@trpc/react-query": "^10.32.0",
"@trpc/server": "^10.32.0",
"@vercel/analytics": "^1.0.1",
"eventsource-parser": "^1.0.0",
"next": "^13.4.5",
"next": "^13.4.7",
"pdfjs-dist": "^3.7.107",
"plantuml-encoder": "^1.4.0",
"prismjs": "^1.29.0",
Expand All @@ -43,11 +44,11 @@
"@types/node": "^20.3.1",
"@types/plantuml-encoder": "^1.4.0",
"@types/prismjs": "^1.26.0",
"@types/react": "^18.2.12",
"@types/react-dom": "^18.2.5",
"@types/react": "^18.2.13",
"@types/react-dom": "^18.2.6",
"@types/uuid": "^9.0.2",
"eslint": "^8.42.0",
"eslint-config-next": "^13.4.5",
"eslint": "^8.43.0",
"eslint-config-next": "^13.4.7",
"prettier": "^2.8.8",
"typescript": "^5.1.3"
}
Expand Down
12 changes: 11 additions & 1 deletion pages/api/openai/stream-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ async function chatStreamRepeater(access: ChatGenerateSchema['access'], model: C
try {
const json: OpenAI.Wire.ChatCompletion.ResponseStreamingChunk = JSON.parse(event.data);

// handle errors here
if (json.error) {
// suppress this new error that popped up on 2023-06-19
if (json.error.message !== 'The server had an error while processing your request. Sorry about that!')
console.error('stream-chat: unexpected error from upstream', json.error);
controller.enqueue(textEncoder.encode(`[OpenAI Issue] ${json.error.message}`));
controller.close();
return;
}

// ignore any 'role' delta update
if (json.choices[0].delta?.role && !json.choices[0].delta?.content)
return;
Expand All @@ -92,7 +102,7 @@ async function chatStreamRepeater(access: ChatGenerateSchema['access'], model: C

} catch (error) {
// maybe parse error
console.error('Error parsing OpenAI response', error);
console.error('stream-chat: error parsing chunked response', error, event);
controller.error(error);
}
});
Expand Down
146 changes: 146 additions & 0 deletions pages/share.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import * as React from 'react';
import Image from 'next/image';
import { useRouter } from 'next/router';

import { Alert, Box, Button, CircularProgress, Typography } from '@mui/joy';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';

import { useComposerStore } from '../src/apps/chat/components/composer/store-composer';

// import { callBrowseFetchSinglePage } from '~/modules/browse/browse.client';

import { AppLayout } from '~/common/layouts/AppLayout';
import { asValidURL } from '~/common/util/urlUtils';


const LogoProgress = (props: { showProgress: boolean }) =>
<Box sx={{
width: 64,
height: 64,
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Box sx={{ position: 'absolute', mt: 0.75 }}>
<Image src='/icons/favicon-32x32.png' alt='App Logo' width={32} height={32} />
</Box>
{props.showProgress && <CircularProgress size='lg' sx={{ position: 'absolute' }} />}
</Box>;


/**
* This page will be invoked on mobile when sharing Text/URLs/Files from other APPs
* Example URL: https://get.big-agi.com/share?title=This+Title&text=https%3A%2F%2Fexample.com%2Fapp%2Fpath
*/
export default function SharePage() {

// state
const [errorMessage, setErrorMessage] = React.useState<string | null>(null);
const [intentText, setIntentText] = React.useState<string | null>(null);
const [intentURL, setIntentURL] = React.useState<string | null>(null);
const [isDownloading, setIsDownloading] = React.useState(false);

// external state
const { query, push: routerPush, replace: routerReplace } = useRouter();


const queueComposerTextAndLaunchApp = React.useCallback((text: string) => {
useComposerStore.getState().setStartupText(text);
routerReplace('/').then(() => null);
}, [routerReplace]);


// Detect the share Intent from the query
React.useEffect(() => {
// skip when query is not parsed yet
if (!Object.keys(query).length)
return;

// single item from the query
let queryTextItem: string[] | string | null = query.url || query.text || null;
if (Array.isArray(queryTextItem))
queryTextItem = queryTextItem[0];

// check if the item is a URL
const url = asValidURL(queryTextItem);
if (url)
setIntentURL(url);
else if (queryTextItem)
setIntentText(queryTextItem);
else
setErrorMessage('No text or url. Received: ' + JSON.stringify(query));

}, [query.url, query.text, query]);


// Text -> Composer
React.useEffect(() => {
if (intentText)
queueComposerTextAndLaunchApp(intentText);
}, [intentText, queueComposerTextAndLaunchApp]);


// URL -> download -> Composer
React.useEffect(() => {
if (intentURL) {
setIsDownloading(true);
// TEMP: until the Browse module is ready, just use the URL, verbatim
queueComposerTextAndLaunchApp(intentURL);
setIsDownloading(false)
/*callBrowseFetchSinglePage(intentURL)
.then(pageContent => {
if (pageContent)
queueComposerTextAndLaunchApp('\n\n```' + intentURL + '\n' + pageContent + '\n```\n');
else
setErrorMessage('Could not read any data');
})
.catch(error => setErrorMessage(error?.message || error || 'Unknown error'))
.finally(() => setIsDownloading(false));*/
}
}, [intentURL, queueComposerTextAndLaunchApp]);


return (
<AppLayout noSettings noModelsSetup>

<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
minHeight: '100vh',
}}>

{/* Logo with Circular Progress */}
<LogoProgress showProgress={isDownloading} />

{/* Title */}
<Typography level='h5' sx={{ mt: 2, mb: 1 }}>
{isDownloading ? 'Loading...' : errorMessage ? '' : intentURL ? 'Done' : 'Receiving...'}
</Typography>

{/* Possible Error */}
{errorMessage && <>
<Alert variant='soft' color='danger' sx={{ my: 1 }}>
<Typography>{errorMessage}</Typography>
</Alert>
<Button
variant='solid' color='danger'
onClick={() => routerPush('/')}
endDecorator={<ArrowBackIcon />}
sx={{ mt: 2 }}
>
Cancel
</Button>
</>}

{/* URL under analysis */}
<Typography level='body3'>
{intentURL}
</Typography>
</Box>

</AppLayout>
);
}
12 changes: 11 additions & 1 deletion public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,15 @@
"sizes": "1024x1024",
"type": "image/png"
}
]
],
"share_target": {
"action": "/share",
"method": "GET",
"enctype": "application/x-www-form-urlencoded",
"params": {
"title": "title",
"text": "text",
"url": "url"
}
}
}
10 changes: 5 additions & 5 deletions src/apps/chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import { extractCommands } from '~/common/util/extractCommands';
import { useApplicationBarStore } from '~/common/layouts/appbar/store-applicationbar';
import { useUIPreferencesStore } from '~/common/state/store-ui';

import { ActionItems } from './components/appbar/ActionItems';
import { ChatContextItems } from './components/appbar/ChatContextItems';
import { ChatMessageList } from './components/ChatMessageList';
import { Composer } from './components/composer/Composer';
import { ConversationItems } from './components/appbar/ConversationItems';
import { Dropdowns } from './components/appbar/Dropdowns';
import { Ephemerals } from './components/ephemerals/Ephemerals';
import { Ephemerals } from './components/Ephemerals';
import { ImportedModal, ImportedOutcome } from './components/appbar/ImportedModal';
import { runAssistantUpdatingState } from './editors/chat-stream';
import { runImageGenerationUpdatingState } from './editors/image-generate';
Expand Down Expand Up @@ -237,7 +237,7 @@ export function Chat() {
);

const actionItems = React.useMemo(() =>
<ActionItems
<ChatContextItems
conversationId={activeConversationId} isConversationEmpty={isConversationEmpty}
isMessageSelectionMode={isMessageSelectionMode} setIsMessageSelectionMode={setIsMessageSelectionMode}
onClearConversation={handleClearConversation}
Expand All @@ -247,8 +247,8 @@ export function Chat() {
);

React.useEffect(() => {
useApplicationBarStore.getState().register(dropdowns, conversationsBadge, conversationItems, actionItems);
return () => useApplicationBarStore.getState().unregister();
useApplicationBarStore.getState().registerClientComponents(dropdowns, conversationsBadge, conversationItems, actionItems);
return () => useApplicationBarStore.getState().unregisterClientComponents();
}, [dropdowns, conversationsBadge, conversationItems, actionItems]);

return <>
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import FileDownloadIcon from '@mui/icons-material/FileDownload';
import SettingsSuggestIcon from '@mui/icons-material/SettingsSuggest';

import { downloadConversationJson, useChatStore } from '~/common/state/store-chats';
import { useApplicationBarStore } from '~/common/layouts/appbar/store-applicationbar';
import { useUIPreferencesStore } from '~/common/state/store-ui';


export function ActionItems(props: {
export function ChatContextItems(props: {
conversationId: string | null, isConversationEmpty: boolean,
isMessageSelectionMode: boolean, setIsMessageSelectionMode: (isMessageSelectionMode: boolean) => void,
onClearConversation: (conversationId: string) => void,
Expand All @@ -25,6 +26,8 @@ export function ActionItems(props: {
showSystemMessages: state.showSystemMessages, setShowSystemMessages: state.setShowSystemMessages,
}), shallow);

const closeContextMenu = () => useApplicationBarStore.getState().setContextMenuAnchor(null);

const handleSystemMessagesToggle = () => setShowSystemMessages(!showSystemMessages);

const handleConversationPublish = (e: React.MouseEvent<HTMLDivElement>) => {
Expand All @@ -41,7 +44,7 @@ export function ActionItems(props: {

const handleToggleMessageSelectionMode = (e: React.MouseEvent) => {
e.stopPropagation();
/// FIXME closeActionsMenu();
closeContextMenu();
props.setIsMessageSelectionMode(!props.isMessageSelectionMode);
};

Expand Down
7 changes: 6 additions & 1 deletion src/apps/chat/components/appbar/ConversationItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import FileUploadIcon from '@mui/icons-material/FileUpload';

import { MAX_CONVERSATIONS, useChatStore } from '~/common/state/store-chats';
import { useApplicationBarStore } from '~/common/layouts/appbar/store-applicationbar';
import { useUIPreferencesStore } from '~/common/state/store-ui';

import { ConversationItem } from './ConversationItem';
Expand Down Expand Up @@ -37,17 +38,21 @@ export function ConversationItems(props: {
const singleChat = conversationIDs.length === 1;
const maxReached = conversationIDs.length >= MAX_CONVERSATIONS;

const closeAppMenu = () => useApplicationBarStore.getState().setAppMenuAnchor(null);

const handleNew = () => {
// if the first in the stack is a new conversation, just activate it
if (topNewConversationId)
setActiveConversationId(topNewConversationId);
else
createConversation();
/// FIXME props.onClose();
closeAppMenu();
};

const handleConversationActivate = React.useCallback((conversationId: string) => {
setActiveConversationId(conversationId);
// Disabled, because otherwise the menu disappears when trying to delete...
// closeAppMenu();
}, [setActiveConversationId]);

const handleConversationDelete = React.useCallback((conversationId: string) => {
Expand Down
Loading

1 comment on commit ec92683

@vercel
Copy link

@vercel vercel bot commented on ec92683 Jun 24, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

bigagi – ./

bigagi.vercel.app
bigagi-raphaelmansuy.vercel.app
bigagi-git-main-raphaelmansuy.vercel.app

Please sign in to comment.