Spaces:
Runtime error
Runtime error
shigeru saito
commited on
Commit
·
917851d
1
Parent(s):
2d789b8
first commit
Browse files- .env.example +3 -0
- .gitignore +1 -0
- app.py +319 -0
- requirements.txt +3 -0
- schema.json +70 -0
- stub/replicate.py +16 -0
- template.md +11 -0
.env.example
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
REPLICATE_API_TOKEN=
|
| 2 |
+
OPENAI_API_KEY=
|
| 3 |
+
ENV=PRODUCTION
|
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.env
|
app.py
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import openai
|
| 3 |
+
import sys
|
| 4 |
+
import os
|
| 5 |
+
import json
|
| 6 |
+
import threading
|
| 7 |
+
import time
|
| 8 |
+
import requests
|
| 9 |
+
import argparse
|
| 10 |
+
import markdown2
|
| 11 |
+
|
| 12 |
+
from dotenv import load_dotenv
|
| 13 |
+
from IPython.display import Image
|
| 14 |
+
from moviepy.editor import VideoFileClip, concatenate_videoclips, ImageClip
|
| 15 |
+
from moviepy.video.fx.all import fadein, fadeout
|
| 16 |
+
from PIL import Image as PIL_Image
|
| 17 |
+
|
| 18 |
+
from jinja2 import Template
|
| 19 |
+
|
| 20 |
+
load_dotenv()
|
| 21 |
+
openai.api_key = os.getenv('OPENAI_API_KEY')
|
| 22 |
+
REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN")
|
| 23 |
+
ENV = os.getenv("ENV")
|
| 24 |
+
MODEL = "gpt-3.5-turbo"
|
| 25 |
+
# MODEL = "gpt-4"
|
| 26 |
+
|
| 27 |
+
if ENV == "PRODUCTION":
|
| 28 |
+
import replicate
|
| 29 |
+
else:
|
| 30 |
+
from stub import replicate
|
| 31 |
+
|
| 32 |
+
class Video:
|
| 33 |
+
def __init__(self, scene, index):
|
| 34 |
+
self.scene = scene
|
| 35 |
+
self.prompt = "masterpiece, awards, best quality, dramatic-lighting, key-visual, "
|
| 36 |
+
self.prompt = self.prompt + scene.get("visual_prompt_in_en")
|
| 37 |
+
self.prompt = self.prompt + ", cinematic-angles-" + scene.get("cinematic_angles")
|
| 38 |
+
self.nagative_prompt = "badhandv4, easynegative, ng_deepnegative_v1_75t, verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, "
|
| 39 |
+
self.index = index
|
| 40 |
+
self.output_url = None
|
| 41 |
+
self.file_path = f"assets/thread_{index}_video.mp4"
|
| 42 |
+
|
| 43 |
+
def run_replicate(self):
|
| 44 |
+
start_time = time.time()
|
| 45 |
+
|
| 46 |
+
self.output_url = replicate.run(
|
| 47 |
+
"lucataco/animate-diff:1531004ee4c98894ab11f8a4ce6206099e732c1da15121987a8eef54828f0663",
|
| 48 |
+
input={
|
| 49 |
+
"motion_module": "mm_sd_v14",
|
| 50 |
+
"prompt": self.prompt,
|
| 51 |
+
"n_prompt": self.nagative_prompt,
|
| 52 |
+
}
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
end_time = time.time()
|
| 56 |
+
duration = end_time - start_time
|
| 57 |
+
|
| 58 |
+
self.download_and_save(url=self.output_url, file_path=self.file_path)
|
| 59 |
+
self.print_thread_info(start_time, end_time, duration)
|
| 60 |
+
|
| 61 |
+
def download_and_save(self, url, file_path):
|
| 62 |
+
response = requests.get(url)
|
| 63 |
+
with open(file_path, "wb") as f:
|
| 64 |
+
f.write(response.content)
|
| 65 |
+
|
| 66 |
+
def print_thread_info(self, start_time, end_time, duration):
|
| 67 |
+
print(f"Thread {self.index} output_url: {self.output_url}")
|
| 68 |
+
print(f"Thread {self.index} start time: {start_time}")
|
| 69 |
+
print(f"Thread {self.index} end time: {end_time}")
|
| 70 |
+
print(f"Thread {self.index} duration: {duration}")
|
| 71 |
+
|
| 72 |
+
class ThreadController:
|
| 73 |
+
def __init__(self, args):
|
| 74 |
+
self.args = args
|
| 75 |
+
self.num_threads = len(args)
|
| 76 |
+
scenes = args.get("scenes")
|
| 77 |
+
# prompts = []
|
| 78 |
+
# if scenes:
|
| 79 |
+
# for scene_data in scenes:
|
| 80 |
+
# prompt = scene_data.get("visual_prompt_in_en")
|
| 81 |
+
# prompt = prompt + ", " + scene_data.get("cinematic_angles")
|
| 82 |
+
# prompt = prompt + ", " + scene_data.get("visual_prompt_in_en")
|
| 83 |
+
# prompts.append(prompt)
|
| 84 |
+
|
| 85 |
+
self.videos = [Video(scene, index) for index, scene in enumerate(scenes)]
|
| 86 |
+
self.threads = []
|
| 87 |
+
|
| 88 |
+
def run_threads(self):
|
| 89 |
+
os.makedirs("assets", exist_ok=True)
|
| 90 |
+
|
| 91 |
+
for video in self.videos:
|
| 92 |
+
thread = threading.Thread(target=video.run_replicate)
|
| 93 |
+
self.threads.append(thread)
|
| 94 |
+
thread.start()
|
| 95 |
+
|
| 96 |
+
for thread in self.threads:
|
| 97 |
+
thread.join()
|
| 98 |
+
|
| 99 |
+
def merge_videos(self):
|
| 100 |
+
clips = []
|
| 101 |
+
for video in self.videos:
|
| 102 |
+
clips.append(VideoFileClip(video.file_path))
|
| 103 |
+
|
| 104 |
+
final_clip = concatenate_videoclips(clips)
|
| 105 |
+
|
| 106 |
+
os.makedirs("videos", exist_ok=True)
|
| 107 |
+
output_path = "videos/final_concatenated_video.mp4"
|
| 108 |
+
|
| 109 |
+
final_clip.write_videofile(output_path, codec='libx264', fps=24)
|
| 110 |
+
|
| 111 |
+
return output_path
|
| 112 |
+
|
| 113 |
+
def print_prompts(self):
|
| 114 |
+
for video in self.videos:
|
| 115 |
+
print(f"Thread {video.index} prompt: {video.prompt}")
|
| 116 |
+
|
| 117 |
+
def main(args):
|
| 118 |
+
thread_controller = ThreadController(args)
|
| 119 |
+
thread_controller.run_threads()
|
| 120 |
+
merged_video_path = thread_controller.merge_videos()
|
| 121 |
+
|
| 122 |
+
thread_controller.print_prompts()
|
| 123 |
+
|
| 124 |
+
return merged_video_path
|
| 125 |
+
|
| 126 |
+
def load_prompts(file_path):
|
| 127 |
+
with open(file_path, "r") as f:
|
| 128 |
+
prompts = f.read().splitlines()
|
| 129 |
+
return prompts
|
| 130 |
+
|
| 131 |
+
def get_filetext(filename):
|
| 132 |
+
with open(filename, "r") as file:
|
| 133 |
+
filetext = file.read()
|
| 134 |
+
return filetext
|
| 135 |
+
|
| 136 |
+
def get_functions_from_schema(filename):
|
| 137 |
+
schema = get_filetext(filename)
|
| 138 |
+
schema_json = json.loads(schema)
|
| 139 |
+
functions = schema_json.get("functions")
|
| 140 |
+
return functions
|
| 141 |
+
|
| 142 |
+
functions = get_functions_from_schema('schema.json')
|
| 143 |
+
|
| 144 |
+
class OpenAI:
|
| 145 |
+
|
| 146 |
+
@classmethod
|
| 147 |
+
def chat_completion_with_function(cls, prompt, messages, functions):
|
| 148 |
+
print("prompt:"+prompt)
|
| 149 |
+
|
| 150 |
+
# 文章生成にかかる時間を計測する
|
| 151 |
+
start = time.time()
|
| 152 |
+
# ChatCompletion APIを呼び出す
|
| 153 |
+
response = openai.ChatCompletion.create(
|
| 154 |
+
model=MODEL,
|
| 155 |
+
messages=messages,
|
| 156 |
+
functions=functions,
|
| 157 |
+
function_call={"name": "generate_video"}
|
| 158 |
+
)
|
| 159 |
+
print("gpt generation time: "+str(time.time() - start))
|
| 160 |
+
|
| 161 |
+
# ChatCompletion APIから返された結果を取得する
|
| 162 |
+
message = response.choices[0].message
|
| 163 |
+
print("chat completion message: " + json.dumps(message, indent=2))
|
| 164 |
+
|
| 165 |
+
return message
|
| 166 |
+
|
| 167 |
+
class NajiminoAI:
|
| 168 |
+
|
| 169 |
+
def __init__(self, user_message):
|
| 170 |
+
self.user_message = user_message
|
| 171 |
+
|
| 172 |
+
def generate_markdown(self, args, generation_time):
|
| 173 |
+
|
| 174 |
+
# # lang=args.get("lang")
|
| 175 |
+
# title=args.get("title")
|
| 176 |
+
# description=args.get("description")
|
| 177 |
+
# visual_prompt_in_en=args.get("visual_prompt_in_en")
|
| 178 |
+
# scenes = args.get("scenes")
|
| 179 |
+
|
| 180 |
+
# prompt_for_visual_expression = \
|
| 181 |
+
# visual_prompt_in_en
|
| 182 |
+
|
| 183 |
+
# print("prompt_for_visual_expression: "+prompt_for_visual_expression)
|
| 184 |
+
|
| 185 |
+
# prompts = []
|
| 186 |
+
# if scenes:
|
| 187 |
+
# for scene_data in scenes:
|
| 188 |
+
# prompt = scene_data.get("visual_prompt_in_en")
|
| 189 |
+
# prompt = prompt + ", " + scene_data.get("cinematic_angles")
|
| 190 |
+
# prompt = prompt + ", " + scene_data.get("visual_prompt_in_en")
|
| 191 |
+
# prompts.append(prompt)
|
| 192 |
+
# print("scenes: " + json.dumps(scenes, indent=2))
|
| 193 |
+
# if scenes:
|
| 194 |
+
# for scene_data in scenes:
|
| 195 |
+
# scene = scene_data.get("scene")
|
| 196 |
+
# cinematic_angles = scene_data.get("cinematic_angles")
|
| 197 |
+
# visual_prompt_in_en = scene_data.get("visual_prompt_in_en")
|
| 198 |
+
# print("scene: ", scene)
|
| 199 |
+
# print("cinematic_angles: ", cinematic_angles)
|
| 200 |
+
# print("visual_prompt_in_en: ", visual_prompt_in_en)
|
| 201 |
+
|
| 202 |
+
template_string = get_filetext(filename = "template.md")
|
| 203 |
+
|
| 204 |
+
template = Template(template_string)
|
| 205 |
+
result = template.render(args=args, generation_time=generation_time)
|
| 206 |
+
|
| 207 |
+
print(result)
|
| 208 |
+
|
| 209 |
+
return result
|
| 210 |
+
|
| 211 |
+
@classmethod
|
| 212 |
+
def generate(cls, user_message):
|
| 213 |
+
|
| 214 |
+
najiminoai = NajiminoAI(user_message)
|
| 215 |
+
|
| 216 |
+
return najiminoai.create_video()
|
| 217 |
+
|
| 218 |
+
def create_video(self):
|
| 219 |
+
main_start_time = time.time()
|
| 220 |
+
|
| 221 |
+
user_message = self.user_message + " 4シーン"
|
| 222 |
+
|
| 223 |
+
messages = [
|
| 224 |
+
{"role": "user", "content": user_message}
|
| 225 |
+
]
|
| 226 |
+
|
| 227 |
+
functions = get_functions_from_schema('schema.json')
|
| 228 |
+
|
| 229 |
+
message = OpenAI.chat_completion_with_function(prompt=user_message, messages=messages, functions=functions)
|
| 230 |
+
|
| 231 |
+
video_path = None
|
| 232 |
+
html = None
|
| 233 |
+
if message.get("function_call") is None:
|
| 234 |
+
|
| 235 |
+
print("message: " + json.dumps(message, indent=2))
|
| 236 |
+
return [video_path, html]
|
| 237 |
+
|
| 238 |
+
function_name = message["function_call"]["name"]
|
| 239 |
+
|
| 240 |
+
args = json.loads(message["function_call"]["arguments"])
|
| 241 |
+
|
| 242 |
+
print("args: " + json.dumps(args, indent=2))
|
| 243 |
+
|
| 244 |
+
# # lang=args.get("lang")
|
| 245 |
+
# title=args.get("title")
|
| 246 |
+
# description=args.get("description")
|
| 247 |
+
# visual_prompt_in_en=args.get("visual_prompt_in_en")
|
| 248 |
+
# scenes = args.get("scenes")
|
| 249 |
+
|
| 250 |
+
# prompt_for_visual_expression = \
|
| 251 |
+
# visual_prompt_in_en
|
| 252 |
+
|
| 253 |
+
# print("prompt_for_visual_expression: "+prompt_for_visual_expression)
|
| 254 |
+
|
| 255 |
+
# prompts = []
|
| 256 |
+
# if scenes:
|
| 257 |
+
# for scene_data in scenes:
|
| 258 |
+
# prompt = scene_data.get("visual_prompt_in_en")
|
| 259 |
+
# prompt = prompt + ", " + scene_data.get("cinematic_angles")
|
| 260 |
+
# prompt = prompt + ", " + scene_data.get("visual_prompt_in_en")
|
| 261 |
+
# prompts.append(prompt)
|
| 262 |
+
|
| 263 |
+
video_path = main(args)
|
| 264 |
+
|
| 265 |
+
main_end_time = time.time()
|
| 266 |
+
main_duration = main_end_time - main_start_time
|
| 267 |
+
|
| 268 |
+
print("Thread Main start time:", main_start_time)
|
| 269 |
+
print("Thread Main end time:", main_end_time)
|
| 270 |
+
print("Thread Main duration:", main_duration)
|
| 271 |
+
print("All threads finished.")
|
| 272 |
+
|
| 273 |
+
function_response = self.generate_markdown(args, main_duration)
|
| 274 |
+
|
| 275 |
+
html = (
|
| 276 |
+
"<div style='max-width:100%; overflow:auto'>"
|
| 277 |
+
+ "<p>"
|
| 278 |
+
+ markdown2.markdown(function_response,extras=["tables"])
|
| 279 |
+
+ "</div>"
|
| 280 |
+
)
|
| 281 |
+
return [video_path, html]
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
if __name__ == "__main__":
|
| 285 |
+
parser = argparse.ArgumentParser(description="Generate videos from text prompts")
|
| 286 |
+
|
| 287 |
+
parser.add_argument("--prompts_file", type=str, help="File containing prompts (one per line)")
|
| 288 |
+
|
| 289 |
+
args = parser.parse_args()
|
| 290 |
+
|
| 291 |
+
if args.prompts_file:
|
| 292 |
+
prompts = load_prompts(args.prompts_file)
|
| 293 |
+
# main(prompts)
|
| 294 |
+
NajiminoAI.generate("伝統工芸と最新技術の融合")
|
| 295 |
+
else:
|
| 296 |
+
# def create_video(prompt):
|
| 297 |
+
# prompts = prompt.strip().split('\n')
|
| 298 |
+
# output_path = main(prompts)
|
| 299 |
+
# return output_path
|
| 300 |
+
|
| 301 |
+
iface = gr.Interface(
|
| 302 |
+
fn=NajiminoAI.generate,
|
| 303 |
+
# inputs=gr.Textbox(label=inputs_label),
|
| 304 |
+
outputs=[
|
| 305 |
+
gr.Video(),
|
| 306 |
+
"html"
|
| 307 |
+
],
|
| 308 |
+
# title=title,
|
| 309 |
+
inputs=gr.inputs.Textbox(lines=2, placeholder="Enter your prompt"),
|
| 310 |
+
title="Video Generator",
|
| 311 |
+
description="Generate a video based on the text prompt you enter.",
|
| 312 |
+
examples=[
|
| 313 |
+
["伝統工芸と最新技術の融合"],
|
| 314 |
+
["子どもたちが笑ったり怒ったり泣いたり楽しんだりする"],
|
| 315 |
+
["光、闇、氷、水、雲、風、自然、渦、土"],
|
| 316 |
+
],
|
| 317 |
+
)
|
| 318 |
+
iface.launch()
|
| 319 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
replicate
|
| 2 |
+
moviepy
|
| 3 |
+
openai
|
schema.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"functions": [
|
| 3 |
+
{
|
| 4 |
+
"name": "generate_video",
|
| 5 |
+
"description": "指定された文章からビデオを生成する",
|
| 6 |
+
"parameters": {
|
| 7 |
+
"type": "object",
|
| 8 |
+
"required": [
|
| 9 |
+
"title",
|
| 10 |
+
"visual_style",
|
| 11 |
+
"visual_prompt_in_en",
|
| 12 |
+
"scene_count",
|
| 13 |
+
"scenes"
|
| 14 |
+
],
|
| 15 |
+
"properties": {
|
| 16 |
+
"title": {
|
| 17 |
+
"type": "string",
|
| 18 |
+
"description": "動画のタイトル"
|
| 19 |
+
},
|
| 20 |
+
"visual_style": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "ビデオの視覚的なスタイル (例: 'anime')"
|
| 23 |
+
},
|
| 24 |
+
"visual_prompt_in_en": {
|
| 25 |
+
"type": "string",
|
| 26 |
+
"description": "映像に関連する簡単な説明"
|
| 27 |
+
},
|
| 28 |
+
"negative_visual_prompt_in_en": {
|
| 29 |
+
"type": "string",
|
| 30 |
+
"description": "映像に含めないでほしい視覚的説明"
|
| 31 |
+
},
|
| 32 |
+
"scene_count": {
|
| 33 |
+
"type": "integer",
|
| 34 |
+
"description": "シーンの数"
|
| 35 |
+
},
|
| 36 |
+
"scenes": {
|
| 37 |
+
"type": "array",
|
| 38 |
+
"description": "シーンの詳細",
|
| 39 |
+
"items": {
|
| 40 |
+
"type": "object",
|
| 41 |
+
"required": [
|
| 42 |
+
"scene",
|
| 43 |
+
"visual_prompt_in_en",
|
| 44 |
+
"cinematic_angles"
|
| 45 |
+
],
|
| 46 |
+
"properties": {
|
| 47 |
+
"scene": {
|
| 48 |
+
"type": "integer",
|
| 49 |
+
"description": "シーン番号"
|
| 50 |
+
},
|
| 51 |
+
"visual_prompt_in_en": {
|
| 52 |
+
"type": "string",
|
| 53 |
+
"description": "シーンの視覚的説明"
|
| 54 |
+
},
|
| 55 |
+
"cinematic_angles": {
|
| 56 |
+
"type": "string",
|
| 57 |
+
"description": "カメラアングルや動きの説明 (例: 'dolly-in', 'spinning-shot', 'dutch-angle')"
|
| 58 |
+
},
|
| 59 |
+
"negative_visual_prompt_in_en": {
|
| 60 |
+
"type": "string",
|
| 61 |
+
"description": "シーンの含まないでほしい視覚的説明"
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
]
|
| 70 |
+
}
|
stub/replicate.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# stub/replicate.py
|
| 2 |
+
def run(model_path, input):
|
| 3 |
+
print("Stub called for replicate.run with model_path and input")
|
| 4 |
+
|
| 5 |
+
prompt = input["prompt"]
|
| 6 |
+
if "Introduction".lower() in prompt.lower():
|
| 7 |
+
url = "https://replicate.delivery/pbxt/sLBtHnGDMVK7AV5x24dl29lp9pQnbsfcuMbusXcJEl9kG8rIA/out.mp4"
|
| 8 |
+
elif "Development".lower() in prompt.lower():
|
| 9 |
+
url = "https://replicate.delivery/pbxt/QVgesepHS7pvZE9UWs2SPDMsEeCMrteelrmuegvvr7iITDerIA/out.mp4"
|
| 10 |
+
elif "Climax".lower() in prompt.lower():
|
| 11 |
+
url = "https://replicate.delivery/pbxt/H1bJ3dp0r95OM5XPXoK6gfABF9vOCsFT7gxH0I4ceg75N4XRA/out.mp4"
|
| 12 |
+
elif "Resolution".lower() in prompt.lower():
|
| 13 |
+
url = "https://replicate.delivery/pbxt/qNdKneAbNaRtdK6pZnoAO17JCJfD5neffTw193F1XXUkvBfVE/out.mp4"
|
| 14 |
+
else:
|
| 15 |
+
url = "https://replicate.delivery/pbxt/cgT0Aef4haodP04HybKaOrsHOQKkYcV8mpzGj7WHx3eFMuviA/out.mp4"
|
| 16 |
+
return url
|
template.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Movie Title: {{ args.title }}
|
| 2 |
+
|
| 3 |
+
## Generation Time
|
| 4 |
+
|
| 5 |
+
{{ generation_time }}
|
| 6 |
+
|
| 7 |
+
## Prompts
|
| 8 |
+
|
| 9 |
+
| Scene | visual_prompt_in_en | negative_visual_prompt_in_en | cinematic_angles |
|
| 10 |
+
|----:|----|----|----|{% for item in args.scenes %}
|
| 11 |
+
|{{ item.scene }}|{{ item.visual_prompt_in_en }}|{{ item.negative_visual_prompt_in_en }}|{{ item.camera_work}}|{% endfor %}
|