Compare commits

...

11 Commits

Author SHA1 Message Date
Enrico Ros f9d30114c5 Auth: Clerk provider 2024-05-13 12:11:26 -07:00
Enrico Ros 564cf0fed0 1.16.1: default:hidden on the first Turbo 2024-05-13 12:04:31 -07:00
Enrico Ros dee9492d4c 1.16.0: update 2024-05-13 12:02:02 -07:00
Enrico Ros 6ae026f7c5 OpenAI: un-star Turbo 2024-05-13 11:49:10 -07:00
Enrico Ros 6bcbe286f3 OpenAI: add support for 'o' models 2024-05-13 11:47:55 -07:00
Enrico Ros 6f35f72607 Beam: auto-merge 2024-05-12 23:39:06 -07:00
Enrico Ros 3a7aa75538 Soft-wrap as a global preference. Fixes #517 2024-05-10 04:05:50 -07:00
Enrico Ros e4e7ac260a pdfjs: image generation (just in case) 2024-05-10 02:46:28 -07:00
Enrico Ros b8aaa4bb42 pdfjs: better parsing (for humans) 2024-05-10 02:19:45 -07:00
Enrico Ros 7793e2694b pdfjs: roll 2024-05-10 02:19:32 -07:00
Enrico Ros 83f2c72f29 Roll packages 2024-05-10 01:38:56 -07:00
26 changed files with 956 additions and 328 deletions
+4
View File
@@ -21,6 +21,10 @@ Or fork & run on Vercel
[//]: # (big-AGI is an open book; see the **[ready-to-ship and future ideas](https://github.com/users/enricoros/projects/4/views/2)** in our open roadmap)
### What's New in 1.16.1 · May 13, 2024 (minor release, models support)
- Support for the new OpenAI GPT-4o 2024-05-13 model
### What's New in 1.16.0 · May 9, 2024 · Crystal Clear
- [Beam](https://big-agi.com/blog/beam-multi-model-ai-reasoning) core and UX improvements based on user feedback
+4
View File
@@ -10,6 +10,10 @@ by release.
- milestone: [1.17.0](https://github.com/enricoros/big-agi/milestone/17)
- work in progress: [big-AGI open roadmap](https://github.com/users/enricoros/projects/4/views/2), [help here](https://github.com/users/enricoros/projects/4/views/4)
### What's New in 1.16.1 · May 13, 2024 (minor release, models support)
- Support for the new OpenAI GPT-4o 2024-05-13 model
### What's New in 1.16.0 · May 9, 2024 · Crystal Clear
- [Beam](https://big-agi.com/blog/beam-multi-model-ai-reasoning) core and UX improvements based on user feedback
+7
View File
@@ -0,0 +1,7 @@
import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware();
export const config = {
matcher: ['/((?!.+.[w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
};
+629 -245
View File
File diff suppressed because it is too large Load Diff
+20 -18
View File
@@ -18,17 +18,19 @@
"schema": "src/server/prisma/schema.prisma"
},
"dependencies": {
"@clerk/nextjs": "^5.0.8",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.4",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.5",
"@mui/icons-material": "^5.15.15",
"@mui/joy": "^5.0.0-beta.32",
"@next/bundle-analyzer": "^14.2.2",
"@next/third-parties": "^14.2.2",
"@prisma/client": "^5.12.1",
"@mui/icons-material": "^5.15.17",
"@mui/joy": "^5.0.0-beta.36",
"@mui/material": "^5.15.17",
"@next/bundle-analyzer": "^14.2.3",
"@next/third-parties": "^14.2.3",
"@prisma/client": "^5.13.0",
"@sanity/diff-match-patch": "^3.1.1",
"@t3-oss/env-nextjs": "^0.9.2",
"@t3-oss/env-nextjs": "^0.10.1",
"@tanstack/react-query": "~4.36.1",
"@trpc/client": "10.44.1",
"@trpc/next": "10.44.1",
@@ -41,46 +43,46 @@
"idb-keyval": "^6.2.1",
"next": "~14.1.4",
"nprogress": "^0.2.0",
"pdfjs-dist": "4.1.392",
"pdfjs-dist": "4.2.67",
"plantuml-encoder": "^1.4.0",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1",
"react-csv": "^2.2.2",
"react-dom": "^18.2.0",
"react-dom": "^18.3.1",
"react-katex": "^3.0.1",
"react-markdown": "^9.0.1",
"react-player": "^2.16.0",
"react-resizable-panels": "^2.0.18",
"react-resizable-panels": "^2.0.19",
"react-timeago": "^7.2.0",
"rehype-katex": "^7.0.0",
"remark-gfm": "^4.0.0",
"remark-math": "^6.0.0",
"sharp": "^0.33.3",
"superjson": "^2.2.1",
"tesseract.js": "^5.0.5",
"tesseract.js": "^5.1.0",
"tiktoken": "^1.0.14",
"uuid": "^9.0.1",
"zod": "^3.23.0",
"zod": "^3.23.8",
"zustand": "^4.5.2"
},
"devDependencies": {
"@cloudflare/puppeteer": "0.0.5",
"@types/node": "^20.12.7",
"@types/node": "^20.12.11",
"@types/nprogress": "^0.2.3",
"@types/plantuml-encoder": "^1.4.2",
"@types/prismjs": "^1.26.3",
"@types/react": "^18.2.79",
"@types/prismjs": "^1.26.4",
"@types/react": "^18.3.1",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-csv": "^1.1.10",
"@types/react-dom": "^18.2.25",
"@types/react-dom": "^18.3.0",
"@types/react-katex": "^3.0.4",
"@types/react-timeago": "^4.1.7",
"@types/uuid": "^9.0.8",
"eslint": "^8.57.0",
"eslint-config-next": "14.2.2",
"eslint-config-next": "^14.2.3",
"prettier": "^3.2.5",
"prisma": "^5.12.1",
"prisma": "^5.13.0",
"typescript": "^5.4.5"
},
"engines": {
+15 -12
View File
@@ -13,6 +13,7 @@ import '~/common/styles/GithubMarkdown.css';
import '~/common/styles/NProgress.css';
import '~/common/styles/app.styles.css';
import { ProviderAuth } from '~/common/providers/ProviderAuth';
import { ProviderBackendCapabilities } from '~/common/providers/ProviderBackendCapabilities';
import { ProviderBootstrapLogic } from '~/common/providers/ProviderBootstrapLogic';
import { ProviderSingleTab } from '~/common/providers/ProviderSingleTab';
@@ -32,18 +33,20 @@ const MyApp = ({ Component, emotionCache, pageProps }: MyAppProps) =>
</Head>
<ProviderTheming emotionCache={emotionCache}>
<ProviderSingleTab>
<ProviderTRPCQuerySettings>
<ProviderBackendCapabilities>
{/* ^ SSR boundary */}
<ProviderBootstrapLogic>
<ProviderSnacks>
<Component {...pageProps} />
</ProviderSnacks>
</ProviderBootstrapLogic>
</ProviderBackendCapabilities>
</ProviderTRPCQuerySettings>
</ProviderSingleTab>
<ProviderAuth>
<ProviderSingleTab>
<ProviderTRPCQuerySettings>
<ProviderBackendCapabilities>
{/* ^ SSR boundary */}
<ProviderBootstrapLogic>
<ProviderSnacks>
<Component {...pageProps} />
</ProviderSnacks>
</ProviderBootstrapLogic>
</ProviderBackendCapabilities>
</ProviderTRPCQuerySettings>
</ProviderSingleTab>
</ProviderAuth>
</ProviderTheming>
{isVercelFromFrontend && <VercelAnalytics debug={false} />}
+3 -2
View File
@@ -17,7 +17,7 @@ import { Brand } from '~/common/app.config';
import { ROUTE_APP_CHAT, ROUTE_INDEX } from '~/common/app.routes';
// apps access
import { incrementalNewsVersion } from '../../src/apps/news/news.version';
import { incrementalNewsVersion, useAppNewsStateStore } from '../../src/apps/news/news.version';
// capabilities access
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs, useCapabilityTextToImage } from '~/common/components/useCapabilities';
@@ -81,7 +81,8 @@ function AppDebug() {
const chatsCount = useChatStore.getState().conversations?.length;
const uxLabsExperiments = Object.entries(useUXLabsStore.getState()).filter(([_k, v]) => v === true).map(([k, _]) => k).join(', ');
const { folders, enableFolders } = useFolderStore.getState();
const { lastSeenNewsVersion, usageCount } = useAppStateStore.getState();
const { lastSeenNewsVersion } = useAppNewsStateStore.getState();
const { usageCount } = useAppStateStore.getState();
// derived state
File diff suppressed because one or more lines are too long
@@ -153,7 +153,11 @@ export function AttachmentMenu(props: {
{/* Converters: {aConverters.map(((converter, idx) => ` ${converter.id}${(idx === aConverterIdx) ? '*' : ''}`)).join(', ')}*/}
{/*</Typography>*/}
<Typography level='body-xs'>
🡒 {isOutputMissing ? 'empty' : aOutputs.map(output => `${output.type}, ${output.type === 'text-block' ? output.text.length.toLocaleString() : '(base64 image)'} bytes`).join(' · ')}
🡒 {isOutputMissing ? 'empty' : aOutputs.map(output => `${output.type}, ${output.type === 'text-block'
? output.text.length.toLocaleString()
: output.type === 'image-part'
? output.base64Url.length.toLocaleString()
: '(other)'} bytes`).join(' · ')}
</Typography>
{!!tokenCountApprox && <Typography level='body-xs'>
🡒 {tokenCountApprox.toLocaleString()} tokens
@@ -2,7 +2,7 @@ import { callBrowseFetchPage } from '~/modules/browse/browse.client';
import { createBase36Uid } from '~/common/util/textUtils';
import { htmlTableToMarkdown } from '~/common/util/htmlTableToMarkdown';
import { pdfToText } from '~/common/util/pdfUtils';
import { pdfToImageDataURLs, pdfToText } from '~/common/util/pdfUtils';
import type { Attachment, AttachmentConverter, AttachmentId, AttachmentInput, AttachmentSource } from './store-attachments';
import type { ComposerOutputMultiPart } from '../composer.types';
@@ -297,7 +297,7 @@ export async function attachmentPerformConversion(attachment: Readonly<Attachmen
case 'pdf-text':
if (!(input.data instanceof ArrayBuffer)) {
console.log('Expected ArrayBuffer for PDF converter, got:', typeof input.data);
console.log('Expected ArrayBuffer for PDF text converter, got:', typeof input.data);
break;
}
// duplicate the ArrayBuffer to avoid mutation
@@ -312,7 +312,29 @@ export async function attachmentPerformConversion(attachment: Readonly<Attachmen
break;
case 'pdf-images':
// TODO: extract all pages as individual images
if (!(input.data instanceof ArrayBuffer)) {
console.log('Expected ArrayBuffer for PDF images converter, got:', typeof input.data);
break;
}
// duplicate the ArrayBuffer to avoid mutation
const pdfData2 = new Uint8Array(input.data.slice(0));
try {
const imageDataURLs = await pdfToImageDataURLs(pdfData2);
imageDataURLs.forEach((pdfImg, index) => {
outputs.push({
type: 'image-part',
base64Url: pdfImg.base64Url,
metadata: {
title: `Page ${index + 1}`,
width: pdfImg.width,
height: pdfImg.height,
},
collapsible: false,
});
});
} catch (error) {
console.error('Error converting PDF to images:', error);
}
break;
case 'image':
@@ -9,6 +9,13 @@ export type ComposerOutputPart = {
// TODO: not implemented yet
type: 'image-part',
base64Url: string,
metadata: {
title?: string,
generatedBy?: string,
altText?: string,
width?: number,
height?: number,
},
collapsible: false,
};
+4 -2
View File
@@ -60,9 +60,10 @@ export const NewsItems: NewsItem[] = [
]
}*/
{
versionCode: '1.16',
versionCode: '1.16.1',
versionName: 'Crystal Clear',
versionDate: new Date('2024-05-09T00:00:00Z'),
versionDate: new Date('2024-05-13T19:00:00Z'),
// versionDate: new Date('2024-05-09T00:00:00Z'),
versionCoverImage: coverV116,
items: [
{ text: <><B href={beamBlogUrl} wow>Beam</B> core and UX improvements based on user feedback</>, issue: 470, icon: ChatBeamIcon },
@@ -74,6 +75,7 @@ export const NewsItems: NewsItem[] = [
{ text: <>More: <B issue={517}>code soft-wrap</B>, selection toolbar, <B issue={507}>3x faster</B> on Apple silicon</>, issue: 507 },
{ text: <>Updated <B>Anthropic</B>*, <B>Groq</B>, <B>Ollama</B>, <B>OpenAI</B>*, <B>OpenRouter</B>*, and <B>Perplexity</B></> },
{ text: <>Developers: update LLMs data structures</>, dev: true },
{ text: <>1.16.1: Support for <B>OpenAI</B> <B href='https://openai.com/index/hello-gpt-4o/'>GPT-4o</B> (refresh your OpenAI models)</> },
],
},
{
+24 -5
View File
@@ -1,21 +1,40 @@
// NOTE: this is a separate file to help with bundle tracing, as it's included by the ProviderBootstrapLogic (i.e. by All pages)
// update this variable every time you want to broadcast a new version to clients
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useAppStateStore } from '~/common/state/store-appstate';
export const incrementalNewsVersion: number = 15;
// update this variable every time you want to broadcast a new version to clients
export const incrementalNewsVersion: number = 16.1;
interface NewsState {
lastSeenNewsVersion: number;
}
export const useAppNewsStateStore = create<NewsState>()(
persist(
(set) => ({
lastSeenNewsVersion: 0,
}),
{
name: 'app-news',
},
),
);
export function shallRedirectToNews() {
const { usageCount, lastSeenNewsVersion } = useAppStateStore.getState();
const { lastSeenNewsVersion } = useAppNewsStateStore.getState();
const { usageCount } = useAppStateStore.getState();
const isNewsOutdated = (lastSeenNewsVersion || 0) < incrementalNewsVersion;
return isNewsOutdated && usageCount > 2;
}
export function markNewsAsSeen() {
const { setLastSeenNewsVersion } = useAppStateStore.getState();
setLastSeenNewsVersion(incrementalNewsVersion);
useAppNewsStateStore.setState({ lastSeenNewsVersion: incrementalNewsVersion });
}
+2
View File
@@ -9,6 +9,7 @@ import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import { useModelsStore } from '~/modules/llms/store-llms';
import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon';
import { authUserButton } from '~/common/providers/ProviderAuth';
import { checkDivider, checkVisibileIcon, NavItemApp, navItems } from '~/common/app.nav';
import { themeZIndexDesktopNav } from '~/common/app.theme';
@@ -184,6 +185,7 @@ export function DesktopNav(props: { component: React.ElementType, currentApp?: N
<DesktopNavGroupBox sx={{ mb: 'calc(2 * var(--GroupMarginY))' }}>
{navExtLinkItems}
{navModalItems}
{authUserButton}
</DesktopNavGroupBox>
</InvertedBar>
+36
View File
@@ -0,0 +1,36 @@
import * as React from 'react';
import dynamic from 'next/dynamic';
import { RedirectToSignIn, SignedIn, SignedOut, UserButton } from '@clerk/nextjs';
const enableClerk = !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
// Dynamically import ClerkProvider only if ENABLE_CLERK is true
const ClerkProviderDynamic = !enableClerk ? null : dynamic(() =>
import('@clerk/nextjs')
.then(({ ClerkProvider }) => ClerkProvider)
.catch(err => {
console.error('Failed to load ClerkProvider:', err);
const AuthLoadIssue = () => <>Issue Loading Auth</>;
AuthLoadIssue.displayName = 'AuthLoadIssue';
return AuthLoadIssue;
}),
);
export const ProviderAuth = (props: { children: React.ReactNode }) => (enableClerk && ClerkProviderDynamic)
? (
<ClerkProviderDynamic>
<SignedIn>
{props.children}
</SignedIn>
<SignedOut>
<RedirectToSignIn />
</SignedOut>
</ClerkProviderDynamic>
) : props.children;
export const authUserButton = (enableClerk && ClerkProviderDynamic)
? <>
<UserButton />
</>
: null;
+1 -12
View File
@@ -6,24 +6,13 @@ import { persist } from 'zustand/middleware';
interface AppStateData {
usageCount: number;
lastSeenNewsVersion: number;
// suppressedItems: Record<string, boolean>;
}
interface AppStateActions {
setLastSeenNewsVersion: (version: number) => void;
}
export const useAppStateStore = create<AppStateData & AppStateActions>()(
export const useAppStateStore = create<AppStateData>()(
persist(
(set) => ({
usageCount: 0,
lastSeenNewsVersion: 0,
// suppressedItems: {},
setLastSeenNewsVersion: (version: number) => set({ lastSeenNewsVersion: version }),
}),
{
+6
View File
@@ -32,6 +32,9 @@ interface UIPreferencesStore {
renderMarkdown: boolean;
setRenderMarkdown: (renderMarkdown: boolean) => void;
renderCodeSoftWrap: boolean;
setRenderCodeSoftWrap: (renderCodeSoftWrap: boolean) => void;
// showPersonaExamples: boolean;
// setShowPersonaExamples: (showPersonaExamples: boolean) => void;
@@ -75,6 +78,9 @@ export const useUIPreferencesStore = create<UIPreferencesStore>()(
renderMarkdown: true,
setRenderMarkdown: (renderMarkdown: boolean) => set({ renderMarkdown }),
renderCodeSoftWrap: false,
setRenderCodeSoftWrap: (renderCodeSoftWrap: boolean) => set({ renderCodeSoftWrap }),
// showPersonaExamples: false,
// setShowPersonaExamples: (showPersonaExamples: boolean) => set({ showPersonaExamples }),
+74 -8
View File
@@ -10,12 +10,7 @@
* @param pdfBuffer The content of a PDF file
*/
export async function pdfToText(pdfBuffer: ArrayBuffer): Promise<string> {
// Dynamically import the 'pdfjs-dist' library [nextjs]
const { getDocument, GlobalWorkerOptions } = await import('pdfjs-dist');
// Set the worker script path
GlobalWorkerOptions.workerSrc = '/workers/pdf.worker.min.mjs';
const { getDocument } = await dynamicImportPdfJs();
const pdf = await getDocument(pdfBuffer).promise;
const textPages: string[] = []; // Initialize an array to hold text from all pages
@@ -25,10 +20,81 @@ export async function pdfToText(pdfBuffer: ArrayBuffer): Promise<string> {
const strings = content.items
.filter(isTextItem) // Use the type guard to filter out items with the 'str' property
.map((item) => (item as { str: string }).str); // Use type assertion to ensure that the item has the 'str' property
textPages.push(strings.join(' ') + '\n'); // Add the joined strings to the array
// textPages.push(strings.join(' ')); // Add the joined strings to the array
// New way: join the strings to form a page text. treat empty lines as newlines, otherwise join with a space (or not if the line is just 1 space)
textPages.push(strings.reduce((acc, str) => {
// empty line -> newline
if (str === '')
return acc + '\n';
// single space
if (str === ' ')
return acc + str;
// trick: de-hyphenation of consecutive lines
if (/\w-$/.test(acc) && /^\w/.test(str))
return acc.slice(0, -1) + str;
// add a space if the last char is not a space or return (regex)
if (/\S$/.test(acc))
return acc + ' ' + str;
// otherwise just concatenate
return acc + str;
}, ''));
}
return textPages.join('\n\n'); // Join all the page texts at the end
}
type PdfPageImage = { base64Url: string, scale: number, width: number, height: number };
/**
* Renders all pages of a PDF to images
*
* @param pdfBuffer The content of a PDF file
* @param scale The scale factor for the image resolution (default 1.5 for moderate quality)
*/
export async function pdfToImageDataURLs(pdfBuffer: ArrayBuffer, scale = 1.5): Promise<PdfPageImage[]> {
const { getDocument } = await dynamicImportPdfJs();
const pdf = await getDocument({ data: pdfBuffer }).promise;
const images: PdfPageImage[] = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
await page.render({
canvasContext: context!,
viewport,
}).promise;
images.push({
base64Url: canvas.toDataURL('image/jpeg'),
scale,
width: viewport.width,
height: viewport.height,
});
}
return textPages.join(''); // Join all the page texts at the end
return images;
}
// Dynamically import the 'pdfjs-dist' library
async function dynamicImportPdfJs() {
// Dynamically import the 'pdfjs-dist' library [nextjs]
const { getDocument, GlobalWorkerOptions } = await import('pdfjs-dist');
// Set the worker script path
GlobalWorkerOptions.workerSrc = '/workers/pdf.worker.min.mjs';
return { getDocument };
}
// Type guard to check if an item has a 'str' property
+36 -12
View File
@@ -14,6 +14,7 @@ import { BeamRayGrid } from './scatter/BeamRayGrid';
import { BeamScatterInput } from './scatter/BeamScatterInput';
import { BeamScatterPane } from './scatter/BeamScatterPane';
import { BeamStoreApi, useBeamStore } from './store-beam.hooks';
import { useModuleBeamStore } from './store-module-beam';
export function BeamView(props: {
@@ -24,6 +25,7 @@ export function BeamView(props: {
}) {
// state
const [hasAutoMerged, setHasAutoMerged] = React.useState(false);
const [warnIsScattering, setWarnIsScattering] = React.useState(false);
// external state
@@ -36,7 +38,9 @@ export function BeamView(props: {
/* root */ inputHistory, inputIssues, inputReady,
/* scatter */ isScattering, raysReady,
/* gather (composite) */ canGather,
/* IDs */ rayIds, fusionIds,
} = useBeamStore(props.beamStore, useShallow(state => ({
// input
inputHistory: state.inputHistory,
inputIssues: state.inputIssues,
inputReady: state.inputReady,
@@ -45,9 +49,13 @@ export function BeamView(props: {
raysReady: state.raysReady,
// gather (composite)
canGather: state.raysReady >= 2 && state.currentFactoryId !== null && state.currentGatherLlmId !== null,
// IDs
rayIds: state.rays.map(ray => ray.rayId),
fusionIds: state.fusions.map(fusion => fusion.fusionId),
})));
const { gatherAutoStartAfterScatter } = useModuleBeamStore(useShallow(state => ({
gatherAutoStartAfterScatter: state.gatherAutoStartAfterScatter,
})));
const rayIds = useBeamStore(props.beamStore, useShallow(state => state.rays.map(ray => ray.rayId)));
const fusionIds = useBeamStore(props.beamStore, useShallow(state => state.fusions.map(fusion => fusion.fusionId)));
// derived state
const raysCount = rayIds.length;
@@ -59,6 +67,11 @@ export function BeamView(props: {
const handleRayIncreaseCount = React.useCallback(() => setRayCount(raysCount + 1), [setRayCount, raysCount]);
const handleScatterStart = React.useCallback(() => {
setHasAutoMerged(false);
startScatteringAll();
}, [startScatteringAll]);
const handleCreateFusion = React.useCallback(() => {
// if scatter is busy, ask for confirmation
@@ -70,20 +83,31 @@ export function BeamView(props: {
}, [isScattering, props.beamStore]);
const handleStopScatterConfirmation = React.useCallback(() => {
const handleStartMergeConfirmation = React.useCallback(() => {
setWarnIsScattering(false);
stopScatteringAll();
handleCreateFusion();
}, [handleCreateFusion, stopScatteringAll]);
const handleStopScatterDenial = React.useCallback(() => setWarnIsScattering(false), []);
const handleStartMergeDenial = React.useCallback(() => setWarnIsScattering(false), []);
// (this is great ux) scatter freed up while we were asking the question, proceed
// auto-merge
const shallAutoMerge = gatherAutoStartAfterScatter && canGather && !isScattering && !hasAutoMerged;
React.useEffect(() => {
if (warnIsScattering && !isScattering)
handleStopScatterConfirmation();
}, [handleStopScatterConfirmation, isScattering, warnIsScattering]);
if (shallAutoMerge) {
setHasAutoMerged(true);
handleStartMergeConfirmation();
}
}, [handleStartMergeConfirmation, shallAutoMerge]);
// (great ux) scatter finished while the "start merge" (warning) dialog is up: dismiss dialog and proceed
// here we assume that 'warnIsScattering' shows the intention of the user to proceed with a merge asap
const shallResumeMerge = warnIsScattering && !isScattering && !gatherAutoStartAfterScatter;
React.useEffect(() => {
if (shallResumeMerge)
handleStartMergeConfirmation();
}, [handleStartMergeConfirmation, shallResumeMerge]);
// runnning
@@ -138,7 +162,7 @@ export function BeamView(props: {
setRayCount={handleRaySetCount}
startEnabled={inputReady}
startBusy={isScattering}
onStart={startScatteringAll}
onStart={handleScatterStart}
onStop={stopScatteringAll}
onExplainerShow={explainerShow}
/>
@@ -163,7 +187,7 @@ export function BeamView(props: {
beamStore={props.beamStore}
canGather={canGather}
isMobile={props.isMobile}
onAddFusion={handleCreateFusion}
// onAddFusion={handleCreateFusion}
raysReady={raysReady}
/>
@@ -184,8 +208,8 @@ export function BeamView(props: {
{warnIsScattering && (
<ConfirmationModal
open
onClose={handleStopScatterDenial}
onPositive={handleStopScatterConfirmation}
onClose={handleStartMergeDenial}
onPositive={handleStartMergeConfirmation}
// lowStakes
noTitleBar
confirmationText='Some responses are still being generated. Do you want to stop and proceed with merging the available responses now?'
+1 -1
View File
@@ -147,7 +147,7 @@ export function BeamFusionGrid(props: {
</Box> : (
<Typography level='body-sm' sx={{ opacity: 0.8 }}>
{/*You need two or more replies for a {currentFactory?.shortLabel?.toLocaleLowerCase() ?? ''} merge.*/}
Waiting for multiple Beams.
Waiting for multiple responses.
</Typography>
)}
</BeamCard>
+1 -1
View File
@@ -57,7 +57,7 @@ export function BeamGatherPane(props: {
beamStore: BeamStoreApi,
canGather: boolean,
isMobile: boolean,
onAddFusion: () => void,
// onAddFusion: () => void,
raysReady: number,
}) {
+4
View File
@@ -104,6 +104,7 @@ interface GatherStateSlice {
// derived state (just acts as a cache to avoid re-calculating)
isGatheringAny: boolean;
// fusionsReady: number;
}
@@ -118,6 +119,7 @@ export const reInitGatherStateSlice = (prevFusions: BFusion[], gatherLlmId: DLLM
fusions: [],
isGatheringAny: false,
// fusionsReady: 0,
};
};
@@ -170,10 +172,12 @@ export const createGatherSlice: StateCreator<RootStoreSlice & ScatterStoreSlice
// 'or' the status of all fusions
const isGatheringAny = newFusions.some(fusionIsFusing);
// const fusionsReady = newFusions.filter(fusionIsUsableOutput).length;
_set({
fusions: newFusions,
isGatheringAny,
// fusionsReady,
});
},
@@ -7,6 +7,8 @@ import DriveFileRenameOutlineRoundedIcon from '@mui/icons-material/DriveFileRena
import MoreVertIcon from '@mui/icons-material/MoreVert';
import SchoolRoundedIcon from '@mui/icons-material/SchoolRounded';
import { DEV_MODE_SETTINGS } from '../../../apps/settings-modal/UxLabsSettings';
import type { DLLMId } from '~/modules/llms/store-llms';
import type { BeamStoreApi } from '../store-beam.hooks';
@@ -69,6 +71,7 @@ export function BeamScatterDropdown(props: {
cardScrolling, toggleCardScrolling,
scatterShowPrevMessages, toggleScatterShowPrevMessages,
scatterShowLettering, toggleScatterShowLettering,
gatherAutoStartAfterScatter, toggleGatherAutoStartAfterScatter,
gatherShowAllPrompts, toggleGatherShowAllPrompts,
} = useModuleBeamStore();
@@ -163,10 +166,15 @@ export function BeamScatterDropdown(props: {
Response Numbers
</MenuItem>
<ListItem onClick={() => handleClearLastConfig()}>
<ListItem onClick={DEV_MODE_SETTINGS ? () => handleClearLastConfig() : undefined}>
<Typography level='body-sm'>Advanced</Typography>
</ListItem>
<MenuItem onClick={toggleGatherAutoStartAfterScatter}>
<ListItemDecorator>{gatherAutoStartAfterScatter && <CheckRoundedIcon />}</ListItemDecorator>
Auto-Merge
</MenuItem>
<MenuItem onClick={toggleGatherShowAllPrompts}>
<ListItemDecorator>{gatherShowAllPrompts && <CheckRoundedIcon />}</ListItemDecorator>
Detailed Custom Merge
+5
View File
@@ -23,6 +23,7 @@ interface ModuleBeamState {
cardScrolling: boolean;
scatterShowLettering: boolean;
scatterShowPrevMessages: boolean;
gatherAutoStartAfterScatter: boolean;
gatherShowAllPrompts: boolean;
}
@@ -37,6 +38,7 @@ interface ModuleBeamStore extends ModuleBeamState {
toggleCardScrolling: () => void;
toggleScatterShowLettering: () => void;
toggleScatterShowPrevMessages: () => void;
toggleGatherAutoStartAfterScatter: () => void;
toggleGatherShowAllPrompts: () => void;
}
@@ -50,6 +52,7 @@ export const useModuleBeamStore = create<ModuleBeamStore>()(persist(
scatterShowLettering: false,
scatterShowPrevMessages: false,
gatherShowAllPrompts: false,
gatherAutoStartAfterScatter: false,
addPreset: (name, rayLlmIds, gatherLlmId, gatherFactoryId) => _set(state => ({
@@ -86,6 +89,8 @@ export const useModuleBeamStore = create<ModuleBeamStore>()(persist(
toggleScatterShowPrevMessages: () => _set(state => ({ scatterShowPrevMessages: !state.scatterShowPrevMessages })),
toggleGatherAutoStartAfterScatter: () => _set(state => ({ gatherAutoStartAfterScatter: !state.gatherAutoStartAfterScatter })),
toggleGatherShowAllPrompts: () => _set(state => ({ gatherShowAllPrompts: !state.gatherShowAllPrompts })),
}), {
+3 -2
View File
@@ -12,6 +12,7 @@ import WrapTextIcon from '@mui/icons-material/WrapText';
import { copyToClipboard } from '~/common/util/clipboardUtils';
import { frontendSideFetch } from '~/common/util/clientFetchers';
import { useUIPreferencesStore } from '~/common/state/store-ui';
import type { CodeBlock } from '../blocks';
import { ButtonCodePen, isCodePenSupported } from './ButtonCodePen';
@@ -107,7 +108,7 @@ function RenderCodeImpl(props: RenderCodeImplProps) {
const [showMermaid, setShowMermaid] = React.useState(true);
const [showPlantUML, setShowPlantUML] = React.useState(true);
const [showSVG, setShowSVG] = React.useState(true);
const [softWrap, setSoftWrap] = React.useState(false);
const [softWrap, setSoftWrap] = useUIPreferencesStore(state => [state.renderCodeSoftWrap, state.setRenderCodeSoftWrap]);
// derived props
const {
@@ -274,7 +275,7 @@ function RenderCodeImpl(props: RenderCodeImplProps) {
{/* Soft Wrap toggle */}
{(!renderHTML && !renderMermaid && !renderPlantUML && !renderSVG) && (
<Tooltip title='Toggle Soft Wrap'>
<OverlayButton variant={softWrap ? 'solid' : 'outlined'} onClick={() => setSoftWrap(on => !on)}>
<OverlayButton variant={softWrap ? 'solid' : 'outlined'} onClick={() => setSoftWrap(!softWrap)}>
<WrapTextIcon />
</OverlayButton>
</Tooltip>
+30 -2
View File
@@ -11,11 +11,39 @@ import { wireTogetherAIListOutputSchema } from './togetherai.wiretypes';
// [Azure] / [OpenAI]
const _knownOpenAIChatModels: ManualMappings = [
// GPT-4o -> 2024-05-13
{
idPrefix: 'gpt-4o',
label: 'GPT-4o',
description: 'Currently points to gpt-4o-2024-05-13.',
symLink: 'gpt-4o-2024-05-13',
hidden: true,
// copied from symlinked
contextWindow: 128000,
maxCompletionTokens: 4096,
trainingDataCutoff: 'Oct 2023',
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_OAI_Json],
pricing: { chatIn: 5, chatOut: 15 },
benchmark: { cbaElo: 1310 },
},
{
isLatest: true,
idPrefix: 'gpt-4o-2024-05-13',
label: 'GPT-4o (2024-05-13)',
description: 'Advanced, multimodal flagship model thats cheaper and faster than GPT-4 Turbo.',
contextWindow: 128000,
maxCompletionTokens: 4096,
trainingDataCutoff: 'Oct 2023',
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Vision, LLM_IF_OAI_Fn, LLM_IF_OAI_Json],
pricing: { chatIn: 5, chatOut: 15 },
benchmark: { cbaElo: 1310 },
},
// GPT4 Turbo with Vision -> 2024-04-09
{
idPrefix: 'gpt-4-turbo',
label: 'GPT-4 Turbo',
description: 'GPT-4 Turbo with Vision. The latest GPT-4 Turbo model with vision capabilities. Vision requests can now use JSON mode and function calling. Currently points to gpt-4-turbo-2024-04-09.',
description: 'New GPT-4 Turbo with Vision. The latest GPT-4 Turbo model with vision capabilities. Vision requests can now use JSON mode and function calling. Currently points to gpt-4-turbo-2024-04-09.',
symLink: 'gpt-4-turbo-2024-04-09',
hidden: true,
// copied from symlinked
@@ -27,7 +55,6 @@ const _knownOpenAIChatModels: ManualMappings = [
benchmark: { cbaElo: 1261 },
},
{
isLatest: true,
idPrefix: 'gpt-4-turbo-2024-04-09',
label: 'GPT-4 Turbo (2024-04-09)',
description: 'GPT-4 Turbo with Vision model. Vision requests can now use JSON mode and function calling. gpt-4-turbo currently points to this version.',
@@ -66,6 +93,7 @@ const _knownOpenAIChatModels: ManualMappings = [
interfaces: [LLM_IF_OAI_Chat, LLM_IF_OAI_Fn, LLM_IF_OAI_Json],
pricing: { chatIn: 10, chatOut: 30 },
benchmark: { cbaElo: 1251 },
hidden: true,
},
{
idPrefix: 'gpt-4-1106-preview', // GPT-4 Turbo preview model