This commit is contained in:
liqiang-fit2cloud 2024-12-05 08:47:15 +08:00
commit 7811e8cdf3
20 changed files with 120 additions and 73 deletions

View File

@ -46,6 +46,8 @@ class BaseFormNode(IFormNode):
if form_data is not None:
self.context['is_submit'] = True
self.context['form_data'] = form_data
for key in form_data:
self.context[key] = form_data.get(key)
else:
self.context['is_submit'] = False
form_setting = {"form_field_list": form_field_list, "runtime_node_id": self.runtime_node_id,

View File

@ -90,7 +90,8 @@ class XlsxSplitHandle(BaseParseTableHandle):
for sheetname in workbook.sheetnames:
sheet = workbook[sheetname] if sheetname else workbook.active
rows = self.fill_merged_cells(sheet, image_dict)
if len(rows) == 0:
continue
# 提取表头和内容
headers = [f"{key}" for key, value in rows[0].items()]

View File

@ -1,3 +1,5 @@
import math
from django.core.management.base import BaseCommand
from django.db.models import TextChoices
@ -93,7 +95,8 @@ class BaseActionCommand(BaseCommand):
'services', nargs='+', choices=Services.export_services_values(), help='Service',
)
parser.add_argument('-d', '--daemon', nargs="?", const=True)
parser.add_argument('-w', '--worker', type=int, nargs="?", default=3 if os.cpu_count() > 3 else os.cpu_count())
parser.add_argument('-w', '--worker', type=int, nargs="?",
default=3 if os.cpu_count() > 6 else math.floor(os.cpu_count() / 2))
parser.add_argument('-f', '--force', nargs="?", const=True)
def initial_util(self, *args, **options):

View File

@ -102,3 +102,12 @@ def valid_license(model=None, count=None, message=None):
return run
return inner
def bulk_create_in_batches(model, data, batch_size=1000):
if len(data) == 0:
return
for i in range(0, len(data), batch_size):
batch = data[i:i + batch_size]
model.objects.bulk_create(batch)

View File

@ -15,6 +15,7 @@ from functools import reduce
from typing import Dict, List
from urllib.parse import urlparse
from celery_once import AlreadyQueued, QueueOnce
from django.contrib.postgres.fields import ArrayField
from django.core import validators
from django.db import transaction, models
@ -732,6 +733,7 @@ class DataSetSerializers(serializers.ModelSerializer):
delete_embedding_by_dataset(self.data.get('id'))
return True
@transaction.atomic
def re_embedding(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
@ -743,7 +745,10 @@ class DataSetSerializers(serializers.ModelSerializer):
State.PENDING)
ListenerManagement.get_aggregation_document_status_by_dataset_id(self.data.get('id'))()
embedding_model_id = get_embedding_model_id_by_dataset_id(self.data.get('id'))
embedding_by_dataset.delay(self.data.get('id'), embedding_model_id)
try:
embedding_by_dataset.delay(self.data.get('id'), embedding_model_id)
except AlreadyQueued as e:
raise AppApiException(500, "向量化任务发送失败,请稍后再试!")
def list_application(self, with_valid=True):
if with_valid:

View File

@ -41,7 +41,7 @@ from common.handle.impl.table.xls_parse_table_handle import XlsSplitHandle
from common.handle.impl.table.xlsx_parse_table_handle import XlsxSplitHandle
from common.handle.impl.text_split_handle import TextSplitHandle
from common.mixins.api_mixin import ApiMixin
from common.util.common import post, flat_map
from common.util.common import post, flat_map, bulk_create_in_batches
from common.util.field_message import ErrMessage
from common.util.file_util import get_file_content
from common.util.fork import Fork
@ -301,6 +301,8 @@ class DocumentSerializers(ApiMixin, serializers.Serializer):
ListenerManagement.update_status(QuerySet(Paragraph).filter(document_id__in=document_id_list),
TaskType.EMBEDDING,
State.PENDING)
ListenerManagement.get_aggregation_document_status_by_query_set(
QuerySet(Document).filter(id__in=document_id_list))()
embedding_by_document_list.delay(document_id_list, model_id)
else:
update_embedding_dataset_id(pid_list, target_dataset_id)
@ -621,6 +623,7 @@ class DocumentSerializers(ApiMixin, serializers.Serializer):
_document.save()
return self.one()
@transaction.atomic
def refresh(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
@ -952,12 +955,11 @@ class DocumentSerializers(ApiMixin, serializers.Serializer):
# 插入文档
QuerySet(Document).bulk_create(document_model_list) if len(document_model_list) > 0 else None
# 批量插入段落
QuerySet(Paragraph).bulk_create(paragraph_model_list) if len(paragraph_model_list) > 0 else None
bulk_create_in_batches(Paragraph, paragraph_model_list, batch_size=1000)
# 批量插入问题
QuerySet(Problem).bulk_create(problem_model_list) if len(problem_model_list) > 0 else None
bulk_create_in_batches(Problem, problem_model_list, batch_size=1000)
# 批量插入关联问题
QuerySet(ProblemParagraphMapping).bulk_create(problem_paragraph_mapping_list) if len(
problem_paragraph_mapping_list) > 0 else None
bulk_create_in_batches(ProblemParagraphMapping, problem_paragraph_mapping_list, batch_size=1000)
# 查询文档
query_set = QuerySet(model=Document)
if len(document_model_list) == 0:

View File

@ -18,7 +18,7 @@
:chat_record_id="answer_text.chat_record_id"
:child_node="answer_text.child_node"
:runtime_node_id="answer_text.runtime_node_id"
:loading="loading"
:disabled="loading || type == 'log'"
v-else-if="answer_text.content"
:source="answer_text.content"
:send-message="chatMessage"

View File

@ -6,7 +6,7 @@
<LogoIcon v-else height="32px" width="32px" />
</div>
<div class="content">
<el-card shadow="always" class="dialog-card">
<el-card shadow="always" class="dialog-card" style="--el-card-padding: 10px 16px 12px">
<MdRenderer :source="prologue" :send-message="sendMessage"></MdRenderer>
</el-card>
</div>

View File

@ -42,6 +42,7 @@
:max-scale="7"
:min-scale="0.2"
:preview-src-list="getAttrsArray(image_list, 'url')"
:initial-index="index"
alt=""
fit="cover"
style="width: 170px; height: 170px; display: block"

View File

@ -26,34 +26,6 @@
.text {
padding: 6px 0;
}
.problem-button {
width: 100%;
border: none;
border-radius: 8px;
background: var(--app-layout-bg-color);
height: 46px;
padding: 0 12px;
line-height: 46px;
box-sizing: border-box;
color: var(--el-text-color-regular);
-webkit-line-clamp: 1;
word-break: break-all;
&:hover {
background: var(--el-color-primary-light-9);
}
&.disabled {
&:hover {
background: var(--app-layout-bg-color);
}
}
.el-icon {
color: var(--el-color-primary);
}
}
}
&__operate {
background: #f3f7f9;

View File

@ -1,15 +1,23 @@
<template>
<div class="radio_content" v-resize="resize" :style="radioContentStyle">
<el-card
v-for="item in option_list"
:key="item.value"
class="item"
shadow="never"
:class="[inputDisabled ? 'is-disabled' : '', modelValue == item[valueField] ? 'active' : '']"
@click="inputDisabled ? () => {} : selected(item[valueField])"
>
{{ item[textField] }}
</el-card>
<div class="radio_content" :style="radioContentStyle">
<el-row :gutter="12" class="w-full">
<template v-for="(item,index) in option_list" :key="index">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
<el-card
:key="item.value"
class="item"
shadow="never"
:class="[
inputDisabled ? 'is-disabled' : '',
modelValue == item[valueField] ? 'active' : ''
]"
@click="inputDisabled ? () => {} : selected(item[valueField])"
>
{{ item[textField] }}
</el-card>
</el-col>
</template>
</el-row>
</div>
</template>
<script lang="ts" setup>

View File

@ -1,7 +1,7 @@
<template>
<div>
<DynamicsForm
:disabled="is_submit"
:disabled="is_submit || disabled"
label-position="top"
require-asterisk-position="right"
ref="dynamicsFormRef"
@ -12,7 +12,7 @@
></DynamicsForm>
<el-button
:type="is_submit ? 'info' : 'primary'"
:disabled="is_submit || loading"
:disabled="is_submit || disabled"
@click="submit"
>提交</el-button
>
@ -24,14 +24,14 @@ import DynamicsForm from '@/components/dynamics-form/index.vue'
const props = withDefaults(
defineProps<{
form_setting: string
loading?: boolean
disabled?: boolean
sendMessage?: (question: string, type: 'old' | 'new', other_params_data?: any) => void
child_node?: any
chat_record_id?: string
runtime_node_id?: string
}>(),
{
loading: false
disabled: false
}
)
const form_setting_data = computed(() => {

View File

@ -3,7 +3,7 @@
<div
v-if="item.type === 'question'"
@click="sendMessage ? sendMessage(item.content, 'new') : (content: string) => {}"
class="problem-button ellipsis-2 mb-8"
class="problem-button ellipsis-2 mt-4 mb-4"
:class="sendMessage ? 'cursor' : 'disabled'"
>
<el-icon>
@ -20,7 +20,7 @@
:chat_record_id="chat_record_id"
:runtime_node_id="runtime_node_id"
:child_node="child_node"
:loading="loading"
:disabled="disabled"
:send-message="sendMessage"
v-else-if="item.type === 'form_rander'"
:form_setting="item.content"
@ -70,11 +70,11 @@ const props = withDefaults(
child_node?: any
chat_record_id?: string
runtime_node_id?: string
loading?: boolean
disabled?: boolean
}>(),
{
source: '',
loading: false
disabled: false
}
)
const editorRef = ref()

View File

@ -277,6 +277,10 @@ h5 {
vertical-align: middle;
}
.line-height-22 {
line-height: 22px;
}
.border {
border: 1px solid var(--el-border-color);
}
@ -745,5 +749,5 @@ h5 {
//企业微信
.wwLogin_qrcode_head {
padding:20px 0 !important;
}
padding: 20px 0 !important;
}

View File

@ -185,6 +185,8 @@ const selectUserId = ref('all')
const searchValue = ref('')
const apiInputParams = ref([])
function copyApplication(row: any) {
application.asyncGetApplicationDetail(row.id, loading).then((res: any) => {
CopyApplicationDialogRef.value.open({ ...res.data, model_id: res.data.model })
@ -234,9 +236,44 @@ function searchHandle() {
paginationConfig.total = 0
getList()
}
function mapToUrlParams(map: any[]) {
const params = new URLSearchParams()
map.forEach((item: any) => {
params.append(encodeURIComponent(item.name), encodeURIComponent(item.value))
})
return params.toString() // URL
}
function getAccessToken(id: string) {
applicationList.value.filter((app)=>app.id === id)[0]?.work_flow?.nodes
?.filter((v: any) => v.id === 'base-node')
.map((v: any) => {
apiInputParams.value = v.properties.api_input_field_list
? v.properties.api_input_field_list
.map((v: any) => {
return {
name: v.variable,
value: v.default_value
}
})
: v.properties.input_field_list
? v.properties.input_field_list
.filter((v: any) => v.assignment_method === 'api_input')
.map((v: any) => {
return {
name: v.variable,
value: v.default_value
}
})
: []
})
const apiParams = mapToUrlParams(apiInputParams.value) ? '?' + mapToUrlParams(apiInputParams.value) : ''
application.asyncGetAccessToken(id, loading).then((res: any) => {
window.open(application.location + res?.data?.access_token)
window.open(application.location + res?.data?.access_token + apiParams)
})
}

View File

@ -1,5 +1,10 @@
<template>
<el-popover v-model:visible="visible" placement="top" :width="450" trigger="hover">
<el-popover
v-model:visible="visible"
placement="top"
trigger="hover"
:popper-style="{ width: 'auto' }"
>
<template #default
><StatusTable
v-if="visible"
@ -43,18 +48,21 @@ const checkList: Array<string> = [
State.REVOKE,
State.STARTED,
State.PENDING,
State.REVOKED,
State.FAILURE,
State.REVOKED,
State.SUCCESS
]
const aggStatus = computed(() => {
let obj = { key: 0, value: '' }
for (const i in checkList) {
const state = checkList[i]
const index = props.status.indexOf(state)
if (index > -1) {
return { key: props.status.length - index, value: state }
obj = { key: props.status.length - index, value: state }
break
}
}
return obj
})
const startedMap = {
[TaskType.EMBEDDING]: '索引中',

View File

@ -1,5 +1,5 @@
<template>
<div v-for="status in statusTable" :key="status.type">
<div v-for="status in statusTable" :key="status.type" >
<span> {{ taskTypeMap[status.type] }}</span>
<span>
<el-text v-if="status.state === State.SUCCESS || status.state === State.REVOKED">
@ -37,7 +37,7 @@
Object.values(status.aggs ? status.aggs : {}).reduce((x: any, y: any) => x + y, 0)
}}</span
>
<el-text type="info" class="ml-4">
<el-text type="info" class="ml-12">
{{
status.time
? status.time[status.state == State.REVOKED ? State.REVOKED : State.PENDING]?.substring(

View File

@ -252,11 +252,6 @@ onMounted(() => {
}
})
})
onBeforeMount(() => {
if (user.isEnterprise()) {
user.theme(loading)
}
})
</script>
<style lang="scss" scope>
.login-gradient-divider {

View File

@ -113,7 +113,7 @@ const validate = () => {
return Promise.resolve('')
}
props.nodeModel.graphModel.eventCenter.on('refresh_incoming_node_field', () => {
getIncomingNode(props.nodeModel.id)
options.value = getIncomingNode(props.nodeModel.id)
})
defineExpose({ validate })
onMounted(() => {

View File

@ -44,7 +44,7 @@
<div class="flex align-center">
<img class="mr-12" src="@/assets/icon_file-doc.svg" alt="" />
<div>
<p>文档TXTMDDOCXHTMLCSVXLSXXLSPDF</p>
<p class="line-height-22 mt-4">文档TXTMDDOCXHTMLCSVXLSXXLSPDF</p>
<el-text class="color-secondary">需要使用文档内容提取节点解析文档内容</el-text>
</div>
</div>
@ -61,7 +61,7 @@
<div class="flex align-center">
<img class="mr-12" src="@/assets/icon_file-image.svg" alt="" />
<div>
<p>图片JPGJPEGPNGGIF</p>
<p class="line-height-22 mt-4">图片JPGJPEGPNGGIF</p>
<el-text class="color-secondary">需要使用图片理解节点解析图片内容</el-text>
</div>
</div>