diff --git a/web/app/components/runOnce/text-generation/icons/star.svg b/web/app/components/runOnce/text-generation/icons/star.svg new file mode 100644 index 0000000000..e86a14285e --- /dev/null +++ b/web/app/components/runOnce/text-generation/icons/star.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web/app/components/runOnce/text-generation/no-data/index.tsx b/web/app/components/runOnce/text-generation/no-data/index.tsx new file mode 100644 index 0000000000..7492614131 --- /dev/null +++ b/web/app/components/runOnce/text-generation/no-data/index.tsx @@ -0,0 +1,26 @@ +import type { FC } from 'react' +import React from 'react' +import { useTranslation } from 'react-i18next' + +const StarIcon = ( + + + + +) + +export type INoDataProps = {} +const NoData: FC = () => { + const { t } = useTranslation() + return ( +
+ {StarIcon} +
+ {t('share.generation.noData')} +
+
+ ) +} +export default React.memo(NoData) diff --git a/web/app/components/runOnce/text-generation/result/content.tsx b/web/app/components/runOnce/text-generation/result/content.tsx new file mode 100644 index 0000000000..4e39db42c8 --- /dev/null +++ b/web/app/components/runOnce/text-generation/result/content.tsx @@ -0,0 +1,34 @@ +import type { FC } from 'react' +import React from 'react' +import Header from './header' +import type { FeedbackType } from '@/app/components/base/chat/chat/type' +import { format } from '@/service/base' + +export type IResultProps = { + content: string + showFeedback: boolean + feedback: FeedbackType + onFeedback: (feedback: FeedbackType) => void +} +const Result: FC = ({ + content, + showFeedback, + feedback, + onFeedback, +}) => { + return ( +
+
+
+
+ ) +} +export default React.memo(Result) diff --git a/web/app/components/runOnce/text-generation/result/header.tsx b/web/app/components/runOnce/text-generation/result/header.tsx new file mode 100644 index 0000000000..0233b098d0 --- /dev/null +++ b/web/app/components/runOnce/text-generation/result/header.tsx @@ -0,0 +1,113 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { ClipboardDocumentIcon, HandThumbDownIcon, HandThumbUpIcon } from '@heroicons/react/24/outline' +import copy from 'copy-to-clipboard' +import type { FeedbackType } from '@/app/components/base/chat/chat/type' +import Button from '@/app/components/base/button' +import Toast from '@/app/components/base/toast' +import Tooltip from '@/app/components/base/tooltip' + +type IResultHeaderProps = { + result: string + showFeedback: boolean + feedback: FeedbackType + onFeedback: (feedback: FeedbackType) => void +} + +const Header: FC = ({ + feedback, + showFeedback, + onFeedback, + result, +}) => { + const { t } = useTranslation() + return ( +
+
{t('share.generation.resultTitle')}
+
+ + + {showFeedback && feedback.rating && feedback.rating === 'like' && ( + +
{ + onFeedback({ + rating: null, + }) + }} + className='flex w-7 h-7 items-center justify-center rounded-md cursor-pointer !text-primary-600 border border-primary-200 bg-primary-100 hover:border-primary-300 hover:bg-primary-200'> + +
+
+ )} + + {showFeedback && feedback.rating && feedback.rating === 'dislike' && ( + +
{ + onFeedback({ + rating: null, + }) + }} + className='flex w-7 h-7 items-center justify-center rounded-md cursor-pointer !text-red-600 border border-red-200 bg-red-100 hover:border-red-300 hover:bg-red-200'> + +
+
+ )} + + {showFeedback && !feedback.rating && ( +
+ +
{ + onFeedback({ + rating: 'like', + }) + }} + className='flex w-6 h-6 items-center justify-center rounded-md cursor-pointer hover:bg-gray-100'> + +
+
+ +
{ + onFeedback({ + rating: 'dislike', + }) + }} + className='flex w-6 h-6 items-center justify-center rounded-md cursor-pointer hover:bg-gray-100'> + +
+
+
+ )} +
+ +
+ ) +} + +export default React.memo(Header) diff --git a/web/app/components/runOnce/text-generation/run-batch/csv-download/index.tsx b/web/app/components/runOnce/text-generation/run-batch/csv-download/index.tsx new file mode 100644 index 0000000000..2d50725b54 --- /dev/null +++ b/web/app/components/runOnce/text-generation/run-batch/csv-download/index.tsx @@ -0,0 +1,70 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { + useCSVDownloader, +} from 'react-papaparse' +import { useTranslation } from 'react-i18next' +import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general' + +export type ICSVDownloadProps = { + vars: { name: string }[] +} + +const CSVDownload: FC = ({ + vars, +}) => { + const { t } = useTranslation() + const { CSVDownloader, Type } = useCSVDownloader() + const addQueryContentVars = [...vars] + const template = (() => { + const res: Record = {} + addQueryContentVars.forEach((item) => { + res[item.name] = '' + }) + return res + })() + + return ( +
+
{t('share.generation.csvStructureTitle')}
+
+ + + + {addQueryContentVars.map((item, i) => ( + + ))} + + + + + {addQueryContentVars.map((item, i) => ( + + ))} + + +
{item.name}
{item.name} {t('share.generation.field')}
+
+ +
+ + {t('share.generation.downloadTemplate')} +
+
+
+ + ) +} +export default React.memo(CSVDownload) diff --git a/web/app/components/runOnce/text-generation/run-batch/csv-reader/index.tsx b/web/app/components/runOnce/text-generation/run-batch/csv-reader/index.tsx new file mode 100644 index 0000000000..ac51bca6e6 --- /dev/null +++ b/web/app/components/runOnce/text-generation/run-batch/csv-reader/index.tsx @@ -0,0 +1,70 @@ +'use client' +import type { FC } from 'react' +import React, { useState } from 'react' +import { + useCSVReader, +} from 'react-papaparse' +import { useTranslation } from 'react-i18next' +import s from './style.module.css' +import cn from '@/utils/classnames' +import { Csv as CSVIcon } from '@/app/components/base/icons/src/public/files' + +export type Props = { + onParsed: (data: string[][]) => void +} + +const CSVReader: FC = ({ + onParsed, +}) => { + const { t } = useTranslation() + const { CSVReader } = useCSVReader() + const [zoneHover, setZoneHover] = useState(false) + return ( + { + onParsed(results.data) + setZoneHover(false) + }} + onDragOver={(event: DragEvent) => { + event.preventDefault() + setZoneHover(true) + }} + onDragLeave={(event: DragEvent) => { + event.preventDefault() + setZoneHover(false) + }} + > + {({ + getRootProps, + acceptedFile, + }: any) => ( + <> +
+ { + acceptedFile + ? ( +
+ +
+ {acceptedFile.name.replace(/.csv$/, '')} + .csv +
+
+ ) + : ( +
+ +
{t('share.generation.csvUploadTitle')}{t('share.generation.browse')}
+
+ )} +
+ + )} +
+ ) +} + +export default React.memo(CSVReader) diff --git a/web/app/components/runOnce/text-generation/run-batch/csv-reader/style.module.css b/web/app/components/runOnce/text-generation/run-batch/csv-reader/style.module.css new file mode 100644 index 0000000000..ff0b6aa157 --- /dev/null +++ b/web/app/components/runOnce/text-generation/run-batch/csv-reader/style.module.css @@ -0,0 +1,11 @@ +.zone { + @apply flex items-center h-20 rounded-xl bg-gray-50 border border-gray-200 cursor-pointer text-sm font-normal; +} + +.zoneHover { + @apply border-solid bg-gray-100; +} + +.info { + @apply text-gray-800 text-sm; +} \ No newline at end of file diff --git a/web/app/components/runOnce/text-generation/run-batch/index.tsx b/web/app/components/runOnce/text-generation/run-batch/index.tsx new file mode 100644 index 0000000000..2a632f9cfc --- /dev/null +++ b/web/app/components/runOnce/text-generation/run-batch/index.tsx @@ -0,0 +1,59 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { + PlayIcon, +} from '@heroicons/react/24/solid' +import { useTranslation } from 'react-i18next' +import { + RiLoader2Line, +} from '@remixicon/react' +import CSVReader from './csv-reader' +import CSVDownload from './csv-download' +import cn from '@/utils/classnames' +import Button from '@/app/components/base/button' +export type IRunBatchProps = { + vars: { name: string }[] + onSend: (data: string[][]) => void + isAllFinished: boolean +} + +const RunBatch: FC = ({ + vars, + onSend, + isAllFinished, +}) => { + const { t } = useTranslation() + + const [csvData, setCsvData] = React.useState([]) + const [isParsed, setIsParsed] = React.useState(false) + const handleParsed = (data: string[][]) => { + setCsvData(data) + // console.log(data) + setIsParsed(true) + } + + const handleSend = () => { + onSend(csvData) + } + const Icon = isAllFinished ? PlayIcon : RiLoader2Line + return ( +
+ + +
+
+ +
+
+ ) +} +export default React.memo(RunBatch) diff --git a/web/app/components/runOnce/text-generation/run-batch/res-download/index.tsx b/web/app/components/runOnce/text-generation/run-batch/res-download/index.tsx new file mode 100644 index 0000000000..f835ff70b9 --- /dev/null +++ b/web/app/components/runOnce/text-generation/run-batch/res-download/index.tsx @@ -0,0 +1,41 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import { + useCSVDownloader, +} from 'react-papaparse' +import { useTranslation } from 'react-i18next' +import cn from '@/utils/classnames' +import { Download02 as DownloadIcon } from '@/app/components/base/icons/src/vender/solid/general' +import Button from '@/app/components/base/button' +export type IResDownloadProps = { + isMobile: boolean + values: Record[] +} + +const ResDownload: FC = ({ + isMobile, + values, +}) => { + const { t } = useTranslation() + const { CSVDownloader, Type } = useCSVDownloader() + + return ( + + + + ) +} +export default React.memo(ResDownload)