sql-assistant 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. sql_assistant/__init__.py +3 -0
  2. sql_assistant/api/__init__.py +1 -0
  3. sql_assistant/api/backup.py +116 -0
  4. sql_assistant/api/config.py +183 -0
  5. sql_assistant/api/conversation.py +71 -0
  6. sql_assistant/api/dependencies.py +22 -0
  7. sql_assistant/api/history.py +61 -0
  8. sql_assistant/api/models.py +221 -0
  9. sql_assistant/api/query.py +275 -0
  10. sql_assistant/api/routes.py +19 -0
  11. sql_assistant/api/schema.py +21 -0
  12. sql_assistant/config.py +144 -0
  13. sql_assistant/database/__init__.py +1 -0
  14. sql_assistant/database/backup.py +568 -0
  15. sql_assistant/database/connectors/__init__.py +1 -0
  16. sql_assistant/database/connectors/base.py +185 -0
  17. sql_assistant/database/connectors/exceptions.py +88 -0
  18. sql_assistant/database/connectors/mongodb.py +194 -0
  19. sql_assistant/database/connectors/mysql.py +110 -0
  20. sql_assistant/database/connectors/postgresql.py +133 -0
  21. sql_assistant/database/connectors/redis.py +132 -0
  22. sql_assistant/database/connectors/sqlserver.py +140 -0
  23. sql_assistant/database/history.py +290 -0
  24. sql_assistant/database/manager.py +178 -0
  25. sql_assistant/database/security.py +230 -0
  26. sql_assistant/llm/__init__.py +1 -0
  27. sql_assistant/llm/base.py +28 -0
  28. sql_assistant/llm/exceptions.py +96 -0
  29. sql_assistant/llm/manager.py +82 -0
  30. sql_assistant/llm/prompts.py +29 -0
  31. sql_assistant/llm/providers/__init__.py +1 -0
  32. sql_assistant/llm/providers/claude.py +132 -0
  33. sql_assistant/llm/providers/gemini.py +127 -0
  34. sql_assistant/llm/providers/openai_compatible.py +103 -0
  35. sql_assistant/llm/retry.py +88 -0
  36. sql_assistant/main.py +94 -0
  37. sql_assistant/settings.py +219 -0
  38. sql_assistant/web/__init__.py +1 -0
  39. sql_assistant/web/static/css/base.css +25 -0
  40. sql_assistant/web/static/css/components/backup.css +146 -0
  41. sql_assistant/web/static/css/components/chat.css +465 -0
  42. sql_assistant/web/static/css/components/modal.css +143 -0
  43. sql_assistant/web/static/css/components/settings.css +358 -0
  44. sql_assistant/web/static/css/components/sidebar.css +235 -0
  45. sql_assistant/web/static/css/components/toast.css +30 -0
  46. sql_assistant/web/static/css/style.css +10 -0
  47. sql_assistant/web/static/css/theme.css +200 -0
  48. sql_assistant/web/static/js/api.js +38 -0
  49. sql_assistant/web/static/js/app.js +161 -0
  50. sql_assistant/web/static/js/backup.js +216 -0
  51. sql_assistant/web/static/js/chat.js +238 -0
  52. sql_assistant/web/static/js/color-theme-manager.js +121 -0
  53. sql_assistant/web/static/js/confirm.js +95 -0
  54. sql_assistant/web/static/js/conversations.js +182 -0
  55. sql_assistant/web/static/js/settings.js +425 -0
  56. sql_assistant/web/static/js/state.js +43 -0
  57. sql_assistant/web/static/js/theme-manager.js +64 -0
  58. sql_assistant/web/static/js/ui.js +53 -0
  59. sql_assistant/web/templates/index.html +373 -0
  60. sql_assistant-1.0.0.dist-info/METADATA +24 -0
  61. sql_assistant-1.0.0.dist-info/RECORD +64 -0
  62. sql_assistant-1.0.0.dist-info/WHEEL +4 -0
  63. sql_assistant-1.0.0.dist-info/entry_points.txt +2 -0
  64. sql_assistant-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,358 @@
1
+ /* === Settings === */
2
+ /* Config List */
3
+ .config-list {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 8px;
7
+ margin-bottom: 12px;
8
+ }
9
+
10
+ .config-card {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: 12px;
14
+ padding: 12px;
15
+ background: var(--bg-tertiary);
16
+ border: 1px solid var(--border-color);
17
+ border-radius: var(--radius);
18
+ transition: all var(--transition);
19
+ }
20
+
21
+ .config-card.active {
22
+ border-color: var(--accent);
23
+ background: rgba(88,166,255,0.05);
24
+ }
25
+
26
+ .config-card:hover { border-color: var(--text-muted); }
27
+
28
+ .config-card .provider-icon {
29
+ width: 36px;
30
+ height: 36px;
31
+ background: var(--bg-primary);
32
+ border-radius: var(--radius-sm);
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ font-size: 18px;
37
+ flex-shrink: 0;
38
+ }
39
+
40
+ .config-card .info {
41
+ flex: 1;
42
+ min-width: 0;
43
+ }
44
+
45
+ .config-card .info .name {
46
+ font-size: 14px;
47
+ font-weight: 600;
48
+ color: var(--text-primary);
49
+ }
50
+
51
+ .config-card .info .detail {
52
+ font-size: 12px;
53
+ color: var(--text-muted);
54
+ }
55
+
56
+ .config-card .actions {
57
+ display: flex;
58
+ gap: 4px;
59
+ }
60
+
61
+ .config-card .btn-sm {
62
+ font-size: 11px;
63
+ padding: 4px 10px;
64
+ background: var(--bg-hover);
65
+ border: 1px solid var(--border-color);
66
+ color: var(--text-secondary);
67
+ cursor: pointer;
68
+ border-radius: var(--radius-sm);
69
+ transition: all var(--transition);
70
+ font-family: var(--font-sans);
71
+ }
72
+
73
+ .config-card .btn-sm:hover { background: var(--bg-primary); color: var(--text-primary); }
74
+ .config-card .btn-sm.active-btn { background: rgba(63,185,80,0.15); color: var(--success); border-color: rgba(63,185,80,0.3); }
75
+ .config-card .btn-sm.danger { color: var(--danger); }
76
+
77
+ .btn-add {
78
+ width: 100%;
79
+ padding: 10px;
80
+ background: none;
81
+ border: 1px dashed var(--border-color);
82
+ color: var(--text-secondary);
83
+ font-size: 13px;
84
+ cursor: pointer;
85
+ border-radius: var(--radius);
86
+ transition: all var(--transition);
87
+ font-family: var(--font-sans);
88
+ }
89
+
90
+ .btn-add:hover {
91
+ background: var(--bg-hover);
92
+ color: var(--text-primary);
93
+ }
94
+
95
+ /* Config Form */
96
+ .config-form {
97
+ margin-top: 16px;
98
+ padding: 16px;
99
+ background: var(--bg-secondary);
100
+ border: 1px solid var(--border-color);
101
+ border-radius: var(--radius);
102
+ font-family: var(--font-sans);
103
+ }
104
+
105
+ .config-form h4 {
106
+ font-size: 14px;
107
+ margin-bottom: 12px;
108
+ color: var(--text-primary);
109
+ font-family: var(--font-sans);
110
+ }
111
+
112
+ .form-group {
113
+ margin-bottom: 12px;
114
+ }
115
+
116
+ .form-group label {
117
+ display: block;
118
+ font-size: 12px;
119
+ color: var(--text-secondary);
120
+ margin-bottom: 4px;
121
+ font-weight: 500;
122
+ font-family: var(--font-sans);
123
+ }
124
+
125
+ .form-group input,
126
+ .form-group select {
127
+ width: 100%;
128
+ padding: 8px 12px;
129
+ background: var(--bg-tertiary);
130
+ border: 1px solid var(--border-color);
131
+ border-radius: var(--radius-sm);
132
+ color: var(--text-primary);
133
+ font-size: 13px;
134
+ outline: none;
135
+ transition: border-color var(--transition);
136
+ font-family: var(--font-mono);
137
+ }
138
+
139
+ .form-group input:focus,
140
+ .form-group select:focus {
141
+ border-color: var(--accent);
142
+ }
143
+
144
+ .form-group input::placeholder {
145
+ color: var(--text-muted);
146
+ }
147
+
148
+ .form-group label input[type="checkbox"] {
149
+ width: auto;
150
+ margin-right: 8px;
151
+ vertical-align: middle;
152
+ display: inline-block;
153
+ }
154
+
155
+ /* Streaming Toggle */
156
+ .streaming-toggle {
157
+ margin: 12px 0;
158
+ padding: 12px;
159
+ background: var(--bg-secondary);
160
+ border: 1px solid var(--border-color);
161
+ border-radius: var(--radius);
162
+ }
163
+
164
+ .toggle-label {
165
+ display: flex;
166
+ align-items: center;
167
+ cursor: pointer;
168
+ font-size: 14px;
169
+ }
170
+
171
+ .toggle-label input[type="checkbox"] {
172
+ display: none;
173
+ }
174
+
175
+ .toggle-switch {
176
+ position: relative;
177
+ width: 40px;
178
+ height: 22px;
179
+ background: var(--border-color);
180
+ border-radius: 11px;
181
+ margin-right: 10px;
182
+ transition: background var(--transition);
183
+ }
184
+
185
+ .toggle-switch::after {
186
+ content: '';
187
+ position: absolute;
188
+ top: 2px;
189
+ left: 2px;
190
+ width: 18px;
191
+ height: 18px;
192
+ background: white;
193
+ border-radius: 50%;
194
+ transition: transform var(--transition);
195
+ }
196
+
197
+ .toggle-label input:checked + .toggle-switch {
198
+ background: var(--accent);
199
+ }
200
+
201
+ .toggle-label input:checked + .toggle-switch::after {
202
+ transform: translateX(18px);
203
+ }
204
+
205
+ .toggle-text {
206
+ color: var(--text-primary);
207
+ font-weight: 500;
208
+ }
209
+
210
+ .toggle-hint {
211
+ margin: 6px 0 0 50px;
212
+ font-size: 12px;
213
+ color: var(--text-muted);
214
+ }
215
+
216
+ /* Streaming Indicator */
217
+ .streaming-indicator {
218
+ color: var(--text-secondary);
219
+ font-size: 13px;
220
+ margin-bottom: 8px;
221
+ display: flex;
222
+ align-items: center;
223
+ gap: 6px;
224
+ }
225
+
226
+ .streaming-indicator::before {
227
+ content: '';
228
+ display: inline-block;
229
+ width: 12px;
230
+ height: 12px;
231
+ border: 2px solid var(--border-color);
232
+ border-top-color: var(--accent);
233
+ border-radius: 50%;
234
+ animation: spin 0.8s linear infinite;
235
+ }
236
+
237
+ @keyframes spin {
238
+ to { transform: rotate(360deg); }
239
+ }
240
+
241
+ /* SQL Block Streaming Cursor */
242
+ .sql-block.streaming .sql-content::after {
243
+ content: '▋';
244
+ animation: blink 1s step-end infinite;
245
+ color: var(--accent);
246
+ }
247
+
248
+ @keyframes blink {
249
+ 50% { opacity: 0; }
250
+ }
251
+
252
+ /* Result Pagination */
253
+ .result-pagination {
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ gap: 12px;
258
+ margin-top: 12px;
259
+ padding-top: 12px;
260
+ border-top: 1px solid var(--border-color);
261
+ }
262
+
263
+ .btn-page {
264
+ padding: 6px 16px;
265
+ background: var(--bg-secondary);
266
+ border: 1px solid var(--border-color);
267
+ border-radius: var(--radius);
268
+ color: var(--text-primary);
269
+ font-size: 13px;
270
+ cursor: pointer;
271
+ transition: all var(--transition);
272
+ }
273
+
274
+ .btn-page:hover:not(:disabled) {
275
+ background: var(--bg-hover);
276
+ border-color: var(--accent);
277
+ }
278
+
279
+ .btn-page:disabled {
280
+ opacity: 0.5;
281
+ cursor: not-allowed;
282
+ }
283
+
284
+ .page-info {
285
+ font-size: 13px;
286
+ color: var(--text-secondary);
287
+ }
288
+
289
+ .form-actions {
290
+ display: flex;
291
+ gap: 8px;
292
+ margin-top: 16px;
293
+ }
294
+
295
+ .btn-primary {
296
+ padding: 8px 20px;
297
+ background: var(--accent);
298
+ border: none;
299
+ color: white;
300
+ font-size: 13px;
301
+ font-weight: 600;
302
+ cursor: pointer;
303
+ border-radius: var(--radius-sm);
304
+ transition: all var(--transition);
305
+ font-family: var(--font-sans);
306
+ }
307
+
308
+ .btn-primary:hover { background: var(--accent-hover); }
309
+
310
+ .btn-test {
311
+ background: var(--accent);
312
+ }
313
+
314
+ .btn-test:hover { background: var(--accent-hover); }
315
+
316
+ /* About */
317
+ .about-content {
318
+ text-align: center;
319
+ padding: 20px;
320
+ }
321
+
322
+ .about-content h3 {
323
+ font-size: 20px;
324
+ margin-bottom: 4px;
325
+ }
326
+
327
+ .about-content p {
328
+ color: var(--text-secondary);
329
+ }
330
+
331
+ .about-features {
332
+ text-align: left;
333
+ margin-top: 20px;
334
+ padding: 16px;
335
+ background: var(--bg-tertiary);
336
+ border-radius: var(--radius);
337
+ }
338
+
339
+ .about-features h4 {
340
+ font-size: 14px;
341
+ margin-bottom: 8px;
342
+ }
343
+
344
+ .about-features ul {
345
+ list-style: none;
346
+ padding: 0;
347
+ }
348
+
349
+ .about-features li {
350
+ padding: 4px 0;
351
+ color: var(--text-secondary);
352
+ font-size: 13px;
353
+ }
354
+
355
+ .about-features li::before {
356
+ content: "✓ ";
357
+ color: var(--success);
358
+ }
@@ -0,0 +1,235 @@
1
+ /* === Sidebar === */
2
+ .sidebar {
3
+ width: 300px;
4
+ min-width: 300px;
5
+ background: var(--bg-secondary);
6
+ border-right: 1px solid var(--border-color);
7
+ display: flex;
8
+ flex-direction: column;
9
+ overflow: hidden;
10
+ }
11
+
12
+ .sidebar-header {
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: space-between;
16
+ padding: 16px;
17
+ border-bottom: 1px solid var(--border-color);
18
+ }
19
+
20
+ .app-logo {
21
+ font-size: 18px;
22
+ font-weight: 700;
23
+ }
24
+
25
+ .btn-icon {
26
+ background: none;
27
+ border: 1px solid var(--border-color);
28
+ color: var(--text-secondary);
29
+ cursor: pointer;
30
+ padding: 8px;
31
+ border-radius: var(--radius-sm);
32
+ display: flex;
33
+ align-items: center;
34
+ transition: all var(--transition);
35
+ }
36
+
37
+ .btn-icon:hover {
38
+ background: var(--bg-hover);
39
+ color: var(--text-primary);
40
+ }
41
+
42
+ /* Connection Status */
43
+ .connection-status {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 8px;
47
+ padding: 12px 16px;
48
+ background: var(--bg-tertiary);
49
+ border-bottom: 1px solid var(--border-color);
50
+ }
51
+
52
+ .status-dot {
53
+ width: 8px;
54
+ height: 8px;
55
+ border-radius: 50%;
56
+ flex-shrink: 0;
57
+ }
58
+
59
+ .status-dot.online { background: var(--success); box-shadow: 0 0 6px var(--success); }
60
+ .status-dot.offline { background: var(--text-muted); }
61
+ .status-dot.error { background: var(--danger); }
62
+
63
+ .status-text {
64
+ font-size: 13px;
65
+ color: var(--text-secondary);
66
+ }
67
+
68
+ /* History Section */
69
+ .history-section {
70
+ flex: 1;
71
+ display: flex;
72
+ flex-direction: column;
73
+ overflow: hidden;
74
+ }
75
+
76
+ .history-header {
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: space-between;
80
+ padding: 12px 16px;
81
+ }
82
+
83
+ .history-header h3 {
84
+ font-size: 13px;
85
+ font-weight: 600;
86
+ color: var(--text-secondary);
87
+ text-transform: uppercase;
88
+ letter-spacing: 0.5px;
89
+ }
90
+
91
+ .btn-text {
92
+ background: none;
93
+ border: none;
94
+ color: var(--accent);
95
+ cursor: pointer;
96
+ font-size: 13px;
97
+ padding: 4px 8px;
98
+ border-radius: var(--radius-sm);
99
+ transition: all var(--transition);
100
+ }
101
+
102
+ .btn-text:hover { background: var(--bg-hover); }
103
+ .btn-text.danger { color: var(--danger); }
104
+
105
+ .history-list {
106
+ flex: 1;
107
+ overflow-y: auto;
108
+ padding: 0 8px;
109
+ }
110
+
111
+ .history-empty {
112
+ text-align: center;
113
+ color: var(--text-muted);
114
+ font-size: 13px;
115
+ padding: 24px 16px;
116
+ }
117
+
118
+ .history-item {
119
+ padding: 10px 12px;
120
+ margin-bottom: 4px;
121
+ border-radius: var(--radius-sm);
122
+ cursor: pointer;
123
+ transition: all var(--transition);
124
+ border: 1px solid transparent;
125
+ }
126
+
127
+ .history-item:hover {
128
+ background: var(--bg-hover);
129
+ }
130
+
131
+ .history-item.active {
132
+ background: rgba(88,166,255,0.1);
133
+ border-color: var(--accent);
134
+ }
135
+
136
+ .history-item-main {
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: space-between;
140
+ gap: 8px;
141
+ }
142
+
143
+ .history-item-actions {
144
+ display: flex;
145
+ gap: 4px;
146
+ flex-shrink: 0;
147
+ }
148
+
149
+ .history-item .question {
150
+ font-size: 13px;
151
+ color: var(--text-primary);
152
+ white-space: nowrap;
153
+ overflow: hidden;
154
+ text-overflow: ellipsis;
155
+ flex: 1;
156
+ }
157
+
158
+ .history-item .meta {
159
+ font-size: 11px;
160
+ color: var(--text-muted);
161
+ margin-top: 4px;
162
+ display: flex;
163
+ justify-content: space-between;
164
+ }
165
+
166
+ .history-item .btn-delete-chat {
167
+ background: none;
168
+ border: none;
169
+ color: var(--text-muted);
170
+ cursor: pointer;
171
+ padding: 4px;
172
+ border-radius: 4px;
173
+ opacity: 0;
174
+ transition: all var(--transition);
175
+ flex-shrink: 0;
176
+ }
177
+
178
+ .history-item:hover .btn-delete-chat {
179
+ opacity: 1;
180
+ }
181
+
182
+ .history-item .btn-delete-chat:hover {
183
+ background: var(--danger);
184
+ color: white;
185
+ }
186
+
187
+ .history-item-title {
188
+ flex: 1;
189
+ white-space: nowrap;
190
+ overflow: hidden;
191
+ text-overflow: ellipsis;
192
+ cursor: pointer;
193
+ }
194
+
195
+ .btn-icon-chat {
196
+ background: none;
197
+ border: none;
198
+ color: var(--text-muted);
199
+ cursor: pointer;
200
+ padding: 4px;
201
+ border-radius: 4px;
202
+ opacity: 0;
203
+ transition: all var(--transition);
204
+ display: flex;
205
+ align-items: center;
206
+ }
207
+
208
+ .history-item:hover .btn-icon-chat {
209
+ opacity: 1;
210
+ }
211
+
212
+ .btn-icon-chat:hover {
213
+ background: var(--accent);
214
+ color: white;
215
+ }
216
+
217
+ .rename-input {
218
+ width: 100%;
219
+ padding: 2px 6px;
220
+ font-size: 13px;
221
+ background: var(--bg-primary);
222
+ border: 1px solid var(--accent);
223
+ border-radius: 4px;
224
+ color: var(--text-primary);
225
+ outline: none;
226
+ font-family: var(--font-sans);
227
+ }
228
+
229
+ .history-item .badge {
230
+ font-size: 10px;
231
+ padding: 1px 6px;
232
+ border-radius: 10px;
233
+ background: var(--bg-tertiary);
234
+ color: var(--text-secondary);
235
+ }
@@ -0,0 +1,30 @@
1
+ /* === Toast === */
2
+ .toast-container {
3
+ position: fixed;
4
+ top: 16px;
5
+ right: 16px;
6
+ z-index: 2000;
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 8px;
10
+ }
11
+
12
+ .toast {
13
+ padding: 12px 20px;
14
+ border-radius: var(--radius);
15
+ font-size: 13px;
16
+ font-family: var(--font-sans);
17
+ animation: slideIn 200ms ease;
18
+ max-width: 360px;
19
+ box-shadow: var(--shadow);
20
+ border: 1px solid;
21
+ }
22
+
23
+ .toast.success { background: var(--bg-tertiary); border-color: var(--success); color: var(--success); }
24
+ .toast.error { background: var(--bg-tertiary); border-color: var(--danger); color: var(--danger); }
25
+ .toast.info { background: var(--bg-tertiary); border-color: var(--accent); color: var(--accent); }
26
+
27
+ @keyframes slideIn {
28
+ from { opacity: 0; transform: translateX(100%); }
29
+ to { opacity: 1; transform: translateX(0); }
30
+ }
@@ -0,0 +1,10 @@
1
+ /* === Main Style File === */
2
+ /* This file imports all component styles */
3
+
4
+ @import url('base.css');
5
+ @import url('components/sidebar.css');
6
+ @import url('components/chat.css');
7
+ @import url('components/modal.css');
8
+ @import url('components/settings.css');
9
+ @import url('components/backup.css');
10
+ @import url('components/toast.css');