excel-upload.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { ChatContext } from '@/app/chat-context';
  2. import { apiInterceptors, postChatModeParamsFileLoad } from '@/client/api';
  3. import { LinkOutlined, SelectOutlined, UploadOutlined } from '@ant-design/icons';
  4. import { Button, Tooltip, Upload, UploadFile, UploadProps, message } from 'antd';
  5. import { PropsWithChildren, useContext, useState } from 'react';
  6. interface Props {
  7. convUid: string;
  8. chatMode: string;
  9. onComplete?: () => void;
  10. }
  11. function ExcelUpload({ convUid, chatMode, onComplete, ...props }: PropsWithChildren<Props & UploadProps>) {
  12. const [loading, setLoading] = useState(false);
  13. const [messageApi, contextHolder] = message.useMessage();
  14. const [fileList, setFileList] = useState<UploadFile[]>([]);
  15. const [percent, setPercent] = useState<number>();
  16. const { model } = useContext(ChatContext);
  17. const onChange: UploadProps['onChange'] = async info => {
  18. if (!info) {
  19. message.error('Please select the *.(csv|xlsx|xls) file');
  20. return;
  21. }
  22. if (!/\.(csv|xlsx|xls)$/.test(info.file.name ?? '')) {
  23. message.error('File type must be csv, xlsx or xls');
  24. return;
  25. }
  26. setFileList([info.file]);
  27. };
  28. const onUpload = async () => {
  29. setLoading(true);
  30. try {
  31. const formData = new FormData();
  32. formData.append('doc_file', fileList[0] as any);
  33. messageApi.open({ content: `Uploading ${fileList[0].name}`, type: 'loading', duration: 0 });
  34. const [err] = await apiInterceptors(
  35. postChatModeParamsFileLoad({
  36. convUid,
  37. chatMode,
  38. data: formData,
  39. model,
  40. config: {
  41. /** timeout 1h */
  42. timeout: 1000 * 60 * 60,
  43. onUploadProgress: progressEvent => {
  44. const progress = Math.ceil((progressEvent.loaded / (progressEvent.total || 0)) * 100);
  45. setPercent(progress);
  46. },
  47. },
  48. }),
  49. );
  50. if (err) return;
  51. message.success('success');
  52. onComplete?.();
  53. } catch (e: any) {
  54. message.error(e?.message || 'Upload Error');
  55. } finally {
  56. setLoading(false);
  57. messageApi.destroy();
  58. }
  59. };
  60. return (
  61. <>
  62. <div className='flex items-start gap-2'>
  63. {contextHolder}
  64. <Tooltip placement='bottom' title='File cannot be changed after upload'>
  65. <Upload
  66. disabled={loading}
  67. className='mr-1'
  68. beforeUpload={() => false}
  69. fileList={fileList}
  70. name='file'
  71. accept='.csv,.xlsx,.xls'
  72. multiple={false}
  73. onChange={onChange}
  74. showUploadList={{
  75. showDownloadIcon: false,
  76. showPreviewIcon: false,
  77. showRemoveIcon: false,
  78. }}
  79. itemRender={() => <></>}
  80. {...props}
  81. >
  82. <Button
  83. className='flex justify-center items-center'
  84. type='primary'
  85. disabled={loading}
  86. icon={<SelectOutlined />}
  87. >
  88. Select File
  89. </Button>
  90. </Upload>
  91. </Tooltip>
  92. <Button
  93. type='primary'
  94. loading={loading}
  95. className='flex justify-center items-center'
  96. disabled={!fileList.length}
  97. icon={<UploadOutlined />}
  98. onClick={onUpload}
  99. >
  100. {loading ? (percent === 100 ? 'Analysis' : 'Uploading') : 'Upload'}
  101. </Button>
  102. {!!fileList.length && (
  103. <div className='mt-2 text-gray-500 text-sm flex items-center' onClick={() => setFileList([])}>
  104. <LinkOutlined className='mr-2' />
  105. <span>{fileList[0]?.name}</span>
  106. </div>
  107. )}
  108. </div>
  109. </>
  110. );
  111. }
  112. export default ExcelUpload;