Spaces:
Runtime error
Runtime error
shigeru saito
commited on
Commit
·
59876db
1
Parent(s):
f19a595
REPLICATE複数トークン対応、トークン数を取得できるように修正、シーン数を環境変数化、
Browse files- .env.example +1 -0
- app.py +76 -43
- schema.json +2 -2
.env.example
CHANGED
@@ -1,3 +1,4 @@
|
|
1 |
REPLICATE_API_TOKEN_LIST=key1,key2
|
2 |
OPENAI_API_KEY=
|
3 |
ENV=PRODUCTION
|
|
|
|
1 |
REPLICATE_API_TOKEN_LIST=key1,key2
|
2 |
OPENAI_API_KEY=
|
3 |
ENV=PRODUCTION
|
4 |
+
NUMBER_OF_SCENES=4
|
app.py
CHANGED
@@ -8,6 +8,8 @@ import time
|
|
8 |
import requests
|
9 |
import argparse
|
10 |
import markdown2
|
|
|
|
|
11 |
|
12 |
from dotenv import load_dotenv
|
13 |
from IPython.display import Image
|
@@ -27,6 +29,7 @@ openai.api_key = os.getenv('OPENAI_API_KEY')
|
|
27 |
# REPLICATE_API_TOKEN_LISTをロードし、カンマで分割してリストに変換
|
28 |
REPLICATE_API_TOKEN_LIST = os.getenv("REPLICATE_API_TOKEN_LIST").split(',')
|
29 |
REPLICATE_API_TOKEN_INDEX = 0 # トークンのインデックスを初期化
|
|
|
30 |
|
31 |
if ENV == "PRODUCTION":
|
32 |
import replicate
|
@@ -34,7 +37,8 @@ else:
|
|
34 |
from stub import replicate
|
35 |
|
36 |
class Video:
|
37 |
-
def __init__(self, scene, index):
|
|
|
38 |
self.scene = scene
|
39 |
self.prompt = "masterpiece, awards, best quality, dramatic-lighting, "
|
40 |
self.prompt = self.prompt + scene.get("visual_prompt_in_en")
|
@@ -42,33 +46,47 @@ class Video:
|
|
42 |
self.nagative_prompt = "badhandv4, easynegative, ng_deepnegative_v1_75t, verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, nsfw, "
|
43 |
self.index = index
|
44 |
self.output_url = None
|
45 |
-
self.
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
end_time = time.time()
|
68 |
-
duration = end_time - start_time
|
69 |
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
def download_and_save(self, url, file_path):
|
74 |
response = requests.get(url)
|
@@ -84,18 +102,17 @@ class Video:
|
|
84 |
class ThreadController:
|
85 |
def __init__(self, args):
|
86 |
self.args = args
|
87 |
-
self.num_threads = len(args)
|
88 |
scenes = args.get("scenes")
|
89 |
-
|
90 |
-
# if scenes:
|
91 |
-
# for scene_data in scenes:
|
92 |
-
# prompt = scene_data.get("visual_prompt_in_en")
|
93 |
-
# prompt = prompt + ", " + scene_data.get("cinematic_angles")
|
94 |
-
# prompt = prompt + ", " + scene_data.get("visual_prompt_in_en")
|
95 |
-
# prompts.append(prompt)
|
96 |
-
|
97 |
-
self.videos = [Video(scene, index) for index, scene in enumerate(scenes)]
|
98 |
self.threads = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
def run_threads(self):
|
101 |
os.makedirs("assets", exist_ok=True)
|
@@ -104,6 +121,8 @@ class ThreadController:
|
|
104 |
thread = threading.Thread(target=video.run_replicate)
|
105 |
self.threads.append(thread)
|
106 |
thread.start()
|
|
|
|
|
107 |
|
108 |
for thread in self.threads:
|
109 |
thread.join()
|
@@ -111,12 +130,17 @@ class ThreadController:
|
|
111 |
def merge_videos(self):
|
112 |
clips = []
|
113 |
for video in self.videos:
|
114 |
-
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
final_clip = concatenate_videoclips(clips)
|
117 |
|
118 |
os.makedirs("videos", exist_ok=True)
|
119 |
-
output_path = "videos/
|
120 |
|
121 |
final_clip.write_videofile(output_path, codec='libx264', fps=24)
|
122 |
|
@@ -126,6 +150,12 @@ class ThreadController:
|
|
126 |
for video in self.videos:
|
127 |
print(f"Thread {video.index} prompt: {video.prompt}")
|
128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
def main(args):
|
130 |
thread_controller = ThreadController(args)
|
131 |
thread_controller.run_threads()
|
@@ -173,8 +203,8 @@ class OpenAI:
|
|
173 |
# ChatCompletion APIから返された結果を取得する
|
174 |
message = response.choices[0].message
|
175 |
print("chat completion message: " + json.dumps(message, indent=2))
|
176 |
-
|
177 |
-
return
|
178 |
|
179 |
class NajiminoAI:
|
180 |
|
@@ -230,7 +260,7 @@ class NajiminoAI:
|
|
230 |
def create_video(self):
|
231 |
main_start_time = time.time()
|
232 |
|
233 |
-
user_message = self.user_message + "
|
234 |
|
235 |
messages = [
|
236 |
{"role": "user", "content": user_message}
|
@@ -238,7 +268,10 @@ class NajiminoAI:
|
|
238 |
|
239 |
functions = get_functions_from_schema('schema.json')
|
240 |
|
241 |
-
|
|
|
|
|
|
|
242 |
|
243 |
video_path = None
|
244 |
html = None
|
|
|
8 |
import requests
|
9 |
import argparse
|
10 |
import markdown2
|
11 |
+
import uuid
|
12 |
+
from pathlib import Path
|
13 |
|
14 |
from dotenv import load_dotenv
|
15 |
from IPython.display import Image
|
|
|
29 |
# REPLICATE_API_TOKEN_LISTをロードし、カンマで分割してリストに変換
|
30 |
REPLICATE_API_TOKEN_LIST = os.getenv("REPLICATE_API_TOKEN_LIST").split(',')
|
31 |
REPLICATE_API_TOKEN_INDEX = 0 # トークンのインデックスを初期化
|
32 |
+
NUMBER_OF_SCENES = os.getenv("NUMBER_OF_SCENES")
|
33 |
|
34 |
if ENV == "PRODUCTION":
|
35 |
import replicate
|
|
|
37 |
from stub import replicate
|
38 |
|
39 |
class Video:
|
40 |
+
def __init__(self, scene, index, token_controller):
|
41 |
+
self.token_controller = token_controller
|
42 |
self.scene = scene
|
43 |
self.prompt = "masterpiece, awards, best quality, dramatic-lighting, "
|
44 |
self.prompt = self.prompt + scene.get("visual_prompt_in_en")
|
|
|
46 |
self.nagative_prompt = "badhandv4, easynegative, ng_deepnegative_v1_75t, verybadimagenegative_v1.3, bad-artist, bad_prompt_version2-neg, nsfw, "
|
47 |
self.index = index
|
48 |
self.output_url = None
|
49 |
+
self.video_id = uuid.uuid4()
|
50 |
+
self.file_path = f"assets/thread_{index}_request_{self.video_id}_video.mp4"
|
51 |
+
|
52 |
+
MAX_RETRIES = 2
|
53 |
+
def run_replicate(self, retries=0):
|
54 |
+
try:
|
55 |
+
self.token = self.token_controller.get_next_token()
|
56 |
+
start_time = time.time()
|
57 |
+
|
58 |
+
os.environ["REPLICATE_API_TOKEN"] = self.token
|
59 |
+
#tokenの最初の10文字だけ出力
|
60 |
+
print(f"Thread {self.index} token: {self.token[:10]}")
|
61 |
+
|
62 |
+
self.output_url = replicate.run(
|
63 |
+
"lucataco/animate-diff:1531004ee4c98894ab11f8a4ce6206099e732c1da15121987a8eef54828f0663",
|
64 |
+
input={
|
65 |
+
"motion_module": "mm_sd_v14",
|
66 |
+
"prompt": self.prompt,
|
67 |
+
"n_prompt": self.nagative_prompt,
|
68 |
+
"seed": 0,
|
69 |
+
}
|
70 |
+
)
|
|
|
|
|
71 |
|
72 |
+
end_time = time.time()
|
73 |
+
duration = end_time - start_time
|
74 |
+
|
75 |
+
self.download_and_save(url=self.output_url, file_path=self.file_path)
|
76 |
+
self.print_thread_info(start_time, end_time, duration)
|
77 |
+
except replicate.exceptions.ReplicateError as e:
|
78 |
+
if str(e) == "The requested resource could not be found." and retries < self.MAX_RETRIES:
|
79 |
+
print("リソースが見つからないエラーが発生しました。2秒後に再試行します。")
|
80 |
+
time.sleep(2)
|
81 |
+
self.run_replicate(retries + 1) # 再帰的に関数を呼び出して再試行
|
82 |
+
elif retries >= self.MAX_RETRIES:
|
83 |
+
print("最大再試行回数に達しました。スレッドを終了します。")
|
84 |
+
# 最大再試行回数に達した場合の追加処理
|
85 |
+
else:
|
86 |
+
print("予期しないエラーが発生しました。スレッドを終了します。")
|
87 |
+
# 予期しないエラーが発生した場合の追加処理
|
88 |
+
except Exception as e:
|
89 |
+
print(f"Error in thread {self.index}: {e}")
|
90 |
|
91 |
def download_and_save(self, url, file_path):
|
92 |
response = requests.get(url)
|
|
|
102 |
class ThreadController:
|
103 |
def __init__(self, args):
|
104 |
self.args = args
|
|
|
105 |
scenes = args.get("scenes")
|
106 |
+
self.videos = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
self.threads = []
|
108 |
+
self.token_index = 0
|
109 |
+
self.lock = threading.Lock()
|
110 |
+
for index, scene in enumerate(scenes):
|
111 |
+
for _ in REPLICATE_API_TOKEN_LIST:
|
112 |
+
# token = REPLICATE_API_TOKEN_LIST[self.token_index]
|
113 |
+
video = Video(scene, index, self)
|
114 |
+
self.videos.append(video)
|
115 |
+
self.token_index = (self.token_index + 1) % len(REPLICATE_API_TOKEN_LIST)
|
116 |
|
117 |
def run_threads(self):
|
118 |
os.makedirs("assets", exist_ok=True)
|
|
|
121 |
thread = threading.Thread(target=video.run_replicate)
|
122 |
self.threads.append(thread)
|
123 |
thread.start()
|
124 |
+
# 1秒待ってから実行
|
125 |
+
# time.sleep(1)
|
126 |
|
127 |
for thread in self.threads:
|
128 |
thread.join()
|
|
|
130 |
def merge_videos(self):
|
131 |
clips = []
|
132 |
for video in self.videos:
|
133 |
+
video_path = Path(video.file_path)
|
134 |
+
if video_path.exists():
|
135 |
+
clips.append(VideoFileClip(video.file_path))
|
136 |
+
else:
|
137 |
+
print(f"Error: Video file {video.file_path} could not be found! Skipping this file.")
|
138 |
+
# 他のログ出力方法も使用可能、例: loggingモジュール
|
139 |
|
140 |
final_clip = concatenate_videoclips(clips)
|
141 |
|
142 |
os.makedirs("videos", exist_ok=True)
|
143 |
+
output_path = f"videos/final_concatenated_video_{uuid.uuid4()}.mp4"
|
144 |
|
145 |
final_clip.write_videofile(output_path, codec='libx264', fps=24)
|
146 |
|
|
|
150 |
for video in self.videos:
|
151 |
print(f"Thread {video.index} prompt: {video.prompt}")
|
152 |
|
153 |
+
def get_next_token(self):
|
154 |
+
with self.lock:
|
155 |
+
token = REPLICATE_API_TOKEN_LIST[self.token_index]
|
156 |
+
self.token_index = (self.token_index + 1) % len(REPLICATE_API_TOKEN_LIST)
|
157 |
+
return token
|
158 |
+
|
159 |
def main(args):
|
160 |
thread_controller = ThreadController(args)
|
161 |
thread_controller.run_threads()
|
|
|
203 |
# ChatCompletion APIから返された結果を取得する
|
204 |
message = response.choices[0].message
|
205 |
print("chat completion message: " + json.dumps(message, indent=2))
|
206 |
+
|
207 |
+
return response
|
208 |
|
209 |
class NajiminoAI:
|
210 |
|
|
|
260 |
def create_video(self):
|
261 |
main_start_time = time.time()
|
262 |
|
263 |
+
user_message = self.user_message + f" {NUMBER_OF_SCENES}シーン"
|
264 |
|
265 |
messages = [
|
266 |
{"role": "user", "content": user_message}
|
|
|
268 |
|
269 |
functions = get_functions_from_schema('schema.json')
|
270 |
|
271 |
+
response = OpenAI.chat_completion_with_function(prompt=user_message, messages=messages, functions=functions)
|
272 |
+
|
273 |
+
message = response.choices[0].message
|
274 |
+
total_tokens = response.usage.total_tokens
|
275 |
|
276 |
video_path = None
|
277 |
html = None
|
schema.json
CHANGED
@@ -16,11 +16,11 @@
|
|
16 |
"properties": {
|
17 |
"title": {
|
18 |
"type": "string",
|
19 |
-
"description": "
|
20 |
},
|
21 |
"story": {
|
22 |
"type": "string",
|
23 |
-
"description": "
|
24 |
},
|
25 |
"visual_style": {
|
26 |
"type": "string",
|
|
|
16 |
"properties": {
|
17 |
"title": {
|
18 |
"type": "string",
|
19 |
+
"description": "映画のタイトル"
|
20 |
},
|
21 |
"story": {
|
22 |
"type": "string",
|
23 |
+
"description": "映画のあらすじを、起承転結を交えて時系列に詳しく説明する"
|
24 |
},
|
25 |
"visual_style": {
|
26 |
"type": "string",
|