🧹 Refactor architecture: purify models layer and move validation to service layer - #89
Conversation
…d move validation to service layer Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
@jules However, looking at , dynamic reflection and circular dependency still remain: if loader is None:
try:
import app.main as main_mod
fetch_func = getattr(main_mod, "get_model", get_model)
except Exception:
fetch_func = get_model
else:
fetch_func = loaderWe can eliminate this reflection entirely by properly wiring Dependency Injection:
def get_validated_model(
model_name: str,
allowed_models: Collection[str],
service_name: str,
loader: Optional[Callable[[str], Any]] = None,
) -> Any:
if model_name not in allowed_models:
suffix = "s" if not service_name.endswith("s") else ""
raise HTTPException(
status_code=400,
detail=f"Model '{model_name}' not found for {service_name}{suffix}.",
)
fetch_func = loader or get_model
try:
return fetch_func(model_name)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
def _get_model_or_400(model_name: str, model_type: str) -> Any:
"""
Helper for backwards compatibility with legacy tests calling _get_model_or_400.
"""
supported_models = EMBEDDING_MODELS if model_type == "embedding" else RERANK_MODELS
return get_validated_model(
model_name, supported_models, model_type, loader=get_model
)
# Dependency Injection Providers
def get_embedding_service() -> BaseEmbeddingService:
return EmbeddingService(proxy_to_tei_func=_proxy_to_tei, model_loader=get_model)
def get_rerank_service() -> BaseRerankService:
return RerankService(proxy_to_tei_func=_proxy_to_tei, model_loader=get_model)This cleanly satisfies all 149 existing unit tests (including tests patching Could you please update the PR with these changes? |
|
@jules However, in if loader is None:
try:
import app.main as main_mod
fetch_func = getattr(main_mod, "get_model", get_model)
except Exception:
fetch_func = get_model
else:
fetch_func = loaderWe can eliminate this reflection entirely by properly wiring Dependency Injection:
def get_validated_model(
model_name: str,
allowed_models: Collection[str],
service_name: str,
loader: Optional[Callable[[str], Any]] = None,
) -> Any:
if model_name not in allowed_models:
suffix = "s" if not service_name.endswith("s") else ""
raise HTTPException(
status_code=400,
detail=f"Model '{model_name}' not found for {service_name}{suffix}.",
)
fetch_func = loader or get_model
try:
return fetch_func(model_name)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
def _get_model_or_400(model_name: str, model_type: str) -> Any:
"""
Helper for backwards compatibility with legacy tests calling _get_model_or_400.
"""
supported_models = EMBEDDING_MODELS if model_type == "embedding" else RERANK_MODELS
return get_validated_model(
model_name, supported_models, model_type, loader=get_model
)
# Dependency Injection Providers
def get_embedding_service() -> BaseEmbeddingService:
return EmbeddingService(proxy_to_tei_func=_proxy_to_tei, model_loader=get_model)
def get_rerank_service() -> BaseRerankService:
return RerankService(proxy_to_tei_func=_proxy_to_tei, model_loader=get_model)This cleanly satisfies all 149 existing unit tests (including tests patching Could you please update the PR with these changes? |
Thank you for the detailed feedback! I have updated |
Thank you for the suggestion! I have removed |
…er via dependency injection Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
|
LGTM! The dynamic reflection has been cleanly replaced with standard Dependency Injection, models layer is purified, and all tests and CI checks pass. Merging. |
Thank you! Acknowledged and glad to hear the architectural refactoring met all requirements. |
What
src/app/models.pyby removing allfastapiimports (HTTPException) and dynamic reflection code (import app.main), turning it into a pure ML infrastructure layer.get_validated_modelwithinsrc/app/services/base.py.EmbeddingServiceandRerankServiceto utilizeget_validated_modelwith support for optionalmodel_loaderdependency injection.src/app/main.pyto delegate_get_model_or_400calls toget_validated_model, maintaining 100% backwards compatibility for existing unit tests.Why
models.pyandmain.py.Verification
src/app/models.pyhas no references tofastapiorapp.main.uv run ruff check srcanduv run ruff format --check srcwith 0 errors.uv run pytest- all 149 test cases passed without modifying any test files.PR created automatically by Jules for task 3909149081493120938 started by @chottokun