Skip to content

Commit d3858ad

Browse files
committed
Enhances AI chat UI and improves model selection
Refactors the AI chat UI to improve responsiveness across different screen sizes, ensuring a consistent user experience. Improves the model selection process by fetching and caching the model catalog from the AI service. Updates styles to enhance the visual appeal and usability of the chat interface.
1 parent 3bb9062 commit d3858ad

File tree

6 files changed

+74
-20
lines changed

6 files changed

+74
-20
lines changed

frontend/src/App.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,61 +152,63 @@ async function handleTest(updatedConfig?: AIConfig) {
152152
display: flex;
153153
flex-direction: column;
154154
width: 100%;
155-
height: 100%;
156-
max-height: 100%;
155+
height: 100vh;
156+
max-height: 100vh;
157157
min-height: 0;
158158
padding: clamp(16px, 4vw, 32px);
159159
box-sizing: border-box;
160160
gap: clamp(12px, 2vw, 20px);
161161
background: var(--atest-bg-base);
162+
overflow: hidden;
162163
}
163164
164165
.welcome-panel {
165166
flex: 1;
166167
display: flex;
167168
align-items: center;
168169
justify-content: center;
170+
overflow: auto;
169171
}
170172
171173
.chat-content {
172174
flex: 1;
173-
display: grid;
174-
grid-template-rows: minmax(0, 1fr) auto;
175-
gap: var(--atest-spacing-md);
175+
display: flex;
176+
flex-direction: column;
177+
gap: 0;
176178
overflow: hidden;
177179
border-radius: var(--atest-radius-lg);
178180
background: var(--atest-bg-surface);
179181
box-shadow: var(--atest-shadow-md);
180-
padding: clamp(12px, 3vw, 24px);
181182
min-height: 0;
182183
max-height: 100%;
183184
}
184185
185186
@media (max-width: 1024px) {
186187
.ai-chat-container {
187188
padding: 24px;
189+
height: 100vh;
190+
max-height: 100vh;
188191
}
189192
}
190193
191194
@media (max-width: 768px) {
192195
.ai-chat-container {
193196
padding: 20px;
194197
gap: 12px;
198+
height: 100vh;
199+
max-height: 100vh;
195200
}
196201
197202
.chat-content {
198203
border-radius: var(--atest-radius-md);
199-
padding: 16px;
200204
}
201205
}
202206
203207
@media (max-width: 480px) {
204208
.ai-chat-container {
205209
padding: 16px;
206-
}
207-
208-
.chat-content {
209-
padding: 12px;
210+
height: 100vh;
211+
max-height: 100vh;
210212
}
211213
}
212214
</style>

frontend/src/components/AIChatHeader.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ const statusText = computed(() => t(`ai.status.${props.status}`))
4141

4242
<style scoped>
4343
.ai-chat-header {
44+
flex-shrink: 0;
4445
display: flex;
4546
justify-content: space-between;
4647
align-items: center;
47-
padding: var(--atest-spacing-md) clamp(20px, 4vw, 28px);
48+
padding: var(--atest-spacing-md) clamp(20px, 4vw, 40px);
4849
background: var(--atest-bg-surface);
4950
border-bottom: 1px solid var(--atest-border-color);
5051
}

frontend/src/components/AIChatInput.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,10 @@ function handleSubmit() {
176176

177177
<style scoped>
178178
.chat-input {
179-
padding: 20px 40px 24px;
179+
flex-shrink: 0;
180+
padding: clamp(16px, 3vw, 20px) clamp(20px, 4vw, 40px) clamp(20px, 3vw, 24px);
180181
background: var(--atest-bg-surface);
181182
border-top: 1px solid var(--atest-border-color);
182-
box-shadow: var(--atest-shadow-sm);
183-
border-radius: var(--atest-radius-md);
184183
display: flex;
185184
flex-direction: column;
186185
gap: var(--atest-spacing-sm);

frontend/src/components/AIChatMessages.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ async function copySQL(sql: string) {
123123

124124
<style scoped>
125125
.chat-messages {
126-
height: 100%;
126+
flex: 1;
127127
min-height: 0;
128128
overflow-y: auto;
129-
padding: 24px 40px;
129+
overflow-x: hidden;
130+
padding: clamp(12px, 3vw, 24px) clamp(20px, 4vw, 40px);
130131
background: var(--atest-bg-surface);
131132
color: var(--atest-text-primary);
132-
border: 1px solid var(--atest-border-color);
133-
border-radius: var(--atest-radius-md);
133+
border-bottom: 1px solid var(--atest-border-color);
134134
}
135135
136136
/* Empty state */

frontend/src/composables/useAIChat.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ref, computed, watch } from 'vue'
22
import type { AppContext, AIConfig, Message, Model, DatabaseDialect } from '@/types'
3-
import { loadConfig, loadConfigForProvider, saveConfig, getMockModels, generateId, type Provider } from '@/utils/config'
3+
import { loadConfig, loadConfigForProvider, saveConfig, generateId, type Provider } from '@/utils/config'
44
import { aiService } from '@/services/aiService'
55

66
/**
@@ -27,6 +27,33 @@ export function useAIChat(_context: AppContext) {
2727
deepseek: []
2828
})
2929

30+
const catalogCache = ref<Record<string, Model[]>>({})
31+
32+
async function initializeModelCatalog() {
33+
try {
34+
const catalog = await aiService.fetchModelCatalog()
35+
const normalizedCatalog: Record<string, Model[]> = {}
36+
37+
Object.entries(catalog).forEach(([provider, entry]) => {
38+
normalizedCatalog[provider] = entry.models || []
39+
})
40+
41+
catalogCache.value = normalizedCatalog
42+
43+
for (const [provider, models] of Object.entries(normalizedCatalog)) {
44+
if (!modelsByProvider.value[provider]) {
45+
modelsByProvider.value[provider] = models
46+
} else if ((modelsByProvider.value[provider] || []).length === 0 && models.length > 0) {
47+
modelsByProvider.value[provider] = models
48+
}
49+
}
50+
} catch (error) {
51+
console.error('Failed to load model catalog', error)
52+
}
53+
}
54+
55+
void initializeModelCatalog()
56+
3057
// Computed property to get models for current provider
3158
const availableModels = computed(() => {
3259
const key = resolveProviderKey(config.value.provider)

frontend/src/services/aiService.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,22 @@ export const aiService = {
4444
return result.models || []
4545
},
4646

47+
/**
48+
* Fetch model catalog metadata (either for a specific provider or all providers)
49+
*/
50+
async fetchModelCatalog(provider?: string): Promise<Record<string, ModelCatalogEntry>> {
51+
const payload = provider ? { provider } : {}
52+
const result = await callAPI<{ catalog: Record<string, ModelCatalogEntry> }>('models_catalog', payload)
53+
const catalog = result.catalog || {}
54+
55+
// Normalize provider keys to lowercase for consistent lookups
56+
const normalized: Record<string, ModelCatalogEntry> = {}
57+
for (const [key, entry] of Object.entries(catalog)) {
58+
normalized[key.toLowerCase()] = entry
59+
}
60+
return normalized
61+
},
62+
4763
/**
4864
* Test connection to AI provider
4965
*/
@@ -223,6 +239,15 @@ export const aiService = {
223239
}
224240
}
225241

242+
export interface ModelCatalogEntry {
243+
display_name: string
244+
category: string
245+
endpoint: string
246+
requires_api_key: boolean
247+
models: Model[]
248+
tags?: string[]
249+
}
250+
226251
function formatTimeout(timeout: number | undefined): string {
227252
const value = Number(timeout)
228253
if (!Number.isFinite(value) || value <= 0) {

0 commit comments

Comments
 (0)