| | import databases |
| | import orm |
| | import asyncio, os |
| | import uuid, random |
| | from pydub import AudioSegment |
| | from .DescriptAPI import Speak |
| | from .Vercel import AsyncImageGenerator |
| | import aiohttp |
| | from typing import List |
| |
|
| | database_url = "sqlite+aiosqlite:///ok.db" |
| | database = databases.Database(database_url) |
| | models = orm.ModelRegistry(database=database) |
| |
|
| |
|
| | class Project(orm.Model): |
| | tablename = "projects" |
| | start = 0 |
| | registry = models |
| | fields = { |
| | "id": orm.Integer(primary_key=True), |
| | "name": orm.String(max_length=10_000), |
| | "aspect_ratio": orm.Float(allow_null=True, default=0), |
| | "transcript": orm.JSON(allow_null=True, default=[]), |
| | "duration": orm.Integer(allow_null=True, default=0), |
| | "assets": orm.JSON(allow_null=True, default=[]), |
| | "links": orm.JSON(allow_null=True, default=[]), |
| | "constants": orm.JSON(allow_null=True, default={}), |
| | } |
| |
|
| | """ |
| | assets.extend( |
| | [ |
| | {"type": "video", "sequence": video_sequence}, |
| | { |
| | "type": "audio", |
| | "sequence": [ |
| | { |
| | "type": "audio", |
| | "name": "transcript.wav", |
| | "start": trans_start, |
| | "end": trans_end, |
| | "props": { |
| | "startFrom": trans_start * 30, |
| | "endAt": trans_end * 30, |
| | "volume": 5, |
| | }, |
| | }, |
| | ], |
| | }, |
| | { |
| | "type": "background", |
| | "sequence": [ |
| | { |
| | "type": "background", |
| | "name": "background.mp3", |
| | "start": trans_start, |
| | "end": trans_end, |
| | "props": { |
| | "startFrom": trans_start * 30, |
| | "endAt": trans_end * 30, |
| | "volume": 0.4, |
| | }, |
| | }, |
| | ], |
| | }, |
| | ] |
| | ) |
| | |
| | |
| | { |
| | "type": "image", |
| | "name": file_name, |
| | "start": image["start"], |
| | "end": image["end"], |
| | } |
| | """ |
| |
|
| | async def get_all_scenes(self): |
| | return await Scene.objects.filter(project=self).all() |
| |
|
| | async def generate_json(self): |
| | project_scenes: List[Scene] = await self.get_all_scenes() |
| | self.links = [] |
| | self.assets = [] |
| | image_assets = [] |
| | video_assets = [] |
| | audio_assets = [] |
| |
|
| | transitions = [ |
| | "WaveRight_transparent.webm", |
| | "WaveLeft_transparent.webm", |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ] |
| |
|
| | self.links.append( |
| | { |
| | "file_name": "sfx_1.mp3", |
| | "link": "https://dm0qx8t0i9gc9.cloudfront.net/previews/audio/BsTwCwBHBjzwub4i4/camera-shutter-05_MJn9CZV__NWM.mp3?type=preview&origin=AUDIOBLOCKS×tamp_ms=1715270679690&publicKey=kUhrS9sKVrQMTvByQMAGMM0jwRbJ4s31HTPVkfDGmwGhYqzmWJHsjIw5fZCkI7ba&organizationId=105711&apiVersion=2.0&stockItemId=2248&resolution=&endUserId=414d29f16694d76c58e7998200a8dcf6f28dc165&projectId=f734c6d7-e39d-4c1d-8f41-417f94cd37ce&searchId=4b01b35a-fafc-45fb-9f40-e98849cb71ac&searchPageId=f24f4c5b-9976-4fd3-9bac-d217d87c723d", |
| | } |
| | ) |
| | for scene in project_scenes: |
| | _, file_name = os.path.split(scene.narration_path) |
| | self.duration += scene.narration_duration + 1 |
| | self.links.append({"file_name": file_name, "link": scene.narration_link}) |
| |
|
| | |
| | audio_assets.append( |
| | { |
| | "type": "audio", |
| | "name": file_name, |
| | "start": self.start, |
| | "end": self.start + scene.narration_duration + 1, |
| | "props": { |
| | "startFrom": 0, |
| | "endAt": scene.narration_duration * 30, |
| | "volume": 5, |
| | }, |
| | } |
| | ) |
| |
|
| | |
| | for image in scene.images: |
| | file_name = str(uuid.uuid4()) + ".png" |
| | self.links.append({"file_name": file_name, "link": image}) |
| | image_assets.append( |
| | { |
| | "type": "image", |
| | "name": file_name, |
| | "start": self.start, |
| | "end": self.start + scene.image_duration, |
| | } |
| | ) |
| | self.start = self.start + scene.image_duration |
| |
|
| | |
| | video_assets.append( |
| | { |
| | "type": "video", |
| | "name": "Effects/" + random.choice(transitions), |
| | "start": self.start - 1, |
| | "end": self.start + 2, |
| | "props": { |
| | "startFrom": 1 * 30, |
| | "endAt": 3 * 30, |
| | "volume": 0, |
| | }, |
| | } |
| | ) |
| |
|
| | self.assets.append({"type": "audio", "sequence": audio_assets}) |
| | |
| | self.assets.append({"type": "image", "sequence": image_assets}) |
| | self.assets.append( |
| | {"type": "video", "sequence": video_assets}, |
| | ) |
| | self.constants = { |
| | "duration": self.duration * 30, |
| | "height": 1920, |
| | "width": 1080, |
| | } |
| |
|
| | await self.update(**self.__dict__) |
| | return {"links": self.links, "assets": self.assets, "constants": self.constants} |
| |
|
| | async def generate_transcript(self): |
| | pass |
| |
|
| |
|
| | class Scene(orm.Model): |
| | tts = Speak() |
| | tablename = "scenes" |
| | registry = models |
| | fields = { |
| | "id": orm.Integer(primary_key=True), |
| | "project": orm.ForeignKey(Project), |
| | "images": orm.JSON(default=None), |
| | "narration": orm.String(max_length=10_000, allow_null=True, default=""), |
| | "image_prompts": orm.JSON(default=None), |
| | "narration_duration": orm.Float(allow_null=True, default=0), |
| | "image_duration": orm.Float(allow_null=True, default=0), |
| | "narration_path": orm.String( |
| | max_length=100, |
| | allow_null=True, |
| | default="", |
| | ), |
| | "narration_link": orm.String(max_length=10_000, allow_null=True, default=""), |
| | } |
| |
|
| | async def generate_scene_data(self): |
| | |
| | await asyncio.gather(self.narrate(), self.generate_images()) |
| | self.calculate_durations() |
| |
|
| | async def narrate(self): |
| | link, path = await self._retry_narration_generation() |
| | self.narration_path = path |
| | self.narration_link = link |
| |
|
| | async def _retry_narration_generation(self): |
| |
|
| | retry_count = 0 |
| | while retry_count < 3: |
| | try: |
| | return await self.tts.say(text=self.narration) |
| | except Exception as e: |
| | print(f"Failed to generate narration: {e}") |
| | retry_count += 1 |
| | await asyncio.sleep(1) |
| |
|
| | print("Failed to generate narration after 3 attempts.") |
| |
|
| | def calculate_durations(self): |
| | wav_file = AudioSegment.from_file(self.narration_path, format="wav") |
| | self.narration_duration = int(len(wav_file) / 1000) |
| | self.image_duration = self.narration_duration / len(self.image_prompts) |
| |
|
| | async def generate_images(self): |
| | self.images = [] |
| | async with aiohttp.ClientSession() as session: |
| | image_generator = AsyncImageGenerator(session) |
| | for payload in self.image_prompts: |
| | result = await image_generator.generate_image(payload) |
| | status = await image_generator.fetch_image_status(result["id"]) |
| | self.images.extend(status["output"]) |
| |
|
| |
|
| | class Transition(orm.Model): |
| | tablename = "transitions" |
| | registry = models |
| | fields = { |
| | "id": orm.Integer(primary_key=True), |
| | "name": orm.String(max_length=100), |
| | "file_path": orm.String(max_length=100), |
| | } |
| |
|
| |
|
| | class BackgroundMusic(orm.Model): |
| | tablename = "background_music" |
| | registry = models |
| | fields = { |
| | "id": orm.Integer(primary_key=True), |
| | "name": orm.String(max_length=100), |
| | "file_path": orm.String(max_length=100), |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| |
|
| | |
| | async def create_tables(): |
| | datas = { |
| | "narration": "Welcome to a journey through some of history's strangest moments! Get ready to explore the bizarre, the unusual, and the downright weird.", |
| | "image_prompts": [ |
| | "Vintage book opening, revealing strange facts, mixed media collage, curious and intriguing, mysterious, eccentric, macro lens, soft lighting, conceptual photography, cross-processed film, surreal, warm tones, textured paper." |
| | ], |
| | } |
| |
|
| | await models._create_all(database_url) |
| | x = await Project.objects.create(name="avatar") |
| | scene = await Scene.objects.create(project=x) |
| | scene.narration = datas["narration"] |
| | scene.image_prompts = datas["image_prompts"] |
| |
|
| | await scene.generate_scene_data() |
| | await scene.objects.update(**scene.__dict__) |
| | p = await x.get_all_scenes() |
| | print(p) |
| | print(scene.__dict__) |
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| |
|