@@ -0,0 +1,28 @@ +# Generated by Django 5.0.11 on 2025-01-31 09:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ml_model', '0041_alter_modelconfiguration_version'), + ] + + operations = [ + migrations.CreateModel( + name='ModelStat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('generation_time', models.DurationField(verbose_name='Время генерации')), + ('tokens_cost', models.DecimalField(decimal_places=10, max_digits=50, verbose_name='Цена в токенах')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Когда создано')), + ('model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='model_%(class)ss', to='ml_model.neuronmodel', verbose_name='Model')), + ], + options={ + 'verbose_name': 'Статистика по модели', + 'verbose_name_plural': 'Статистики по моделям', + }, + ), + ] @@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _ from authentication.models.choices import InvitationStatus from authentication.models.user import CustomUserModel from authentication.selectors.user_selector import UserSelector -from ml_model.models import NeuronModel, ModelParameter +from ml_model.models import ModelParameter, NeuronModel from ml_model.serializers import NeuronModelSerializer, NeuronModelsSerializer @@ -14,31 +14,39 @@ class NeuronModelSelector: def __init__(self, user: CustomUserModel): self.user = user - def get_models_by_input_content_type(self, serialize: bool = False, hidden_parameter: bool = False): + def get_models_by_input_content_type( + self, serialize: bool = False, hidden: bool = False + ): models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).all() if serialize: return NeuronModelSerializer(models, many=True) return models - def get_models_by_output_content_type(self, serialize: bool = False, hidden_parameter: bool = False): + def get_models_by_output_content_type( + self, serialize: bool = False, hidden: bool = False + ): models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).all() if serialize: return NeuronModelSerializer(models, many=True) return models def get_models( - self, - category: str | None = None, - serialize: bool = True, - hidden_parameter: bool = False + self, + category: str | None = None, + serialize: bool = True, + hidden: bool = False, ): - models = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) - ).all() + models = NeuronModel.objects.prefetch_related(Prefetch('model_modelstats')).all() if category: models = models.filter(category__slug=category) if self.user.is_anonymous: @@ -57,9 +65,14 @@ class NeuronModelSelector: return NeuronModelsSerializer(models, many=True) return models - def get_model_by_id(self, id: UUID, hidden_parameter: bool = False, **kwargs) -> NeuronModel: + def get_model_by_id(self, id: UUID, hidden: bool = False, **kwargs) -> NeuronModel: model = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ), + Prefetch('model_modelinputs'), + Prefetch('model_modelversions'), ).filter(uid=id) if not model.exists(): @@ -67,9 +80,12 @@ class NeuronModelSelector: return model.first() - def get_model_by_slug(self, slug: str, serialize: bool = False, hidden_parameter: bool = False): + def get_model_by_slug(self, slug: str, serialize: bool = False, hidden: bool = False): model = NeuronModel.objects.prefetch_related( - Prefetch('model_modelparameters', queryset=ModelParameter.objects.filter(hidden=hidden_parameter)) + Prefetch( + 'model_modelparameters', + queryset=ModelParameter.objects.filter(hidden=hidden), + ) ).get(slug=slug) if serialize: return NeuronModelSerializer(instance=model) @@ -15,6 +15,7 @@ from ml_model.models import ( ModelParameter, ModelPaymentRule, ModelSettings, + ModelStat, ModelVersion, NeuronModel, ) @@ -50,7 +51,6 @@ class ModelInputsInline(admin.TabularInline): class ModelVersionsInline(OrderedTabularInline): model = ModelVersion - fk_name = 'model' extra = 0 classes = ['collapse'] fields = ('name', 'description', 'slug', 'default', 'order', 'move_up_down_links') @@ -58,6 +58,13 @@ class ModelVersionsInline(OrderedTabularInline): ordering = ('order',) +class ModelStatInline(admin.TabularInline): + model = ModelStat + verbose_name_plural = 'Статистика по модели' + extra = 0 + classes = ['collapse'] + + @admin.register(ModelCategory) class ModelCategoryAdmin(admin.ModelAdmin): list_display = ['title', 'slug'] @@ -76,6 +83,7 @@ class NeuronModelModelAdmin( ModelSettingsInline, ModelVersionsInline, ModelPaymentRulesInline, + ModelStatInline, ModelInputsInline, ModelParametersInline, ] @@ -74,6 +74,14 @@ class NeuronModel(BaseModel, OrderedModel): def payment_rules(self) -> QuerySet['ModelPaymentRule']: return self.model_modelpaymentrules.all() + @property + def stats(self) -> QuerySet['ModelStat']: + return self.model_modelstats.all() + + @property + def first_stat(self) -> 'ModelStat': + return self.stats[0] + @property def settings(self) -> 'ModelSettings': return self.model_settings @@ -283,6 +291,19 @@ class ModelPaymentRule(ModelDepends, ModelVersionsDepends): verbose_name_plural = _('Payment Rules') +class ModelStat(ModelDepends): + generation_time = models.DurationField(verbose_name='Время генерации') + tokens_cost = models.DecimalField( + max_digits=50, decimal_places=10, verbose_name='Цена в токенах' + ) + created_at = models.DateTimeField(auto_now_add=True, verbose_name='Когда создано') + + class Meta: + verbose_name = 'Статистика по модели' + verbose_name_plural = 'Статистики по моделям' + ordering = ('-created_at',) + + class ModelConfiguration(models.Model): id = models.UUIDField( primary_key=True, default=uuid4, editable=False, verbose_name='ID' @@ -5,6 +5,7 @@ from ml_model.models import ( ModelInput, ModelParameter, ModelSettings, + ModelStat, ModelVersion, NeuronModel, ) @@ -38,6 +39,12 @@ class ModelInputSerializer(serializers.ModelSerializer): exclude = ('id', 'model') +class ModelStatSerializer(serializers.ModelSerializer): + class Meta: + model = ModelStat + exclude = ('id', 'created_at', 'model') + + class NeuronModelSerializer(serializers.ModelSerializer): settings = ModelSettingsSerializer() parameters = ModelParameterSerializer(many=True) @@ -50,6 +57,8 @@ class NeuronModelSerializer(serializers.ModelSerializer): class NeuronModelsSerializer(serializers.ModelSerializer): + actual_stat = ModelStatSerializer(source='first_stat') + class Meta: model = NeuronModel exclude = ('created_at', 'updated_at', 'order', 'category', 'uid') @@ -56,6 +56,8 @@ class NeuronModelAPIView(APIView): """Retrieve model by slug""" return Response( NeuronModelSerializer( - NeuronModelSelector(request.user).get_model_by_slug(slug=slug, hidden_parameter=False) + NeuronModelSelector(request.user).get_model_by_slug( + slug=slug, hidden=False + ) ).data )