import * as React from 'react';
import { fileSave } from 'browser-fs-access';
import { Box, Button, Card, CardContent, Typography } from '@mui/joy';
import DownloadIcon from '@mui/icons-material/Download';
import { AppPlaceholder } from '../../src/apps/AppPlaceholder';
import { getBackendCapabilities } from '~/modules/backend/store-backend-capabilities';
import { getPlantUmlServerUrl } from '~/modules/blocks/code/code-renderers/RenderCodePlantUML';
import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
// basics
import { Brand } from '~/common/app.config';
import { ROUTE_APP_CHAT, ROUTE_INDEX } from '~/common/app.routes';
import { Release } from '~/common/app.release';
// capabilities access
import { useCapabilityBrowserSpeechRecognition, useCapabilityTextToImage } from '~/common/components/useCapabilities';
// stores access
import { getLLMsDebugInfo } from '~/common/stores/llms/store-llms';
import { useChatStore } from '~/common/stores/chat/store-chats';
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
import { useLogicSherpaStore } from '~/common/logic/store-logic-sherpa';
import { useUXLabsStore } from '~/common/stores/store-ux-labs';
// utils access
import { BrowserLang, clientHostName, Is, isPwa } from '~/common/util/pwaUtils';
import { getGA4MeasurementId } from '~/common/components/3rdparty/GoogleAnalytics';
import { prettyTimestampForFilenames } from '~/common/util/timeUtils';
import { supportsClipboardRead } from '~/common/util/clipboardUtils';
import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
function DebugCard(props: { title: string, children: React.ReactNode }) {
return (
{props.title}
{props.children}
);
}
function prettifyJsonString(jsonString: string, deleteChars: number, removeDoubleQuotes: boolean, removeTrailComma: boolean): string {
return jsonString.split('\n').map(l => {
if (deleteChars > 0)
l = l.substring(deleteChars);
if (removeDoubleQuotes)
l = l.replaceAll('\"', '');
if (removeTrailComma && l.endsWith(','))
l = l.substring(0, l.length - 1);
return l;
}).join('\n').trim();
}
function DebugJsonCard(props: { title: string, data: any }) {
return (
{prettifyJsonString(JSON.stringify(props.data, null, 2), 2, true, true)}
);
}
const frontendBuild = Release.buildInfo('frontend');
function AppDebug() {
// state
const [saved, setSaved] = React.useState(false);
// external state
const backendCaps = getBackendCapabilities();
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 } = useLogicSherpaStore.getState();
// derived state
const cClient = {
// isBrowser,
Is,
BrowserLang,
isPWA: isPwa(),
supportsClipboardPaste: supportsClipboardRead(),
supportsScreenCapture,
};
const cProduct = {
capabilities: {
mic: useCapabilityBrowserSpeechRecognition(),
textToImage: useCapabilityTextToImage(),
},
models: getLLMsDebugInfo(),
state: {
chatsCount,
foldersCount: folders?.length,
foldersEnabled: enableFolders,
newsCurrent: Release.Monotonics.NewsVersion,
newsSeen: lastSeenNewsVersion,
labsActive: uxLabsExperiments,
reloads: usageCount,
},
release: {
build: frontendBuild,
},
};
const cBackend = {
configuration: backendCaps,
deployment: {
home: Brand.URIs.Home,
hostName: clientHostName(),
measurementId: getGA4MeasurementId(),
plantUmlServerUrl: getPlantUmlServerUrl(),
routeIndex: ROUTE_INDEX,
routeChat: ROUTE_APP_CHAT,
},
};
const handleDownload = async () => {
fileSave(
new Blob([JSON.stringify({ client: cClient, agi: cProduct, backend: cBackend }, null, 2)], { type: 'application/json' }),
{ fileName: `big-agi_debug_${prettyTimestampForFilenames()}.json`, extensions: ['.json'] },
)
.then(() => setSaved(true))
.catch(e => console.error('Error saving debug.json', e));
};
return (
}
sx={{
backgroundColor: saved ? undefined : 'background.surface',
boxShadow: 'sm',
placeSelf: 'start',
minWidth: 260,
}}
>
Download debug JSON
);
}
export default withNextJSPerPageLayout({ type: 'container' }, () => );