Spaces:
Sleeping
Sleeping
refactor(vite.config.js): enhance build configuration with manual chunking and dependency optimization
Browse files- src/App.jsx +275 -261
- vite.config.js +15 -1
src/App.jsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import React, { useState, useRef, useEffect } from 'react';
|
2 |
import {
|
3 |
Box,
|
4 |
Container,
|
@@ -16,6 +16,7 @@ import {
|
|
16 |
Badge,
|
17 |
Flex,
|
18 |
Divider,
|
|
|
19 |
Textarea,
|
20 |
Tooltip,
|
21 |
InputGroup,
|
@@ -25,8 +26,10 @@ import {
|
|
25 |
HStack,
|
26 |
} from '@chakra-ui/react';
|
27 |
import axios from 'axios';
|
28 |
-
|
29 |
-
|
|
|
|
|
30 |
|
31 |
// Function to get filename without extension
|
32 |
const getFilenameWithoutExtension = filename => {
|
@@ -340,13 +343,18 @@ const App = () => {
|
|
340 |
setDownloading(true);
|
341 |
|
342 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
// Create a new zip file
|
344 |
-
const zip = new JSZip();
|
345 |
|
346 |
// Add text files to the zip with the same filenames as the images but .txt extension
|
347 |
completedImages.forEach(image => {
|
348 |
const fileName = getFilenameWithoutExtension(image.name) + ".txt";
|
349 |
-
// Use the edited caption if available, otherwise use the original caption
|
350 |
const captionToSave = image.isEdited ? image.editedCaption : image.caption;
|
351 |
zip.file(fileName, captionToSave);
|
352 |
});
|
@@ -470,272 +478,278 @@ const App = () => {
|
|
470 |
const hasCaptions = uploadedImages.some(img => img.status === 'completed' && img.caption);
|
471 |
|
472 |
return (
|
473 |
-
<
|
474 |
-
<
|
475 |
-
<
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
490 |
<Input
|
491 |
-
type="
|
492 |
-
placeholder="Enter
|
493 |
-
value={
|
494 |
-
onChange={
|
495 |
-
mr={2}
|
496 |
/>
|
497 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
498 |
size="md"
|
499 |
-
|
500 |
-
variant="outline"
|
501 |
-
colorScheme="red"
|
502 |
>
|
503 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
</Button>
|
505 |
</Flex>
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
type="text"
|
516 |
-
placeholder="Enter custom Glif ID or URL (optional)"
|
517 |
-
value={customGlifInput}
|
518 |
-
onChange={handleCustomGlifInputChange}
|
519 |
/>
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
603 |
>
|
604 |
-
|
605 |
-
</
|
606 |
-
</Flex>
|
607 |
-
|
608 |
-
{processing && (
|
609 |
-
<Progress
|
610 |
-
value={progress}
|
611 |
-
size="sm"
|
612 |
-
colorScheme="blue"
|
613 |
-
hasStripe
|
614 |
-
mb={4}
|
615 |
-
borderRadius="md"
|
616 |
-
/>
|
617 |
)}
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
<
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
borderWidth="1px"
|
626 |
-
borderRadius="lg"
|
627 |
-
overflow="hidden"
|
628 |
-
bg="gray.900"
|
629 |
-
position="relative"
|
630 |
-
>
|
631 |
-
<Box position="absolute" top={2} right={2} zIndex={1}>
|
632 |
-
{getStatusBadge(image.status)}
|
633 |
-
{image.isEdited && (
|
634 |
-
<Badge ml={2} colorScheme="purple">Edited</Badge>
|
635 |
-
)}
|
636 |
-
</Box>
|
637 |
-
<Image
|
638 |
-
src={image.preview}
|
639 |
-
alt={image.name}
|
640 |
-
w="100%"
|
641 |
-
h="200px"
|
642 |
-
objectFit="cover"
|
643 |
-
/>
|
644 |
-
<Box p={4}>
|
645 |
-
<Flex justify="space-between" align="center" mb={2}>
|
646 |
-
<Text fontWeight="semibold" isTruncated maxW="70%">{image.name}</Text>
|
647 |
-
<Button
|
648 |
-
size="xs"
|
649 |
-
onClick={() => removeImage(image.id)}
|
650 |
-
disabled={processing}
|
651 |
-
>
|
652 |
-
Remove
|
653 |
-
</Button>
|
654 |
-
</Flex>
|
655 |
-
|
656 |
-
{image.status === 'completed' && (
|
657 |
-
<>
|
658 |
-
{editingImageId === image.id ? (
|
659 |
-
<Box mt={2}>
|
660 |
-
<Textarea
|
661 |
-
value={image.editedCaption}
|
662 |
-
onChange={(e) => handleEditCaptionChange(image.id, e.target.value)}
|
663 |
-
size="sm"
|
664 |
-
mb={2}
|
665 |
-
/>
|
666 |
-
<Flex justify="flex-end" gap={2}>
|
667 |
-
<Button size="xs" onClick={cancelEditingCaption}>
|
668 |
-
Cancel
|
669 |
-
</Button>
|
670 |
-
<Button
|
671 |
-
size="xs"
|
672 |
-
colorScheme="blue"
|
673 |
-
onClick={() => saveEditedCaption(image.id, image.editedCaption)}
|
674 |
-
>
|
675 |
-
Save
|
676 |
-
</Button>
|
677 |
-
</Flex>
|
678 |
-
</Box>
|
679 |
-
) : (
|
680 |
-
<Box mt={2} p={2} bg="gray.800" borderRadius="md">
|
681 |
-
<Text fontSize="sm">
|
682 |
-
{image.isEdited ? image.editedCaption : image.caption}
|
683 |
-
</Text>
|
684 |
-
<Flex justify="flex-end" mt={2} gap={2}>
|
685 |
-
{image.isEdited && (
|
686 |
-
<Tooltip label="Reset to original caption">
|
687 |
-
<Button
|
688 |
-
size="xs"
|
689 |
-
colorScheme="orange"
|
690 |
-
onClick={() => resetCaption(image.id)}
|
691 |
-
>
|
692 |
-
Reset
|
693 |
-
</Button>
|
694 |
-
</Tooltip>
|
695 |
-
)}
|
696 |
-
<Button
|
697 |
-
size="xs"
|
698 |
-
colorScheme="teal"
|
699 |
-
onClick={() => startEditingCaption(image.id)}
|
700 |
-
>
|
701 |
-
Edit
|
702 |
-
</Button>
|
703 |
-
</Flex>
|
704 |
-
</Box>
|
705 |
-
)}
|
706 |
-
</>
|
707 |
-
)}
|
708 |
-
|
709 |
-
{image.status === 'error' && (
|
710 |
-
<Box mt={2} p={2} bg="red.900" borderRadius="md">
|
711 |
-
<Text fontSize="sm" color="red.200">{image.error}</Text>
|
712 |
-
</Box>
|
713 |
-
)}
|
714 |
-
</Box>
|
715 |
-
</Box>
|
716 |
-
))}
|
717 |
-
</SimpleGrid>
|
718 |
-
) : (
|
719 |
-
<Box
|
720 |
-
textAlign="center"
|
721 |
-
p={10}
|
722 |
-
borderWidth="1px"
|
723 |
-
borderRadius="lg"
|
724 |
-
borderStyle="dashed"
|
725 |
-
>
|
726 |
-
<Text color="gray.500">Upload images to get started</Text>
|
727 |
</Box>
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
<Box as="footer" textAlign="center">
|
733 |
-
<Text fontSize="sm" color="gray.500">
|
734 |
-
Glif LoRA Autocaption • {new Date().getFullYear()}
|
735 |
-
</Text>
|
736 |
-
</Box>
|
737 |
-
</VStack>
|
738 |
-
</Container>
|
739 |
);
|
740 |
};
|
741 |
|
|
|
1 |
+
import React, { useState, useRef, useEffect, lazy, Suspense } from 'react';
|
2 |
import {
|
3 |
Box,
|
4 |
Container,
|
|
|
16 |
Badge,
|
17 |
Flex,
|
18 |
Divider,
|
19 |
+
Spinner,
|
20 |
Textarea,
|
21 |
Tooltip,
|
22 |
InputGroup,
|
|
|
26 |
HStack,
|
27 |
} from '@chakra-ui/react';
|
28 |
import axios from 'axios';
|
29 |
+
|
30 |
+
// Lazy load heavier components that aren't needed immediately
|
31 |
+
const JSZip = lazy(() => import('jszip'));
|
32 |
+
const { saveAs } = lazy(() => import('file-saver'));
|
33 |
|
34 |
// Function to get filename without extension
|
35 |
const getFilenameWithoutExtension = filename => {
|
|
|
343 |
setDownloading(true);
|
344 |
|
345 |
try {
|
346 |
+
// Dynamically import JSZip and file-saver only when needed
|
347 |
+
const [JSZip, { saveAs }] = await Promise.all([
|
348 |
+
import('jszip'),
|
349 |
+
import('file-saver')
|
350 |
+
]);
|
351 |
+
|
352 |
// Create a new zip file
|
353 |
+
const zip = new JSZip.default();
|
354 |
|
355 |
// Add text files to the zip with the same filenames as the images but .txt extension
|
356 |
completedImages.forEach(image => {
|
357 |
const fileName = getFilenameWithoutExtension(image.name) + ".txt";
|
|
|
358 |
const captionToSave = image.isEdited ? image.editedCaption : image.caption;
|
359 |
zip.file(fileName, captionToSave);
|
360 |
});
|
|
|
478 |
const hasCaptions = uploadedImages.some(img => img.status === 'completed' && img.caption);
|
479 |
|
480 |
return (
|
481 |
+
<Suspense fallback={
|
482 |
+
<Box display="flex" justifyContent="center" alignItems="center" height="100vh">
|
483 |
+
<Spinner size="xl" />
|
484 |
+
</Box>
|
485 |
+
}>
|
486 |
+
<Container maxW="container.xl" py={10}>
|
487 |
+
<VStack spacing={8} align="stretch">
|
488 |
+
<Box textAlign="center">
|
489 |
+
<Heading as="h1" size="2xl" mb={2} bgGradient="linear(to-r, cyan.400, blue.500, purple.600)" bgClip="text">
|
490 |
+
Glif LoRA Autocaption
|
491 |
+
</Heading>
|
492 |
+
<Text fontSize="lg" color="gray.400">
|
493 |
+
Generate captions for your images using Glif API
|
494 |
+
</Text>
|
495 |
+
</Box>
|
496 |
+
|
497 |
+
<Divider />
|
498 |
+
|
499 |
+
<Box>
|
500 |
+
<FormControl mb={4}>
|
501 |
+
<FormLabel>API Key</FormLabel>
|
502 |
+
<Flex>
|
503 |
+
<Input
|
504 |
+
type="password"
|
505 |
+
placeholder="Enter your Glif API key"
|
506 |
+
value={apiKey}
|
507 |
+
onChange={handleApiKeyChange}
|
508 |
+
mr={2}
|
509 |
+
/>
|
510 |
+
<Button
|
511 |
+
size="md"
|
512 |
+
onClick={clearApiKey}
|
513 |
+
variant="outline"
|
514 |
+
colorScheme="red"
|
515 |
+
>
|
516 |
+
Clear
|
517 |
+
</Button>
|
518 |
+
</Flex>
|
519 |
+
<Text fontSize="xs" color="gray.500" mt={1}>
|
520 |
+
Your API key is securely saved in your browser for future use.
|
521 |
+
</Text>
|
522 |
+
</FormControl>
|
523 |
+
|
524 |
+
<FormControl mb={4}>
|
525 |
+
<FormLabel>Custom Glif ID or URL</FormLabel>
|
526 |
+
<InputGroup>
|
527 |
+
<Input
|
528 |
+
type="text"
|
529 |
+
placeholder="Enter custom Glif ID or URL (optional)"
|
530 |
+
value={customGlifInput}
|
531 |
+
onChange={handleCustomGlifInputChange}
|
532 |
+
/>
|
533 |
+
<InputRightElement width="auto" mr={2}>
|
534 |
+
<Button size="sm" onClick={saveCustomGlifId} mr={2}>
|
535 |
+
Save
|
536 |
+
</Button>
|
537 |
+
<Button size="sm" onClick={clearCustomGlifId} variant="outline" colorScheme="red">
|
538 |
+
Clear
|
539 |
+
</Button>
|
540 |
+
</InputRightElement>
|
541 |
+
</InputGroup>
|
542 |
+
<Text fontSize="xs" color="gray.500" mt={1}>
|
543 |
+
Enter a custom Glif ID or URL to use for autocaption, follow the format here: https://glif.app/@saqib/glifs/cm7yya7850000la0ckalxpix2. Leave empty to use the default Glif.
|
544 |
+
</Text>
|
545 |
+
</FormControl>
|
546 |
+
|
547 |
+
<FormControl mb={4}>
|
548 |
+
<FormLabel>Trigger Word</FormLabel>
|
549 |
<Input
|
550 |
+
type="text"
|
551 |
+
placeholder="Enter trigger word (optional)"
|
552 |
+
value={triggerWord}
|
553 |
+
onChange={handleTriggerWordChange}
|
|
|
554 |
/>
|
555 |
+
<Text fontSize="xs" color="gray.500" mt={1}>
|
556 |
+
Add a trigger word to all captions (e.g., "masterpiece", "best quality").
|
557 |
+
</Text>
|
558 |
+
</FormControl>
|
559 |
+
|
560 |
+
<FormControl mb={4}>
|
561 |
+
<FormLabel>Trigger Word Placement</FormLabel>
|
562 |
+
<RadioGroup onChange={handleTriggerPlacementChange} value={triggerPlacement}>
|
563 |
+
<HStack spacing={4}>
|
564 |
+
<Radio value="none">No Trigger</Radio>
|
565 |
+
<Radio value="before">Before Caption</Radio>
|
566 |
+
<Radio value="after">After Caption</Radio>
|
567 |
+
</HStack>
|
568 |
+
</RadioGroup>
|
569 |
+
<Text fontSize="xs" color="gray.500" mt={1}>
|
570 |
+
Choose where to place the trigger word in relation to the generated caption.
|
571 |
+
</Text>
|
572 |
+
</FormControl>
|
573 |
+
|
574 |
+
<Flex flexWrap="wrap" gap={4} mb={6} justify="center">
|
575 |
+
<Button
|
576 |
+
onClick={() => fileInputRef.current?.click()}
|
577 |
+
variant="solid"
|
578 |
size="md"
|
579 |
+
disabled={processing}
|
|
|
|
|
580 |
>
|
581 |
+
Upload Images
|
582 |
+
</Button>
|
583 |
+
<input
|
584 |
+
type="file"
|
585 |
+
multiple
|
586 |
+
accept="image/*"
|
587 |
+
onChange={handleFileChange}
|
588 |
+
style={{ display: 'none' }}
|
589 |
+
ref={fileInputRef}
|
590 |
+
/>
|
591 |
+
|
592 |
+
<Button
|
593 |
+
onClick={processImages}
|
594 |
+
colorScheme="blue"
|
595 |
+
isLoading={processing}
|
596 |
+
loadingText="Processing"
|
597 |
+
disabled={processing || uploadedImages.filter(img => img.status === 'pending').length === 0}
|
598 |
+
>
|
599 |
+
Process Images
|
600 |
+
</Button>
|
601 |
+
|
602 |
+
<Button
|
603 |
+
onClick={downloadCaptions}
|
604 |
+
colorScheme="teal"
|
605 |
+
isLoading={downloading}
|
606 |
+
loadingText="Downloading"
|
607 |
+
disabled={downloading || !hasCaptions}
|
608 |
+
>
|
609 |
+
Download Captions
|
610 |
+
</Button>
|
611 |
+
|
612 |
+
<Button
|
613 |
+
onClick={clearAll}
|
614 |
+
variant="outline"
|
615 |
+
disabled={processing || uploadedImages.length === 0}
|
616 |
+
>
|
617 |
+
Clear All
|
618 |
</Button>
|
619 |
</Flex>
|
620 |
+
|
621 |
+
{processing && (
|
622 |
+
<Progress
|
623 |
+
value={progress}
|
624 |
+
size="sm"
|
625 |
+
colorScheme="blue"
|
626 |
+
hasStripe
|
627 |
+
mb={4}
|
628 |
+
borderRadius="md"
|
|
|
|
|
|
|
|
|
629 |
/>
|
630 |
+
)}
|
631 |
+
</Box>
|
632 |
+
|
633 |
+
{uploadedImages.length > 0 ? (
|
634 |
+
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={6}>
|
635 |
+
{uploadedImages.map((image) => (
|
636 |
+
<Box
|
637 |
+
key={image.id}
|
638 |
+
borderWidth="1px"
|
639 |
+
borderRadius="lg"
|
640 |
+
overflow="hidden"
|
641 |
+
bg="gray.900"
|
642 |
+
position="relative"
|
643 |
+
>
|
644 |
+
<Box position="absolute" top={2} right={2} zIndex={1}>
|
645 |
+
{getStatusBadge(image.status)}
|
646 |
+
{image.isEdited && (
|
647 |
+
<Badge ml={2} colorScheme="purple">Edited</Badge>
|
648 |
+
)}
|
649 |
+
</Box>
|
650 |
+
<Image
|
651 |
+
src={image.preview}
|
652 |
+
alt={image.name}
|
653 |
+
w="100%"
|
654 |
+
h="200px"
|
655 |
+
objectFit="cover"
|
656 |
+
/>
|
657 |
+
<Box p={4}>
|
658 |
+
<Flex justify="space-between" align="center" mb={2}>
|
659 |
+
<Text fontWeight="semibold" isTruncated maxW="70%">{image.name}</Text>
|
660 |
+
<Button
|
661 |
+
size="xs"
|
662 |
+
onClick={() => removeImage(image.id)}
|
663 |
+
disabled={processing}
|
664 |
+
>
|
665 |
+
Remove
|
666 |
+
</Button>
|
667 |
+
</Flex>
|
668 |
+
|
669 |
+
{image.status === 'completed' && (
|
670 |
+
<>
|
671 |
+
{editingImageId === image.id ? (
|
672 |
+
<Box mt={2}>
|
673 |
+
<Textarea
|
674 |
+
value={image.editedCaption}
|
675 |
+
onChange={(e) => handleEditCaptionChange(image.id, e.target.value)}
|
676 |
+
size="sm"
|
677 |
+
mb={2}
|
678 |
+
/>
|
679 |
+
<Flex justify="flex-end" gap={2}>
|
680 |
+
<Button size="xs" onClick={cancelEditingCaption}>
|
681 |
+
Cancel
|
682 |
+
</Button>
|
683 |
+
<Button
|
684 |
+
size="xs"
|
685 |
+
colorScheme="blue"
|
686 |
+
onClick={() => saveEditedCaption(image.id, image.editedCaption)}
|
687 |
+
>
|
688 |
+
Save
|
689 |
+
</Button>
|
690 |
+
</Flex>
|
691 |
+
</Box>
|
692 |
+
) : (
|
693 |
+
<Box mt={2} p={2} bg="gray.800" borderRadius="md">
|
694 |
+
<Text fontSize="sm">
|
695 |
+
{image.isEdited ? image.editedCaption : image.caption}
|
696 |
+
</Text>
|
697 |
+
<Flex justify="flex-end" mt={2} gap={2}>
|
698 |
+
{image.isEdited && (
|
699 |
+
<Tooltip label="Reset to original caption">
|
700 |
+
<Button
|
701 |
+
size="xs"
|
702 |
+
colorScheme="orange"
|
703 |
+
onClick={() => resetCaption(image.id)}
|
704 |
+
>
|
705 |
+
Reset
|
706 |
+
</Button>
|
707 |
+
</Tooltip>
|
708 |
+
)}
|
709 |
+
<Button
|
710 |
+
size="xs"
|
711 |
+
colorScheme="teal"
|
712 |
+
onClick={() => startEditingCaption(image.id)}
|
713 |
+
>
|
714 |
+
Edit
|
715 |
+
</Button>
|
716 |
+
</Flex>
|
717 |
+
</Box>
|
718 |
+
)}
|
719 |
+
</>
|
720 |
+
)}
|
721 |
+
|
722 |
+
{image.status === 'error' && (
|
723 |
+
<Box mt={2} p={2} bg="red.900" borderRadius="md">
|
724 |
+
<Text fontSize="sm" color="red.200">{image.error}</Text>
|
725 |
+
</Box>
|
726 |
+
)}
|
727 |
+
</Box>
|
728 |
+
</Box>
|
729 |
+
))}
|
730 |
+
</SimpleGrid>
|
731 |
+
) : (
|
732 |
+
<Box
|
733 |
+
textAlign="center"
|
734 |
+
p={10}
|
735 |
+
borderWidth="1px"
|
736 |
+
borderRadius="lg"
|
737 |
+
borderStyle="dashed"
|
738 |
>
|
739 |
+
<Text color="gray.500">Upload images to get started</Text>
|
740 |
+
</Box>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
741 |
)}
|
742 |
+
|
743 |
+
<Divider mt={6} />
|
744 |
+
|
745 |
+
<Box as="footer" textAlign="center">
|
746 |
+
<Text fontSize="sm" color="gray.500">
|
747 |
+
Glif LoRA Autocaption • {new Date().getFullYear()}
|
748 |
+
</Text>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
749 |
</Box>
|
750 |
+
</VStack>
|
751 |
+
</Container>
|
752 |
+
</Suspense>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
753 |
);
|
754 |
};
|
755 |
|
vite.config.js
CHANGED
@@ -4,8 +4,22 @@ import react from '@vitejs/plugin-react';
|
|
4 |
export default defineConfig({
|
5 |
plugins: [react()],
|
6 |
server: {
|
7 |
-
port: 7860,
|
8 |
host: '0.0.0.0',
|
9 |
allowedHosts: ["saq1b-glif-lora-autocaption.hf.space"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
}
|
11 |
});
|
|
|
4 |
export default defineConfig({
|
5 |
plugins: [react()],
|
6 |
server: {
|
7 |
+
port: 7860,
|
8 |
host: '0.0.0.0',
|
9 |
allowedHosts: ["saq1b-glif-lora-autocaption.hf.space"]
|
10 |
+
},
|
11 |
+
build: {
|
12 |
+
rollupOptions: {
|
13 |
+
output: {
|
14 |
+
manualChunks: {
|
15 |
+
'chakra': ['@chakra-ui/react', '@emotion/react', '@emotion/styled', 'framer-motion'],
|
16 |
+
'utils': ['jszip', 'file-saver', 'axios']
|
17 |
+
}
|
18 |
+
}
|
19 |
+
},
|
20 |
+
chunkSizeWarningLimit: 1000
|
21 |
+
},
|
22 |
+
optimizeDeps: {
|
23 |
+
include: ['@chakra-ui/react', '@emotion/react', '@emotion/styled', 'framer-motion']
|
24 |
}
|
25 |
});
|