1
import * as React from 'react';
2
import { fileSave } from 'browser-fs-access';
4
import { Box, Button, Card, CardContent, Typography } from '@mui/joy';
5
import DownloadIcon from '@mui/icons-material/Download';
7
import { AppPlaceholder } from '../../src/apps/AppPlaceholder';
9
import { backendCaps } from '~/modules/backend/state-backend';
10
import { getPlantUmlServerUrl } from '~/modules/blocks/code/RenderCode';
12
import { withLayout } from '~/common/layout/withLayout';
16
import { Brand } from '~/common/app.config';
17
import { ROUTE_APP_CHAT, ROUTE_INDEX } from '~/common/app.routes';
20
import { incrementalNewsVersion } from '../../src/apps/news/news.version';
23
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs, useCapabilityTextToImage } from '~/common/components/useCapabilities';
26
import { getLLMsDebugInfo } from '~/modules/llms/store-llms';
27
import { useAppStateStore } from '~/common/state/store-appstate';
28
import { useChatStore } from '~/common/state/store-chats';
29
import { useFolderStore } from '~/common/state/store-folders';
30
import { useUXLabsStore } from '~/common/state/store-ux-labs';
33
import { clientHostName, isChromeDesktop, isFirefox, isIPhoneUser, isMacUser, isPwa, isVercelFromFrontend } from '~/common/util/pwaUtils';
34
import { getGA4MeasurementId } from '~/common/components/GoogleAnalytics';
35
import { supportsClipboardRead } from '~/common/util/clipboardUtils';
36
import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
39
function DebugCard(props: { title: string, children: React.ReactNode }) {
42
<Typography level='title-lg'>
50
function prettifyJsonString(jsonString: string, deleteChars: number, removeDoubleQuotes: boolean, removeTrailComma: boolean): string {
51
return jsonString.split('\n').map(l => {
53
l = l.substring(deleteChars);
54
if (removeDoubleQuotes)
55
l = l.replaceAll('\"', '');
56
if (removeTrailComma && l.endsWith(','))
57
l = l.substring(0, l.length - 1);
62
function DebugJsonCard(props: { title: string, data: any }) {
64
<DebugCard title={props.title}>
65
<Typography level='body-sm' sx={{ whiteSpace: 'break-spaces', fontFamily: 'code', fontSize: { xs: 'xs' } }}>
66
{prettifyJsonString(JSON.stringify(props.data, null, 2), 2, true, true)}
76
const [saved, setSaved] = React.useState(false);
79
const backendCapabilities = backendCaps();
80
const chatsCount = useChatStore.getState().conversations?.length;
81
const uxLabsExperiments = Object.entries(useUXLabsStore.getState()).filter(([_k, v]) => v === true).map(([k, _]) => k).join(', ');
82
const { folders, enableFolders } = useFolderStore.getState();
83
const { lastSeenNewsVersion, usageCount } = useAppStateStore.getState();
91
isIPhone: isIPhoneUser,
94
supportsClipboardPaste: supportsClipboardRead,
95
supportsScreenCapture,
99
mic: useCapabilityBrowserSpeechRecognition(),
100
elevenLabs: useCapabilityElevenLabs(),
101
textToImage: useCapabilityTextToImage(),
103
models: getLLMsDebugInfo(),
106
foldersCount: folders?.length,
107
foldersEnabled: enableFolders,
108
newsCurrent: incrementalNewsVersion,
109
newsSeen: lastSeenNewsVersion,
110
labsActive: uxLabsExperiments,
115
configuration: backendCapabilities,
117
home: Brand.URIs.Home,
118
hostName: clientHostName(),
119
isVercelFromFrontend,
120
measurementId: getGA4MeasurementId(),
121
plantUmlServerUrl: getPlantUmlServerUrl(),
122
routeIndex: ROUTE_INDEX,
123
routeChat: ROUTE_APP_CHAT,
127
const handleDownload = async () => {
129
new Blob([JSON.stringify({ client: cClient, agi: cProduct, backend: cBackend }, null, 2)], { type: 'application/json' }),
130
{ fileName: `big-agi-debug-${new Date().toISOString().replace(/:/g, '-')}.json`, extensions: ['.json'] },
132
.then(() => setSaved(true))
133
.catch(e => console.error('Error saving debug.json', e));
137
<AppPlaceholder title={`${Brand.Title.Common} Debug`}>
138
<Box sx={{ display: 'grid', gap: 3, my: 3 }}>
140
variant={saved ? 'soft' : 'outlined'} color={saved ? 'success' : 'neutral'}
141
onClick={handleDownload}
142
endDecorator={<DownloadIcon />}
144
backgroundColor: saved ? undefined : 'background.surface',
153
<CardContent sx={{ display: 'grid', gap: 3 }}>
154
<DebugJsonCard title='Client' data={cClient} />
155
<DebugJsonCard title='AGI' data={cProduct} />
156
<DebugJsonCard title='Backend' data={cBackend} />
165
export default function DebugPage() {
166
return withLayout({ type: 'plain' }, <AppDebug />);