Skip to content

Commit adf4fca

Browse files
committed
Refactor model deployment listing to FoundryService
Moved the Azure model deployment listing logic from TeamService to FoundryService for better separation of concerns and code reuse. Updated TeamService to use FoundryService for model deployment validation and status summary. Improved logging and configuration handling in FoundryService.
1 parent 0b33b5c commit adf4fca

File tree

2 files changed

+73
-70
lines changed

2 files changed

+73
-70
lines changed

src/backend/v3/common/services/foundry_service.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from typing import Any, Dict
2-
2+
import logging
33
from azure.ai.projects.aio import AIProjectClient
4-
4+
from git import List
5+
import aiohttp
56
from common.config.app_config import config
67

78

@@ -15,6 +16,12 @@ class FoundryService:
1516

1617
def __init__(self, client: AIProjectClient | None = None) -> None:
1718
self._client = client
19+
self.logger = logging.getLogger(__name__)
20+
# Model validation configuration
21+
self.subscription_id = config.AZURE_AI_SUBSCRIPTION_ID
22+
self.resource_group = config.AZURE_AI_RESOURCE_GROUP
23+
self.project_name = config.AZURE_AI_PROJECT_NAME
24+
self.project_endpoint = config.AZURE_AI_PROJECT_ENDPOINT
1825

1926
async def get_client(self) -> AIProjectClient:
2027
if self._client is None:
@@ -31,3 +38,62 @@ async def get_connection(self, name: str) -> Dict[str, Any]:
3138
client = await self.get_client()
3239
conn = await client.connections.get(name=name)
3340
return conn.as_dict() if hasattr(conn, "as_dict") else dict(conn)
41+
42+
# -----------------------
43+
# Model validation methods
44+
# -----------------------
45+
46+
async def list_model_deployments(self) -> List[Dict[str, Any]]:
47+
"""
48+
List all model deployments in the Azure AI project using the REST API.
49+
"""
50+
if not all([self.subscription_id, self.resource_group, self.project_name]):
51+
self.logger.error("Azure AI project configuration is incomplete")
52+
return []
53+
54+
try:
55+
token = await config.get_access_token()
56+
57+
url = (
58+
f"https://management.azure.com/subscriptions/{self.subscription_id}/"
59+
f"resourceGroups/{self.resource_group}/providers/Microsoft.MachineLearningServices/"
60+
f"workspaces/{self.project_name}/onlineEndpoints"
61+
)
62+
63+
headers = {
64+
"Authorization": f"Bearer {token}",
65+
"Content-Type": "application/json",
66+
}
67+
params = {"api-version": "2024-10-01"}
68+
69+
async with aiohttp.ClientSession() as session:
70+
async with session.get(url, headers=headers, params=params) as response:
71+
if response.status == 200:
72+
data = await response.json()
73+
deployments = data.get("value", [])
74+
deployment_info: List[Dict[str, Any]] = []
75+
for deployment in deployments:
76+
deployment_info.append(
77+
{
78+
"name": deployment.get("name"),
79+
"model": deployment.get("properties", {}).get(
80+
"model", {}
81+
),
82+
"status": deployment.get("properties", {}).get(
83+
"provisioningState"
84+
),
85+
"endpoint_uri": deployment.get(
86+
"properties", {}
87+
).get("scoringUri"),
88+
}
89+
)
90+
return deployment_info
91+
else:
92+
error_text = await response.text()
93+
self.logger.error(
94+
f"Failed to list deployments. Status: {response.status}, Error: {error_text}"
95+
)
96+
return []
97+
except Exception as e:
98+
self.logger.error(f"Error listing model deployments: {e}")
99+
return []

src/backend/v3/common/services/team_service.py

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from datetime import datetime, timezone
66
from typing import Any, Dict, List, Optional, Tuple
77

8-
import aiohttp
98
from azure.core.credentials import AzureKeyCredential
109
from azure.core.exceptions import (
1110
ClientAuthenticationError,
@@ -24,6 +23,7 @@
2423

2524
from common.config.app_config import config
2625
from common.database.database_base import DatabaseBase
26+
from v3.common.services.foundry_service import FoundryService
2727

2828

2929
class TeamService:
@@ -39,12 +39,6 @@ def __init__(self, memory_context: Optional[DatabaseBase] = None):
3939

4040
self.search_credential = config.get_azure_credentials()
4141

42-
# Model validation configuration
43-
self.subscription_id = config.AZURE_AI_SUBSCRIPTION_ID
44-
self.resource_group = config.AZURE_AI_RESOURCE_GROUP
45-
self.project_name = config.AZURE_AI_PROJECT_NAME
46-
self.project_endpoint = config.AZURE_AI_PROJECT_ENDPOINT
47-
4842
async def validate_and_parse_team_config(
4943
self, json_data: Dict[str, Any], user_id: str
5044
) -> TeamConfiguration:
@@ -279,65 +273,6 @@ async def delete_team_configuration(self, team_id: str, user_id: str) -> bool:
279273
self.logger.error("Error deleting team configuration: %s", str(e))
280274
return False
281275

282-
# -----------------------
283-
# Model validation methods
284-
# -----------------------
285-
286-
async def list_model_deployments(self) -> List[Dict[str, Any]]:
287-
"""
288-
List all model deployments in the Azure AI project using the REST API.
289-
"""
290-
if not all([self.subscription_id, self.resource_group, self.project_name]):
291-
self.logger.error("Azure AI project configuration is incomplete")
292-
return []
293-
294-
try:
295-
token = await config.get_access_token()
296-
297-
url = (
298-
f"https://management.azure.com/subscriptions/{self.subscription_id}/"
299-
f"resourceGroups/{self.resource_group}/providers/Microsoft.MachineLearningServices/"
300-
f"workspaces/{self.project_name}/onlineEndpoints"
301-
)
302-
303-
headers = {
304-
"Authorization": f"Bearer {token}",
305-
"Content-Type": "application/json",
306-
}
307-
params = {"api-version": "2024-10-01"}
308-
309-
async with aiohttp.ClientSession() as session:
310-
async with session.get(url, headers=headers, params=params) as response:
311-
if response.status == 200:
312-
data = await response.json()
313-
deployments = data.get("value", [])
314-
deployment_info: List[Dict[str, Any]] = []
315-
for deployment in deployments:
316-
deployment_info.append(
317-
{
318-
"name": deployment.get("name"),
319-
"model": deployment.get("properties", {}).get(
320-
"model", {}
321-
),
322-
"status": deployment.get("properties", {}).get(
323-
"provisioningState"
324-
),
325-
"endpoint_uri": deployment.get(
326-
"properties", {}
327-
).get("scoringUri"),
328-
}
329-
)
330-
return deployment_info
331-
else:
332-
error_text = await response.text()
333-
self.logger.error(
334-
f"Failed to list deployments. Status: {response.status}, Error: {error_text}"
335-
)
336-
return []
337-
except Exception as e:
338-
self.logger.error(f"Error listing model deployments: {e}")
339-
return []
340-
341276
def extract_models_from_agent(self, agent: Dict[str, Any]) -> set:
342277
"""
343278
Extract all possible model references from a single agent configuration.
@@ -397,7 +332,8 @@ async def validate_team_models(
397332
) -> Tuple[bool, List[str]]:
398333
"""Validate that all models required by agents in the team config are deployed."""
399334
try:
400-
deployments = await self.list_model_deployments()
335+
foundry_service = FoundryService()
336+
deployments = await foundry_service.list_model_deployments()
401337
available_models = [
402338
d.get("name", "").lower()
403339
for d in deployments
@@ -434,7 +370,8 @@ async def validate_team_models(
434370
async def get_deployment_status_summary(self) -> Dict[str, Any]:
435371
"""Get a summary of deployment status for debugging/monitoring."""
436372
try:
437-
deployments = await self.list_model_deployments()
373+
foundry_service = FoundryService()
374+
deployments = await foundry_service.list_model_deployments()
438375
summary: Dict[str, Any] = {
439376
"total_deployments": len(deployments),
440377
"successful_deployments": [],

0 commit comments

Comments
 (0)