@@ -70,9 +70,20 @@ class Flux(SimpleService): def make(self, input_message: Message, save: bool = True) -> list[Message]: start_time = time.time() version = input_message.info.get('version') + user_prompt = self.translate_prompt(input_message.content) + prompt = f""" + {user_prompt}. + Clear main subject and coherent scene context. + Balanced composition with readable foreground, midground, and background. + Natural, consistent lighting with clean shadows and good tonal balance. + Accurate proportions, clean geometry, and stable spatial relationships. + Crisp important details, clear textures, and minimal visual artifacts. + """ callback_data = dict( { - 'prompt': self.translate_prompt(input_message.content), + 'prompt': prompt, + 'go_fast': False, + 'output_quality': 100, **input_message.info, } ) @@ -17,17 +17,14 @@ from payments.selectors.payment_plan_selector import PaymentPlanSelector class Lyria(SimpleService): - TOKENS_COST = Decimal('0.6') # per 1 sec of output audio + TOKENS_COST = {'lyria-3': Decimal('12'), 'lyria-3-pro': Decimal('24')} @classmethod def predict_price(cls, content: str, file_exists: bool, info: dict[str, Any]) -> Decimal | None: - duration = info.get('duration', 32) - price = cls.TOKENS_COST * duration - return price.quantize(Decimal('0.1'), rounding='ROUND_UP') + return cls.TOKENS_COST[info['version']] - def calculate_price(self, duration: int) -> Decimal: - price = self.TOKENS_COST * duration - return price.quantize(Decimal('0.1'), rounding='ROUND_UP') + def calculate_price(self, version: str) -> Decimal: + return self.TOKENS_COST[version] def save_results(self, content: str, t: timedelta, audio: str, save: bool = True) -> list[Message]: msg = Message( @@ -41,23 +38,22 @@ class Lyria(SimpleService): return [msg] def make(self, input_message: Message, save: bool = True) -> list[Message]: - if ( - (balance := PaymentPlanSelector(self.store.user).get_current_balance()) - < (cost := self.TOKENS_COST * 32) + version = input_message.info.pop('version', 'lyria-3') + if (balance := PaymentPlanSelector(self.store.user).get_current_balance()) < ( + cost := self.TOKENS_COST[version] ): raise InsufficientBalance(balance, cost) - callback_data = { - 'prompt': self.translate_prompt(input_message.content), - **input_message.info - } + callback_data = {'prompt': input_message.content} + if file := input_message.file: + callback_data.update({'images': [file.url]}) start_time = time.time() try: - video = replicate_run(f'google/lyria-2', callback_data) + video = replicate_run(f'google/{version}', callback_data) except ModelError as exc: if any(error in str(exc) for error in ('E005', 'E006', 'sexual')): raise RequestBlocked raise GenerationException from exc process_time = timedelta(seconds=(time.time() - start_time)) - self.handle_invoice(input_message.content_object.model, duration=32) + self.handle_invoice(input_message.content_object.model, version) msgs = self.save_results(input_message.content, process_time, video, save) return msgs @@ -52,9 +52,36 @@ class Midjourney(SimpleService): def make(self, input_message: Message, save: bool = True) -> list[Message]: start_time = time.time() - translated_prompt = self.translate_prompt(input_message.content) - activation_prompt = f'mdjrny-v4 style a highly detailed {translated_prompt}' - callback_data = dict(prompt=activation_prompt, **input_message.info) + base_prompt = input_message.content + activation_prompt = f""" + Transform the user input into a single high-quality photographic image prompt. + USER INPUT: + {base_prompt} + RULES: + - Convert input into a realistic visual scene + - Keep one clear main subject unless multiple are explicitly required + - Ensure the scene looks like a real photograph, not an illustration or CGI + STYLE: + real-world photography, natural and believable scene, no artificial or cartoon look + COMPOSITION: + clear subject focus, natural framing, balanced but unposed layout, + real depth between foreground, subject, and background + CAMERA: + professional camera look, 35–85mm lens perspective, + natural depth of field, realistic focus and perspective + LIGHTING: + natural or practical lighting only (sunlight, indoor lamps, ambient light), + soft realistic shadows, no artificial glow or dramatic effects + COLOR: + neutral and realistic color reproduction, + slight natural tonal variation, no heavy grading or stylization + DETAIL: + real materials and textures, natural imperfections, + avoid smooth plastic-like or CGI surfaces + OUTPUT: + Return ONLY a single concise image-generation prompt describing the final scene. + """ + callback_data = dict(prompt=activation_prompt, prompt_optimizer=False,**input_message.info) results = replicate_run(self._CALLBACK, callback_data) process_time = timedelta(seconds=(time.time() - start_time)) self.handle_invoice(input_message.content_object.model, input_message=input_message)