Skip to content

Commit 2fe1803

Browse files
feat: document
1 parent 636f961 commit 2fe1803

File tree

59 files changed

+541
-258
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+541
-258
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<template>
2+
<el-tooltip
3+
v-bind="$attrs"
4+
:disabled="!(containerWeight > contentWeight)"
5+
effect="dark"
6+
placement="bottom"
7+
popper-class="auto-tooltip-popper"
8+
>
9+
<div ref="tagLabel" :class="['auto-tooltip', className]" :style="style">
10+
<slot></slot>
11+
</div>
12+
</el-tooltip>
13+
</template>
14+
<script setup lang="ts">
15+
import { ref, computed, onMounted, nextTick } from 'vue'
16+
defineOptions({ name: 'AutoTooltip' })
17+
const props = defineProps({ className: String, style: Object })
18+
const tagLabel = ref()
19+
const containerWeight = ref(0)
20+
const contentWeight = ref(0)
21+
22+
onMounted(() => {
23+
nextTick(() => {
24+
containerWeight.value = tagLabel.value?.scrollWidth
25+
contentWeight.value = tagLabel.value?.clientWidth
26+
})
27+
window.addEventListener('resize', function () {
28+
containerWeight.value = tagLabel.value?.scrollWidth
29+
contentWeight.value = tagLabel.value?.clientWidth
30+
})
31+
})
32+
</script>
33+
<style lang="scss" scoped>
34+
.auto-tooltip {
35+
overflow: hidden;
36+
white-space: nowrap;
37+
text-overflow: ellipsis;
38+
}
39+
</style>
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
<template>
2+
<el-dialog
3+
:title="$t('views.document.generateQuestion.title')"
4+
v-model="dialogVisible"
5+
width="650"
6+
:close-on-click-modal="false"
7+
:close-on-press-escape="false"
8+
>
9+
<div class="content-height">
10+
<el-form
11+
ref="FormRef"
12+
:model="form"
13+
:rules="rules"
14+
label-position="top"
15+
require-asterisk-position="right"
16+
>
17+
<div class="update-info flex border-r-4 mb-16 p-8-12">
18+
<div class="mt-4">
19+
<AppIcon iconName="app-warning-colorful" style="font-size: 16px"></AppIcon>
20+
</div>
21+
<div class="ml-12 lighter">
22+
<p>{{ $t('views.document.generateQuestion.tip1', { data: '{data}' }) }}</p>
23+
<p>
24+
{{ $t('views.document.generateQuestion.tip2')+ '<question></question>' +
25+
$t('views.document.generateQuestion.tip3') }}
26+
</p>
27+
<p>{{ $t('views.document.generateQuestion.tip4') }}</p>
28+
</div>
29+
</div>
30+
<el-form-item
31+
:label="$t('views.application.form.aiModel.label')"
32+
prop="model_id"
33+
>
34+
<ModelSelect
35+
v-model="form.model_id"
36+
:placeholder="$t('views.application.form.aiModel.placeholder')"
37+
:options="modelOptions"
38+
showFooter
39+
:model-type="'LLM'"
40+
></ModelSelect>
41+
</el-form-item>
42+
<el-form-item
43+
:label="$t('views.application.form.prompt.label')"
44+
prop="prompt"
45+
>
46+
<el-input
47+
v-model="form.prompt"
48+
:placeholder="$t('views.application.form.prompt.placeholder')"
49+
:rows="7"
50+
type="textarea"
51+
/>
52+
</el-form-item>
53+
<el-form-item
54+
v-if="['document', 'dataset'].includes(apiType)"
55+
:label="$t('components.selectParagraph.title')"
56+
prop="state"
57+
>
58+
<el-radio-group v-model="state" class="radio-block">
59+
<el-radio value="error" size="large">{{
60+
$t('components.selectParagraph.error')
61+
}}</el-radio>
62+
<el-radio value="all" size="large">{{ $t('components.selectParagraph.all') }}</el-radio>
63+
</el-radio-group>
64+
</el-form-item>
65+
</el-form>
66+
</div>
67+
<template #footer>
68+
<span class="dialog-footer">
69+
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
70+
<el-button type="primary" @click="submitHandle(FormRef)" :disabled="!model || loading">
71+
{{ $t('common.confirm') }}
72+
</el-button>
73+
</span>
74+
</template>
75+
</el-dialog>
76+
</template>
77+
<script setup lang="ts">
78+
import { reactive, ref, watch } from 'vue'
79+
import { useRoute } from 'vue-router'
80+
import documentApi from '@/api/knowledge/document'
81+
import paragraphApi from '@/api/knowledge/paragraph'
82+
import knowledgeApi from '@/api/knowledge/knowledge'
83+
import useStore from '@/stores'
84+
import { groupBy } from 'lodash'
85+
import { MsgSuccess } from '@/utils/message'
86+
import { t } from '@/locales'
87+
import type { FormInstance } from 'element-plus'
88+
89+
const route = useRoute()
90+
const {
91+
params: { id, documentId } // id为datasetID
92+
} = route as any
93+
94+
const { model, prompt, user } = useStore()
95+
96+
const emit = defineEmits(['refresh'])
97+
98+
const loading = ref<boolean>(false)
99+
100+
const dialogVisible = ref<boolean>(false)
101+
const modelOptions = ref<any>(null)
102+
const idList = ref<string[]>([])
103+
const apiType = ref('') // 文档document或段落paragraph
104+
const state = ref<'all' | 'error'>('error')
105+
const stateMap = {
106+
all: ['0', '1', '2', '3', '4', '5', 'n'],
107+
error: ['0', '1', '3', '4', '5', 'n']
108+
}
109+
const FormRef = ref()
110+
const datasetId = ref<string>()
111+
const userId = user.userInfo?.id as string
112+
const form = ref(prompt.get(userId))
113+
const rules = reactive({
114+
model_id: [
115+
{
116+
required: true,
117+
message: t('views.application.form.aiModel.placeholder'),
118+
trigger: 'blur'
119+
}
120+
],
121+
prompt: [
122+
{
123+
required: true,
124+
message: t('views.application.form.prompt.placeholder'),
125+
trigger: 'blur'
126+
}
127+
]
128+
})
129+
130+
watch(dialogVisible, (bool) => {
131+
if (!bool) {
132+
form.value = prompt.get(userId)
133+
FormRef.value?.clearValidate()
134+
}
135+
})
136+
137+
const open = (ids: string[], type: string, _datasetId?: string) => {
138+
datasetId.value = _datasetId
139+
getModel()
140+
idList.value = ids
141+
apiType.value = type
142+
dialogVisible.value = true
143+
}
144+
145+
const submitHandle = async (formEl: FormInstance) => {
146+
if (!formEl) {
147+
return
148+
}
149+
await formEl.validate((valid, fields) => {
150+
if (valid) {
151+
// 保存提示词
152+
prompt.save(user.userInfo?.id as string, form.value)
153+
if (apiType.value === 'paragraph') {
154+
const data = {
155+
...form.value,
156+
paragraph_id_list: idList.value
157+
}
158+
paragraphApi.batchGenerateRelated(id, documentId, data, loading).then(() => {
159+
MsgSuccess(t('views.document.generateQuestion.successMessage'))
160+
emit('refresh')
161+
dialogVisible.value = false
162+
})
163+
} else if (apiType.value === 'document') {
164+
const data = {
165+
...form.value,
166+
document_id_list: idList.value,
167+
state_list: stateMap[state.value]
168+
}
169+
documentApi.batchGenerateRelated(id, data, loading).then(() => {
170+
MsgSuccess(t('views.document.generateQuestion.successMessage'))
171+
emit('refresh')
172+
dialogVisible.value = false
173+
})
174+
} else if (apiType.value === 'dataset') {
175+
const data = {
176+
...form.value,
177+
state_list: stateMap[state.value]
178+
}
179+
datasetApi.generateRelated(id ? id : datasetId.value, data, loading).then(() => {
180+
MsgSuccess(t('views.document.generateQuestion.successMessage'))
181+
dialogVisible.value = false
182+
})
183+
}
184+
}
185+
})
186+
}
187+
188+
function getModel() {
189+
loading.value = true
190+
datasetApi
191+
.getDatasetModel(id ? id : datasetId.value)
192+
.then((res: any) => {
193+
modelOptions.value = groupBy(res?.data, 'provider')
194+
loading.value = false
195+
})
196+
.catch(() => {
197+
loading.value = false
198+
})
199+
}
200+
201+
defineExpose({ open })
202+
</script>
203+
<style lang="scss" scoped></style>

ui/src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import CodemirrorEditor from './codemirror-editor/index.vue'
1515
import InfiniteScroll from './infinite-scroll/index.vue'
1616
import ModelSelect from './model-select/index.vue'
1717
import ReadWrite from './read-write/index.vue'
18+
import AutoTooltip from './auto-tooltip/index.vue'
1819
export default {
1920
install(app: App) {
2021
app.component('LogoFull', LogoFull)
@@ -33,5 +34,6 @@ export default {
3334
app.component('InfiniteScroll', InfiniteScroll)
3435
app.component('ModelSelect', ModelSelect)
3536
app.component('ReadWrite', ReadWrite)
37+
app.component('AutoTooltip', AutoTooltip)
3638
},
3739
}

ui/src/layout/components/breadcrumb/index.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,26 +81,26 @@
8181
shape="square"
8282
:size="24"
8383
/>
84-
<AppAvatar
84+
<el-avatar
8585
v-else-if="isDataset && item.type === '1'"
8686
class="mr-12 avatar-purple"
8787
shape="square"
8888
:size="24"
8989
>
9090
<img src="@/assets/knowledge/icon_web.svg" style="width: 58%" alt="" />
91-
</AppAvatar>
92-
<AppAvatar
91+
</el-avatar>
92+
<el-avatar
9393
v-else-if="isDataset && item.type === '2'"
9494
class="mr-8 avatar-purple"
9595
shape="square"
9696
:size="24"
9797
style="background: none"
9898
>
9999
<img src="@/assets/knowledge/logo_lark.svg" style="width: 100%" alt="" />
100-
</AppAvatar>
101-
<AppAvatar v-else class="mr-12 avatar-blue" shape="square" :size="24">
100+
</el-avatar>
101+
<el-avatar v-else class="mr-12 avatar-blue" shape="square" :size="24">
102102
<img src="@/assets/knowledge/icon_document.svg" style="width: 58%" alt="" />
103-
</AppAvatar>
103+
</el-avatar>
104104
<span class="ellipsis" :title="item?.name"> {{ item?.name }}</span>
105105
</div>
106106
</el-dropdown-item>

ui/src/stores/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import useFolderStore from './modules/folder'
55
import useThemeStore from './modules/theme'
66
import useKnowledgeStore from './modules/knowledge'
77
import useModelStore from './modules/model'
8+
import usePromptStore from './modules/prompt'
89

910
const useStore = () => ({
1011
common: useCommonStore(),
@@ -14,6 +15,7 @@ const useStore = () => ({
1415
theme: useThemeStore(),
1516
knowledge: useKnowledgeStore(),
1617
model: useModelStore(),
18+
prompt: usePromptStore(),
1719
})
1820

1921
export default useStore

ui/src/stores/modules/prompt.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { defineStore } from 'pinia'
2+
import { t } from '@/locales'
3+
export interface promptTypes {
4+
user: string
5+
formValue: { model_id: string; prompt: string }
6+
}
7+
8+
const usePromptStore = defineStore('prompt', {
9+
state: (): promptTypes[] => JSON.parse(localStorage.getItem('PROMPT_CACHE') || '[]'),
10+
actions: {
11+
save(user: string, formValue: any) {
12+
this.$state.forEach((item: any, index: number) => {
13+
if (item.user === user) {
14+
this.$state.splice(index, 1)
15+
}
16+
})
17+
this.$state.push({ user, formValue })
18+
localStorage.setItem('PROMPT_CACHE', JSON.stringify(this.$state))
19+
},
20+
get(user: string) {
21+
for (let i = 0; i < this.$state.length; i++) {
22+
if (this.$state[i].user === user) {
23+
return this.$state[i].formValue
24+
}
25+
}
26+
return {
27+
model_id: '',
28+
prompt:
29+
t('views.document.generateQuestion.prompt1', { data: '{data}' }) +
30+
'<question></question>' +
31+
t('views.document.generateQuestion.prompt2'),
32+
}
33+
},
34+
},
35+
})
36+
37+
export default usePromptStore

ui/src/views/application-overview/component/EditAvatarDialog.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<el-radio-group v-model="radioType" class="radio-block mb-16">
1010
<el-radio value="default">
1111
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.default') }}</p>
12-
<AppAvatar
12+
<el-avatar
1313
v-if="detail?.name"
1414
:name="detail?.name"
1515
pinyinColor
@@ -21,15 +21,15 @@
2121
<el-radio value="custom">
2222
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.customizeUpload') }}</p>
2323
<div class="flex mt-8">
24-
<AppAvatar
24+
<el-avatar
2525
v-if="fileURL"
2626
shape="square"
2727
:size="32"
2828
style="background: none"
2929
class="mr-16"
3030
>
3131
<img :src="fileURL" alt="" />
32-
</AppAvatar>
32+
</el-avatar>
3333
<el-upload
3434
ref="uploadRef"
3535
action="#"

0 commit comments

Comments
 (0)