fix: product feature review

This commit is contained in:
dolphin
2024-03-01 18:27:40 +08:00
parent fe0b282ab9
commit 80da30c640
16 changed files with 103 additions and 73 deletions
+1
View File
@@ -100,6 +100,7 @@
"inputPlaceholder": "Enter your question",
"uploadFileTooltip": "Upload File",
"sendTooltip": "Send",
"forms": "Forms",
"skillTempsTitle": "Skill Selection",
"skillTempsDesc": "Choose an online skill you want to use",
"skillDeleted": "This skill has been deleted",
+1
View File
@@ -97,6 +97,7 @@
"inputPlaceholder": "请输入问题",
"uploadFileTooltip": "上传文件",
"sendTooltip": "发送",
"forms": "表单",
"skillTempsTitle": "技能选择",
"skillTempsDesc": "选择一个您想使用的线上技能",
"networkError": "网络连接出现错误,请尝试以下方法",
+13 -15
View File
@@ -34,21 +34,19 @@ export const getTasksApi = async (params: Tasks_query): Promise<TaskDB[]> => {
// 创建任务
export const createTaskApi = async (data: any): Promise<TaskDB> => {
const train_data = data.train_data?.map(el => ({
id: el.id,
num: el.sampleSize,
url: el.dataSource,
name: el.name
})) || []
const preset_data = data.preset_data?.reduce((res, el) => {
const item = {
id: el.id,
num: el.sampleSize,
url: el.dataSource,
name: el.name
}
return el.checked ? [...res, item] : res
}, []) || []
const filterData = (arr) => {
return arr?.reduce((res, el) => {
const item = {
id: el.id,
num: el.sampleSize,
url: el.dataSource,
name: el.name
}
return el.checked ? [...res, item] : res
}, []) || []
}
const train_data = filterData(data.train_data)
const preset_data = filterData(data.preset_data)
return await axios.post(`/api/v1/finetune/job`, { ...data, train_data, preset_data });
};
@@ -1,5 +1,5 @@
import cloneDeep from "lodash-es/cloneDeep";
import { FileInput, Send, StopCircle } from "lucide-react";
import { ClipboardList, FileInput, FileText, Send, StopCircle } from "lucide-react";
import { forwardRef, useContext, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import ShadTooltip from "../../../components/ShadTooltipComponent";
@@ -222,8 +222,8 @@ export default forwardRef(function ChatPanne({ chatId, flow, queryString, versio
}}></textarea>
<div className="absolute right-6 bottom-4 flex gap-2">
{
isForm && <ShadTooltip content={t('chat.sendTooltip')}>
<button disabled={chating} className=" disabled:text-gray-400" onClick={() => setFormShow(!formShow)}><FileInput /></button>
isForm && <ShadTooltip content={t('chat.forms')}>
<button disabled={chating} className=" disabled:text-gray-400" onClick={() => setFormShow(!formShow)}><ClipboardList /></button>
</ShadTooltip>
}
<ShadTooltip content={t('chat.sendTooltip')}>
@@ -57,7 +57,7 @@ export default function ChatReportForm({ flow, onStart }) {
}
return <div className="absolute right-20 bottom-32 w-[90%] max-w-[680px] flex flex-col gap-6 rounded-xl p-4 md:p-6 border bg-gray-50">
<div className="max-h-[600px] overflow-y-auto">
<div className="max-h-[520px] overflow-y-auto">
{items.map((item, i) => <div key={item.id} className="w-full text-sm">
{item.name}
<span className="text-status-red">{item.required ? " *" : ""}</span>
+5 -2
View File
@@ -16,7 +16,7 @@ import {
TabsTrigger,
} from "../../components/ui/tabs";
import { ArrowLeft, Filter, RotateCw } from "lucide-react";
import { ArrowLeft, Filter, RotateCw, Search } from "lucide-react";
import { useContext, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { bsconfirm } from "../../alerts/confirm";
@@ -122,7 +122,10 @@ export default function FilesPage() {
<div className="flex justify-between items-center">
<span className=" text-gray-800">{title}</span>
<div className="flex gap-4 items-center">
<Input placeholder={t('lib.fileName')} className="w-[140px]" onChange={(e) => search(e.target.value)}></Input>
<div className="w-[180px] relative">
<Input placeholder={t('lib.fileName')} onChange={(e) => search(e.target.value)}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
{hasPermission && <Button className="h-8 rounded-full" onClick={() => setOpen(true)}>{t('lib.upload')}</Button>}
</div>
</div>
+5 -1
View File
@@ -28,6 +28,7 @@ import { createFileLib, deleteFileLib, getEmbeddingModel, readFileLibDatabase }
import { captureAndAlertRequestErrorHoc } from "../../controllers/request";
import PaginationComponent from "../../components/PaginationComponent";
import { useTable } from "../../util/hook";
import { Search } from "lucide-react";
function CreateModal({ datalist, open, setOpen }) {
const { t } = useTranslation()
@@ -164,7 +165,10 @@ export default function FileLibPage() {
<TabsContent value="account">
<div className="flex justify-end gap-4 items-center">
<Input placeholder={t('lib.libraryName')} className="w-[140px]" onChange={(e) => search(e.target.value)}></Input>
<div className="w-[180px] relative">
<Input placeholder={t('lib.libraryName')} onChange={(e) => search(e.target.value)}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
<Button className="h-8 rounded-full" onClick={() => setOpen(true)}>{t('create')}</Button>
</div>
<Table>
@@ -22,7 +22,7 @@ export default function CreateTaskList({ onChange }) {
const { prsetList, handleChangePrsetList } = usePresetList(onChange)
const [downloadMap, setDownloadMap] = useState({}) // 下载loading
// 个人数据集
const { userList, setUserList, handleChangeUserList } = useUserList(onChange);
const { userList, setUserList, handleChangeUserList, handleUploadUserList } = useUserList(onChange);
const [isCustom, setIsCustom] = useState(false)
@@ -41,7 +41,7 @@ export default function CreateTaskList({ onChange }) {
accept={['json']}
onClose={closePopUp}
onUpload={uploadTaskFileApi}
onSubmit={(res) => handleChangeUserList(res, closePopUp)}
onSubmit={(res) => handleUploadUserList(res, closePopUp)}
/>)}>{t('finetune.uploadDataset')}</Button>
<Button variant="link" onClick={() => downloadJson(sampleData)}>{t('finetune.downloadSampleFile')}</Button>
</div>
@@ -93,7 +93,9 @@ export default function CreateTaskList({ onChange }) {
{
userList.length ? userList.map(data =>
<div className="flex gap-4 items-center mt-2 h-8 hover:bg-gray-200">
<Checkbox checked={data.checked} />
<Checkbox
checked={data.checked}
onCheckedChange={(val: boolean) => handleChangeUserList(data.id, 'checked', val)} />
<span className="text-sm">{data.name}</span>
<div className="flex ml-auto gap-4">
<Button
@@ -113,14 +115,7 @@ export default function CreateTaskList({ onChange }) {
placeholder={t('finetune.sampleSizePlaceholder')}
type="number"
value={data.sampleSize}
onChange={(e) => {
setUserList(prev => {
const newData = prev.map(item =>
item.id === data.id ? { ...item, sampleSize: Number(e.target.value) } : item);
onChange('train_data', newData)
return newData
})
}}
onChange={(e) => handleChangeUserList(data.id, 'sampleSize', e.target.value)}
className="bg-[#fff] rounded-full w-28 h-6"
></Input> :
<Badge variant="outline" className="text-sm">{t('finetune.sampleSize')}:{data.sampleSize}</Badge>}
@@ -158,7 +153,7 @@ export function usePresetList(onChange) {
export function useUserList(onChange) {
const [userList, setUserList] = useState([]);
const handleChangeUserList = (res, closePopUp) => {
const handleUploadUserList = (res, closePopUp) => {
setUserList(state => {
const newState = [...res[0], ...state];
onChange('train_data', newState);
@@ -167,5 +162,15 @@ export function useUserList(onChange) {
closePopUp();
};
return { userList, setUserList, handleChangeUserList };
const handleChangeUserList = (id, key, val) => {
setUserList((prevState) => {
const newState = prevState.map(item =>
item.id === id ? { ...item, [key]: val } : item);
onChange('train_data', newState);
return newState;
});
};
return { userList, setUserList, handleChangeUserList, handleUploadUserList };
}
@@ -14,6 +14,7 @@ import {
import { ToggleGroup, ToggleGroupItem } from "../../../components/ui/toggle-group";
import { getAllServicesApi, getServicesApi } from "../../../controllers/API";
import { useDebounce } from "../../../util/hook";
import { Search } from "lucide-react";
interface IProps {
onSearch: (searchkey) => void,
@@ -76,7 +77,10 @@ export default function FinetuneHead({ onSearch, onFilter, rtClick, onCreate }:
</SelectGroup>
</SelectContent>
</Select>
<Input ref={inputRef} className="w-[140px]" placeholder={t('finetune.modelName')} onChange={useDebounce(handleSearch, 600, false)}></Input>
<div className="w-[180px] relative">
<Input ref={inputRef} placeholder={t('finetune.modelName')} onChange={useDebounce(handleSearch, 600, false)}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
</div>
<div className="flex gap-4">
<Button size="sm" className="rounded-full h-8" onClick={onCreate}>{t('finetune.createTrainingTask')}</Button>
+1 -1
View File
@@ -35,7 +35,7 @@ export const CpuDetail = ({ type }) => {
return <Table className="w-full">
<TableHeader>
<TableRow>
<TableHead className="w-[200px]">{t('model.machine')}</TableHead>
<TableHead className="w-[200px]">{t('model.machineName')}</TableHead>
<TableHead>{t('model.gpuNumber')}</TableHead>
<TableHead>{t('model.gpuID')}</TableHead>
<TableHead>{t('model.totalMemory')}</TableHead>
+23 -21
View File
@@ -53,27 +53,29 @@ export const Finetune = ({ rtClick, gpuClick }) => {
{tasks?.length === 0 ?
<div className="mt-6 text-center text-gray-400">{t('finetune.noData')}</div>
: <div className="flex gap-4 mt-4">
<div className="w-[40%] border-r overflow-y-auto max-h-[calc(100vh-180px)]">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">{t('finetune.modelName')}</TableHead>
<TableHead></TableHead>
<TableHead>{t('finetune.rtService')}</TableHead>
<TableHead className="text-right">{t('finetune.createTime')}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tasks.map((task) => (
<TableRow key={task.id} onClick={() => changeItem(task.id)} className={`cursor-pointer ${task.id === taskId && 'bg-gray-100'}`}>
<TableCell className="font-medium">{task.model_name}</TableCell>
<TableCell><BadgeView value={task.status}></BadgeView></TableCell>
<TableCell>{task.server_name}</TableCell>
<TableCell className="text-right">{task.create_time.replace('T', ' ')}</TableCell>
<div className="w-[40%]">
<div className="border-r overflow-y-auto max-h-[calc(100vh-208px)]">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">{t('finetune.modelName')}</TableHead>
<TableHead></TableHead>
<TableHead>{t('finetune.rtService')}</TableHead>
<TableHead className="text-right">{t('finetune.createTime')}</TableHead>
</TableRow>
))}
</TableBody>
</Table>
</TableHeader>
<TableBody>
{tasks.map((task) => (
<TableRow key={task.id} onClick={() => changeItem(task.id)} className={`cursor-pointer ${task.id === taskId && 'bg-gray-100'}`}>
<TableCell className="font-medium">{task.model_name}</TableCell>
<TableCell><BadgeView value={task.status}></BadgeView></TableCell>
<TableCell>{task.server_name}</TableCell>
<TableCell className="text-right">{task.create_time.replace('T', ' ')}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<PaginationComponent
page={page}
pageSize={pageSize}
@@ -81,7 +83,7 @@ export const Finetune = ({ rtClick, gpuClick }) => {
onChange={(newPage) => setPage(newPage)}
/>
</div>
<div className="flex-1 overflow-hidden">
<div className="flex-1 overflow-hidden overflow-y-auto max-h-[calc(100vh-180px)]">
{taskId ?
<FinetuneDetail id={taskId} onDelete={handleDeleteTask} onStatusChange={reload}></FinetuneDetail> :
<div className="flex justify-center items-center h-full">
+1 -1
View File
@@ -225,7 +225,7 @@ export default function FileLibPage() {
<TableCaption>{t('model.modelCollectionCaption')}.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[200px]">{t('model.machine')}</TableHead>
<TableHead className="w-[200px]">{t('model.machineName')}</TableHead>
<TableHead>{t('model.modelName')}</TableHead>
<TableHead>{t('model.serviceAddress')}</TableHead>
<TableHead>{t('model.status')}</TableHead>
+10 -7
View File
@@ -16,6 +16,7 @@ import CreateTemp from "./components/CreateTemp";
import SkillTemps from "./components/SkillTemps";
import Templates from "./temps";
import { captureAndAlertRequestErrorHoc } from "../../controllers/request";
import { Search } from "lucide-react";
export default function SkillPage() {
const { t } = useTranslation()
@@ -73,13 +74,15 @@ export default function SkillPage() {
<Button className="h-8 rounded-full" onClick={() => setOpen(true)}>{t('skills.createNew')}</Button>
</div>
<span className="main-page-description-text">{t('skills.manageProjects')}</span>
<Input
ref={inputRef}
defaultValue={window.SearchSkillsPage?.key || ''}
placeholder={t('skills.skillSearch')}
className=" w-[400px] relative top-[-20px]"
onChange={e => search(e.target.value)}></Input>
<div className="w-[400px] relative top-[-20px]">
<Input
ref={inputRef}
defaultValue={window.SearchSkillsPage?.key || ''}
placeholder={t('skills.skillSearch')}
className=""
onChange={e => search(e.target.value)}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
{/* cards */}
<div className="w-full flex flex-wrap mt-1">
{page.flows.map((flow) => (
@@ -16,6 +16,7 @@ import { captureAndAlertRequestErrorHoc } from "../../../controllers/request";
import { ROLE } from "../../../types/api/user";
import EditRole from "./EditRole";
import { Input } from "../../../components/ui/input";
import { Search } from "lucide-react";
export default function Roles() {
const { t } = useTranslation()
@@ -68,7 +69,10 @@ export default function Roles() {
return <div className=" relative">
<div className="flex gap-4 items-center justify-end">
<Input value={searchWord} placeholder={t('system.roleName')} className="w-[140px]" onChange={handleSearch}></Input>
<div className="w-[180px] relative">
<Input value={searchWord} placeholder={t('system.roleName')} onChange={handleSearch}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
<Button className="h-8 rounded-full" onClick={() => setRole({})}>{t('create')}</Button>
</div>
<Table>
@@ -16,6 +16,7 @@ import { captureAndAlertRequestErrorHoc } from "../../../controllers/request";
import { useTable } from "../../../util/hook";
import { Input } from "../../../components/ui/input";
import PaginationComponent from "../../../components/PaginationComponent";
import { Search } from "lucide-react";
export default function Users(params) {
const { user } = useContext(userContext);
@@ -49,7 +50,10 @@ export default function Users(params) {
return <>
<div className="flex justify-end">
<Input placeholder={t('system.username')} className="w-[140px]" onChange={(e) => search(e.target.value)}></Input>
<div className="w-[180px] relative">
<Input placeholder={t('system.username')} onChange={(e) => search(e.target.value)}></Input>
<Search className="absolute right-4 top-2 text-gray-300 pointer-events-none"></Search>
</div>
</div>
<Table>
{/* <TableCaption>用户列表.</TableCaption> */}
+6 -5
View File
@@ -4,7 +4,7 @@ import { alertContext } from "../contexts/alertContext";
import { useTranslation } from "react-i18next";
// 防抖
export function useDebounce(func: any, wait: number, immediate: boolean, callback?: any,): (any) => any {
export function useDebounce(func: any, wait: number, immediate: boolean, callback?: any,): (any?: any) => any {
let timer = useRef<NodeJS.Timeout | null>();
const fnRef = useRef<any>(func);
useEffect(() => { fnRef.current = func; }, [func]);
@@ -82,9 +82,10 @@ export function useTable(apiFun) {
setLoading(false);
})
}
const debounceLoad = useDebounce(loadData, 600, false)
useEffect(() => {
loadData();
debounceLoad();
}, [page])
return {
@@ -94,15 +95,15 @@ export function useTable(apiFun) {
loading,
data,
setPage: (p) => setPage({ ...page, page: p }),
reload: loadData,
reload: debounceLoad,
// 检索
search: useDebounce((keyword) => {
setPage({ ...page, page: 1, keyword });
}, 600, false),
}, 100, false),
// 数据过滤
filterData: (p) => {
paramRef.current = { ...paramRef.current, ...p };
loadData()
debounceLoad()
},
// 更新数据
refreshData: (compareFn, data) => {