This commit is contained in:
dataeaseShu
2025-07-28 17:39:51 +08:00
5 changed files with 165 additions and 17 deletions
+10 -7
View File
@@ -1,17 +1,18 @@
from datetime import datetime
from typing import List, Optional
from fastapi import Body
from pydantic import BaseModel
from sqlalchemy import Column, Integer, Text, BigInteger, DateTime, Identity, Boolean
from sqlmodel import SQLModel, Field
from apps.template.filter.generator import get_permissions_template
from apps.template.generate_analysis.generator import get_analysis_template
from apps.template.generate_chart.generator import get_chart_template
from apps.template.generate_guess_question.generator import get_guess_question_template
from apps.template.generate_predict.generator import get_predict_template
from apps.template.generate_sql.generator import get_sql_template
from apps.template.select_datasource.generator import get_datasource_template
from apps.template.filter.generator import get_permissions_template
class Chat(SQLModel, table=True):
@@ -24,7 +25,8 @@ class Chat(SQLModel, table=True):
chat_type: str = Field(max_length=20, default="chat") # chat, datasource
datasource: int = Field(sa_column=Column(BigInteger, nullable=True))
engine_type: str = Field(max_length=64)
origin: Optional[int] = Field(sa_column=Column(Integer, nullable=False, default=0)) # 0: default, 1: mcp, 2: assistant
origin: Optional[int] = Field(
sa_column=Column(Integer, nullable=False, default=0)) # 0: default, 1: mcp, 2: assistant
class ChatRecord(SQLModel, table=True):
@@ -152,13 +154,14 @@ class AiModelQuestion(BaseModel):
class ChatQuestion(AiModelQuestion):
question: str = ''
chat_id: int = 0
question: str = Body(description='用户提问')
chat_id: int = Body(description='会话ID')
class ChatMcp(ChatQuestion):
token: str = ''
token: str = Body(description='token')
class ChatStart(BaseModel):
username: str = ''
password: str = ''
username: str = Body(description='用户名')
password: str = Body(description='密码')
+14 -4
View File
@@ -132,14 +132,24 @@ class AssistantOutDs:
def get_db_schema(self, ds_id: int) -> str:
ds = self.get_ds(ds_id)
schema_str = ""
db_name = ds.db_schema
#db_name = ds.db_schema
db_name = ds.db_schema if ds.db_schema is not None and ds.db_schema != "" else ds.dataBase
schema_str += f"【DB_ID】 {db_name}\n【Schema】\n"
for table in ds.tables:
schema_str += f"# Table: {db_name}.{table.name}"
schema_str += f", {table.comment}\n[\n"
schema_str += f"# Table: {db_name}.{table.name}" if ds.type != "mysql" else f"# Table: {table.name}"
table_comment = table.comment
if table_comment == '':
schema_str += '\n[\n'
else:
schema_str += f", {table_comment}\n[\n"
field_list = []
for field in table.fields:
field_list.append(f"({field.name}:{field.type}, {field.comment})")
field_comment = field.comment
if field_comment == '':
field_list.append(f"({field.name}:{field.type})")
else:
field_list.append(f"({field.name}:{field.type}, {field_comment})")
schema_str += ",\n".join(field_list)
schema_str += '\n]\n'
return schema_str
+3 -1
View File
@@ -76,7 +76,9 @@ def extract_nested_json(text):
def string_to_numeric_hash(text: str, bits: Optional[int] = 64) -> int:
hash_bytes = hashlib.sha256(text.encode()).digest()
return int.from_bytes(hash_bytes[:bits//8], byteorder='big')
hash_num = int.from_bytes(hash_bytes, byteorder='big')
max_bigint = 2**63 - 1
return hash_num % max_bigint
def setup_logging():
@@ -2,7 +2,7 @@
import ChartComponent from '@/views/chat/component/ChartComponent.vue'
import icon_window_mini_outlined from '@/assets/svg/icon_window-mini_outlined.svg'
import SqViewDisplay from '@/views/dashboard/components/sq-view/index.vue'
defineProps({
const props = defineProps({
viewInfo: {
type: Object,
required: true,
@@ -14,20 +14,80 @@ defineProps({
},
})
import { ref } from 'vue'
import { computed, nextTick, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import ChartPopover from '@/views/chat/chat-block/ChartPopover.vue'
import ICON_TABLE from '@/assets/svg/chart/icon_form_outlined.svg'
import ICON_COLUMN from '@/assets/svg/chart/icon_dashboard_outlined.svg'
import ICON_BAR from '@/assets/svg/chart/icon_bar_outlined.svg'
import ICON_LINE from '@/assets/svg/chart/icon_chart-line.svg'
import ICON_PIE from '@/assets/svg/chart/icon_pie_outlined.svg'
import type { ChartTypes } from '@/views/chat/component/BaseChart.ts'
const { t } = useI18n()
const chartRef = ref(null)
const currentChartType = ref<ChartTypes | undefined>(undefined)
const renderChart = () => {
//@ts-expect-error eslint-disable-next-line @typescript-eslint/no-unused-expressions
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
chartRef.value?.renderChart
}
const enlargeDialogVisible = ref(false)
const enlargeView = () => {
enlargeDialogVisible.value = true
}
const chartTypeList = computed(() => {
const _list = []
if (props.viewInfo.chart) {
switch (props.viewInfo.chart.type) {
case 'table':
break
case 'column':
case 'bar':
case 'line':
_list.push({
value: 'column',
name: t('chat.chart_type.column'),
icon: ICON_COLUMN,
})
_list.push({
value: 'bar',
name: t('chat.chart_type.bar'),
icon: ICON_BAR,
})
_list.push({
value: 'line',
name: t('chat.chart_type.line'),
icon: ICON_LINE,
})
break
case 'pie':
_list.push({
value: 'pie',
name: t('chat.chart_type.pie'),
icon: ICON_PIE,
})
}
}
return _list
})
function changeTable() {
onTypeChange('table')
}
function onTypeChange(val: any) {
// eslint-disable-next-line vue/no-mutating-props
props.viewInfo.chart.type = val
nextTick(() => {
//@ts-expect-error eslint-disable-next-line @typescript-eslint/no-unused-expressions
chartRef.value?.renderChart()
})
}
defineExpose({
renderChart,
enlargeView,
@@ -40,6 +100,32 @@ defineExpose({
<div class="title">
{{ viewInfo.chart.title }}
</div>
<div class="buttons-bar">
<div class="chart-select-container">
<el-tooltip effect="dark" :content="t('chat.type')" placement="top">
<ChartPopover
v-if="chartTypeList.length > 0"
:chart-type-list="chartTypeList"
:chart-type="viewInfo.chartType"
:title="t('chat.type')"
@type-change="onTypeChange"
></ChartPopover>
</el-tooltip>
<el-tooltip effect="dark" :content="t('chat.chart_type.table')" placement="top">
<el-button
class="tool-btn"
:class="{ 'chart-active': currentChartType === 'table' }"
text
@click="changeTable"
>
<el-icon size="16">
<ICON_TABLE />
</el-icon>
</el-button>
</el-tooltip>
</div>
<div class="divider" />
</div>
</div>
<div class="chart-show-area">
<ChartComponent
@@ -109,6 +195,7 @@ defineExpose({
.header-bar {
height: 32px;
display: flex;
margin-bottom: 16px;
align-items: center;
flex-direction: row;
@@ -172,9 +259,8 @@ defineExpose({
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
margin-right: 36px;
.divider {
width: 1px;
height: 16px;
@@ -221,4 +307,51 @@ defineExpose({
width: 100%;
height: calc(100% - 32px);
}
.buttons-bar {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
.divider {
width: 1px;
height: 16px;
border-left: 1px solid rgba(31, 35, 41, 0.15);
}
}
.chart-select-container {
padding: 3px;
display: flex;
flex-direction: row;
gap: 4px;
border-radius: 6px;
border: 1px solid rgba(217, 220, 223, 1);
.chart-select {
min-width: 40px;
width: 40px;
height: 24px;
:deep(.ed-select__wrapper) {
padding: 4px;
min-height: 24px;
box-shadow: unset;
border-radius: 6px;
&:hover {
background: rgba(31, 35, 41, 0.1);
}
&:active {
background: rgba(31, 35, 41, 0.1);
}
}
:deep(.ed-select__caret) {
font-size: 12px !important;
}
}
}
</style>
@@ -39,7 +39,7 @@ const curSelectChange = (value: boolean) => {
overflow: hidden;
.select-area {
position: absolute;
top: 20px;
top: 26px;
right: 20px;
}
}