@@ -64,7 +64,7 @@ from ml_model.services.runway import Runway from ml_model.services.sdxlemoji import Sdxlemoji from ml_model.services.seedream import Seedream from ml_model.services.sora import Sora -from ml_model.services.speedance import Speedance +from ml_model.services.seedance import Seedance from ml_model.services.stablediffusion import Stablediffusion from ml_model.services.stablemusic import Stablemusic from ml_model.services.suno import Suno @@ -19,23 +19,33 @@ from payments.exceptions.insufficient_balance import InsufficientBalance from payments.selectors.payment_plan_selector import PaymentPlanSelector -class Speedance(SimpleService): +class Seedance(SimpleService): TOKENS_COST = { - '480p': Decimal('4.5'), - '720p': Decimal('7.5'), - '1080p': Decimal('18'), + 'seedance-2.0': { + '480p': Decimal('21'), + # '480p_video': Decimal('39'), + '720p': Decimal('51'), +# '720p_video': Decimal('87') + }, # 1 second + 'seedance-2.0-fast': { + '480p': Decimal('18'), +# '480p_video': Decimal('33'), + '720p': Decimal('39'), +# '720p_video': Decimal('66') + }, # 1 second } @classmethod def predict_price(cls, content: str, file_exists: bool, info: dict[str, Any]) -> Decimal | None: resolution = info['resolution'] duration = info['duration'] - price = cls.TOKENS_COST[resolution] * duration + version = info['version'] + price = cls.TOKENS_COST[version][resolution] * duration return price.quantize(Decimal('0.1'), rounding='ROUND_UP') - def calculate_price(self, resolution: str, duration: int) -> Decimal: - price = self.TOKENS_COST[resolution] * duration + def calculate_price(self, resolution: str, duration: int, version: str) -> Decimal: + price = self.TOKENS_COST[version][resolution] * duration return price.quantize(Decimal('0.1'), rounding='ROUND_UP') def save_results(self, content: str, t: timedelta, video: str, save: bool = True) -> list[Message]: @@ -50,28 +60,24 @@ class Speedance(SimpleService): return [msg] def make(self, input_message: Message, save: bool = True) -> list[Message]: + version = input_message.info.pop('version', 'seedance-2.0') resolution = input_message.info.get('resolution', '720p') - duration = input_message.info.get('duration', 8) - if (balance := PaymentPlanSelector(self.store.user).get_current_balance()) < (cost := self.TOKENS_COST[resolution] * duration): + duration = input_message.info.get('duration', 5) + if (balance := PaymentPlanSelector(self.store.user).get_current_balance()) < (cost := self.TOKENS_COST[version][resolution] * duration): raise InsufficientBalance(balance, 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': image}) + callback_data = dict({'prompt': input_message.content, **input_message.info}) + if image := input_message.file: + callback_data.update({'image': image.url}) start_time = time.time() try: video = replicate_run( - f'bytedance/{input_message.info.get("version", "seedance-1-pro-fast")}', callback_data + f'bytedance/{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, resolution=resolution, duration=duration) + self.handle_invoice(input_message.content_object.model, resolution=resolution, duration=duration, version=version) msgs = self.save_results(input_message.content, process_time, video, save) return msgs