CzRger пре 3 месеци
родитељ
комит
4b329b2866

+ 94 - 0
web/app/components/skill/corpus/index.tsx

@@ -0,0 +1,94 @@
+'use client'
+
+import List from './list'
+import React, { useEffect, useState } from 'react'
+import Input from '@/app/components/base/input'
+import cn from '@/utils/classnames'
+import { RiAddLine, RiRefreshLine, RiSearchLine } from '@remixicon/react'
+import Button from '@/app/components/base/button'
+import useSWR from 'swr'
+import { fetchCorpus } from '@/service/common'
+
+const CorpusIndex = () => {
+  const [page, setPage] = React.useState<number>(0)
+  const [limit, setLimit] = useState<number>(10)
+  const [inputValue, setInputValue] = useState<string>('') // the input value
+  const [query, setQuery] = useState<any>({})
+  const { data, mutate }: any = useSWR(
+    {
+      url: '/xxx',
+      params: {
+        page: page + 1,
+        limit,
+        ...query,
+      },
+    },
+    fetchCorpus,
+  )
+  const list: any = data?.data || []
+  const total = data?.total || 0
+  const handleSearch = () => {
+    const params: any = {}
+    if (inputValue)
+      params.question = inputValue
+
+    setQuery(params)
+    setPage(0)
+  }
+  useEffect(() => {
+    console.log(234234)
+    mutate()
+  }, [page, limit])
+  return (
+    <>
+      <div className='flex h-full w-full flex-col bg-background-default-subtle p-6'>
+        <div className="flex items-center gap-2">
+          <div className="flex shrink-0 items-center text-gray-500">
+            标准问题
+            <Input
+              className="ml-1"
+              showClearIcon
+              wrapperClassName='!w-[200px]'
+              value={inputValue}
+              onChange={e => setInputValue(e.target.value)}
+              onClear={() => setInputValue('')}
+            />
+          </div>
+          <Button variant='primary' className={cn('ml-auto shrink-0')} onClick={() => {
+            handleSearch()
+          }}>
+            <RiSearchLine className='mr-1 h-4 w-4' />
+            搜索
+          </Button>
+          <Button variant='primary' className={cn('shrink-0')} onClick={() => {
+            setInputValue('')
+            handleSearch()
+          }}>
+            <RiRefreshLine className='mr-1 h-4 w-4' />
+            重置
+          </Button>
+        </div>
+        <div className="mt-2">
+          <Button variant='primary' className={cn('shrink-0')}>
+            <RiAddLine className='mr-1 h-4 w-4' />
+            新增
+          </Button>
+        </div>
+        <div className="flex-1">
+          <List
+            list={list || []}
+            onUpdate={mutate}
+            pagination={{
+              total,
+              limit,
+              onLimitChange: setLimit,
+              current: page,
+              onChange: setPage,
+            }}
+          />
+        </div>
+      </div>
+    </>
+  )
+}
+export default CorpusIndex

+ 68 - 0
web/app/components/skill/corpus/list.tsx

@@ -0,0 +1,68 @@
+'use client'
+import Pagination, { type Props as PaginationProps } from '@/app/components/base/pagination'
+import type { FC } from 'react'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+
+type PageListProps = {
+  list: []
+  pagination: PaginationProps
+  onUpdate: () => void
+}
+
+const CorpusPageList: FC<PageListProps> = ({
+  list = [],
+  pagination,
+  onUpdate,
+}) => {
+  console.log(list)
+  console.log(pagination)
+  return (
+    <div className='relative flex h-full w-full flex-col'>
+      <div className='relative grow overflow-x-auto'>
+        <table className={'mt-3 w-full min-w-[700px] max-w-full border-collapse border-0 text-sm'}>
+          <thead className="h-8 border-b border-divider-subtle text-xs font-medium uppercase leading-8 text-text-tertiary">
+            <tr>
+              <td>语料</td>
+              <td>相似问题数量</td>
+              <td>意图类型</td>
+              <td>意图名称</td>
+              <td>创建时间</td>
+              <td className="w-[120px] text-center">操作</td>
+            </tr>
+          </thead>
+          <tbody className="text-text-secondary">
+            {list.map((item: any, index) => (
+              <tr
+                key={item.id}
+                className={'h-8 border-b border-divider-subtle hover:bg-background-default-hover'}
+              >
+                <td>1</td>
+                <td>2</td>
+                <td>3</td>
+                <td>4</td>
+                <td>2025-02-02 22:44:33</td>
+                <td>
+                  <Button variant='ghost-accent' size='small' className={cn('shrink-0')}>
+                    编辑
+                  </Button>
+                  <Button variant='ghost' size='small' className={cn('shrink-0 text-red-600')}>
+                    刪除
+                  </Button>
+                </td>
+              </tr>
+            ))}
+          </tbody>
+        </table>
+      </div>
+      {/* Show Pagination only if the total is more than the limit */}
+      {pagination.total && (
+        <Pagination
+          {...pagination}
+          className='w-full shrink-0 px-0 pb-0'
+        />
+      )}
+    </div>
+  )
+}
+export default CorpusPageList

+ 18 - 75
web/app/components/skill/index.tsx

@@ -1,14 +1,13 @@
 'use client'
-import { useMemo, useRef, useState } from 'react'
-import { useTranslation } from 'react-i18next'
+import { useRef } from 'react'
 import cn from '@/utils/classnames'
 import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
 import TabSliderNew from '@/app/components/base/tab-slider-new'
-import Input from '@/app/components/base/input'
-import { useAllToolProviders } from '@/service/use-tools'
+import CorpusIndex from '@/app/components/skill/corpus'
+import IntentIndex from '@/app/components/skill/intent'
+import LogIndex from '@/app/components/skill/log'
 
 const SkillIndex = () => {
-  const { t } = useTranslation()
   const containerRef = useRef<HTMLDivElement>(null)
 
   const [activeTab, setActiveTab] = useTabSearchParams({
@@ -19,89 +18,33 @@ const SkillIndex = () => {
     { value: 'intent', text: '意图识别' },
     { value: 'log', text: '训练日志' },
   ]
-  const [tagFilterValue, setTagFilterValue] = useState<string[]>([])
-
-  const [keywords, setKeywords] = useState<string>('')
-  const handleKeywordsChange = (value: string) => {
-    setKeywords(value)
-  }
-  const { data: collectionList = [], refetch } = useAllToolProviders()
-  const filteredCollectionList = useMemo(() => {
-    return collectionList.filter((collection) => {
-      if (collection.type !== activeTab)
-        return false
-      if (tagFilterValue.length > 0 && (!collection.labels || collection.labels.every(label => !tagFilterValue.includes(label))))
-        return false
-      if (keywords)
-        return Object.values(collection.label).some(value => value.toLowerCase().includes(keywords.toLowerCase()))
-      return true
-    })
-  }, [activeTab, tagFilterValue, keywords, collectionList])
-
   return (
     <>
-      <div className='relative flex h-0 shrink-0 grow overflow-hidden'>
+      <div className='relative flex h-0 shrink-0 grow flex-col overflow-hidden'>
         <div
           ref={containerRef}
-          className='relative flex grow flex-col overflow-y-auto bg-background-body'
+          className='relative flex flex-col overflow-y-auto bg-background-body'
         >
-          <div className={cn(
-            'sticky top-0 z-20 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]',
-            currentProvider && 'pr-6',
-          )}>
+          <div className={cn('sticky top-0 z-20 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]')}>
             <TabSliderNew
               value={activeTab}
               onChange={(state) => {
                 setActiveTab(state)
-                if (state !== activeTab)
-                  setCurrentProvider(undefined)
               }}
               options={options}
             />
-            <div className='flex items-center gap-2'>
-              <Input
-                showLeftIcon
-                showClearIcon
-                wrapperClassName='w-[200px]'
-                value={keywords}
-                onChange={e => handleKeywordsChange(e.target.value)}
-                onClear={() => handleKeywordsChange('')}
-              />
-            </div>
           </div>
-          {/* {(filteredCollectionList.length > 0 || activeTab !== 'builtin') && ( */}
-          {/*  <div className={cn( */}
-          {/*    'relative grid shrink-0 grid-cols-1 content-start gap-4 px-12 pb-4 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4', */}
-          {/*    !filteredCollectionList.length && activeTab === 'workflow' && 'grow', */}
-          {/*  )}> */}
-          {/*    {activeTab === 'api' && <CustomCreateCard onRefreshData={refetch} />} */}
-          {/*    {filteredCollectionList.map(collection => ( */}
-          {/*      <div */}
-          {/*        key={collection.id} */}
-          {/*        onClick={() => setCurrentProvider(collection)} */}
-          {/*      > */}
-          {/*        <Card */}
-          {/*          className={cn( */}
-          {/*            'cursor-pointer border-[1.5px] border-transparent', */}
-          {/*            currentProvider?.id === collection.id && 'border-components-option-card-option-selected-border', */}
-          {/*          )} */}
-          {/*          hideCornerMark */}
-          {/*          payload={{ */}
-          {/*            ...collection, */}
-          {/*            brief: collection.description, */}
-          {/*            org: collection.plugin_id ? collection.plugin_id.split('/')[0] : '', */}
-          {/*            name: collection.plugin_id ? collection.plugin_id.split('/')[1] : collection.name, */}
-          {/*          } as any} */}
-          {/*          footer={ */}
-          {/*            <CardMoreInfo */}
-          {/*              tags={collection.labels} */}
-          {/*            /> */}
-          {/*          } */}
-          {/*        /> */}
-          {/*      </div> */}
-          {/*    ))} */}
-          {/*  </div> */}
-          {/* )} */}
+        </div>
+        <div className="flex-1">
+          {
+            activeTab === 'corpus' && <CorpusIndex/>
+          }
+          {
+            activeTab === 'intent' && <IntentIndex/>
+          }
+          {
+            activeTab === 'log' && <LogIndex/>
+          }
         </div>
       </div>
     </>

+ 12 - 0
web/app/components/skill/intent/index.tsx

@@ -0,0 +1,12 @@
+'use client'
+
+const IntentIndex = () => {
+  return (
+    <>
+      <div className=''>
+        意图
+      </div>
+    </>
+  )
+}
+export default IntentIndex

+ 46 - 0
web/app/components/skill/log/index.tsx

@@ -0,0 +1,46 @@
+'use client'
+
+import List from './list'
+import React, { useEffect, useState } from 'react'
+import useSWR from 'swr'
+import { fetchLog } from '@/service/common'
+
+const LogIndex = () => {
+  const [page, setPage] = React.useState<number>(0)
+  const [limit, setLimit] = useState<number>(10)
+  const { data, mutate }: any = useSWR(
+    {
+      url: '/xxx',
+      params: {
+        page: page + 1,
+        limit,
+      },
+    },
+    fetchLog,
+  )
+  const list: any = data?.data || []
+  const total = data?.total || 0
+  useEffect(() => {
+    mutate()
+  }, [page, limit])
+  return (
+    <>
+      <div className='flex h-full w-full flex-col bg-background-default-subtle p-6'>
+        <div className="flex-1">
+          <List
+            list={list || []}
+            onUpdate={mutate}
+            pagination={{
+              total,
+              limit,
+              onLimitChange: setLimit,
+              current: page,
+              onChange: setPage,
+            }}
+          />
+        </div>
+      </div>
+    </>
+  )
+}
+export default LogIndex

+ 59 - 0
web/app/components/skill/log/list.tsx

@@ -0,0 +1,59 @@
+'use client'
+import Pagination, { type Props as PaginationProps } from '@/app/components/base/pagination'
+import type { FC } from 'react'
+import Button from '@/app/components/base/button'
+import cn from '@/utils/classnames'
+
+type PageListProps = {
+  list: []
+  pagination: PaginationProps
+  onUpdate: () => void
+}
+
+const LogPageList: FC<PageListProps> = ({
+  list = [],
+  pagination,
+  onUpdate,
+}) => {
+  return (
+    <div className='relative flex h-full w-full flex-col'>
+      <div className='relative grow overflow-x-auto'>
+        <table className={'mt-3 w-full min-w-[700px] max-w-full border-collapse border-0 text-sm'}>
+          <thead className="h-8 border-b border-divider-subtle text-xs font-medium uppercase leading-8 text-text-tertiary">
+            <tr>
+              <td>训练语料数据集版本</td>
+              <td>训练时间</td>
+              <td>训练模型结果版本</td>
+              <td className="w-[120px] text-center">操作</td>
+            </tr>
+          </thead>
+          <tbody className="text-text-secondary">
+            {list.map((item: any, index) => (
+              <tr
+                key={item.id}
+                className={'h-8 border-b border-divider-subtle hover:bg-background-default-hover'}
+              >
+                <td>{item.version}</td>
+                <td>{item.time}</td>
+                <td>{item.version}</td>
+                <td>
+                  <Button variant='ghost-accent' size='small' className={cn('shrink-0')}>
+                    下载
+                  </Button>
+                </td>
+              </tr>
+            ))}
+          </tbody>
+        </table>
+      </div>
+      {/* Show Pagination only if the total is more than the limit */}
+      {pagination.total && (
+        <Pagination
+          {...pagination}
+          className='w-full shrink-0 px-0 pb-0'
+        />
+      )}
+    </div>
+  )
+}
+export default LogPageList

+ 63 - 0
web/service/common.ts

@@ -482,3 +482,66 @@ export const submitDeleteAccountFeedback = (body: { feedback: string; email: str
 
 export const getDocDownloadUrl = (doc_name: string) =>
   get<{ url: string }>('/compliance/download', { params: { doc_name } }, { silent: true })
+
+export const fetchLog = ({ url, params }: any) => {
+  console.log('查询训练日志列表', url, params)
+  // return get(url, { params })
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      const arr: any = []
+      for (let i = 1; i < 10; i++) {
+        arr.push({
+          id: i,
+          version: `${i}.${i}.${i}`,
+          time: '2022-02-02 02:21:23',
+        })
+      }
+      resolve({
+        data: arr,
+        has_more: false,
+        limit: 10,
+        total: 100,
+        page: 1,
+      })
+    }, 1000)
+  })
+}
+
+export const fetchCorpus = ({ url, params }: any) => {
+  console.log('查询训练语料列表', url, params)
+  // return get(url, { params })
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      const arr: any = []
+      for (let i = 1; i < 10; i++) {
+        arr.push({
+          id: i,
+          name: `类型${i}`,
+          relation: i % 2,
+        })
+      }
+      resolve({
+        data: arr,
+        has_more: false,
+        limit: 10,
+        total: 100,
+        page: 1,
+      })
+    }, 1000)
+  })
+}
+
+export const addCorpus = ({ url, body }: any) => {
+  console.log('新增训练语料', url, body)
+  return post(url, { body })
+}
+
+export const editCorpus = ({ url, body }: any) => {
+  console.log('编辑训练语料', url, body)
+  return patch(url, { body })
+}
+
+export const delCorpus = ({ url, body }: any) => {
+  console.log('删除训练语料', url, body)
+  return del(url, { body })
+}