From f62462fcc5f9ae5cbc3a0dc8bc84e2432740f621 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Mon, 3 Feb 2025 17:38:15 +0100 Subject: [PATCH 01/17] AI assistant place --- packages/web/src/icons/FontIcon.svelte | 1 + packages/web/src/tabs/QueryTab.svelte | 151 ++++++++++++++----------- 2 files changed, 89 insertions(+), 63 deletions(-) diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte index 95feb253f..084ef9b7b 100644 --- a/packages/web/src/icons/FontIcon.svelte +++ b/packages/web/src/icons/FontIcon.svelte @@ -148,6 +148,7 @@ 'icon parent-filter-outline': 'mdi mdi-home-alert-outline', 'icon download': 'mdi mdi-download', 'icon text': 'mdi mdi-text', + 'icon ai': 'mdi mdi-head-lightbulb', 'icon run': 'mdi mdi-play', 'icon chevron-down': 'mdi mdi-chevron-down', diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index b8198c89b..f01692cac 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -12,6 +12,15 @@ testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().formatCode(), }); + registerCommand({ + id: 'query.switchAiAssistant', + category: 'Query', + name: 'AI Assistant', + keyText: 'Shift+Alt+A', + icon: 'icon ai', + testEnabled: () => isProApp(), + onClick: () => getCurrentEditor().toggleAiAssistant(), + }); registerCommand({ id: 'query.insertSqlJoin', category: 'Query', @@ -89,6 +98,8 @@ import ToolStripDropDownButton from '../buttons/ToolStripDropDownButton.svelte'; import { extractQueryParameters, replaceQueryParameters } from 'dbgate-query-splitter'; import QueryParametersModal from '../modals/QueryParametersModal.svelte'; + import { isProApp } from '../utility/proTools'; + import HorizontalSplitter from '../elements/HorizontalSplitter.svelte'; export let tabid; export let conid; @@ -137,6 +148,7 @@ let domEditor; let domToolStrip; let intervalId; + let isAiAssistantVisible = false; onMount(() => { intervalId = setInterval(() => { @@ -210,6 +222,10 @@ visibleResultTabs = !visibleResultTabs; } + export function toggleAiAssistant() { + isAiAssistantVisible = !isAiAssistantVisible; + } + function getParameterSplitterOptions() { if (!queryParameterStyle) { return null; @@ -401,6 +417,7 @@ { command: 'query.replace' }, { divider: true }, { command: 'query.toggleVisibleResultTabs' }, + { command: 'query.switchAiAssistant', hideDisabled: true }, ]; } @@ -423,73 +440,80 @@ - + - {#if driver?.databaseEngineTypes?.includes('sql')} - { - setEditorData(e.detail); - if (isInitialized) { - markTabUnsaved(tabid); - } - errorMessages = []; - }} - on:focus={() => { - activator.activate(); - domToolStrip?.activate(); - invalidateCommands(); - setTimeout(() => { - isInitialized = true; - }, 100); - }} - bind:this={domEditor} - onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)} - {errorMessages} - /> - {:else} - setEditorData(e.detail)} - on:focus={() => { - activator.activate(); - domToolStrip?.activate(); - invalidateCommands(); - }} - bind:this={domEditor} - /> - {/if} + + + {#if driver?.databaseEngineTypes?.includes('sql')} + { + setEditorData(e.detail); + if (isInitialized) { + markTabUnsaved(tabid); + } + errorMessages = []; + }} + on:focus={() => { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + setTimeout(() => { + isInitialized = true; + }, 100); + }} + bind:this={domEditor} + onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)} + {errorMessages} + /> + {:else} + setEditorData(e.detail)} + on:focus={() => { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + /> + {/if} + + + + + + + + + - - - - - +
AI Assistant
-
+ @@ -511,6 +535,7 @@ icon="icon at" title="Query parameter style" /> +
From 91fcf4bd721401ac74f4561c87c154174e3de045 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 4 Feb 2025 08:54:56 +0100 Subject: [PATCH 02/17] query assistant WIP --- packages/web/src/query/QueryAiAssistant.svelte | 1 + packages/web/src/tabs/QueryTab.svelte | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 packages/web/src/query/QueryAiAssistant.svelte diff --git a/packages/web/src/query/QueryAiAssistant.svelte b/packages/web/src/query/QueryAiAssistant.svelte new file mode 100644 index 000000000..b44912f77 --- /dev/null +++ b/packages/web/src/query/QueryAiAssistant.svelte @@ -0,0 +1 @@ +AI Assistant \ No newline at end of file diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index f01692cac..4ebd0b50a 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -100,6 +100,7 @@ import QueryParametersModal from '../modals/QueryParametersModal.svelte'; import { isProApp } from '../utility/proTools'; import HorizontalSplitter from '../elements/HorizontalSplitter.svelte'; + import QueryAiAssistant from '../query/QueryAiAssistant.svelte'; export let tabid; export let conid; @@ -511,7 +512,7 @@ -
AI Assistant
+
From babfcb610867d02fdc3faf2a2110970f22c1400c Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 5 Feb 2025 18:56:00 +0100 Subject: [PATCH 03/17] AI assistant --- .../src/controllers/databaseConnections.js | 33 +++++++++++++++++++ packages/web/src/tabs/QueryTab.svelte | 9 ++++- .../src/widgets/WidgetColumnBarItem.svelte | 4 ++- packages/web/src/widgets/WidgetTitle.svelte | 21 ++++++++++-- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index fd51b5b32..b81fe77cc 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -34,6 +34,8 @@ const pipeForkLogs = require('../utility/pipeForkLogs'); const crypto = require('crypto'); const loadModelTransform = require('../utility/loadModelTransform'); const exportDbModelSql = require('../utility/exportDbModelSql'); +const axios = require('axios'); +const { getAuthProxyUrl } = require('../utility/authProxy'); const logger = getLogger('databaseConnections'); @@ -562,4 +564,35 @@ module.exports = { return true; }, + + textToSql_meta: true, + async textToSql({ conid, database, text, dialect }) { + const existing = this.opened.find(x => x.conid == conid && x.database == database); + const { structure } = existing || {}; + if (!structure) return { errorMessage: 'No database structure' }; + const model = { + tables: structure.tables.map(table => ({ + name: table.pureName, + columns: table.columns.map(column => column.columnName), + primaryKey: table.primaryKey?.columns?.map(column => column.columnName), + foreignKeys: table.foreignKeys.map(fk => ({ + refTable: fk.refTableName, + column: fk.columns[0]?.columnName, + refColumn: fk.columns[0]?.refColumnName, + })), + })), + }; + + const resp = await axios.default.post(`${getAuthProxyUrl()}/text-to-sql`, { + text, + model, + dialect, + }); + + if (!resp.data.sql) { + return { errorMessage: 'No SQL generated' }; + } + + return resp.data; + }, }; diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index 4ebd0b50a..c81d2e56f 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -512,7 +512,14 @@ - + { + isAiAssistantVisible = false; + }} + /> diff --git a/packages/web/src/widgets/WidgetColumnBarItem.svelte b/packages/web/src/widgets/WidgetColumnBarItem.svelte index f973957cd..f52f95654 100644 --- a/packages/web/src/widgets/WidgetColumnBarItem.svelte +++ b/packages/web/src/widgets/WidgetColumnBarItem.svelte @@ -16,6 +16,7 @@ export let collapsed = null; export let storageName = null; + export let onClose = null; let size = 0; @@ -70,7 +71,8 @@ (visible = !visible) : null} - data-testid={$$props['data-testid']}>{title}{title} {#if visible} diff --git a/packages/web/src/widgets/WidgetTitle.svelte b/packages/web/src/widgets/WidgetTitle.svelte index a4a3bd0f3..b7c692277 100644 --- a/packages/web/src/widgets/WidgetTitle.svelte +++ b/packages/web/src/widgets/WidgetTitle.svelte @@ -1,18 +1,35 @@ -
+
+ {#if onClose} +
+ +
+ {/if}