Ava2lon commited on
Commit
097e344
·
verified ·
1 Parent(s): c972d30

Upload 9 files

Browse files
Files changed (9) hide show
  1. .gitignore +144 -0
  2. README.md +122 -5
  3. app.py +595 -0
  4. demo.py +135 -0
  5. forg.jpg +0 -0
  6. gitignore +6 -0
  7. peng.png +0 -0
  8. pyproject.toml +52 -0
  9. requirements.txt +35 -0
.gitignore ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ run_*.sh
2
+ log/
3
+ saves
4
+ saves/
5
+ output/
6
+ output
7
+ pretrained/
8
+ workspace
9
+ workspace/
10
+ .checkpoints/
11
+ weights/
12
+ ext_weights/
13
+ *.pth
14
+ *.pt
15
+
16
+ # Byte-compiled / optimized / DLL files
17
+ __pycache__/
18
+ *.py[cod]
19
+ *$py.class
20
+
21
+ # C extensions
22
+ *.so
23
+
24
+ # Distribution / packaging
25
+ .Python
26
+ build/
27
+ develop-eggs/
28
+ dist/
29
+ downloads/
30
+ eggs/
31
+ .eggs/
32
+ lib/
33
+ lib64/
34
+ parts/
35
+ sdist/
36
+ var/
37
+ wheels/
38
+ pip-wheel-metadata/
39
+ share/python-wheels/
40
+ *.egg-info/
41
+ .installed.cfg
42
+ *.egg
43
+ MANIFEST
44
+
45
+ # PyInstaller
46
+ # Usually these files are written by a python script from a template
47
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
48
+ *.manifest
49
+ *.spec
50
+
51
+ # Installer logs
52
+ pip-log.txt
53
+ pip-delete-this-directory.txt
54
+
55
+ # Unit test / coverage reports
56
+ htmlcov/
57
+ .tox/
58
+ .nox/
59
+ .coverage
60
+ .coverage.*
61
+ .cache
62
+ nosetests.xml
63
+ coverage.xml
64
+ *.cover
65
+ *.py,cover
66
+ .hypothesis/
67
+ .pytest_cache/
68
+
69
+ # Translations
70
+ *.mo
71
+ *.pot
72
+
73
+ # Django stuff:
74
+ *.log
75
+ local_settings.py
76
+ db.sqlite3
77
+ db.sqlite3-journal
78
+
79
+ # Flask stuff:
80
+ instance/
81
+ .webassets-cache
82
+
83
+ # Scrapy stuff:
84
+ .scrapy
85
+
86
+ # Sphinx documentation
87
+ docs/_build/
88
+
89
+ # PyBuilder
90
+ target/
91
+
92
+ # Jupyter Notebook
93
+ .ipynb_checkpoints
94
+
95
+ # IPython
96
+ profile_default/
97
+ ipython_config.py
98
+
99
+ # pyenv
100
+ .python-version
101
+
102
+ # pipenv
103
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
104
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
105
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
106
+ # install all needed dependencies.
107
+ #Pipfile.lock
108
+
109
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
110
+ __pypackages__/
111
+
112
+ # Celery stuff
113
+ celerybeat-schedule
114
+ celerybeat.pid
115
+
116
+ # SageMath parsed files
117
+ *.sage.py
118
+
119
+ # Environments
120
+ .env
121
+ .venv
122
+ env/
123
+ venv/
124
+ ENV/
125
+ env.bak/
126
+ venv.bak/
127
+
128
+ # Spyder project settings
129
+ .spyderproject
130
+ .spyproject
131
+
132
+ # Rope project settings
133
+ .ropeproject
134
+
135
+ # mkdocs documentation
136
+ /site
137
+
138
+ # mypy
139
+ .mypy_cache/
140
+ .dmypy.json
141
+ dmypy.json
142
+
143
+ # Pyre type checker
144
+ .pyre/
README.md CHANGED
@@ -1,12 +1,129 @@
1
  ---
2
- title: Automation
3
- emoji: 🌖
4
- colorFrom: red
5
  colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
  app_file: app.py
9
  pinned: false
 
 
 
 
 
 
 
10
  ---
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: VEO3 Free
3
+ emoji: 🔊
4
+ colorFrom: blue
5
  colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: 5.35.0
8
  app_file: app.py
9
  pinned: false
10
+ short_description: Wan2.1-T2V-14B + Fast 4-step with NAG + Automatic Audio
11
+ models:
12
+ - VIDraft/Gemma-3-R1984-4B
13
+ - google/gemma-3-4b-it
14
+ - Wan-AI/Wan2.1-T2V-14B-Diffusers
15
+ - vrgamedevgirl84/Wan14BT2VFusioniX
16
+ - Kijai/WanVideo_comfy
17
  ---
18
+ ## English Explanation
19
 
20
+ ### Overview
21
+ This is a **VEO3 Free** application - an advanced AI video generation system that combines Wan2.1-T2V-14B model with automatic audio generation capabilities. It creates videos from text descriptions and automatically generates matching audio using MMAudio technology.
22
+
23
+ ### Key Features
24
+
25
+ 1. **Text-to-Video Generation**
26
+ - Uses Wan2.1-T2V-14B Diffusion model (14 billion parameters)
27
+ - Fast 4-step generation with NAG (Noise-Augmented Generation)
28
+ - Supports various resolutions from 128x128 to 896x896
29
+ - Duration: 1-8 seconds at 16 FPS
30
+ - Cinema-quality output with professional camera movements
31
+
32
+ 2. **Automatic Audio Generation**
33
+ - MMAudio integration for synchronized sound effects
34
+ - Uses the same text prompt for both video and audio
35
+ - Configurable audio quality and guidance strength
36
+ - Optional feature - can be disabled if needed
37
+
38
+ 3. **Advanced Controls**
39
+ - **NAG Scale**: Controls guidance strength (1.0-20.0)
40
+ - **Inference Steps**: Balances quality vs speed (1-8 steps)
41
+ - **Seed Control**: For reproducible results
42
+ - **Negative Prompts**: Specify what to avoid in generation
43
+
44
+ ### How It Works
45
+ 1. **Input**: Enter a detailed scene description
46
+ 2. **Video Generation**: The AI creates video frames based on your prompt
47
+ 3. **Audio Synthesis**: Automatically generates matching sound effects
48
+ 4. **Output**: Combined video with synchronized audio
49
+
50
+ ### Example Use Cases
51
+ - Film previews and concept visualization
52
+ - Music video creation
53
+ - Advertising content
54
+ - Creative storytelling
55
+ - Game cinematics
56
+
57
+ ### Technical Details
58
+ - **GPU Acceleration**: Uses CUDA for fast processing
59
+ - **Model Architecture**: Transformer-based diffusion model
60
+ - **Audio Model**: Flow-matching based audio synthesis
61
+ - **Processing Time**: ~30-70 seconds depending on settings
62
+
63
+ ### Tips for Best Results
64
+ - Use detailed, cinematic descriptions
65
+ - Include camera movements and visual style
66
+ - Specify lighting, colors, and atmosphere
67
+ - Add sound descriptions for better audio matching
68
+ - Higher NAG scale = more prompt adherence
69
+
70
+ ---
71
+
72
+ ## 한글 설명
73
+
74
+ ### 개요
75
+ **VEO3 Free**는 Wan2.1-T2V-14B 모델과 자동 오디오 생성 기능을 결합한 고급 AI 비디오 생성 시스템입니다. 텍스트 설명으로부터 비디오를 생성하고 MMAudio 기술을 사용해 자동으로 일치하는 오디오를 생성합니다.
76
+
77
+ ### 주요 기능
78
+
79
+ 1. **텍스트-비디오 변환**
80
+ - Wan2.1-T2V-14B Diffusion 모델 사용 (140억 파라미터)
81
+ - NAG(노이즈 증강 생성)를 통한 빠른 4단계 생성
82
+ - 128x128부터 896x896까지 다양한 해상도 지원
83
+ - 지속 시간: 16 FPS로 1-8초
84
+ - 전문적인 카메라 움직임을 포함한 영화 품질 출력
85
+
86
+ 2. **자동 오디오 생성**
87
+ - 동기화된 사운드 효과를 위한 MMAudio 통합
88
+ - 비디오와 오디오 모두 동일한 텍스트 프롬프트 사용
89
+ - 오디오 품질과 가이던스 강도 조절 가능
90
+ - 선택적 기능 - 필요시 비활성화 가능
91
+
92
+ 3. **고급 제어 기능**
93
+ - **NAG 스케일**: 가이던스 강도 제어 (1.0-20.0)
94
+ - **추론 단계**: 품질 대 속도 균형 조절 (1-8단계)
95
+ - **시드 제어**: 재현 가능한 결과를 위한 설정
96
+ - **네거티브 프롬프트**: 생성에서 피할 요소 지정
97
+
98
+ ### 작동 방식
99
+ 1. **입력**: 상세한 장면 설명 입력
100
+ 2. **비디오 생성**: AI가 프롬프트 기반 비디오 프레임 생성
101
+ 3. **오디오 합성**: 자동으로 일치하는 사운드 효과 생성
102
+ 4. **출력**: 동기화된 오디오가 포함된 비디오 출력
103
+
104
+ ### 활용 사례
105
+ - 영화 프리뷰 및 컨셉 시각화
106
+ - 뮤직 비디오 제작
107
+ - 광고 콘텐츠 생성
108
+ - 창의적 스토리텔링
109
+ - 게임 시네마틱
110
+
111
+ ### 기술 사양
112
+ - **GPU 가속**: 빠른 처리를 위한 CUDA 사용
113
+ - **모델 아키텍처**: 트랜스포머 기반 확산 모델
114
+ - **오디오 모델**: 플로우 매칭 기반 오디오 합성
115
+ - **처리 시간**: 설정에 따라 약 30-70초
116
+
117
+ ### 최상의 결과를 위한 팁
118
+ - 상세하고 영화적인 설명 사용
119
+ - 카메라 움직임과 시각적 스타일 포함
120
+ - 조명, 색상, 분위기 명시
121
+ - 더 나은 오디오 매칭을 위해 사운드 설명 추가
122
+ - 높은 NAG 스케일 = 프롬프트에 더 충실한 생성
123
+
124
+ ### 특별 기능
125
+ - **영화급 프롬프트 예제**: 전문적인 촬영 기법이 포함된 3가지 예제 ��공
126
+ - **실시간 진행 표시**: 생성 과정을 실시간으로 확인
127
+ - **원클릭 예제 적용**: 예제를 클릭하면 자동으로 설정값 적용
128
+
129
+ 이 도구는 전문가 수준의 비디오 콘텐츠를 쉽게 생성할 수 있도록 설계되었으며, 창의적인 아이디어를 빠르게 시각화하는 데 이상적입니다.
app.py CHANGED
@@ -0,0 +1,595 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import types
2
+ import random
3
+ import spaces
4
+ import logging
5
+ import os
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ import re
9
+
10
+ import torch
11
+ import numpy as np
12
+ import torchaudio
13
+ from diffusers import AutoencoderKLWan, UniPCMultistepScheduler
14
+ from diffusers.utils import export_to_video
15
+ from diffusers import AutoModel
16
+ import gradio as gr
17
+ import tempfile
18
+ from huggingface_hub import hf_hub_download
19
+ import traceback
20
+
21
+ # Patch for scaled_dot_product_attention to fix enable_gqa issue
22
+ import torch.nn.functional as F
23
+
24
+ original_sdpa = F.scaled_dot_product_attention
25
+
26
+ def patched_scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=None):
27
+ # enable_gqa 파라미터를 무시하고 나머지 파라미터만 전달
28
+ kwargs = {}
29
+ if attn_mask is not None:
30
+ kwargs['attn_mask'] = attn_mask
31
+ if dropout_p != 0.0:
32
+ kwargs['dropout_p'] = dropout_p
33
+ if is_causal:
34
+ kwargs['is_causal'] = is_causal
35
+ if scale is not None:
36
+ kwargs['scale'] = scale
37
+
38
+ return original_sdpa(query, key, value, **kwargs)
39
+
40
+ # 패치 적용
41
+ F.scaled_dot_product_attention = patched_scaled_dot_product_attention
42
+
43
+ from src.pipeline_wan_nag import NAGWanPipeline
44
+ from src.transformer_wan_nag import NagWanTransformer3DModel
45
+
46
+ # MMAudio imports
47
+ try:
48
+ import mmaudio
49
+ except ImportError:
50
+ os.system("pip install -e .")
51
+ import mmaudio
52
+
53
+ from mmaudio.eval_utils import (ModelConfig, all_model_cfg, generate as mmaudio_generate,
54
+ load_video, make_video, setup_eval_logging)
55
+ from mmaudio.model.flow_matching import FlowMatching
56
+ from mmaudio.model.networks import MMAudio, get_my_mmaudio
57
+ from mmaudio.model.sequence_config import SequenceConfig
58
+ from mmaudio.model.utils.features_utils import FeaturesUtils
59
+
60
+ # NAG Video Settings
61
+ MOD_VALUE = 32
62
+ DEFAULT_DURATION_SECONDS = 4
63
+ DEFAULT_STEPS = 4
64
+ DEFAULT_SEED = 2025
65
+ DEFAULT_H_SLIDER_VALUE = 480
66
+ DEFAULT_W_SLIDER_VALUE = 832
67
+ NEW_FORMULA_MAX_AREA = 480.0 * 832.0
68
+
69
+ SLIDER_MIN_H, SLIDER_MAX_H = 128, 896
70
+ SLIDER_MIN_W, SLIDER_MAX_W = 128, 896
71
+ MAX_SEED = np.iinfo(np.int32).max
72
+
73
+ FIXED_FPS = 16
74
+ MIN_FRAMES_MODEL = 8
75
+ MAX_FRAMES_MODEL = 129
76
+
77
+ DEFAULT_NAG_NEGATIVE_PROMPT = "Static, motionless, still, ugly, bad quality, worst quality, poorly drawn, low resolution, blurry, lack of details"
78
+ DEFAULT_AUDIO_NEGATIVE_PROMPT = "music, speech, voice, singing, narration"
79
+
80
+ # NAG Model Settings
81
+ MODEL_ID = "Wan-AI/Wan2.1-T2V-14B-Diffusers"
82
+ SUB_MODEL_ID = "vrgamedevgirl84/Wan14BT2VFusioniX"
83
+ SUB_MODEL_FILENAME = "Wan14BT2VFusioniX_fp16_.safetensors"
84
+ LORA_REPO_ID = "Kijai/WanVideo_comfy"
85
+ LORA_FILENAME = "Wan21_CausVid_14B_T2V_lora_rank32.safetensors"
86
+
87
+ # MMAudio Settings
88
+ torch.backends.cuda.matmul.allow_tf32 = True
89
+ torch.backends.cudnn.allow_tf32 = True
90
+ log = logging.getLogger()
91
+ device = 'cuda'
92
+ dtype = torch.bfloat16
93
+ audio_model_config: ModelConfig = all_model_cfg['large_44k_v2']
94
+ audio_model_config.download_if_needed()
95
+ setup_eval_logging()
96
+
97
+ # Initialize NAG Video Model
98
+ try:
99
+ vae = AutoencoderKLWan.from_pretrained(MODEL_ID, subfolder="vae", torch_dtype=torch.float32)
100
+ wan_path = hf_hub_download(repo_id=SUB_MODEL_ID, filename=SUB_MODEL_FILENAME)
101
+ transformer = NagWanTransformer3DModel.from_single_file(wan_path, torch_dtype=torch.bfloat16)
102
+ pipe = NAGWanPipeline.from_pretrained(
103
+ MODEL_ID, vae=vae, transformer=transformer, torch_dtype=torch.bfloat16
104
+ )
105
+ pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=5.0)
106
+ pipe.to("cuda")
107
+
108
+ pipe.transformer.__class__.attn_processors = NagWanTransformer3DModel.attn_processors
109
+ pipe.transformer.__class__.set_attn_processor = NagWanTransformer3DModel.set_attn_processor
110
+ pipe.transformer.__class__.forward = NagWanTransformer3DModel.forward
111
+ print("NAG Video Model loaded successfully!")
112
+ except Exception as e:
113
+ print(f"Error loading NAG Video Model: {e}")
114
+ pipe = None
115
+
116
+ # Initialize MMAudio Model
117
+ def get_mmaudio_model() -> tuple[MMAudio, FeaturesUtils, SequenceConfig]:
118
+ seq_cfg = audio_model_config.seq_cfg
119
+
120
+ net: MMAudio = get_my_mmaudio(audio_model_config.model_name).to(device, dtype).eval()
121
+ net.load_weights(torch.load(audio_model_config.model_path, map_location=device, weights_only=True))
122
+ log.info(f'Loaded MMAudio weights from {audio_model_config.model_path}')
123
+
124
+ feature_utils = FeaturesUtils(tod_vae_ckpt=audio_model_config.vae_path,
125
+ synchformer_ckpt=audio_model_config.synchformer_ckpt,
126
+ enable_conditions=True,
127
+ mode=audio_model_config.mode,
128
+ bigvgan_vocoder_ckpt=audio_model_config.bigvgan_16k_path,
129
+ need_vae_encoder=False)
130
+ feature_utils = feature_utils.to(device, dtype).eval()
131
+
132
+ return net, feature_utils, seq_cfg
133
+
134
+ try:
135
+ audio_net, audio_feature_utils, audio_seq_cfg = get_mmaudio_model()
136
+ print("MMAudio Model loaded successfully!")
137
+ except Exception as e:
138
+ print(f"Error loading MMAudio Model: {e}")
139
+ audio_net = None
140
+
141
+ # 비디오 프롬프트를 오디오 프롬프트로 변환하는 함수
142
+ def extract_audio_description(video_prompt):
143
+ """비디오 프롬프트에서 오디오 관련 설명 추출/변환"""
144
+
145
+ # 키워드 매핑
146
+ audio_keywords = {
147
+ 'car': 'car engine sound, vehicle noise',
148
+ 'porsche': 'sports car engine roar, exhaust sound',
149
+ 'guitar': 'electric guitar playing, guitar music',
150
+ 'concert': 'crowd cheering, live music, applause',
151
+ 'motorcycle': 'motorcycle engine sound, motor rumble',
152
+ 'highway': 'traffic noise, road ambience',
153
+ 'rain': 'rain sounds, water drops',
154
+ 'wind': 'wind blowing sound',
155
+ 'ocean': 'ocean waves, water sounds',
156
+ 'city': 'urban ambience, city traffic sounds',
157
+ 'singer': 'singing voice, vocals',
158
+ 'crowd': 'crowd noise, people talking',
159
+ 'flames': 'fire crackling sound',
160
+ 'pyro': 'fire whoosh, flame burst sound',
161
+ 'explosion': 'explosion sound, blast',
162
+ 'countryside': 'nature ambience, birds chirping',
163
+ 'wheat fields': 'wind through grass, rural ambience',
164
+ 'engine': 'motor sound, mechanical noise',
165
+ 'flat-six engine': 'sports car engine sound',
166
+ 'roaring': 'loud engine roar',
167
+ 'thunderous': 'loud booming sound',
168
+ 'child': 'children playing sounds',
169
+ 'running': 'footsteps sound',
170
+ 'woman': 'ambient sounds',
171
+ 'phone': 'subtle electronic ambience',
172
+ 'advertisement': 'modern ambient sounds'
173
+ }
174
+
175
+ # 간단한 키워드 기반 변환
176
+ audio_descriptions = []
177
+ lower_prompt = video_prompt.lower()
178
+
179
+ for key, value in audio_keywords.items():
180
+ if key in lower_prompt:
181
+ audio_descriptions.append(value)
182
+
183
+ # 기본값 설정
184
+ if not audio_descriptions:
185
+ # 프롬프트에 명시적인 오디오 설명이 있는지 확인
186
+ if 'sound' in lower_prompt or 'audio' in lower_prompt or 'noise' in lower_prompt:
187
+ # 프롬프트에서 오디오 관련 부분만 추출
188
+ audio_pattern = r'([^.]*(?:sound|audio|noise|music|voice|roar|rumble)[^.]*)'
189
+ matches = re.findall(audio_pattern, lower_prompt, re.IGNORECASE)
190
+ if matches:
191
+ return ', '.join(matches)
192
+
193
+ # 기본 ambient sound
194
+ return "ambient environmental sounds matching the scene"
195
+
196
+ return ', '.join(audio_descriptions)
197
+
198
+ # Audio generation function
199
+ @torch.inference_mode()
200
+ def add_audio_to_video(video_path, prompt, audio_custom_prompt, audio_negative_prompt, audio_steps, audio_cfg_strength, duration):
201
+ """Generate and add audio to video using MMAudio"""
202
+ if audio_net is None:
203
+ print("MMAudio model not loaded, returning video without audio")
204
+ return video_path
205
+
206
+ try:
207
+ # 커스텀 오디오 프롬프트가 있으면 사용, 없으면 비디오 프롬프트에서 추출
208
+ if audio_custom_prompt and audio_custom_prompt.strip():
209
+ audio_prompt = audio_custom_prompt.strip()
210
+ else:
211
+ audio_prompt = extract_audio_description(prompt)
212
+
213
+ print(f"Original prompt: {prompt}")
214
+ print(f"Audio prompt: {audio_prompt}")
215
+
216
+ rng = torch.Generator(device=device)
217
+ rng.manual_seed(random.randint(0, 2**32 - 1)) # 더 명확한 랜덤 시드
218
+ fm = FlowMatching(min_sigma=0, inference_mode='euler', num_steps=audio_steps)
219
+
220
+ video_info = load_video(video_path, duration)
221
+ clip_frames = video_info.clip_frames
222
+ sync_frames = video_info.sync_frames
223
+ duration = video_info.duration_sec
224
+ clip_frames = clip_frames.unsqueeze(0)
225
+ sync_frames = sync_frames.unsqueeze(0)
226
+ audio_seq_cfg.duration = duration
227
+ audio_net.update_seq_lengths(audio_seq_cfg.latent_seq_len, audio_seq_cfg.clip_seq_len, audio_seq_cfg.sync_seq_len)
228
+
229
+ # 향상된 네거티브 프롬프트
230
+ enhanced_negative = f"{audio_negative_prompt}, distortion, static noise, silence, random beeps"
231
+
232
+ audios = mmaudio_generate(clip_frames,
233
+ sync_frames, [audio_prompt], # 변환된 오디오 프롬프트 사용
234
+ negative_text=[enhanced_negative],
235
+ feature_utils=audio_feature_utils,
236
+ net=audio_net,
237
+ fm=fm,
238
+ rng=rng,
239
+ cfg_strength=audio_cfg_strength)
240
+ audio = audios.float().cpu()[0]
241
+
242
+ # Create video with audio
243
+ video_with_audio_path = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4').name
244
+ make_video(video_info, video_with_audio_path, audio, sampling_rate=audio_seq_cfg.sampling_rate)
245
+
246
+ return video_with_audio_path
247
+ except Exception as e:
248
+ print(f"Error in audio generation: {e}")
249
+ traceback.print_exc()
250
+ return video_path
251
+
252
+ # Combined generation function
253
+ def get_duration(prompt, nag_negative_prompt, nag_scale, height, width, duration_seconds,
254
+ steps, seed, randomize_seed, enable_audio, audio_custom_prompt,
255
+ audio_negative_prompt, audio_steps, audio_cfg_strength):
256
+ # Calculate total duration including audio processing if enabled
257
+ video_duration = int(duration_seconds) * int(steps) * 2.25 + 5
258
+ audio_duration = 30 if enable_audio else 0 # Additional time for audio processing
259
+ return video_duration + audio_duration
260
+
261
+ @spaces.GPU(duration=get_duration)
262
+ def generate_video_with_audio(
263
+ prompt,
264
+ nag_negative_prompt, nag_scale,
265
+ height=DEFAULT_H_SLIDER_VALUE, width=DEFAULT_W_SLIDER_VALUE, duration_seconds=DEFAULT_DURATION_SECONDS,
266
+ steps=DEFAULT_STEPS,
267
+ seed=DEFAULT_SEED, randomize_seed=False,
268
+ enable_audio=True, audio_custom_prompt="",
269
+ audio_negative_prompt=DEFAULT_AUDIO_NEGATIVE_PROMPT,
270
+ audio_steps=30, audio_cfg_strength=4.5,
271
+ ):
272
+ if pipe is None:
273
+ return None, DEFAULT_SEED
274
+
275
+ try:
276
+ # Generate video first
277
+ target_h = max(MOD_VALUE, (int(height) // MOD_VALUE) * MOD_VALUE)
278
+ target_w = max(MOD_VALUE, (int(width) // MOD_VALUE) * MOD_VALUE)
279
+
280
+ num_frames = np.clip(int(round(int(duration_seconds) * FIXED_FPS) + 1), MIN_FRAMES_MODEL, MAX_FRAMES_MODEL)
281
+
282
+ current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
283
+
284
+ print(f"Generating video with: prompt='{prompt}', resolution={target_w}x{target_h}, frames={num_frames}")
285
+
286
+ with torch.inference_mode():
287
+ nag_output_frames_list = pipe(
288
+ prompt=prompt,
289
+ nag_negative_prompt=nag_negative_prompt,
290
+ nag_scale=nag_scale,
291
+ nag_tau=3.5,
292
+ nag_alpha=0.5,
293
+ height=target_h, width=target_w, num_frames=num_frames,
294
+ guidance_scale=0.,
295
+ num_inference_steps=int(steps),
296
+ generator=torch.Generator(device="cuda").manual_seed(current_seed)
297
+ ).frames[0]
298
+
299
+ # Save initial video without audio
300
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
301
+ temp_video_path = tmpfile.name
302
+ export_to_video(nag_output_frames_list, temp_video_path, fps=FIXED_FPS)
303
+ print(f"Video saved to: {temp_video_path}")
304
+
305
+ # Add audio if enabled
306
+ if enable_audio:
307
+ try:
308
+ print("Adding audio to video...")
309
+ final_video_path = add_audio_to_video(
310
+ temp_video_path,
311
+ prompt,
312
+ audio_custom_prompt,
313
+ audio_negative_prompt,
314
+ audio_steps,
315
+ audio_cfg_strength,
316
+ duration_seconds
317
+ )
318
+ # Clean up temp video
319
+ if os.path.exists(temp_video_path) and final_video_path != temp_video_path:
320
+ os.remove(temp_video_path)
321
+ print(f"Final video with audio: {final_video_path}")
322
+ except Exception as e:
323
+ log.error(f"Audio generation failed: {e}")
324
+ final_video_path = temp_video_path
325
+ else:
326
+ final_video_path = temp_video_path
327
+
328
+ return final_video_path, current_seed
329
+ except Exception as e:
330
+ print(f"Error in video generation: {e}")
331
+ return None, current_seed
332
+
333
+ # Example generation function - simplified
334
+ def set_example(prompt, nag_negative_prompt, nag_scale):
335
+ """Set example values in the UI without triggering generation"""
336
+ return (
337
+ prompt,
338
+ nag_negative_prompt,
339
+ nag_scale,
340
+ DEFAULT_H_SLIDER_VALUE,
341
+ DEFAULT_W_SLIDER_VALUE,
342
+ DEFAULT_DURATION_SECONDS,
343
+ DEFAULT_STEPS,
344
+ DEFAULT_SEED,
345
+ True, # randomize_seed
346
+ True, # enable_audio
347
+ "", # audio_custom_prompt
348
+ DEFAULT_AUDIO_NEGATIVE_PROMPT,
349
+ 30, # audio_steps
350
+ 4.5 # audio_cfg_strength
351
+ )
352
+
353
+ # Examples with audio descriptions
354
+ examples = [
355
+ ["Midnight highway outside a neon-lit city. A black 1973 Porsche 911 Carrera RS speeds at 120 km/h. Inside, a stylish singer-guitarist sings while driving, vintage sunburst guitar on the passenger seat. Sodium streetlights streak over the hood; RGB panels shift magenta to blue on the driver. Camera: drone dive, Russian-arm low wheel shot, interior gimbal, FPV barrel roll, overhead spiral. Neo-noir palette, rain-slick asphalt reflections, roaring flat-six engine blended with live guitar.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
356
+ ["Arena rock concert packed with 20 000 fans. A flamboyant lead guitarist in leather jacket and mirrored aviators shreds a cherry-red Flying V on a thrust stage. Pyro flames shoot up on every downbeat, CO₂ jets burst behind. Moving-head spotlights swirl teal and amber, follow-spots rim-light the guitarist's hair. Steadicam 360-orbit, crane shot rising over crowd, ultra-slow-motion pick attack at 1 000 fps. Film-grain teal-orange grade, thunderous crowd roar mixes with screaming guitar solo.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
357
+ ["Golden-hour countryside road winding through rolling wheat fields. A man and woman ride a vintage café-racer motorcycle, hair and scarf fluttering in the warm breeze. Drone chase shot reveals endless patchwork farmland; low slider along rear wheel captures dust trail. Sun-flare back-lights the riders, lens blooms on highlights. Soft acoustic rock underscore; engine rumble mixed at –8 dB. Warm pastel color grade, gentle film-grain for nostalgic vibe.", DEFAULT_NAG_NEGATIVE_PROMPT, 11],
358
+ ]
359
+
360
+ # CSS styling - Fixed for better layout
361
+ css = """
362
+ /* Right column - video output */
363
+ .video-output {
364
+ border-radius: 15px;
365
+ overflow: hidden;
366
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
367
+ width: 100% !important;
368
+ height: auto !important;
369
+ min-height: 400px;
370
+ }
371
+
372
+ /* Ensure video container is responsive */
373
+ .video-output video {
374
+ width: 100% !important;
375
+ height: auto !important;
376
+ max-height: 600px;
377
+ object-fit: contain;
378
+ display: block;
379
+ }
380
+
381
+ /* Remove any overlay or background from video container */
382
+ .video-output > div {
383
+ background: transparent !important;
384
+ padding: 0 !important;
385
+ }
386
+
387
+ /* Remove gradio's default video player overlay */
388
+ .video-output .wrap {
389
+ background: transparent !important;
390
+ }
391
+
392
+ /* Ensure no gray overlay on video controls */
393
+ .video-output video::-webkit-media-controls-enclosure {
394
+ background: transparent;
395
+ }
396
+ """
397
+
398
+ # Gradio interface - Fixed structure
399
+ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
400
+ gr.HTML("""
401
+ <div class="container">
402
+ <h1 class="main-title">🎬 VEO3 Free</h1>
403
+ <p class="subtitle">Wan2.1-T2V-14B + Fast 4-step with NAG + Automatic Audio Generation</p>
404
+ </div>
405
+ """)
406
+
407
+ gr.HTML("""
408
+ <div class='container' style='display:flex; justify-content:center; gap:12px; margin-bottom: 20px;'>
409
+ <a href="https://huggingface.co/spaces/openfree/Best-AI" target="_blank">
410
+ <img src="https://img.shields.io/static/v1?label=OpenFree&message=BEST%20AI%20Services&color=%230000ff&labelColor=%23000080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="OpenFree badge">
411
+ </a>
412
+
413
+ <a href="https://discord.gg/openfreeai" target="_blank">
414
+ <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="Discord badge">
415
+ </a>
416
+ </div>
417
+ """)
418
+
419
+ with gr.Row(equal_height=True):
420
+ with gr.Column(scale=5):
421
+ with gr.Group(elem_classes="prompt-container"):
422
+ prompt = gr.Textbox(
423
+ label="✨ Video Prompt (also used for audio generation)",
424
+ placeholder="Describe your video scene in detail...",
425
+ lines=3,
426
+ elem_classes="prompt-input"
427
+ )
428
+
429
+ with gr.Accordion("🎨 Advanced Video Settings", open=False):
430
+ nag_negative_prompt = gr.Textbox(
431
+ label="Video Negative Prompt",
432
+ value=DEFAULT_NAG_NEGATIVE_PROMPT,
433
+ lines=2,
434
+ )
435
+ nag_scale = gr.Slider(
436
+ label="NAG Scale",
437
+ minimum=1.0,
438
+ maximum=20.0,
439
+ step=0.25,
440
+ value=11.0,
441
+ info="Higher values = stronger guidance"
442
+ )
443
+
444
+ with gr.Group(elem_classes="settings-panel"):
445
+ gr.Markdown("### ⚙️ Video Settings")
446
+
447
+ with gr.Row():
448
+ duration_seconds_input = gr.Slider(
449
+ minimum=1,
450
+ maximum=8,
451
+ step=1,
452
+ value=DEFAULT_DURATION_SECONDS,
453
+ label="📱 Duration (seconds)",
454
+ elem_classes="slider-container"
455
+ )
456
+ steps_slider = gr.Slider(
457
+ minimum=1,
458
+ maximum=8,
459
+ step=1,
460
+ value=DEFAULT_STEPS,
461
+ label="🔄 Inference Steps",
462
+ elem_classes="slider-container"
463
+ )
464
+
465
+ with gr.Row():
466
+ height_input = gr.Slider(
467
+ minimum=SLIDER_MIN_H,
468
+ maximum=SLIDER_MAX_H,
469
+ step=MOD_VALUE,
470
+ value=DEFAULT_H_SLIDER_VALUE,
471
+ label=f"📐 Height (×{MOD_VALUE})",
472
+ elem_classes="slider-container"
473
+ )
474
+ width_input = gr.Slider(
475
+ minimum=SLIDER_MIN_W,
476
+ maximum=SLIDER_MAX_W,
477
+ step=MOD_VALUE,
478
+ value=DEFAULT_W_SLIDER_VALUE,
479
+ label=f"📐 Width (×{MOD_VALUE})",
480
+ elem_classes="slider-container"
481
+ )
482
+
483
+ with gr.Row():
484
+ seed_input = gr.Slider(
485
+ label="🌱 Seed",
486
+ minimum=0,
487
+ maximum=MAX_SEED,
488
+ step=1,
489
+ value=DEFAULT_SEED,
490
+ interactive=True
491
+ )
492
+ randomize_seed_checkbox = gr.Checkbox(
493
+ label="🎲 Random Seed",
494
+ value=True,
495
+ interactive=True
496
+ )
497
+
498
+ with gr.Group(elem_classes="audio-settings"):
499
+ gr.Markdown("### 🎵 Audio Generation Settings")
500
+
501
+ enable_audio = gr.Checkbox(
502
+ label="🔊 Enable Automatic Audio Generation",
503
+ value=True,
504
+ interactive=True
505
+ )
506
+
507
+ with gr.Column(visible=True) as audio_settings_group:
508
+ audio_custom_prompt = gr.Textbox(
509
+ label="Custom Audio Prompt (Optional)",
510
+ placeholder="Leave empty to auto-generate from video prompt, or specify custom audio description (e.g., 'car engine sound, traffic noise')",
511
+ value="",
512
+ )
513
+ audio_negative_prompt = gr.Textbox(
514
+ label="Audio Negative Prompt",
515
+ value=DEFAULT_AUDIO_NEGATIVE_PROMPT,
516
+ placeholder="Elements to avoid in audio",
517
+ )
518
+
519
+ with gr.Row():
520
+ audio_steps = gr.Slider(
521
+ minimum=10,
522
+ maximum=50,
523
+ step=5,
524
+ value=30,
525
+ label="🎚️ Audio Steps",
526
+ info="More steps = better quality"
527
+ )
528
+ audio_cfg_strength = gr.Slider(
529
+ minimum=1.0,
530
+ maximum=10.0,
531
+ step=0.5,
532
+ value=4.5,
533
+ label="🎛️ Audio Guidance",
534
+ info="Strength of prompt guidance"
535
+ )
536
+
537
+ # Toggle audio settings visibility
538
+ enable_audio.change(
539
+ fn=lambda x: gr.update(visible=x),
540
+ inputs=[enable_audio],
541
+ outputs=[audio_settings_group]
542
+ )
543
+
544
+ generate_button = gr.Button(
545
+ "🎬 Generate Video with Audio",
546
+ variant="primary",
547
+ elem_classes="generate-btn"
548
+ )
549
+
550
+ with gr.Column(scale=5):
551
+ video_output = gr.Video(
552
+ label="Generated Video with Audio",
553
+ autoplay=True,
554
+ interactive=False,
555
+ elem_classes="video-output",
556
+ height=600
557
+ )
558
+
559
+ gr.HTML("""
560
+ <div style="text-align: center; margin-top: 20px; color: #6b7280;">
561
+ <p>💡 Tip: For better audio, use Custom Audio Prompt with sound descriptions!</p>
562
+ <p>🎧 Examples: "car engine sound", "crowd cheering", "nature ambience"</p>
563
+ </div>
564
+ """)
565
+
566
+ # Examples section moved outside of columns
567
+ with gr.Row():
568
+ gr.Markdown("### 🎯 Example Prompts")
569
+
570
+ gr.Examples(
571
+ examples=examples,
572
+ inputs=[prompt, nag_negative_prompt, nag_scale],
573
+ outputs=None, # Don't connect outputs to avoid index issues
574
+ cache_examples=False
575
+ )
576
+
577
+ # Connect UI elements
578
+ ui_inputs = [
579
+ prompt,
580
+ nag_negative_prompt, nag_scale,
581
+ height_input, width_input, duration_seconds_input,
582
+ steps_slider,
583
+ seed_input, randomize_seed_checkbox,
584
+ enable_audio, audio_custom_prompt, audio_negative_prompt,
585
+ audio_steps, audio_cfg_strength,
586
+ ]
587
+
588
+ generate_button.click(
589
+ fn=generate_video_with_audio,
590
+ inputs=ui_inputs,
591
+ outputs=[video_output, seed_input],
592
+ )
593
+
594
+ if __name__ == "__main__":
595
+ demo.queue().launch()
demo.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from argparse import ArgumentParser
3
+ from pathlib import Path
4
+
5
+ import torch
6
+ import torchaudio
7
+
8
+ from mmaudio.eval_utils import (ModelConfig, all_model_cfg, generate, load_video, make_video,
9
+ setup_eval_logging)
10
+ from mmaudio.model.flow_matching import FlowMatching
11
+ from mmaudio.model.networks import MMAudio, get_my_mmaudio
12
+ from mmaudio.model.utils.features_utils import FeaturesUtils
13
+
14
+ torch.backends.cuda.matmul.allow_tf32 = True
15
+ torch.backends.cudnn.allow_tf32 = True
16
+
17
+ log = logging.getLogger()
18
+
19
+
20
+ @torch.inference_mode()
21
+ def main():
22
+ setup_eval_logging()
23
+
24
+ parser = ArgumentParser()
25
+ parser.add_argument('--variant',
26
+ type=str,
27
+ default='large_44k_v2',
28
+ help='small_16k, small_44k, medium_44k, large_44k, large_44k_v2')
29
+ parser.add_argument('--video', type=Path, help='Path to the video file')
30
+ parser.add_argument('--prompt', type=str, help='Input prompt', default='')
31
+ parser.add_argument('--negative_prompt', type=str, help='Negative prompt', default='')
32
+ parser.add_argument('--duration', type=float, default=8.0)
33
+ parser.add_argument('--cfg_strength', type=float, default=4.5)
34
+ parser.add_argument('--num_steps', type=int, default=25)
35
+
36
+ parser.add_argument('--mask_away_clip', action='store_true')
37
+
38
+ parser.add_argument('--output', type=Path, help='Output directory', default='./output')
39
+ parser.add_argument('--seed', type=int, help='Random seed', default=42)
40
+ parser.add_argument('--skip_video_composite', action='store_true')
41
+ parser.add_argument('--full_precision', action='store_true')
42
+
43
+ args = parser.parse_args()
44
+
45
+ if args.variant not in all_model_cfg:
46
+ raise ValueError(f'Unknown model variant: {args.variant}')
47
+ model: ModelConfig = all_model_cfg[args.variant]
48
+ model.download_if_needed()
49
+ seq_cfg = model.seq_cfg
50
+
51
+ if args.video:
52
+ video_path: Path = Path(args.video).expanduser()
53
+ else:
54
+ video_path = None
55
+ prompt: str = args.prompt
56
+ negative_prompt: str = args.negative_prompt
57
+ output_dir: str = args.output.expanduser()
58
+ seed: int = args.seed
59
+ num_steps: int = args.num_steps
60
+ duration: float = args.duration
61
+ cfg_strength: float = args.cfg_strength
62
+ skip_video_composite: bool = args.skip_video_composite
63
+ mask_away_clip: bool = args.mask_away_clip
64
+
65
+ device = 'cuda'
66
+ dtype = torch.float32 if args.full_precision else torch.bfloat16
67
+
68
+ output_dir.mkdir(parents=True, exist_ok=True)
69
+
70
+ # load a pretrained model
71
+ net: MMAudio = get_my_mmaudio(model.model_name).to(device, dtype).eval()
72
+ net.load_weights(torch.load(model.model_path, map_location=device, weights_only=True))
73
+ log.info(f'Loaded weights from {model.model_path}')
74
+
75
+ # misc setup
76
+ rng = torch.Generator(device=device)
77
+ rng.manual_seed(seed)
78
+ fm = FlowMatching(min_sigma=0, inference_mode='euler', num_steps=num_steps)
79
+
80
+ feature_utils = FeaturesUtils(tod_vae_ckpt=model.vae_path,
81
+ synchformer_ckpt=model.synchformer_ckpt,
82
+ enable_conditions=True,
83
+ mode=model.mode,
84
+ bigvgan_vocoder_ckpt=model.bigvgan_16k_path,
85
+ need_vae_encoder=False)
86
+ feature_utils = feature_utils.to(device, dtype).eval()
87
+
88
+ if video_path is not None:
89
+ log.info(f'Using video {video_path}')
90
+ video_info = load_video(video_path, duration)
91
+ clip_frames = video_info.clip_frames
92
+ sync_frames = video_info.sync_frames
93
+ duration = video_info.duration_sec
94
+ if mask_away_clip:
95
+ clip_frames = None
96
+ else:
97
+ clip_frames = clip_frames.unsqueeze(0)
98
+ sync_frames = sync_frames.unsqueeze(0)
99
+ else:
100
+ log.info('No video provided -- text-to-audio mode')
101
+ clip_frames = sync_frames = None
102
+
103
+ seq_cfg.duration = duration
104
+ net.update_seq_lengths(seq_cfg.latent_seq_len, seq_cfg.clip_seq_len, seq_cfg.sync_seq_len)
105
+
106
+ log.info(f'Prompt: {prompt}')
107
+ log.info(f'Negative prompt: {negative_prompt}')
108
+
109
+ audios = generate(clip_frames,
110
+ sync_frames, [prompt],
111
+ negative_text=[negative_prompt],
112
+ feature_utils=feature_utils,
113
+ net=net,
114
+ fm=fm,
115
+ rng=rng,
116
+ cfg_strength=cfg_strength)
117
+ audio = audios.float().cpu()[0]
118
+ if video_path is not None:
119
+ save_path = output_dir / f'{video_path.stem}.flac'
120
+ else:
121
+ safe_filename = prompt.replace(' ', '_').replace('/', '_').replace('.', '')
122
+ save_path = output_dir / f'{safe_filename}.flac'
123
+ torchaudio.save(save_path, audio, seq_cfg.sampling_rate)
124
+
125
+ log.info(f'Audio saved to {save_path}')
126
+ if video_path is not None and not skip_video_composite:
127
+ video_save_path = output_dir / f'{video_path.stem}.mp4'
128
+ make_video(video_info, video_save_path, audio, sampling_rate=seq_cfg.sampling_rate)
129
+ log.info(f'Video saved to {output_dir / video_save_path}')
130
+
131
+ log.info('Memory usage: %.2f GB', torch.cuda.max_memory_allocated() / (2**30))
132
+
133
+
134
+ if __name__ == '__main__':
135
+ main()
forg.jpg ADDED
gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .idea/
2
+
3
+ __pycache__/
4
+ *.py[cod]
5
+ *$py.class
6
+
peng.png ADDED
pyproject.toml ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.metadata]
6
+ allow-direct-references = true
7
+
8
+ [tool.yapf]
9
+ based_on_style = "pep8"
10
+ indent_width = 4
11
+ column_limit = 100
12
+
13
+ [project]
14
+ name = "mmaudio"
15
+ version = "1.0.0"
16
+ authors = [{ name = "Rex Cheng", email = "hkchengrex@gmail.com" }]
17
+ description = ""
18
+ readme = "README.md"
19
+ requires-python = ">=3.9"
20
+ classifiers = [
21
+ "Programming Language :: Python :: 3",
22
+ "Operating System :: OS Independent",
23
+ ]
24
+ dependencies = [
25
+ 'torch >= 2.5.1',
26
+ 'python-dotenv',
27
+ 'cython',
28
+ 'gitpython >= 3.1',
29
+ 'tensorboard >= 2.11',
30
+ 'numpy >= 1.21, <2.1',
31
+ 'Pillow >= 9.5',
32
+ 'opencv-python >= 4.8',
33
+ 'scipy >= 1.7',
34
+ 'tqdm >= 4.66.1',
35
+ 'gradio >= 3.34',
36
+ 'einops >= 0.6',
37
+ 'hydra-core >= 1.3.2',
38
+ 'requests',
39
+ 'torchdiffeq',
40
+ 'librosa >= 0.8.1',
41
+ 'nitrous-ema',
42
+ 'safetensors',
43
+ 'auraloss',
44
+ 'hydra_colorlog',
45
+ 'tensordict',
46
+ 'colorlog',
47
+ 'open_clip_torch',
48
+ 'soundfile',
49
+ ]
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["mmaudio"]
requirements.txt ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ git+https://github.com/huggingface/diffusers.git
2
+ transformers
3
+ accelerate
4
+ safetensors
5
+ sentencepiece
6
+ peft
7
+ ftfy
8
+ imageio-ffmpeg
9
+ opencv-python
10
+
11
+ torch == 2.4.0
12
+ torchvision
13
+ torchaudio
14
+ python-dotenv
15
+ cython
16
+ gitpython >= 3.1
17
+ tensorboard >= 2.11
18
+ numpy >= 1.21, <2.1
19
+ Pillow >= 9.5
20
+ scipy >= 1.7
21
+ tqdm >= 4.66.1
22
+ gradio >= 3.34
23
+ einops >= 0.6
24
+ hydra-core >= 1.3.2
25
+ requests
26
+ torchdiffeq
27
+ librosa >= 0.8.1
28
+ nitrous-ema
29
+ auraloss
30
+ hydra_colorlog
31
+ tensordict
32
+ colorlog
33
+ open_clip_torch
34
+ soundfile
35
+ av