import * as React from 'react';
import { Alert, Box, Button, CircularProgress, Divider, FormControl, FormHelperText, FormLabel, Modal, ModalClose, ModalDialog, Option, Select, Slider, Stack, Textarea, Typography } from '@mui/joy';
import { ChatModelId, ChatModels, fastChatModelId } from '@/lib/data';
import { Section } from '@/components/dialogs/SettingsModal';
import { TokenBadge } from '@/components/util/TokenBadge';
import { countModelTokens } from '@/lib/llm/tokens';
import { summerizeToFitContextBudget } from '@/lib/llm/summerize';
function TokenUsageAlert({ usedTokens, tokenLimit }: { usedTokens: number, tokenLimit: number }) {
const remainingTokens = tokenLimit - usedTokens;
const message = remainingTokens >= 1
? `${usedTokens.toLocaleString()} reduced tokens and ${remainingTokens.toLocaleString()} tokens remaining.`
: `⚠️ These ${usedTokens.toLocaleString()} tokens go over budget by ${(-remainingTokens).toLocaleString()} tokens.`;
return = 1 ? 'primary' : 'danger'} sx={{ mt: 1 }}>{message};
}
/**
* Dialog to compress a PDF
*/
export function ContentReducerModal(props: {
initialText: string,
initialTokens: number,
tokenLimit: number,
onClose: () => void,
onReducedText: (text: string) => void,
}) {
// state
const [reducerModelId, setReducerModelId] = React.useState(fastChatModelId);
const [compressionLevel, setCompressionLevel] = React.useState(3);
const [reducedText, setReducedText] = React.useState('');
const [processing, setProcessing] = React.useState(false);
// derived state
const reducedTokens = countModelTokens(reducedText, reducerModelId, 'content reducer reduce');
const remainingTokens = props.tokenLimit - reducedTokens;
const handleChatModelChange = (event: any, value: ChatModelId | null) => value && setReducerModelId(value);
const handleCompressionLevelChange = (event: Event, newValue: number | number[]) => setCompressionLevel(newValue as number);
const handlePreviewClicked = async () => {
setProcessing(true);
const reducedText = await summerizeToFitContextBudget(props.initialText, props.tokenLimit, reducerModelId);
setReducedText(reducedText);
setProcessing(false);
};
const handleUseReducedTextClicked = () => props.onReducedText(reducedText);
// DISABLED: user shall select the model and compression level first
// upon load, click the preview button
// React.useEffect(() => {
// // noinspection JSIgnoredPromiseFromCall
// handlePreviewClicked();
// }, [handlePreviewClicked]);
return (
Content Reducer (preview)
{/* Settings */}
Input: {props.initialTokens.toLocaleString()} tokens · Limit: {props.tokenLimit.toLocaleString()} tokens
compression needed ≥ {props.tokenLimit ? Math.round(100 * props.initialTokens / props.tokenLimit) : 0} %
Reducer model
{ChatModels[reducerModelId]?.tradeoff}
{reducerModelId && }
Compression
{compressionLevel < 2 ? 'Low' : compressionLevel > 4 ? 'High' : 'Medium'}
{/* Outputs */}
{/* Readonly output and token counter */}
{/* indicator we're processing */}
{processing && (
Reduction in progress.
This can take a few minutes
)}
{!!reducedTokens && }
);
}