Add vision model support to LLM Manager admin and rename index for clarity
This commit is contained in:
@@ -166,6 +166,8 @@ Titania provides TLS termination and reverse proxy for all services.
|
|||||||
| `peitho.ouranos.helu.ca` | puck.incus:22981 | Peitho (Django) |
|
| `peitho.ouranos.helu.ca` | puck.incus:22981 | Peitho (Django) |
|
||||||
| `pgadmin.ouranos.helu.ca` | prospero.incus:443 (SSL) | PgAdmin 4 |
|
| `pgadmin.ouranos.helu.ca` | prospero.incus:443 (SSL) | PgAdmin 4 |
|
||||||
| `prometheus.ouranos.helu.ca` | prospero.incus:443 (SSL) | Prometheus |
|
| `prometheus.ouranos.helu.ca` | prospero.incus:443 (SSL) | Prometheus |
|
||||||
|
| `freecad-mcp.ouranos.helu.ca` | caliban.incus:22032 | FreeCAD Robust MCP Server |
|
||||||
|
| `rommie.ouranos.helu.ca` | caliban.incus:22031 | Rommie MCP Server (Agent S GUI automation) |
|
||||||
| `searxng.ouranos.helu.ca` | oberon.incus:22073 | SearXNG (OAuth2-Proxy) |
|
| `searxng.ouranos.helu.ca` | oberon.incus:22073 | SearXNG (OAuth2-Proxy) |
|
||||||
| `smtp4dev.ouranos.helu.ca` | oberon.incus:22085 | smtp4dev |
|
| `smtp4dev.ouranos.helu.ca` | oberon.incus:22085 | smtp4dev |
|
||||||
| `spelunker.ouranos.helu.ca` | puck.incus:22881 | Spelunker (Django) |
|
| `spelunker.ouranos.helu.ca` | puck.incus:22881 | Spelunker (Django) |
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
"system_embedding_badge",
|
"system_embedding_badge",
|
||||||
"system_chat_badge",
|
"system_chat_badge",
|
||||||
"system_reranker_badge",
|
"system_reranker_badge",
|
||||||
|
"system_vision_badge",
|
||||||
"is_active",
|
"is_active",
|
||||||
"created_at",
|
"created_at",
|
||||||
)
|
)
|
||||||
@@ -113,6 +114,7 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
"is_system_embedding_model",
|
"is_system_embedding_model",
|
||||||
"is_system_chat_model",
|
"is_system_chat_model",
|
||||||
"is_system_reranker_model",
|
"is_system_reranker_model",
|
||||||
|
"is_system_vision_model",
|
||||||
)
|
)
|
||||||
search_fields = ("name", "display_name", "api__name")
|
search_fields = ("name", "display_name", "api__name")
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
@@ -121,11 +123,13 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
"is_system_embedding_model",
|
"is_system_embedding_model",
|
||||||
"is_system_chat_model",
|
"is_system_chat_model",
|
||||||
"is_system_reranker_model",
|
"is_system_reranker_model",
|
||||||
|
"is_system_vision_model",
|
||||||
)
|
)
|
||||||
actions = [
|
actions = [
|
||||||
"set_as_system_embedding_model",
|
"set_as_system_embedding_model",
|
||||||
"set_as_system_chat_model",
|
"set_as_system_chat_model",
|
||||||
"set_as_system_reranker_model",
|
"set_as_system_reranker_model",
|
||||||
|
"set_as_system_vision_model",
|
||||||
]
|
]
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
("Model Info", {"fields": ("api", "name", "display_name", "model_type", "is_active")}),
|
("Model Info", {"fields": ("api", "name", "display_name", "model_type", "is_active")}),
|
||||||
@@ -136,6 +140,7 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
"is_system_embedding_model",
|
"is_system_embedding_model",
|
||||||
"is_system_chat_model",
|
"is_system_chat_model",
|
||||||
"is_system_reranker_model",
|
"is_system_reranker_model",
|
||||||
|
"is_system_vision_model",
|
||||||
),
|
),
|
||||||
"classes": ("collapse",),
|
"classes": ("collapse",),
|
||||||
"description": (
|
"description": (
|
||||||
@@ -208,6 +213,16 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
system_reranker_badge.short_description = "Reranker Default"
|
system_reranker_badge.short_description = "Reranker Default"
|
||||||
|
|
||||||
|
def system_vision_badge(self, obj):
|
||||||
|
if obj.is_system_vision_model and obj.model_type in ("vision", "chat"):
|
||||||
|
return format_html(
|
||||||
|
'<span style="background:#6f42c1;color:white;padding:3px 8px;'
|
||||||
|
'border-radius:3px;font-weight:bold;">SYSTEM DEFAULT</span>'
|
||||||
|
)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
system_vision_badge.short_description = "Vision Default"
|
||||||
|
|
||||||
# --- System model actions -----------------------------------------------
|
# --- System model actions -----------------------------------------------
|
||||||
|
|
||||||
def _set_system_model(self, request, queryset, model_type, field_name, label):
|
def _set_system_model(self, request, queryset, model_type, field_name, label):
|
||||||
@@ -225,6 +240,8 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
valid_types = [model_type]
|
valid_types = [model_type]
|
||||||
if model_type == "embedding":
|
if model_type == "embedding":
|
||||||
valid_types = ["embedding", "multimodal_embed"]
|
valid_types = ["embedding", "multimodal_embed"]
|
||||||
|
elif model_type == "vision":
|
||||||
|
valid_types = ["vision", "chat"]
|
||||||
|
|
||||||
if new_model.model_type not in valid_types:
|
if new_model.model_type not in valid_types:
|
||||||
self.message_user(
|
self.message_user(
|
||||||
@@ -269,6 +286,11 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
set_as_system_reranker_model.short_description = "Set as System Reranker Model"
|
set_as_system_reranker_model.short_description = "Set as System Reranker Model"
|
||||||
|
|
||||||
|
def set_as_system_vision_model(self, request, queryset):
|
||||||
|
self._set_system_model(request, queryset, "vision", "is_system_vision_model", "vision model")
|
||||||
|
|
||||||
|
set_as_system_vision_model.short_description = "Set as System Vision Model"
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
"""Ensure only ONE model per type is marked as system default."""
|
"""Ensure only ONE model per type is marked as system default."""
|
||||||
type_field_map = {
|
type_field_map = {
|
||||||
@@ -276,6 +298,7 @@ class LLMModelAdmin(admin.ModelAdmin):
|
|||||||
"multimodal_embed": "is_system_embedding_model",
|
"multimodal_embed": "is_system_embedding_model",
|
||||||
"chat": "is_system_chat_model",
|
"chat": "is_system_chat_model",
|
||||||
"reranker": "is_system_reranker_model",
|
"reranker": "is_system_reranker_model",
|
||||||
|
"vision": "is_system_vision_model",
|
||||||
}
|
}
|
||||||
for mtype, field in type_field_map.items():
|
for mtype, field in type_field_map.items():
|
||||||
if getattr(obj, field, False) and obj.model_type == mtype:
|
if getattr(obj, field, False) and obj.model_type == mtype:
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.11 on 2026-03-22 15:15
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("llm_manager", "0003_add_vision_model_and_usage"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameIndex(
|
||||||
|
model_name="llmmodel",
|
||||||
|
new_name="llm_manager_is_syst_d190bb_idx",
|
||||||
|
old_name="llm_manager__is_syst_b2f4e7_idx",
|
||||||
|
),
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user