diff --git a/aixplain/factories/model_factory.py b/aixplain/factories/model_factory.py index da44600c..d82bdd63 100644 --- a/aixplain/factories/model_factory.py +++ b/aixplain/factories/model_factory.py @@ -31,6 +31,7 @@ from urllib.parse import urljoin from warnings import warn from aixplain.enums.function import FunctionInputOutput +from datetime import datetime class ModelFactory: @@ -67,6 +68,9 @@ def _create_model_from_response(cls, response: Dict) -> Model: if function == Function.TEXT_GENERATION: ModelClass = LLM + created_at = None + if "createdAt" in response and response["createdAt"]: + created_at = datetime.fromisoformat(response["createdAt"].replace("Z", "+00:00")) function_id = response["function"]["id"] function = Function(function_id) function_io = FunctionInputOutput.get(function_id, None) @@ -80,6 +84,7 @@ def _create_model_from_response(cls, response: Dict) -> Model: api_key=response["api_key"], cost=response["pricing"], function=function, + created_at=created_at, parameters=parameters, input_params=input_params, output_params=output_params, diff --git a/aixplain/modules/model/__init__.py b/aixplain/modules/model/__init__.py index e18f1896..2e9445b5 100644 --- a/aixplain/modules/model/__init__.py +++ b/aixplain/modules/model/__init__.py @@ -30,6 +30,7 @@ from urllib.parse import urljoin from aixplain.utils.file_utils import _request_with_retry from typing import Union, Optional, Text, Dict +from datetime import datetime class Model(Asset): @@ -63,6 +64,7 @@ def __init__( function: Optional[Function] = None, is_subscribed: bool = False, cost: Optional[Dict] = None, + created_at: Optional[datetime] = None, input_params: Optional[Dict] = None, output_params: Optional[Dict] = None, **additional_info, @@ -88,8 +90,9 @@ def __init__( self.backend_url = config.BACKEND_URL self.function = function self.is_subscribed = is_subscribed - self.input_params = input_params - self.output_params = output_params + self.created_at = created_at + self.input_params = input_params + self.output_params = output_params def to_dict(self) -> Dict: """Get the model info as a Dictionary @@ -98,7 +101,14 @@ def to_dict(self) -> Dict: Dict: Model Information """ clean_additional_info = {k: v for k, v in self.additional_info.items() if v is not None} - return {"id": self.id, "name": self.name, "supplier": self.supplier, "additional_info": clean_additional_info, "input_params": self.input_params,"output_params": self.output_params,} + return { + "id": self.id, + "name": self.name, + "supplier": self.supplier, + "additional_info": clean_additional_info, + "input_params": self.input_params, + "output_params": self.output_params, + } def __repr__(self): try: @@ -263,7 +273,9 @@ def run_async(self, data: Union[Text, Dict], name: Text = "model_process", param error = "Validation-related error: Please ensure all required fields are provided and correctly formatted." else: status_code = str(r.status_code) - error = f"Status {status_code}: Unspecified error: An unspecified error occurred while processing your request." + error = ( + f"Status {status_code}: Unspecified error: An unspecified error occurred while processing your request." + ) response = {"status": "FAILED", "error_message": error} logging.error(f"Error in request for {name} - {r.status_code}: {error}") except Exception: diff --git a/tests/functional/finetune/finetune_functional_test.py b/tests/functional/finetune/finetune_functional_test.py index 7b45613c..46520137 100644 --- a/tests/functional/finetune/finetune_functional_test.py +++ b/tests/functional/finetune/finetune_functional_test.py @@ -1,5 +1,4 @@ __author__ = "lucaspavanelli" - """ Copyright 2022 The aiXplain SDK authors @@ -26,6 +25,7 @@ from aixplain.factories import FinetuneFactory from aixplain.modules.finetune.cost import FinetuneCost from aixplain.enums import Function, Language +from datetime import datetime, timedelta, timezone import pytest @@ -40,11 +40,6 @@ def read_data(data_path): return json.load(open(data_path, "r")) -@pytest.fixture(scope="module", params=read_data(RUN_FILE)) -def run_input_map(request): - return request.param - - @pytest.fixture(scope="module", params=read_data(ESTIMATE_COST_FILE)) def estimate_cost_input_map(request): return request.param @@ -60,11 +55,32 @@ def validate_prompt_input_map(request): return request.param -def test_end2end(run_input_map): - model = ModelFactory.get(run_input_map["model_id"]) - dataset_list = [DatasetFactory.list(query=run_input_map["dataset_name"])["results"][0]] +def pytest_generate_tests(metafunc): + if "input_map" in metafunc.fixturenames: + four_weeks_ago = datetime.now(timezone.utc) - timedelta(weeks=4) + models = ModelFactory.list(function=Function.TEXT_GENERATION, is_finetunable=True)["results"] + + recent_models = [ + { + "model_name": model.name, + "model_id": model.id, + "dataset_name": "Test text generation dataset", + "inference_data": "Hello!", + "required_dev": True, + "search_metadata": False, + } + for model in models + if model.created_at is not None and model.created_at >= four_weeks_ago + ] + recent_models += read_data(RUN_FILE) + metafunc.parametrize("input_map", recent_models) + + +def test_end2end(input_map): + model = input_map["model_id"] + dataset_list = [DatasetFactory.list(query=input_map["dataset_name"])["results"][0]] train_percentage, dev_percentage = 100, 0 - if run_input_map["required_dev"]: + if input_map["required_dev"]: train_percentage, dev_percentage = 80, 20 finetune = FinetuneFactory.create( str(uuid.uuid4()), dataset_list, model, train_percentage=train_percentage, dev_percentage=dev_percentage @@ -85,12 +101,12 @@ def test_end2end(run_input_map): assert finetune_model.check_finetune_status().model_status.value == "onboarded" time.sleep(30) print(f"Model dict: {finetune_model.__dict__}") - result = finetune_model.run(run_input_map["inference_data"]) + result = finetune_model.run(input_map["inference_data"]) print(f"Result: {result}") assert result is not None - if run_input_map["search_metadata"]: + if input_map["search_metadata"]: assert "details" in result - assert len(result["details"]) > 0 + assert len(result["details"]) > 0 assert "metadata" in result["details"][0] assert len(result["details"][0]["metadata"]) > 0 finetune_model.delete()