diff --git a/frontend/package.json b/frontend/package.json index 30ae5aac..3841e046 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,17 +19,20 @@ "@antv/g2": "^5.3.3", "@antv/s2": "^2.4.3", "@eslint/js": "^9.28.0", + "@highlightjs/vue-plugin": "^2.1.0", "@npkg/tinymce-plugins": "^0.0.7", "@tinymce/tinymce-vue": "^5.1.0", "dayjs": "^1.11.13", "element-plus": "^2.10.1", "element-plus-secondary": "^1.0.0", "element-resize-detector": "^1.2.4", + "highlight.js": "^11.11.1", + "html2canvas": "^1.4.1", "lodash": "^4.17.21", "lodash-es": "^4.17.21", + "markdown-it": "^14.1.0", "snowflake-id": "^1.1.0", "tinymce": "^5.10.9", - "html2canvas": "^1.4.1", "vue": "^3.5.13", "vue-dompurify-html": "^5.3.0", "vue-i18n": "^9.14.4", @@ -41,6 +44,7 @@ "@eslint/migrate-config": "^1.5.0", "@types/crypto-js": "^4.2.2", "@types/element-resize-detector": "^1.1.6", + "@types/markdown-it": "^14.1.2", "@types/node": "^22.14.1", "@typescript-eslint/eslint-plugin": "^8.34.0", "@typescript-eslint/parser": "^8.34.0", diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index 50fb03a7..6d4ba976 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -276,6 +276,9 @@ function deleteChat(id: number | undefined): Promise { function analysis(record_id: number | undefined) { return request.fetchStream(`/chat/record/${record_id}/analysis`, {}) } +function predict(record_id: number | undefined) { + return request.fetchStream(`/chat/record/${record_id}/predict`, {}) +} export const chatApi = { toChatRecord, @@ -288,4 +291,5 @@ export const chatApi = { renameChat, deleteChat, analysis, + predict, } diff --git a/frontend/src/utils/markdown.ts b/frontend/src/utils/markdown.ts new file mode 100644 index 00000000..22cf1992 --- /dev/null +++ b/frontend/src/utils/markdown.ts @@ -0,0 +1,27 @@ +import MarkdownIt from 'markdown-it' +import hljs from 'highlight.js' + +const md = new MarkdownIt({ + html: true, + linkify: true, + highlight: (str, lang): string => { + if (lang && hljs.getLanguage(lang)) { + try { + return ` +
+          
+          ${hljs.highlight(str, { language: lang, ignoreIllegals: true }).value}
+          
+          
+ ` + } catch (e) { + console.error(e) + return str + } + } + + return '
' + md.utils.escapeHtml(str) + '
' + }, +}) + +export default md diff --git a/frontend/src/views/chat/ChatAnswer.vue b/frontend/src/views/chat/ChatAnswer.vue index a55cfde5..c0deb770 100644 --- a/frontend/src/views/chat/ChatAnswer.vue +++ b/frontend/src/views/chat/ChatAnswer.vue @@ -3,6 +3,7 @@ import type { ChatMessage } from '@/api/chat.ts' import { computed, nextTick, ref } from 'vue' import { Loading } from '@element-plus/icons-vue' import ChartComponent from './component/ChartComponent.vue' +import MdComponent from './component/MdComponent.vue' import type { ChartTypes } from '@/views/chat/component/BaseChart.ts' import { ArrowDown } from '@element-plus/icons-vue' import ICON_BAR from '@/assets/svg/chart/bar.svg' @@ -27,13 +28,20 @@ const settings = ref<{ }) const renderSqlThinking = computed(() => { - //todo md render? - return props.message?.record?.sql_answer + return props.message?.record?.sql_answer ?? '' }) const renderChartThinking = computed(() => { - //todo md render? - return props.message?.record?.chart_answer + return props.message?.record?.chart_answer ?? '' +}) + +const renderSQL = computed(() => { + return props.message?.record?.sql + ? `\`\`\`sql + +${props.message?.record?.sql} + ` + : '' }) const dataObject = computed<{ @@ -212,7 +220,7 @@ function onTypeChange() {