浏览代码

模型数据管理

zhengnaiwen_citu 1 周之前
父节点
当前提交
586f800a1b

+ 30 - 0
src/api/dataChart.js

@@ -15,3 +15,33 @@ export function submitTrainingCorrect (data) {
 export function submitTrainingError (data) {
   return http.post('/vanna/v0/training_error_question_sql', data)
 }
+
+// 查询反馈记录(支持分页、筛选、排序)
+export function getFeedbackList (data) {
+  return http.post('/vanna/v0/qa_feedback/query', data)
+}
+
+// 删除指定反馈记录
+export function deleteFeedback (feedbackId) {
+  return http.del(`/vanna/v0/qa_feedback/delete/${feedbackId}`)
+}
+
+// 修改指定反馈记录
+export function updateFeedback (feedbackId, data) {
+  return http.put(`/vanna/v0/qa_feedback/update/${feedbackId}`, data)
+}
+
+// 批量添加到训练集
+export function addFeedbackToTraining (data) {
+  return http.post('/vanna/v0/qa_feedback/add_to_training', data)
+}
+
+// 创建新的反馈记录
+export function addFeedback (data) {
+  return http.post('/vanna/v0/qa_feedback/add', data)
+}
+
+// 获取反馈统计信息
+export function getFeedbackStats (data) {
+  return http.get('/vanna/v0/qa_feedback/stats', data)
+}

+ 95 - 54
src/router/routes.js

@@ -2377,60 +2377,101 @@ export default {
       alwaysShow: 0,
       metastr: '{"allowClick":false,"enName":"data book","title":"数据目录","target":false}',
       open: null
+    },
+    {
+      hidden: 0,
+      rootId: 0,
+      icon: 'mdi-cog-outline',
+      type: 0,
+      path: '/model-system',
+      children: [
+        {
+          hidden: 0,
+          icon: '',
+          type: 1,
+          title: '统计分析',
+          path: '/model-system/model-statistics',
+          children: [],
+          enName: 'model-statistics',
+          redirect: '',
+          active: '',
+          label: '统计分析',
+          sort: 0,
+          component: 'modelSystem/modelStatistics',
+          meta: {
+            roles: [],
+            enName: 'model-statistics',
+            icon: '',
+            title: '统计分析',
+            fullScreen: false
+          },
+          name: 'model-statistics',
+          alwaysShow: 0
+        },
+        {
+          hidden: 0,
+          icon: '',
+          type: 1,
+          title: 'QA反馈管理',
+          path: '/model-system/model-qa',
+          children: [],
+          enName: 'model-qa',
+          redirect: '',
+          active: '',
+          label: 'QA反馈管理',
+          sort: 0,
+          component: 'modelSystem/modelQa',
+          meta: {
+            roles: [],
+            enName: 'model-qa',
+            icon: '',
+            title: 'QA反馈管理',
+            fullScreen: false
+          },
+          name: 'model-qa',
+          alwaysShow: 0
+        },
+        {
+          hidden: 0,
+          icon: '',
+          type: 1,
+          title: '历史对话记录',
+          path: '/model-system/model-history',
+          children: [],
+          enName: 'model-history',
+          redirect: '',
+          active: '',
+          label: '历史对话记录',
+          sort: 0,
+          component: 'modelSystem/modelHistory',
+          meta: {
+            roles: [],
+            enName: 'model-history',
+            icon: '',
+            title: '历史对话记录',
+            fullScreen: false
+          },
+          name: 'model-history',
+          alwaysShow: 0
+        }
+      ],
+      name: 'model-system',
+      enName: 'modelSystem',
+      redirect: '',
+      active: '',
+      sort: 100,
+      component: 'Layout',
+      meta: {
+        allowClick: false,
+        roles: [],
+        enName: 'modelSystem',
+        icon: 'mdi-cog-outline',
+        title: '模型数据管理',
+        target: false,
+        effectiveStatus: true
+      },
+      alwaysShow: 0
     }
-    // {
-    //   hidden: 0,
-    //   rootId: 0,
-    //   icon: 'mdi-robot-outline',
-    //   type: 0,
-    //   path: '/model',
-    //   children: [
-    //     {
-    //       hidden: 1,
-    //       icon: '',
-    //       type: 1,
-    //       title: '模型',
-    //       path: '/model',
-    //       children: [],
-    //       enName: 'model',
-    //       redirect: '',
-    //       active: '',
-    //       label: '模型',
-    //       sort: 0,
-    //       component: 'modelManage',
-    //       meta: {
-    //         roles: [],
-    //         enName: 'model',
-    //         icon: '',
-    //         title: '模型',
-    //         fullScreen: false
-    //       },
-    //       name: 'index',
-    //       alwaysShow: 0
-    //     }
-    //   ],
-    //   enName: 'model',
-    //   redirect: '',
-    //   active: '',
-    //   sort: 0,
-    //   component: 'Layout',
-    //   meta: {
-    //     allowClick: false,
-    //     roles: [],
-    //     enName: 'model',
-    //     icon: 'mdi-robot-outline',
-    //     title: '模型',
-    //     target: false,
-    //     effectiveStatus: true
-    //   },
-    //   name: 'model',
-    //   alwaysShow: 0
-    // }
   ],
-  permission: [
-    'systemManage:roleManage:create',
-    'systemManage:roleManage:edit',
-    'systemManage:roleManage:delete',
-    'systemManage:roleManage:data'
-  ]
+  permission: []
 }

+ 5 - 5
src/views/dataChart/dataChartEditChat.vue

@@ -228,8 +228,7 @@
 <script>
 import {
   getAsk,
-  submitTrainingCorrect,
-  submitTrainingError
+  addFeedback
 } from '@/api/dataChart'
 import { mapGetters } from 'vuex'
 export default {
@@ -345,11 +344,12 @@ export default {
     },
     async onAddTrain (item, bool) {
       this.loading = true
-      const subApi = bool ? submitTrainingCorrect : submitTrainingError
       try {
-        await subApi({
+        await addFeedback({
           question: item.question,
-          sql: item.content.sql
+          sql: item.content.sql,
+          is_thumb_up: bool,
+          user_id: this.userInfo.id
         })
         item.dataValidation = true
         // this.$snackbar.success('操作成功')

+ 1 - 1
src/views/modelManage/index.vue → src/views/modelSystem/modelHistory/index.vue

@@ -6,7 +6,7 @@
 
 <script>
 export default {
-  name: 'modelManage'
+  name: 'modelHistory'
 }
 </script>
 

+ 147 - 0
src/views/modelSystem/modelQa/index.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="pa-3 white">
+    <m-filter :option="filter" @search="handleSearch" />
+    <m-table
+      :loading="loading"
+      :headers="headers"
+      :items="items"
+      :total="total"
+      :page-info="pageInfo"
+      :show-select="false"
+      :is-tools="false"
+      @edit="handleEdit"
+      @delete="handleDelete"
+      @pageHandleChange="pageHandleChange"
+      @sort="handleSort"
+    >
+      <template #is_thumb_up="{ item }">
+        <v-chip :color="item.is_thumb_up ? 'success' : 'error'" small>{{ item.is_thumb_up ? '赞同' : '不赞同' }}</v-chip>
+      </template>
+      <template #is_in_training_data="{ item }">
+        <v-chip :color="item.is_in_training_data ? 'success' : 'error'" small>{{ item.is_in_training_data ? '是' : '否' }}</v-chip>
+      </template>
+      <template #sql="{ item }">
+        <Tooltip :text="item.sql" width="300"></Tooltip>
+      </template>
+      <template #question="{ item }">
+        <Tooltip :text="item.question" width="300"></Tooltip>
+      </template>
+    </m-table>
+    <ModelQaEdit ref="modelQaEditRefs"></ModelQaEdit>
+  </div>
+</template>
+
+<script>
+import Tooltip from '@/components/Tooltip'
+import MFilter from '@/components/Filter'
+import MTable from '@/components/List/table.vue'
+import ModelQaEdit from './modelQaEdit.vue'
+import {
+  getFeedbackList,
+  deleteFeedback
+} from '@/api/dataChart'
+export default {
+  name: 'model-qa',
+  components: { MFilter, MTable, ModelQaEdit, Tooltip },
+  data () {
+    return {
+      loading: false,
+      filter: {
+        list: [
+          {
+            type: 'autocomplete',
+            value: null,
+            label: '赞同与否',
+            key: 'is_thumb_up',
+            items: [
+              { label: '赞同', value: true },
+              { label: '不赞同', value: false }
+            ]
+          },
+          {
+            label: '创建时间',
+            type: 'datePicker',
+            key: 'create_time',
+            value: null,
+            dateType: 'date',
+            placeholder: '请选择创建时间',
+            clearable: true
+          }
+        ]
+      },
+      queryData: {
+        name: null
+      },
+      headers: [
+        { text: '问题', align: 'start', value: 'question' },
+        { text: 'sql', align: 'start', value: 'sql' },
+        { text: '赞同与否', align: 'center', value: 'is_thumb_up' },
+        { text: '是否已加入训练数据', align: 'center', value: 'is_in_training_data' },
+        { text: '创建时间', align: 'start', value: 'create_time' },
+        { text: '操作', align: 'start', value: 'actions' }
+      ],
+      itemData: {},
+      items: [],
+      orders: [],
+      pageInfo: {
+        size: 10,
+        current: 1
+      },
+      total: 0
+    }
+  },
+  created () {
+    this.init()
+  },
+  methods: {
+    async init () {
+      try {
+        this.loading = true
+        const { data } = await getFeedbackList({
+          page: this.pageInfo.current,
+          page_size: this.pageInfo.size
+        })
+        this.items = data.records
+        this.total = data.pagination.total
+      } catch (error) {
+        this.$snackbar.error(error)
+      } finally {
+        this.loading = false
+      }
+    },
+    handleSearch (val) {
+      Object.assign(this.queryData, val)
+      this.pageInfo.current = 1
+      this.init()
+    },
+    async handleEdit (item) {
+      this.$refs.modelQaEditRefs.open(item)
+    },
+    handleDelete (ids, item) {
+      this.$confirm('提示', '是否删除该选项')
+        .then(async () => {
+          try {
+            await deleteFeedback({ id: item.feedback_id })
+            this.$snackbar.success('删除成功')
+            this.init()
+          } catch (error) {
+            this.$snackbar.error('删除失败')
+          }
+        })
+    },
+    pageHandleChange (page) {
+      this.pageInfo.current = page
+      this.init()
+    },
+    handleSort (val) {
+      this.orders = val
+      this.init()
+    },
+    handleSubmit () {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 83 - 0
src/views/modelSystem/modelQa/modelQaEdit.vue

@@ -0,0 +1,83 @@
+<template>
+  <m-dialog title="编辑" :visible.sync="show" @submit="handleSubmit">
+    <MForm ref="form" :items="formItems" v-model="formValues" v-loading="loading"></MForm>
+  </m-dialog>
+</template>
+
+<script>
+import MForm from '@/components/MForm'
+import MDialog from '@/components/Dialog'
+import { updateFeedback } from '@/api/dataChart'
+export default {
+  name: 'modelQaEdit',
+  components: {
+    MDialog,
+    MForm
+  },
+  data () {
+    return {
+      loading: false,
+      show: false,
+      formValues: {},
+      formItems: [
+        {
+          label: '问题',
+          key: 'question',
+          type: 'textarea'
+        },
+        {
+          label: 'SQL',
+          key: 'sql',
+          type: 'textarea',
+          rows: 10
+        },
+        {
+          label: '是否赞同',
+          key: 'is_thumb_up',
+          type: 'ifRadio',
+          items: [
+            {
+              label: '是',
+              value: true
+            },
+            {
+              label: '否',
+              value: false
+            }
+          ]
+        }
+      ]
+    }
+  },
+  methods: {
+    open (item) {
+      this.formValues = {
+        question: item.question,
+        sql: item.sql,
+        is_thumb_up: item.is_thumb_up,
+        id: item.id
+      }
+      this.show = true
+    },
+    async handleSubmit () {
+      if (!this.$refs.form.validate()) {
+        return
+      }
+      this.loading = true
+      const { id, ...params } = this.formValues
+      try {
+        await updateFeedback(id, params)
+        this.$snackbar.success('保存成功')
+      } catch (error) {
+        this.$snackbar.error(error)
+      } finally {
+        this.loading = false
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 31 - 0
src/views/modelSystem/modelStatistics/index.vue

@@ -0,0 +1,31 @@
+<template>
+  <div>
+
+  </div>
+</template>
+
+<script>
+import {
+  getFeedbackStats
+} from '@/api/dataChart'
+export default {
+  name: 'modelStatistics',
+  created () {
+    this.init()
+  },
+  methods: {
+    async init () {
+      try {
+        const { data } = await getFeedbackStats()
+        console.log(data)
+      } catch (error) {
+        this.$snackbar.error(error)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>