refactor:update recommended questions custom config. (#491)

This commit is contained in:
王嘉豪
2025-11-25 18:40:04 +08:00
committed by GitHub
parent 88c885aaa9
commit a5ba14275e
13 changed files with 155 additions and 46 deletions
+10 -1
View File
@@ -8,7 +8,8 @@ from sqlalchemy.orm import aliased
from apps.chat.models.chat_model import Chat, ChatRecord, CreateChat, ChatInfo, RenameChat, ChatQuestion, ChatLog, \
TypeEnum, OperationEnum, ChatRecordResult
from apps.datasource.models.datasource import CoreDatasource
from apps.datasource.crud.recommended_problem import get_datasource_recommended, get_datasource_recommended_chart
from apps.datasource.models.datasource import CoreDatasource, DsRecommendedProblem
from apps.system.crud.assistant import AssistantOutDsFactory
from common.core.deps import CurrentAssistant, SessionDep, CurrentUser
from common.utils.utils import extract_nested_json
@@ -70,6 +71,7 @@ def get_chart_config(session: SessionDep, chart_record_id: int):
pass
return {}
def format_chart_fields(chart_info: dict):
fields = []
if chart_info.get('columns') and len(chart_info.get('columns')) > 0:
@@ -88,6 +90,7 @@ def format_chart_fields(chart_info: dict):
fields.append(column_str)
return fields
def get_last_execute_sql_error(session: SessionDep, chart_id: int):
stmt = select(ChatRecord.error).where(and_(ChatRecord.chat_id == chart_id)).order_by(
ChatRecord.create_time.desc()).limit(1)
@@ -396,6 +399,12 @@ def create_chat(session: SessionDep, current_user: CurrentUser, create_chat_obj:
record.finish = True
record.create_time = datetime.datetime.now()
record.create_by = current_user.id
if ds.recommended_config == 2:
questions = get_datasource_recommended_chart(session, ds.id)
record.recommended_question = orjson.dumps(questions).decode()
record.recommended_question_answer = orjson.dumps({
"content": questions
}).decode()
_record = ChatRecord(**record.model_dump())
@@ -1,7 +1,10 @@
from fastapi import APIRouter
from apps.datasource.crud.recommended_problem import get_datasource_recommended
from common.core.deps import SessionDep
from apps.datasource.crud.datasource import update_ds_recommended_config
from apps.datasource.crud.recommended_problem import get_datasource_recommended, \
save_recommended_problem
from apps.datasource.models.datasource import RecommendedProblemBase
from common.core.deps import SessionDep, CurrentUser
router = APIRouter(tags=["recommended_problem"], prefix="/recommended_problem")
@@ -10,3 +13,8 @@ router = APIRouter(tags=["recommended_problem"], prefix="/recommended_problem")
async def datasource_recommended(session: SessionDep, ds_id: int):
return get_datasource_recommended(session, ds_id)
@router.post("/save_recommended_problem")
async def datasource_recommended(session: SessionDep, user: CurrentUser, data_info: RecommendedProblemBase):
update_ds_recommended_config(session, data_info.datasource_id, data_info.recommended_config)
return save_recommended_problem(session, user, data_info)
@@ -109,6 +109,11 @@ def update_ds(session: SessionDep, trans: Trans, user: CurrentUser, ds: CoreData
run_save_ds_embeddings([ds.id])
return ds
def update_ds_recommended_config(session: SessionDep,datasource_id: int, recommended_config:int):
record = session.exec(select(CoreDatasource).where(CoreDatasource.id == datasource_id)).first()
record.recommended_config = recommended_config
session.add(record)
session.commit()
def delete_ds(session: SessionDep, id: int):
term = session.exec(select(CoreDatasource).where(CoreDatasource.id == id)).first()
@@ -1,11 +1,31 @@
import datetime
from sqlmodel import select
from common.core.deps import SessionDep
from ..models.datasource import DsRecommendedProblem
from common.core.deps import SessionDep, CurrentUser, Trans
from ..models.datasource import DsRecommendedProblem, RecommendedProblemBase, RecommendedProblemBaseChat
def get_datasource_recommended(session: SessionDep, ds_id: int):
statement = select(DsRecommendedProblem).where(DsRecommendedProblem.datasource_id == ds_id)
dsRecommendedProblem = session.exec(statement)
dsRecommendedProblem = session.exec(statement).all()
return dsRecommendedProblem
def get_datasource_recommended_chart(session: SessionDep, ds_id: int):
statement = select(DsRecommendedProblem.question).where(DsRecommendedProblem.datasource_id == ds_id)
dsRecommendedProblems = session.exec(statement).all()
return dsRecommendedProblems
def save_recommended_problem(session: SessionDep,user: CurrentUser, data_info: RecommendedProblemBase):
session.query(DsRecommendedProblem).filter(DsRecommendedProblem.datasource_id == data_info.datasource_id).delete(synchronize_session=False)
problemInfo = data_info.problemInfo
if problemInfo is not None:
for problemItem in problemInfo:
problemItem.id = None
problemItem.create_time = datetime.datetime.now()
problemItem.create_by = user.id
record = DsRecommendedProblem(**problemItem.model_dump())
session.add(record)
session.flush()
session.refresh(record)
session.commit()
@@ -74,6 +74,18 @@ class CreateDatasource(BaseModel):
tables: List[CoreTable] = []
recommended_config: int = 1
class RecommendedProblemBase(BaseModel):
datasource_id: int = None
recommended_config: int = None
problemInfo: List[DsRecommendedProblem] = []
class RecommendedProblemBaseChat:
def __init__(self, content):
self.content = content
content: List[str] = []
# edit local saved table and fields
class TableObj(BaseModel):
+2 -1
View File
@@ -3,5 +3,6 @@ import { request } from '@/utils/request'
export const recommendedApi = {
get_recommended_problem: (dsId: any) =>
request.get(`/recommended_problem/get_datasource_recommended/${dsId}`),
save_recommended_problem: (data: any) => request.post(`/recommended_problem/save`, data),
save_recommended_problem: (data: any) =>
request.post(`/recommended_problem/save_recommended_problem`, data),
}
+1
View File
@@ -309,6 +309,7 @@
}
},
"datasource": {
"recommended_problem_tips": "Custom configuration requires at least one problem, each problem should be 2-200 characters",
"recommended_problem_configuration": "Recommended Problem Configuration",
"problem_generation_method": "Problem Generation Method",
"ai_automatic_generation": "AI Automatic Generation",
+1
View File
@@ -309,6 +309,7 @@
}
},
"datasource": {
"recommended_problem_tips": "사용자 정의 구성으로 최소 한 개의 문제를 생성하세요, 각 문제는 2~200자로 작성",
"recommended_problem_configuration": "추천 문제 구성",
"problem_generation_method": "문제 생성 방식",
"ai_automatic_generation": "AI 자동 생성",
+1
View File
@@ -309,6 +309,7 @@
}
},
"datasource": {
"recommended_problem_tips": "自定义配置至少一个问题,每个问题2-200个字符",
"recommended_problem_configuration": "推荐问题配置",
"problem_generation_method": "问题生成方式",
"ai_automatic_generation": "AI 自动生成",
+1 -1
View File
@@ -704,7 +704,7 @@ function onChatCreatedQuick(chat: ChatInfo) {
}
function onChatCreated(chat: ChatInfo) {
if (chat.records.length === 1) {
if (chat.records.length === 1 && !chat.records[0].recommended_question) {
getRecommendQuestions(chat.records[0].id)
}
}
+2 -2
View File
@@ -136,7 +136,7 @@ const onClickOutside = () => {
</el-icon>
{{ $t('datasource.edit') }}
</div>
<div class="item" style="display: none" @click.stop="handleRecommendation">
<div class="item" @click.stop="handleRecommendation">
<el-icon size="16">
<icon_recommended_problem></icon_recommended_problem>
</el-icon>
@@ -287,7 +287,7 @@ const onClickOutside = () => {
&::after {
position: absolute;
content: '';
top: 40px;
top: 80px !important;
left: 0;
width: 100%;
height: 1px;
+1
View File
@@ -328,6 +328,7 @@ useEmitt({
</template>
<RecommendedProblemConfigDialog
ref="recommendedProblemConfigRef"
@recommended-problem-change="search"
></RecommendedProblemConfigDialog>
<AddDrawer ref="addDrawerRef" @search="search"></AddDrawer>
</div>
@@ -1,29 +1,35 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { recommendedApi } from '@/api/recommendedApi.ts'
import { Delete } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus-secondary'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
interface RecommendedProblem {
id?: number
question: string
datasourceId?: any | undefined
datasource_id?: any | undefined
sort: number
}
const emits = defineEmits(['recommendedProblemChange'])
const dialogShow = ref(false)
const state = reactive({
dsId: null,
datasource_id: null,
recommended: {
recommendedConfig: 1,
recommended_config: 1,
recommendedProblemList: [] as RecommendedProblem[],
},
})
const init = (params: any) => {
dialogShow.value = true
state.recommended.recommendedConfig = params.recommendedConfig
state.dsId = params.id
recommendedApi.get_recommended_problem(state.dsId).then((res: any) => {
state.recommended.recommended_config = params.recommended_config || 1
state.datasource_id = params.id
recommendedApi.get_recommended_problem(state.datasource_id).then((res: any) => {
state.recommended.recommendedProblemList = res
})
}
@@ -31,27 +37,47 @@ const init = (params: any) => {
const addRecommendedProblem = (): void => {
state.recommended.recommendedProblemList.push({
question: '',
datasourceId: state.dsId,
datasource_id: state.datasource_id,
} as RecommendedProblem)
}
const closeDialog = () => {
dialogShow.value = false
state.recommended = {
recommendedConfig: 1,
recommended_config: 1,
recommendedProblemList: [] as RecommendedProblem[],
}
}
const save = () => {
recommendedApi.save_recommended_problem(state.recommended.recommendedProblemList)
closeDialog()
if (state.recommended.recommended_config == 2) {
let checkProblem = false
if (state.recommended.recommendedProblemList.length === 0) {
checkProblem = true
}
state.recommended.recommendedProblemList.forEach((problem: RecommendedProblem): void => {
if (problem.question.length > 200 || problem.question.length < 2) {
checkProblem = true
}
})
if (checkProblem) {
ElMessage.error(t('datasource.recommended_problem_tips'))
return
}
}
recommendedApi
.save_recommended_problem({
recommended_config: state.recommended.recommended_config,
datasource_id: state.datasource_id,
problemInfo: state.recommended.recommendedProblemList,
})
.then(() => {
emits('recommendedProblemChange')
closeDialog()
})
}
const deleteRecommendedProblem = (index: number): void => {
state.recommended.recommendedProblemList.splice(index, 1)
}
const form = ref<any>({
id: null,
question: '',
sort: null,
})
defineExpose({
init,
@@ -69,31 +95,40 @@ defineExpose({
@before-closed="closeDialog"
>
<el-form-item :label="$t('datasource.problem_generation_method')" prop="mode">
<el-radio-group v-model="form.mode">
<el-radio value="1">{{ $t('datasource.ai_automatic_generation') }}</el-radio>
<el-radio value="2">{{ $t('datasource.user_defined') }}</el-radio>
<el-radio-group v-model="state.recommended.recommended_config">
<el-radio :value="1">{{ $t('datasource.ai_automatic_generation') }}</el-radio>
<el-radio :value="2">{{ $t('datasource.user_defined') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-for="(recommendedItem, index) in state.recommended.recommendedProblemList"
:key="index"
prop="mode"
>
<el-input
v-model="recommendedItem.question"
clearable
:placeholder="$t('datasource.question_tips')"
<template v-if="state.recommended.recommended_config === 2">
<el-form-item
v-for="(recommendedItem, index) in state.recommended.recommendedProblemList"
:key="index"
prop="mode"
>
</el-input>
</el-form-item>
<div>
<el-button text @click="addRecommendedProblem">
{{ $t('datasource.add_question') }}</el-button
>
</div>
<el-row class="question-item">
<el-input
v-model="recommendedItem.question"
max="200"
min="2"
class="input-item"
clearable
:placeholder="$t('datasource.question_tips')"
>
</el-input>
<el-icon class="delete-item"><Delete @click="deleteRecommendedProblem(index)" /></el-icon>
</el-row>
</el-form-item>
<div v-if="state.recommended.recommendedProblemList.length < 4">
<el-button text @click="addRecommendedProblem">
{{ $t('datasource.add_question') }}</el-button
>
</div>
</template>
<div style="display: flex; justify-content: flex-end; margin-top: 20px">
<el-button secondary @click="closeDialog">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="save">{{ $t('model.add') }}</el-button>
<el-button type="primary" @click="save">{{ $t('common.save') }}</el-button>
</div>
</el-dialog>
</template>
@@ -104,6 +139,21 @@ defineExpose({
background-color: #fff;
padding: 0 12px;
}
.question-item {
width: 100%;
display: flex;
align-items: center;
.input-item {
width: calc(100% - 40px);
}
.delete-item {
margin-left: 8px;
cursor: pointer;
&:hover {
color: red;
}
}
}
.value-input {
.ed-input-group__append {