isa-model 0.3.91__py3-none-any.whl → 0.4.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.
- isa_model/client.py +732 -573
- isa_model/core/cache/redis_cache.py +401 -0
- isa_model/core/config/config_manager.py +53 -10
- isa_model/core/config.py +1 -1
- isa_model/core/database/__init__.py +1 -0
- isa_model/core/database/migrations.py +277 -0
- isa_model/core/database/supabase_client.py +123 -0
- isa_model/core/models/__init__.py +37 -0
- isa_model/core/models/model_billing_tracker.py +60 -88
- isa_model/core/models/model_manager.py +36 -18
- isa_model/core/models/model_repo.py +44 -38
- isa_model/core/models/model_statistics_tracker.py +234 -0
- isa_model/core/models/model_storage.py +0 -1
- isa_model/core/models/model_version_manager.py +959 -0
- isa_model/core/pricing_manager.py +2 -249
- isa_model/core/resilience/circuit_breaker.py +366 -0
- isa_model/core/security/secrets.py +358 -0
- isa_model/core/services/__init__.py +2 -4
- isa_model/core/services/intelligent_model_selector.py +101 -370
- isa_model/core/storage/hf_storage.py +1 -1
- isa_model/core/types.py +7 -0
- isa_model/deployment/cloud/modal/isa_audio_chatTTS_service.py +520 -0
- isa_model/deployment/cloud/modal/isa_audio_fish_service.py +0 -0
- isa_model/deployment/cloud/modal/isa_audio_openvoice_service.py +758 -0
- isa_model/deployment/cloud/modal/isa_audio_service_v2.py +1044 -0
- isa_model/deployment/cloud/modal/isa_embed_rerank_service.py +296 -0
- isa_model/deployment/cloud/modal/isa_video_hunyuan_service.py +423 -0
- isa_model/deployment/cloud/modal/isa_vision_ocr_service.py +519 -0
- isa_model/deployment/cloud/modal/isa_vision_qwen25_service.py +709 -0
- isa_model/deployment/cloud/modal/isa_vision_table_service.py +467 -323
- isa_model/deployment/cloud/modal/isa_vision_ui_service.py +607 -180
- isa_model/deployment/cloud/modal/isa_vision_ui_service_optimized.py +660 -0
- isa_model/deployment/core/deployment_manager.py +6 -4
- isa_model/deployment/services/auto_hf_modal_deployer.py +894 -0
- isa_model/eval/benchmarks/__init__.py +27 -0
- isa_model/eval/benchmarks/multimodal_datasets.py +460 -0
- isa_model/eval/benchmarks.py +244 -12
- isa_model/eval/evaluators/__init__.py +8 -2
- isa_model/eval/evaluators/audio_evaluator.py +727 -0
- isa_model/eval/evaluators/embedding_evaluator.py +742 -0
- isa_model/eval/evaluators/vision_evaluator.py +564 -0
- isa_model/eval/example_evaluation.py +395 -0
- isa_model/eval/factory.py +272 -5
- isa_model/eval/isa_benchmarks.py +700 -0
- isa_model/eval/isa_integration.py +582 -0
- isa_model/eval/metrics.py +159 -6
- isa_model/eval/tests/unit/test_basic.py +396 -0
- isa_model/inference/ai_factory.py +44 -8
- isa_model/inference/services/audio/__init__.py +21 -0
- isa_model/inference/services/audio/base_realtime_service.py +225 -0
- isa_model/inference/services/audio/isa_tts_service.py +0 -0
- isa_model/inference/services/audio/openai_realtime_service.py +320 -124
- isa_model/inference/services/audio/openai_stt_service.py +32 -6
- isa_model/inference/services/base_service.py +17 -1
- isa_model/inference/services/embedding/__init__.py +13 -0
- isa_model/inference/services/embedding/base_embed_service.py +111 -8
- isa_model/inference/services/embedding/isa_embed_service.py +305 -0
- isa_model/inference/services/embedding/openai_embed_service.py +2 -4
- isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
- isa_model/inference/services/img/__init__.py +2 -2
- isa_model/inference/services/img/base_image_gen_service.py +24 -7
- isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
- isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
- isa_model/inference/services/img/services/replicate_flux.py +226 -0
- isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
- isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
- isa_model/inference/services/img/tests/test_img_client.py +297 -0
- isa_model/inference/services/llm/base_llm_service.py +30 -6
- isa_model/inference/services/llm/helpers/llm_adapter.py +63 -9
- isa_model/inference/services/llm/ollama_llm_service.py +2 -1
- isa_model/inference/services/llm/openai_llm_service.py +652 -55
- isa_model/inference/services/llm/yyds_llm_service.py +2 -1
- isa_model/inference/services/vision/__init__.py +5 -5
- isa_model/inference/services/vision/base_vision_service.py +118 -185
- isa_model/inference/services/vision/helpers/image_utils.py +11 -5
- isa_model/inference/services/vision/isa_vision_service.py +573 -0
- isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
- isa_model/serving/api/fastapi_server.py +88 -16
- isa_model/serving/api/middleware/auth.py +311 -0
- isa_model/serving/api/middleware/security.py +278 -0
- isa_model/serving/api/routes/analytics.py +486 -0
- isa_model/serving/api/routes/deployments.py +339 -0
- isa_model/serving/api/routes/evaluations.py +579 -0
- isa_model/serving/api/routes/logs.py +430 -0
- isa_model/serving/api/routes/settings.py +582 -0
- isa_model/serving/api/routes/unified.py +324 -165
- isa_model/serving/api/startup.py +304 -0
- isa_model/serving/modal_proxy_server.py +249 -0
- isa_model/training/__init__.py +100 -6
- isa_model/training/core/__init__.py +4 -1
- isa_model/training/examples/intelligent_training_example.py +281 -0
- isa_model/training/intelligent/__init__.py +25 -0
- isa_model/training/intelligent/decision_engine.py +643 -0
- isa_model/training/intelligent/intelligent_factory.py +888 -0
- isa_model/training/intelligent/knowledge_base.py +751 -0
- isa_model/training/intelligent/resource_optimizer.py +839 -0
- isa_model/training/intelligent/task_classifier.py +576 -0
- isa_model/training/storage/__init__.py +24 -0
- isa_model/training/storage/core_integration.py +439 -0
- isa_model/training/storage/training_repository.py +552 -0
- isa_model/training/storage/training_storage.py +628 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.0.dist-info}/METADATA +13 -1
- isa_model-0.4.0.dist-info/RECORD +182 -0
- isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
- isa_model/deployment/cloud/modal/register_models.py +0 -321
- isa_model/inference/adapter/unified_api.py +0 -248
- isa_model/inference/services/helpers/stacked_config.py +0 -148
- isa_model/inference/services/img/flux_professional_service.py +0 -603
- isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/others/table_transformer_service.py +0 -61
- isa_model/inference/services/vision/doc_analysis_service.py +0 -640
- isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
- isa_model/inference/services/vision/ui_analysis_service.py +0 -823
- isa_model/scripts/inference_tracker.py +0 -283
- isa_model/scripts/mlflow_manager.py +0 -379
- isa_model/scripts/model_registry.py +0 -465
- isa_model/scripts/register_models.py +0 -370
- isa_model/scripts/register_models_with_embeddings.py +0 -510
- isa_model/scripts/start_mlflow.py +0 -95
- isa_model/scripts/training_tracker.py +0 -257
- isa_model-0.3.91.dist-info/RECORD +0 -138
- {isa_model-0.3.91.dist-info → isa_model-0.4.0.dist-info}/WHEEL +0 -0
- {isa_model-0.3.91.dist-info → isa_model-0.4.0.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
|
4
4
|
"""
|
5
|
-
Intelligent Model Selector -
|
5
|
+
Intelligent Model Selector - Embedding-based model selection
|
6
6
|
Uses embedding similarity matching against model descriptions and metadata
|
7
7
|
"""
|
8
8
|
|
@@ -10,44 +10,28 @@ import logging
|
|
10
10
|
import asyncio
|
11
11
|
import json
|
12
12
|
from typing import Dict, List, Any, Optional, Tuple
|
13
|
-
from pathlib import Path
|
14
|
-
import yaml
|
15
13
|
|
16
14
|
logger = logging.getLogger(__name__)
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
from pgvector.asyncpg import register_vector
|
21
|
-
PGVECTOR_AVAILABLE = True
|
22
|
-
except ImportError:
|
23
|
-
PGVECTOR_AVAILABLE = False
|
24
|
-
logger.warning("pgvector not available, model selector will use in-memory fallback")
|
25
|
-
|
26
|
-
try:
|
27
|
-
from supabase import create_client, Client
|
28
|
-
SUPABASE_AVAILABLE = True
|
29
|
-
except ImportError:
|
30
|
-
SUPABASE_AVAILABLE = False
|
31
|
-
logger.warning("Supabase not available, falling back to SQLite")
|
16
|
+
from ..database.supabase_client import get_supabase_client
|
17
|
+
from ...inference.ai_factory import AIFactory
|
32
18
|
|
33
19
|
|
34
20
|
class IntelligentModelSelector:
|
35
21
|
"""
|
36
|
-
|
22
|
+
Intelligent model selector using embedding similarity
|
37
23
|
|
38
24
|
Features:
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
25
|
+
- Reads models from database registry
|
26
|
+
- Uses unified Supabase client
|
27
|
+
- Uses existing embedding service for similarity matching
|
42
28
|
- Has default models for each service type
|
43
29
|
"""
|
44
30
|
|
45
31
|
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
46
32
|
self.config = config or {}
|
47
|
-
self.db_pool = None
|
48
33
|
self.supabase_client = None
|
49
34
|
self.embedding_service = None
|
50
|
-
self.model_embeddings: Dict[str, List[float]] = {}
|
51
35
|
self.models_metadata: Dict[str, Dict[str, Any]] = {}
|
52
36
|
|
53
37
|
# Default models for each service type
|
@@ -55,7 +39,7 @@ class IntelligentModelSelector:
|
|
55
39
|
"vision": {"model_id": "gpt-4.1-mini", "provider": "openai"},
|
56
40
|
"audio": {"model_id": "whisper-1", "provider": "openai"},
|
57
41
|
"text": {"model_id": "gpt-4.1-mini", "provider": "openai"},
|
58
|
-
"image": {"model_id": "flux-schnell", "provider": "replicate"},
|
42
|
+
"image": {"model_id": "black-forest-labs/flux-schnell", "provider": "replicate"},
|
59
43
|
"embedding": {"model_id": "text-embedding-3-small", "provider": "openai"},
|
60
44
|
"omni": {"model_id": "gpt-4.1", "provider": "openai"}
|
61
45
|
}
|
@@ -65,17 +49,15 @@ class IntelligentModelSelector:
|
|
65
49
|
async def initialize(self):
|
66
50
|
"""Initialize the model selector"""
|
67
51
|
try:
|
52
|
+
# Initialize Supabase client
|
53
|
+
self.supabase_client = get_supabase_client()
|
54
|
+
logger.info("Supabase client initialized")
|
55
|
+
|
68
56
|
# Initialize embedding service
|
69
57
|
await self._init_embedding_service()
|
70
58
|
|
71
|
-
#
|
72
|
-
|
73
|
-
await self._init_supabase()
|
74
|
-
elif PGVECTOR_AVAILABLE:
|
75
|
-
await self._init_database()
|
76
|
-
|
77
|
-
# Load and embed models
|
78
|
-
await self._load_models()
|
59
|
+
# Load models from database
|
60
|
+
await self._load_models_from_database()
|
79
61
|
|
80
62
|
logger.info("Model selector fully initialized")
|
81
63
|
|
@@ -86,199 +68,58 @@ class IntelligentModelSelector:
|
|
86
68
|
async def _init_embedding_service(self):
|
87
69
|
"""Initialize embedding service for text similarity"""
|
88
70
|
try:
|
89
|
-
from isa_model.inference.ai_factory import AIFactory
|
90
71
|
factory = AIFactory.get_instance()
|
91
72
|
self.embedding_service = factory.get_embed("text-embedding-3-small", "openai")
|
92
73
|
logger.info("Embedding service initialized")
|
93
74
|
except Exception as e:
|
94
75
|
logger.warning(f"Failed to initialize embedding service: {e}")
|
95
76
|
|
96
|
-
async def
|
97
|
-
"""
|
77
|
+
async def _load_models_from_database(self):
|
78
|
+
"""Load models from database registry"""
|
98
79
|
try:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
if not url or not key:
|
104
|
-
# Try environment variables
|
105
|
-
import os
|
106
|
-
url = url or os.getenv("SUPABASE_URL")
|
107
|
-
key = key or os.getenv("SUPABASE_ANON_KEY")
|
80
|
+
# Get all models from database
|
81
|
+
result = self.supabase_client.table('models').select('*').execute()
|
82
|
+
models = result.data
|
108
83
|
|
109
|
-
|
110
|
-
raise ValueError("Supabase URL and key are required")
|
111
|
-
|
112
|
-
self.supabase_client = create_client(url, key)
|
113
|
-
logger.info("Supabase client initialized successfully")
|
114
|
-
|
115
|
-
except Exception as e:
|
116
|
-
logger.warning(f"Supabase initialization failed: {e}, using in-memory fallback")
|
117
|
-
self.supabase_client = None
|
118
|
-
|
119
|
-
async def _init_database(self):
|
120
|
-
"""Initialize pgvector database connection"""
|
121
|
-
try:
|
122
|
-
# Get database configuration
|
123
|
-
db_config = self.config.get("database", {
|
124
|
-
"host": "localhost",
|
125
|
-
"port": 5432,
|
126
|
-
"database": "isa_model",
|
127
|
-
"user": "postgres",
|
128
|
-
"password": "password"
|
129
|
-
})
|
130
|
-
|
131
|
-
# Create connection pool
|
132
|
-
self.db_pool = await asyncpg.create_pool(
|
133
|
-
host=db_config["host"],
|
134
|
-
port=db_config["port"],
|
135
|
-
database=db_config["database"],
|
136
|
-
user=db_config["user"],
|
137
|
-
password=db_config["password"],
|
138
|
-
min_size=1,
|
139
|
-
max_size=5
|
140
|
-
)
|
141
|
-
|
142
|
-
# Register vector extension
|
143
|
-
async with self.db_pool.acquire() as conn:
|
144
|
-
await register_vector(conn)
|
145
|
-
|
146
|
-
# Create models table if not exists
|
147
|
-
await conn.execute("""
|
148
|
-
CREATE EXTENSION IF NOT EXISTS vector;
|
149
|
-
|
150
|
-
CREATE TABLE IF NOT EXISTS model_embeddings (
|
151
|
-
id SERIAL PRIMARY KEY,
|
152
|
-
model_id VARCHAR(255) UNIQUE NOT NULL,
|
153
|
-
provider VARCHAR(100) NOT NULL,
|
154
|
-
model_type VARCHAR(50) NOT NULL,
|
155
|
-
description TEXT,
|
156
|
-
metadata JSONB,
|
157
|
-
embedding vector(1536),
|
158
|
-
created_at TIMESTAMP DEFAULT NOW(),
|
159
|
-
updated_at TIMESTAMP DEFAULT NOW()
|
160
|
-
);
|
161
|
-
|
162
|
-
CREATE INDEX IF NOT EXISTS idx_model_embeddings_similarity
|
163
|
-
ON model_embeddings USING ivfflat (embedding vector_cosine_ops);
|
164
|
-
""")
|
165
|
-
|
166
|
-
logger.info("Database initialized successfully")
|
167
|
-
|
168
|
-
except Exception as e:
|
169
|
-
logger.warning(f"Database initialization failed: {e}, using in-memory fallback")
|
170
|
-
self.db_pool = None
|
171
|
-
|
172
|
-
async def _load_models(self):
|
173
|
-
"""Load models from YAML configs and create embeddings"""
|
174
|
-
try:
|
175
|
-
# Get config directory
|
176
|
-
config_dir = Path(__file__).parent.parent.parent / "config" / "models"
|
177
|
-
|
178
|
-
if not config_dir.exists():
|
179
|
-
logger.warning(f"Model config directory not found: {config_dir}")
|
180
|
-
return
|
181
|
-
|
182
|
-
# Load all YAML files
|
183
|
-
for yaml_file in config_dir.glob("*.yaml"):
|
184
|
-
await self._load_models_from_file(yaml_file)
|
185
|
-
|
186
|
-
logger.info(f"Loaded {len(self.models_metadata)} models for similarity matching")
|
187
|
-
|
188
|
-
except Exception as e:
|
189
|
-
logger.error(f"Failed to load models: {e}")
|
190
|
-
|
191
|
-
async def _load_models_from_file(self, yaml_file: Path):
|
192
|
-
"""Load models from a specific YAML file"""
|
193
|
-
try:
|
194
|
-
with open(yaml_file, 'r', encoding='utf-8') as f:
|
195
|
-
data = yaml.safe_load(f)
|
196
|
-
|
197
|
-
provider = data.get("provider", "unknown")
|
198
|
-
models = data.get("models", [])
|
84
|
+
logger.info(f"Found {len(models)} models in database registry")
|
199
85
|
|
86
|
+
# Process each model
|
200
87
|
for model in models:
|
201
|
-
|
88
|
+
model_id = model['model_id']
|
202
89
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
90
|
+
# Parse metadata if it's a string (from JSONB)
|
91
|
+
metadata_raw = model.get('metadata', '{}')
|
92
|
+
if isinstance(metadata_raw, str):
|
93
|
+
try:
|
94
|
+
metadata = json.loads(metadata_raw)
|
95
|
+
except json.JSONDecodeError:
|
96
|
+
metadata = {}
|
97
|
+
else:
|
98
|
+
metadata = metadata_raw if isinstance(metadata_raw, dict) else {}
|
99
|
+
|
100
|
+
# Store model metadata
|
101
|
+
self.models_metadata[model_id] = {
|
102
|
+
"provider": model['provider'],
|
103
|
+
"model_type": model['model_type'],
|
104
|
+
"metadata": metadata
|
105
|
+
}
|
212
106
|
|
213
|
-
#
|
214
|
-
|
215
|
-
|
216
|
-
capabilities = model.get("capabilities", [])
|
107
|
+
# Check embeddings status
|
108
|
+
embeddings_result = self.supabase_client.table('model_embeddings').select('model_id').execute()
|
109
|
+
existing_embeddings = {row['model_id'] for row in embeddings_result.data}
|
217
110
|
|
218
|
-
|
219
|
-
|
220
|
-
search_text += f"Capabilities: {', '.join(capabilities)} "
|
221
|
-
search_text += f"Tasks: {', '.join(specialized_tasks)}"
|
111
|
+
logger.info(f"Found {len(existing_embeddings)} model embeddings")
|
112
|
+
logger.info(f"Loaded {len(self.models_metadata)} models for similarity matching")
|
222
113
|
|
223
|
-
#
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
# Store model metadata
|
229
|
-
self.models_metadata[model_id] = {
|
230
|
-
"provider": provider,
|
231
|
-
"model_type": model.get("model_type"),
|
232
|
-
"capabilities": capabilities,
|
233
|
-
"metadata": model.get("metadata", {}),
|
234
|
-
"search_text": search_text
|
235
|
-
}
|
236
|
-
|
237
|
-
# Store embedding
|
238
|
-
if self.db_pool:
|
239
|
-
await self._store_model_embedding(model_id, provider, model, embedding)
|
240
|
-
else:
|
241
|
-
self.model_embeddings[model_id] = embedding
|
242
|
-
|
243
|
-
except Exception as e:
|
244
|
-
logger.warning(f"Failed to create embedding for {model_id}: {e}")
|
114
|
+
# Warn if models don't have embeddings
|
115
|
+
missing_embeddings = set(self.models_metadata.keys()) - existing_embeddings
|
116
|
+
if missing_embeddings:
|
117
|
+
logger.warning(f"Models without embeddings: {list(missing_embeddings)}")
|
118
|
+
logger.warning("Embeddings are generated during startup. Consider restarting the service.")
|
245
119
|
|
246
120
|
except Exception as e:
|
247
|
-
logger.error(f"Failed to
|
121
|
+
logger.error(f"Failed to load models from database: {e}")
|
248
122
|
|
249
|
-
async def _store_model_embedding(
|
250
|
-
self,
|
251
|
-
model_id: str,
|
252
|
-
provider: str,
|
253
|
-
model: Dict[str, Any],
|
254
|
-
embedding: List[float]
|
255
|
-
):
|
256
|
-
"""Store model embedding in database"""
|
257
|
-
try:
|
258
|
-
async with self.db_pool.acquire() as conn:
|
259
|
-
await conn.execute("""
|
260
|
-
INSERT INTO model_embeddings
|
261
|
-
(model_id, provider, model_type, description, metadata, embedding)
|
262
|
-
VALUES ($1, $2, $3, $4, $5, $6)
|
263
|
-
ON CONFLICT (model_id)
|
264
|
-
DO UPDATE SET
|
265
|
-
provider = $2,
|
266
|
-
model_type = $3,
|
267
|
-
description = $4,
|
268
|
-
metadata = $5,
|
269
|
-
embedding = $6,
|
270
|
-
updated_at = NOW()
|
271
|
-
""",
|
272
|
-
model_id,
|
273
|
-
provider,
|
274
|
-
model.get("model_type"),
|
275
|
-
model.get("metadata", {}).get("description", ""),
|
276
|
-
json.dumps(model.get("metadata", {})),
|
277
|
-
embedding
|
278
|
-
)
|
279
|
-
|
280
|
-
except Exception as e:
|
281
|
-
logger.error(f"Failed to store embedding for {model_id}: {e}")
|
282
123
|
|
283
124
|
async def select_model(
|
284
125
|
self,
|
@@ -304,13 +145,8 @@ class IntelligentModelSelector:
|
|
304
145
|
|
305
146
|
request_embedding = await self.embedding_service.create_text_embedding(request)
|
306
147
|
|
307
|
-
# Find similar models
|
308
|
-
|
309
|
-
candidates = await self._find_similar_models_supabase(request_embedding, service_type)
|
310
|
-
elif self.db_pool:
|
311
|
-
candidates = await self._find_similar_models_db(request_embedding, service_type)
|
312
|
-
else:
|
313
|
-
candidates = await self._find_similar_models_memory(request_embedding, service_type)
|
148
|
+
# Find similar models using Supabase
|
149
|
+
candidates = await self._find_similar_models_supabase(request_embedding, service_type)
|
314
150
|
|
315
151
|
if not candidates:
|
316
152
|
return self._get_default_selection(service_type, "No suitable models found")
|
@@ -338,127 +174,60 @@ class IntelligentModelSelector:
|
|
338
174
|
request_embedding: List[float],
|
339
175
|
service_type: str
|
340
176
|
) -> List[Dict[str, Any]]:
|
341
|
-
"""Find similar models using Supabase
|
177
|
+
"""Find similar models using Supabase and embedding service similarity"""
|
342
178
|
try:
|
343
|
-
#
|
344
|
-
|
345
|
-
|
346
|
-
{
|
347
|
-
'query_embedding': request_embedding,
|
348
|
-
'similarity_threshold': 0.3, # Minimum similarity threshold
|
349
|
-
'match_count': 10,
|
350
|
-
'filter_model_type': service_type
|
351
|
-
}
|
352
|
-
).execute()
|
353
|
-
|
354
|
-
candidates = []
|
355
|
-
for row in result.data:
|
356
|
-
candidates.append({
|
357
|
-
"model_id": row["model_id"],
|
358
|
-
"provider": row["provider"],
|
359
|
-
"model_type": row["model_type"],
|
360
|
-
"similarity": float(row["similarity"]),
|
361
|
-
"description": row.get("description", "")
|
362
|
-
})
|
179
|
+
# Get all model embeddings from database
|
180
|
+
embeddings_result = self.supabase_client.table('model_embeddings').select('*').execute()
|
181
|
+
model_embeddings = embeddings_result.data
|
363
182
|
|
364
|
-
|
183
|
+
if not model_embeddings:
|
184
|
+
logger.warning("No model embeddings found in database")
|
185
|
+
return []
|
365
186
|
|
366
|
-
|
367
|
-
logger.error(f"Supabase similarity search failed: {e}")
|
368
|
-
return []
|
369
|
-
|
370
|
-
async def _find_similar_models_db(
|
371
|
-
self,
|
372
|
-
request_embedding: List[float],
|
373
|
-
service_type: str
|
374
|
-
) -> List[Dict[str, Any]]:
|
375
|
-
"""Find similar models using database"""
|
376
|
-
try:
|
377
|
-
async with self.db_pool.acquire() as conn:
|
378
|
-
# Query for similar models
|
379
|
-
rows = await conn.fetch("""
|
380
|
-
SELECT
|
381
|
-
model_id,
|
382
|
-
provider,
|
383
|
-
model_type,
|
384
|
-
description,
|
385
|
-
metadata,
|
386
|
-
1 - (embedding <=> $1) as similarity
|
387
|
-
FROM model_embeddings
|
388
|
-
WHERE model_type = $2 OR model_type = 'omni'
|
389
|
-
ORDER BY embedding <=> $1
|
390
|
-
LIMIT 10
|
391
|
-
""", request_embedding, service_type)
|
392
|
-
|
393
|
-
candidates = []
|
394
|
-
for row in rows:
|
395
|
-
candidates.append({
|
396
|
-
"model_id": row["model_id"],
|
397
|
-
"provider": row["provider"],
|
398
|
-
"model_type": row["model_type"],
|
399
|
-
"similarity": float(row["similarity"]),
|
400
|
-
"description": row["description"]
|
401
|
-
})
|
402
|
-
|
403
|
-
return candidates
|
404
|
-
|
405
|
-
except Exception as e:
|
406
|
-
logger.error(f"Database similarity search failed: {e}")
|
407
|
-
return []
|
408
|
-
|
409
|
-
async def _find_similar_models_memory(
|
410
|
-
self,
|
411
|
-
request_embedding: List[float],
|
412
|
-
service_type: str
|
413
|
-
) -> List[Dict[str, Any]]:
|
414
|
-
"""Find similar models using in-memory search"""
|
415
|
-
try:
|
187
|
+
# Calculate similarity for each model
|
416
188
|
candidates = []
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
189
|
+
for model_embed in model_embeddings:
|
190
|
+
model_id = model_embed['model_id']
|
191
|
+
model_embedding = model_embed['embedding']
|
192
|
+
|
193
|
+
# Get model metadata
|
194
|
+
model_metadata = self.models_metadata.get(model_id, {})
|
195
|
+
model_type = model_metadata.get('model_type')
|
421
196
|
|
422
197
|
# Filter by service type (including omni models)
|
423
|
-
if model_type not in [service_type,
|
198
|
+
if model_type not in [service_type, 'omni']:
|
424
199
|
continue
|
425
200
|
|
426
|
-
# Calculate
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
201
|
+
# Calculate similarity using embedding service
|
202
|
+
try:
|
203
|
+
similarity_result = await self.embedding_service.invoke(
|
204
|
+
input_data="", # Not used for similarity task
|
205
|
+
task="similarity",
|
206
|
+
embedding1=request_embedding,
|
207
|
+
embedding2=model_embedding
|
208
|
+
)
|
209
|
+
similarity = similarity_result['similarity']
|
210
|
+
|
211
|
+
candidates.append({
|
212
|
+
"model_id": model_id,
|
213
|
+
"provider": model_embed['provider'],
|
214
|
+
"model_type": model_type,
|
215
|
+
"similarity": similarity,
|
216
|
+
"description": model_embed.get('description', '')
|
217
|
+
})
|
218
|
+
|
219
|
+
except Exception as e:
|
220
|
+
logger.warning(f"Failed to calculate similarity for {model_id}: {e}")
|
221
|
+
continue
|
436
222
|
|
437
223
|
# Sort by similarity score
|
438
224
|
candidates.sort(key=lambda x: x["similarity"], reverse=True)
|
439
|
-
return candidates[:10]
|
225
|
+
return candidates[:10] # Return top 10
|
440
226
|
|
441
227
|
except Exception as e:
|
442
|
-
logger.error(f"
|
228
|
+
logger.error(f"Supabase similarity search failed: {e}")
|
443
229
|
return []
|
444
230
|
|
445
|
-
def _cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
|
446
|
-
"""Calculate cosine similarity between two vectors"""
|
447
|
-
try:
|
448
|
-
import math
|
449
|
-
|
450
|
-
dot_product = sum(a * b for a, b in zip(vec1, vec2))
|
451
|
-
norm1 = math.sqrt(sum(a * a for a in vec1))
|
452
|
-
norm2 = math.sqrt(sum(b * b for b in vec2))
|
453
|
-
|
454
|
-
if norm1 * norm2 == 0:
|
455
|
-
return 0.0
|
456
|
-
|
457
|
-
return dot_product / (norm1 * norm2)
|
458
|
-
|
459
|
-
except Exception:
|
460
|
-
return 0.0
|
461
|
-
|
462
231
|
def _get_default_selection(self, service_type: str, reason: str) -> Dict[str, Any]:
|
463
232
|
"""Get default model selection"""
|
464
233
|
default = self.default_models.get(service_type, self.default_models["vision"])
|
@@ -474,50 +243,15 @@ class IntelligentModelSelector:
|
|
474
243
|
async def get_available_models(self, service_type: Optional[str] = None) -> List[Dict[str, Any]]:
|
475
244
|
"""Get list of available models"""
|
476
245
|
try:
|
477
|
-
if
|
478
|
-
#
|
479
|
-
query = self.supabase_client.table(
|
480
|
-
|
481
|
-
if service_type:
|
482
|
-
query = query.or_(f"model_type.eq.{service_type},model_type.eq.omni")
|
483
|
-
|
484
|
-
result = query.order("model_id").execute()
|
485
|
-
return result.data
|
486
|
-
|
487
|
-
elif self.db_pool:
|
488
|
-
async with self.db_pool.acquire() as conn:
|
489
|
-
if service_type:
|
490
|
-
rows = await conn.fetch("""
|
491
|
-
SELECT model_id, provider, model_type, description, metadata
|
492
|
-
FROM model_embeddings
|
493
|
-
WHERE model_type = $1 OR model_type = 'omni'
|
494
|
-
ORDER BY model_id
|
495
|
-
""", service_type)
|
496
|
-
else:
|
497
|
-
rows = await conn.fetch("""
|
498
|
-
SELECT model_id, provider, model_type, description, metadata
|
499
|
-
FROM model_embeddings
|
500
|
-
ORDER BY model_type, model_id
|
501
|
-
""")
|
502
|
-
|
503
|
-
return [dict(row) for row in rows]
|
246
|
+
if service_type:
|
247
|
+
# Filter by service type
|
248
|
+
query = self.supabase_client.table('models').select('*').or_(f'model_type.eq.{service_type},model_type.eq.omni')
|
504
249
|
else:
|
505
|
-
#
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
continue
|
511
|
-
|
512
|
-
models.append({
|
513
|
-
"model_id": model_id,
|
514
|
-
"provider": metadata.get("provider"),
|
515
|
-
"model_type": model_type,
|
516
|
-
"description": metadata.get("metadata", {}).get("description", ""),
|
517
|
-
"metadata": metadata.get("metadata", {})
|
518
|
-
})
|
519
|
-
|
520
|
-
return models
|
250
|
+
# Get all models
|
251
|
+
query = self.supabase_client.table('models').select('*')
|
252
|
+
|
253
|
+
result = query.order('model_id').execute()
|
254
|
+
return result.data
|
521
255
|
|
522
256
|
except Exception as e:
|
523
257
|
logger.error(f"Failed to get available models: {e}")
|
@@ -525,12 +259,9 @@ class IntelligentModelSelector:
|
|
525
259
|
|
526
260
|
async def close(self):
|
527
261
|
"""Clean up resources"""
|
528
|
-
if self.
|
529
|
-
await self.
|
530
|
-
logger.info("
|
531
|
-
if self.supabase_client:
|
532
|
-
# Supabase client doesn't need explicit closing
|
533
|
-
logger.info("Supabase client cleaned up")
|
262
|
+
if self.embedding_service:
|
263
|
+
await self.embedding_service.close()
|
264
|
+
logger.info("Embedding service closed")
|
534
265
|
|
535
266
|
|
536
267
|
# Singleton instance
|
isa_model/core/types.py
CHANGED
@@ -33,6 +33,10 @@ class ModelCapability(str, Enum):
|
|
33
33
|
IMAGE_GENERATION = "image_generation"
|
34
34
|
IMAGE_ANALYSIS = "image_analysis"
|
35
35
|
AUDIO_TRANSCRIPTION = "audio_transcription"
|
36
|
+
AUDIO_REALTIME = "audio_realtime"
|
37
|
+
SPEECH_TO_TEXT = "speech_to_text"
|
38
|
+
TEXT_TO_SPEECH = "text_to_speech"
|
39
|
+
CONVERSATION = "conversation"
|
36
40
|
IMAGE_UNDERSTANDING = "image_understanding"
|
37
41
|
UI_DETECTION = "ui_detection"
|
38
42
|
OCR = "ocr"
|
@@ -56,6 +60,9 @@ class ServiceType(str, Enum):
|
|
56
60
|
EMBEDDING = "embedding"
|
57
61
|
VISION = "vision"
|
58
62
|
AUDIO = "audio"
|
63
|
+
AUDIO_STT = "audio_stt"
|
64
|
+
AUDIO_TTS = "audio_tts"
|
65
|
+
AUDIO_REALTIME = "audio_realtime"
|
59
66
|
IMAGE_GEN = "image_gen"
|
60
67
|
|
61
68
|
class ServiceStatus(str, Enum):
|