@@ -21,6 +21,7 @@ from ml_model.services.hailuo import Hailuo from ml_model.services.hunyuan import Hunyuan from ml_model.services.iconic import Iconic from ml_model.services.ideogram import Ideogram +from ml_model.services.imagen import Imagen from ml_model.services.kandinsky import Kandinsky from ml_model.services.kling import Kling from ml_model.services.leonardo import Leonardo @@ -37,6 +38,7 @@ from ml_model.services.musicgen import Musicgen from ml_model.services.nanobanana import Nanobanana from ml_model.services.perplexity import Perplexity from ml_model.services.pulid import Pulid +from ml_model.services.photon import Photon from ml_model.services.qwen import Qwen from ml_model.services.qwen_235B import Qwen_235B from ml_model.services.qwen_3_max_thinking import Qwen_3_Max_Thinking @@ -0,0 +1,62 @@ +import time +from datetime import timedelta +from decimal import Decimal +from io import BytesIO +from typing import Any + +import requests +from django.core.files import File +from replicate.exceptions import ModelError + +from messages.models import Message +from ml_model.exceptions import ImageContentNotFound, GenerationException, RequestBlocked +from ml_model.services.base import SimpleService +from ml_model.tasks import replicate_run +from payments.exceptions.insufficient_balance import InsufficientBalance +from payments.selectors.payment_plan_selector import PaymentPlanSelector + + +class Imagen(SimpleService): + TOKENS_COST = Decimal('5') + + def calculate_price(self) -> Decimal: + return self.TOKENS_COST + + @classmethod + def predict_price(cls, content: str, file_exists: bool, info: dict[str, Any]) -> Decimal | None: + return cls.TOKENS_COST + + def save_results(self, content: str, t: timedelta, image_url: str, save: bool = True) -> list[Message]: + msg = Message( + content=content, + content_object=self.store, + elapsed_time=t, + file=File(BytesIO(requests.get(image_url).content), '.png'), + ) + if save: + return Message.objects.bulk_create([msg]) + return [msg] + + def make(self, input_message: Message, save: bool = True) -> list[Message]: + try: + if (balance := PaymentPlanSelector(self.store.user).get_current_balance()) < self.TOKENS_COST: + raise InsufficientBalance(balance, self.TOKENS_COST) + callback_data = dict( + { + 'prompt': self.translate_prompt(input_message.content), + 'safety_filter_level': 'block_medium_and_above', + **input_message.info, + } + ) + start_time = time.time() + images = replicate_run('google/imagen-3-fast', callback_data) + process_time = timedelta(seconds=(time.time() - start_time)) + self.handle_invoice(input_message.content_object.model) + msgs = self.save_results(input_message.content, process_time, images, save) + return msgs + except ModelError as exc: + if any(error in str(exc) for error in ('E005', 'E006', 'sexual', 'NSFW')): + raise RequestBlocked + elif exc.prediction.error == 'No image content found in response': + raise ImageContentNotFound + raise GenerationException @@ -0,0 +1,72 @@ +import base64 +import time + +from datetime import timedelta +from decimal import Decimal +from io import BytesIO +from typing import Any + +import filetype +import requests + +from django.core.files import File +from replicate.exceptions import ModelError + +from messages.models import Message +from ml_model.exceptions import ImageContentNotFound, GenerationException, RequestBlocked +from ml_model.services.base import SimpleService +from ml_model.tasks import replicate_run +from payments.exceptions.insufficient_balance import InsufficientBalance +from payments.selectors.payment_plan_selector import PaymentPlanSelector + + +class Photon(SimpleService): + TOKENS_COST = Decimal('2') + + def calculate_price(self) -> Decimal: + return self.TOKENS_COST + + @classmethod + def predict_price(cls, content: str, file_exists: bool, info: dict[str, Any]) -> Decimal | None: + return cls.TOKENS_COST + + def save_results(self, content: str, t: timedelta, image_url: str, save: bool = True) -> list[Message]: + msg = Message( + content=content, + content_object=self.store, + elapsed_time=t, + file=File(BytesIO(requests.get(image_url).content), '.png'), + ) + if save: + return Message.objects.bulk_create([msg]) + return [msg] + + def make(self, input_message: Message, save: bool = True) -> list[Message]: + if (balance := PaymentPlanSelector(self.store.user).get_current_balance()) < self.TOKENS_COST: + raise InsufficientBalance(balance, self.TOKENS_COST) + callback_data = dict( + { + 'prompt': self.translate_prompt(input_message.content), + **input_message.info, + } + ) + if input_message.file: + kind = filetype.guess(input_message.file.read(20)) + mime = kind.mime if kind else 'application/octet-stream' + input_message.file.seek(0) + image = f'data:{mime};base64,{base64.b64encode(input_message.file.read()).decode("utf-8")}' + input_message.file.close() + callback_data.update({'image_reference': image}) + start_time = time.time() + try: + images = replicate_run('luma/photon-flash', callback_data) + except ModelError as exc: + if any(error in str(exc) for error in ('E005', 'E006', 'sexual', 'NSFW')): + raise RequestBlocked + elif exc.prediction.error == 'No image content found in response': + raise ImageContentNotFound + raise GenerationException + process_time = timedelta(seconds=(time.time() - start_time)) + self.handle_invoice(input_message.content_object.model) + msgs = self.save_results(input_message.content, process_time, images, save) + return msgs