mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Attachment Compatibility: Send & Beam
This commit is contained in:
@@ -25,6 +25,7 @@ import { AudioGenerator } from '~/common/util/audio/AudioGenerator';
|
||||
import { AudioPlayer } from '~/common/util/audio/AudioPlayer';
|
||||
import { ButtonAttachFilesMemo, openFileForAttaching } from '~/common/components/ButtonAttachFiles';
|
||||
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
|
||||
import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal';
|
||||
import { ConversationsManager } from '~/common/chat-overlay/ConversationsManager';
|
||||
import { DMessageMetadata, DMetaReferenceItem, messageFragmentsReduceText } from '~/common/stores/chat/chat.message';
|
||||
import { ShortcutKey, ShortcutObject, useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
|
||||
@@ -44,6 +45,7 @@ import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
|
||||
import { useAppStateStore } from '~/common/state/store-appstate';
|
||||
import { useChatComposerOverlayStore } from '~/common/chat-overlay/store-chat-overlay';
|
||||
import { useDebouncer } from '~/common/components/useDebouncer';
|
||||
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
|
||||
import { useUICounter, useUIPreferencesStore } from '~/common/state/store-ui';
|
||||
import { useUXLabsStore } from '~/common/state/store-ux-labs';
|
||||
|
||||
@@ -114,6 +116,7 @@ export function Composer(props: {
|
||||
const micCardRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
// external state
|
||||
const { showPromisedOverlay } = useOverlayComponents();
|
||||
const { labsAttachScreenCapture, labsCameraDesktop, labsShowCost, labsShowShortcutBar } = useUXLabsStore(useShallow(state => ({
|
||||
labsAttachScreenCapture: state.labsAttachScreenCapture,
|
||||
labsCameraDesktop: state.labsCameraDesktop,
|
||||
@@ -217,6 +220,24 @@ export function Composer(props: {
|
||||
}, [composerTextAreaRef, inReferenceTo]);
|
||||
|
||||
|
||||
// Confirmation Modals
|
||||
|
||||
const confirmProceedIfAttachmentsNotSupported = React.useCallback(async (): Promise<boolean> => {
|
||||
if (llmAttachmentDraftsCollection.canAttachAllFragments) return true;
|
||||
return await showPromisedOverlay('composer-unsupported-attachments', { rejectWithValue: false }, ({ onResolve, onUserReject }) => (
|
||||
<ConfirmationModal
|
||||
open
|
||||
onClose={onUserReject}
|
||||
onPositive={() => onResolve(true)}
|
||||
confirmationText="Some attached files may not be fully compatible with the current AI model. This could affect processing. Would you like to review or proceed?"
|
||||
positiveActionText="Proceed"
|
||||
negativeActionText="Review Attachments"
|
||||
title="Attachment Compatibility Notice"
|
||||
/>
|
||||
));
|
||||
}, [llmAttachmentDraftsCollection.canAttachAllFragments, showPromisedOverlay]);
|
||||
|
||||
|
||||
// Primary button
|
||||
|
||||
const handleClear = React.useCallback(() => {
|
||||
@@ -229,6 +250,9 @@ export function Composer(props: {
|
||||
const handleSendAction = React.useCallback(async (_chatExecuteMode: ChatExecuteMode, composerText: string): Promise<boolean> => {
|
||||
if (!isValidConversation(targetConversationId)) return false;
|
||||
|
||||
// await user confirmation (or rejection) if attachments are not supported
|
||||
if (!await confirmProceedIfAttachmentsNotSupported()) return false;
|
||||
|
||||
// validate some chat mode inputs
|
||||
const isDraw = _chatExecuteMode === 'generate-image';
|
||||
const isBlank = !composerText.trim();
|
||||
@@ -550,7 +574,10 @@ export function Composer(props: {
|
||||
|
||||
const sendButtonVariant: VariantProp = (isAppend || (isMobile && isTextBeam)) ? 'outlined' : 'solid';
|
||||
|
||||
const sendButtonColor: ColorPaletteProp = assistantAbortible ? 'warning' : chatExecuteModeSendColor;
|
||||
const sendButtonColor: ColorPaletteProp =
|
||||
assistantAbortible ? 'warning'
|
||||
: !llmAttachmentDraftsCollection.canAttachAllFragments ? 'warning'
|
||||
: chatExecuteModeSendColor;
|
||||
|
||||
const sendButtonLabel = chatExecuteModeSendLabel;
|
||||
|
||||
@@ -562,6 +589,10 @@ export function Composer(props: {
|
||||
: isDraw ? <FormatPaintTwoToneIcon />
|
||||
: <TelegramIcon />;
|
||||
|
||||
const beamButtonColor: ColorPaletteProp | undefined =
|
||||
!llmAttachmentDraftsCollection.canAttachAllFragments ? 'warning'
|
||||
: undefined;
|
||||
|
||||
let textPlaceholder: string =
|
||||
isDraw ? 'Describe an idea or a drawing...'
|
||||
: isReAct ? 'Multi-step reasoning question...'
|
||||
@@ -845,7 +876,7 @@ export function Composer(props: {
|
||||
{!assistantAbortible ? (
|
||||
<Button
|
||||
key='composer-act'
|
||||
fullWidth disabled={noConversation || noLLM || !llmAttachmentDraftsCollection.canAttachAllFragments}
|
||||
fullWidth disabled={noConversation || noLLM}
|
||||
onClick={handleSendClicked}
|
||||
endDecorator={sendButtonIcon}
|
||||
sx={{ '--Button-gap': '1rem' }}
|
||||
@@ -891,7 +922,8 @@ export function Composer(props: {
|
||||
{/* [desktop] secondary-top buttons */}
|
||||
{isDesktop && showChatExtras && !assistantAbortible && (
|
||||
<ButtonBeamMemo
|
||||
disabled={noConversation || noLLM || !llmAttachmentDraftsCollection.canAttachAllFragments}
|
||||
color={beamButtonColor}
|
||||
disabled={noConversation || noLLM}
|
||||
hasContent={!!composeText}
|
||||
onClick={handleSendTextBeamClicked}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { SxProps } from '@mui/joy/styles/types';
|
||||
import type { ColorPaletteProp, SxProps } from '@mui/joy/styles/types';
|
||||
import { Box, Button, IconButton, Tooltip } from '@mui/joy';
|
||||
|
||||
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
|
||||
@@ -35,14 +35,20 @@ const desktopSx: SxProps = {
|
||||
|
||||
export const ButtonBeamMemo = React.memo(ButtonBeam);
|
||||
|
||||
function ButtonBeam(props: { isMobile?: boolean, disabled?: boolean, hasContent?: boolean, onClick: () => void }) {
|
||||
function ButtonBeam(props: {
|
||||
isMobile?: boolean,
|
||||
color?: ColorPaletteProp,
|
||||
disabled?: boolean,
|
||||
hasContent?: boolean,
|
||||
onClick: () => void,
|
||||
}) {
|
||||
return props.isMobile ? (
|
||||
<IconButton variant='soft' color='primary' disabled={props.disabled} onClick={props.onClick} sx={mobileSx}>
|
||||
<IconButton variant='soft' color={props.color ?? 'primary'} disabled={props.disabled} onClick={props.onClick} sx={mobileSx}>
|
||||
<ChatBeamIcon />
|
||||
</IconButton>
|
||||
) : (
|
||||
<Tooltip disableInteractive variant='solid' arrow placement='right' title={props.hasContent ? desktopLegend : desktopLegendNoContent}>
|
||||
<Button variant='soft' color='primary' disabled={props.disabled} onClick={props.onClick} endDecorator={<ChatBeamIcon />} sx={desktopSx}>
|
||||
<Button variant='soft' color={props.color ?? 'primary'} disabled={props.disabled} onClick={props.onClick} endDecorator={<ChatBeamIcon />} sx={desktopSx}>
|
||||
Beam
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -24,6 +24,7 @@ export type GlobalOverlayId = // string - disabled so we keep an orderliness
|
||||
| 'shortcuts-confirm-close'
|
||||
| 'blocks-off-enhance-code'
|
||||
| 'llms-service-remove'
|
||||
| 'composer-unsupported-attachments' // The LLM does not seem to support this mime type - continue anyway?
|
||||
// | 'agi-patch-workflow-save' // make sure we use it
|
||||
;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user