mirror of
https://github.com/dataelement/bisheng.git
synced 2026-09-01 04:47:53 +08:00
fix: product feature review
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
"inputPlaceholder": "请输入问题",
|
||||
"uploadFileTooltip": "上传文件",
|
||||
"sendTooltip": "发送",
|
||||
"forms": "表单",
|
||||
"skillTempsTitle": "技能选择",
|
||||
"skillTempsDesc": "选择一个您想使用的线上技能",
|
||||
"networkError": "网络连接出现错误,请尝试以下方法",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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> */}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user