Download dashboard/src/components/provider/ProviderModelsPanel.vue from qa1145/astrbbbb: direct link, hf CLI and curl.
- Browser
- Download file 8.16 kB
-
https://huggingface.co/spaces/qa1145/astrbbbb/resolve/main/dashboard/src/components/provider/ProviderModelsPanel.vue
- Command line
-
hf download hf://spaces/qa1145/astrbbbb/dashboard/src/components/provider/ProviderModelsPanel.vue
-
curl -L -o ProviderModelsPanel.vue https://huggingface.co/spaces/qa1145/astrbbbb/resolve/main/dashboard/src/components/provider/ProviderModelsPanel.vue
8.16 kB
| <template> | |
| <div class="mt-4"> | |
| <div class="d-flex align-center ga-2 mb-2"> | |
| <h3 class="text-h5 font-weight-bold mb-0">{{ tm('models.configured') }}</h3> | |
| <small style="color: grey;" v-if="availableCount">{{ tm('models.available') }} {{ availableCount }}</small> | |
| <v-text-field | |
| v-model="modelSearchProxy" | |
| density="compact" | |
| prepend-inner-icon="mdi-magnify" | |
| clearable | |
| hide-details | |
| variant="solo-filled" | |
| flat | |
| class="ml-1" | |
| style="max-width: 240px;" | |
| :placeholder="tm('models.searchPlaceholder')" | |
| /> | |
| <v-spacer></v-spacer> | |
| <v-btn | |
| color="primary" | |
| prepend-icon="mdi-download" | |
| :loading="loadingModels" | |
| @click="emit('fetch-models')" | |
| variant="tonal" | |
| size="small" | |
| > | |
| {{ isSourceModified ? tm('providerSources.saveAndFetchModels') : tm('providerSources.fetchModels') }} | |
| </v-btn> | |
| <v-btn | |
| color="primary" | |
| prepend-icon="mdi-pencil-plus" | |
| variant="text" | |
| size="small" | |
| class="ml-1" | |
| @click="emit('open-manual-model')" | |
| > | |
| {{ tm('models.manualAddButton') }} | |
| </v-btn> | |
| </div> | |
| <v-list | |
| density="compact" | |
| class="rounded-lg border" | |
| style="max-height: 520px; overflow-y: auto; font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;" | |
| > | |
| <template v-if="entries.length > 0"> | |
| <template v-for="entry in entries" :key="entry.type === 'configured' ? `provider-${entry.provider.id}` : `model-${entry.model}`"> | |
| <v-tooltip location="top" max-width="400" v-if="entry.type === 'configured'"> | |
| <template #activator="{ props }"> | |
| <v-list-item | |
| v-bind="props" | |
| class="provider-compact-item" | |
| @click="emit('open-provider-edit', entry.provider)" | |
| > | |
| <v-list-item-title class="font-weight-medium text-truncate"> | |
| {{ entry.provider.id }} | |
| </v-list-item-title> | |
| <v-list-item-subtitle class="text-caption text-grey d-flex align-center ga-1" style="font-family: monospace;"> | |
| <span>{{ entry.provider.model }}</span> | |
| <v-icon v-if="supportsImageInput(entry.metadata)" size="14" color="grey"> | |
| mdi-eye-outline | |
| </v-icon> | |
| <v-icon v-if="supportsToolCall(entry.metadata)" size="14" color="grey"> | |
| mdi-wrench | |
| </v-icon> | |
| <v-icon v-if="supportsReasoning(entry.metadata)" size="14" color="grey"> | |
| mdi-brain | |
| </v-icon> | |
| <span v-if="formatContextLimit(entry.metadata)"> | |
| {{ formatContextLimit(entry.metadata) }} | |
| </span> | |
| </v-list-item-subtitle> | |
| <template #append> | |
| <div class="d-flex align-center ga-1" @click.stop> | |
| <v-switch | |
| v-model="entry.provider.enable" | |
| density="compact" | |
| inset | |
| hide-details | |
| color="primary" | |
| class="mr-1" | |
| @update:modelValue="emit('toggle-provider-enable', entry.provider, $event)" | |
| ></v-switch> | |
| <v-tooltip location="top" max-width="300"> | |
| {{ tm('availability.test') }} | |
| <template #activator="{ props }"> | |
| <v-btn | |
| icon="mdi-connection" | |
| size="small" | |
| variant="text" | |
| :disabled="!entry.provider.enable" | |
| :loading="isProviderTesting(entry.provider.id)" | |
| v-bind="props" | |
| @click.stop="emit('test-provider', entry.provider)" | |
| ></v-btn> | |
| </template> | |
| </v-tooltip> | |
| <v-tooltip location="top" max-width="300"> | |
| {{ tm('models.configure') }} | |
| <template #activator="{ props }"> | |
| <v-btn | |
| icon="mdi-cog" | |
| size="small" | |
| variant="text" | |
| v-bind="props" | |
| @click.stop="emit('open-provider-edit', entry.provider)" | |
| ></v-btn> | |
| </template> | |
| </v-tooltip> | |
| <v-btn icon="mdi-delete" size="small" variant="text" color="error" @click.stop="emit('delete-provider', entry.provider)"></v-btn> | |
| </div> | |
| </template> | |
| </v-list-item> | |
| </template> | |
| <div> | |
| <div><strong>{{ tm('models.tooltips.providerId') }}:</strong> {{ entry.provider.id }}</div> | |
| <div><strong>{{ tm('models.tooltips.modelId') }}:</strong> {{ entry.provider.model }}</div> | |
| </div> | |
| </v-tooltip> | |
| <v-tooltip location="top" max-width="400" v-else> | |
| <template #activator="{ props }"> | |
| <v-list-item v-bind="props" class="cursor-pointer" @click="emit('add-model-provider', entry.model)"> | |
| <v-list-item-title>{{ entry.model }}</v-list-item-title> | |
| <v-list-item-subtitle class="text-caption text-grey d-flex align-center ga-1"> | |
| <span>{{ entry.model }}</span> | |
| <v-icon v-if="supportsImageInput(entry.metadata)" size="14" color="grey"> | |
| mdi-eye-outline | |
| </v-icon> | |
| <v-icon v-if="supportsToolCall(entry.metadata)" size="14" color="grey"> | |
| mdi-wrench | |
| </v-icon> | |
| <v-icon v-if="supportsReasoning(entry.metadata)" size="14" color="grey"> | |
| mdi-brain | |
| </v-icon> | |
| <span v-if="formatContextLimit(entry.metadata)"> | |
| {{ formatContextLimit(entry.metadata) }} | |
| </span> | |
| </v-list-item-subtitle> | |
| <template #append> | |
| <v-btn icon="mdi-plus" size="small" variant="text" color="primary"></v-btn> | |
| </template> | |
| </v-list-item> | |
| </template> | |
| <div> | |
| <div><strong>{{ tm('models.tooltips.modelId') }}:</strong> {{ entry.model }}</div> | |
| </div> | |
| </v-tooltip> | |
| </template> | |
| </template> | |
| <template v-else> | |
| <div class="text-center pa-4 text-medium-emphasis"> | |
| <v-icon size="48" color="grey-lighten-1">mdi-package-variant</v-icon> | |
| <p class="text-grey mt-2">{{ tm('models.empty') }}</p> | |
| </div> | |
| </template> | |
| </v-list> | |
| </div> | |
| </template> | |
| <script setup> | |
| import { computed } from 'vue' | |
| import { normalizeTextInput } from '@/utils/inputValue' | |
| const props = defineProps({ | |
| entries: { | |
| type: Array, | |
| default: () => [] | |
| }, | |
| availableCount: { | |
| type: Number, | |
| default: 0 | |
| }, | |
| modelSearch: { | |
| type: String, | |
| default: '' | |
| }, | |
| loadingModels: { | |
| type: Boolean, | |
| default: false | |
| }, | |
| isSourceModified: { | |
| type: Boolean, | |
| default: false | |
| }, | |
| supportsImageInput: { | |
| type: Function, | |
| required: true | |
| }, | |
| supportsToolCall: { | |
| type: Function, | |
| required: true | |
| }, | |
| supportsReasoning: { | |
| type: Function, | |
| required: true | |
| }, | |
| formatContextLimit: { | |
| type: Function, | |
| required: true | |
| }, | |
| testingProviders: { | |
| type: Array, | |
| default: () => [] | |
| }, | |
| tm: { | |
| type: Function, | |
| required: true | |
| } | |
| }) | |
| const emit = defineEmits([ | |
| 'update:modelSearch', | |
| 'fetch-models', | |
| 'open-manual-model', | |
| 'open-provider-edit', | |
| 'toggle-provider-enable', | |
| 'test-provider', | |
| 'delete-provider', | |
| 'add-model-provider' | |
| ]) | |
| const modelSearchProxy = computed({ | |
| get: () => props.modelSearch, | |
| set: (val) => emit('update:modelSearch', normalizeTextInput(val)) | |
| }) | |
| const isProviderTesting = (providerId) => props.testingProviders.includes(providerId) | |
| </script> | |
| <style scoped> | |
| .border { | |
| border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity)); | |
| } | |
| .cursor-pointer { | |
| cursor: pointer; | |
| } | |
| </style> | |