Spaces:
Sleeping
Sleeping
Magenta49 commited on
Commit ยท
9e63fc8
1
Parent(s): 8ff9a44
Add Hugging Face deployment workflow
Browse files- .github/workflows/deploy_to_hf.yml +22 -0
- app.py +71 -89
- logic_image.py +4 -3
.github/workflows/deploy_to_hf.yml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Deploy to Hugging Face Space
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
|
| 8 |
+
jobs:
|
| 9 |
+
deploy:
|
| 10 |
+
runs-on: ubuntu-latest
|
| 11 |
+
steps:
|
| 12 |
+
- name: Checkout repository
|
| 13 |
+
uses: actions/checkout@v4
|
| 14 |
+
with:
|
| 15 |
+
fetch-depth: 0
|
| 16 |
+
|
| 17 |
+
- name: Push to Hugging Face Space
|
| 18 |
+
env:
|
| 19 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 20 |
+
run: |
|
| 21 |
+
git remote add space https://PLXR:${HF_TOKEN}@huggingface.co/spaces/PLXR/youtube_auto_image1
|
| 22 |
+
git push --force space main
|
app.py
CHANGED
|
@@ -28,6 +28,8 @@ if 'final_audio' not in st.session_state:
|
|
| 28 |
st.session_state['final_audio'] = None
|
| 29 |
if 'shared_script' not in st.session_state:
|
| 30 |
st.session_state['shared_script'] = ""
|
|
|
|
|
|
|
| 31 |
|
| 32 |
# [CSS] ๋คํฌ๋ชจ๋ + ์ค๋ ์ง ํฌ์ธํธ ๋์์ธ
|
| 33 |
st.markdown("""
|
|
@@ -310,6 +312,7 @@ with tab2:
|
|
| 310 |
seo_result = logic_seo.generate_seo_content(client, text_model_id, seo_script)
|
| 311 |
|
| 312 |
st.session_state["seo_result"] = seo_result
|
|
|
|
| 313 |
st.success("๋ถ์ ์๋ฃ!")
|
| 314 |
|
| 315 |
c_seo1, c_seo2 = st.columns(2)
|
|
@@ -323,105 +326,84 @@ with tab2:
|
|
| 323 |
st.markdown("##### ๐ ์ค๋ช
๋ (Description)")
|
| 324 |
st.text_area("์ค๋ช
๋ ๊ฒฐ๊ณผ", seo_result['description'], height=200)
|
| 325 |
st.divider()
|
| 326 |
-
st.subheader("๐ผ๏ธ ์ธ๋ค์ผ ์์ฑ")
|
| 327 |
|
| 328 |
-
|
| 329 |
|
| 330 |
-
|
| 331 |
-
st.info("SEO ๋ถ์์ ๋จผ์ ์คํํ๋ฉด ์ธ๋ค์ผ ์์ฑ ๋ฒํผ์ด ๋ํ๋ฉ๋๋ค.")
|
| 332 |
-
else:
|
| 333 |
-
strat_keys = list(THUMBNAIL_STRATEGIES.keys())
|
| 334 |
-
sel_strat = st.selectbox("์ธ๋ค์ผ ์ ๋ต ์ ํ", strat_keys, index=0)
|
| 335 |
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
if not api_key:
|
| 342 |
-
st.error("API Key ํ์")
|
| 343 |
-
else:
|
| 344 |
-
client = genai.Client(api_key=api_key)
|
| 345 |
-
|
| 346 |
-
strategy_block = THUMBNAIL_STRATEGIES[sel_strat]
|
| 347 |
-
|
| 348 |
-
prompt = f"""
|
| 349 |
-
๋๋ ์ ํ๋ธ ์ธ๋ค์ผ ๊ธฐํ์๋ค.
|
| 350 |
-
์๋ '๋๋ณธ'๊ณผ '์ ๋ต'์ ์ฐธ๊ณ ํด์, ์ด๋ฏธ์ง ์์ฑ ๋ชจ๋ธ์ ๋ฃ์ '์ธ๋ค์ผ ํ๋กฌํํธ'๋ฅผ ๋ง๋ ๋ค.
|
| 351 |
-
|
| 352 |
-
[๋๋ณธ]
|
| 353 |
-
{seo_script[:8000]}
|
| 354 |
-
|
| 355 |
-
[์ ๋ต]
|
| 356 |
-
{strategy_block}
|
| 357 |
-
|
| 358 |
-
[์ถ๊ฐ ์กฐ๊ฑด]
|
| 359 |
-
- ์ธ๋ค์ผ ์ด๋ฏธ์ง ์์ ํ
์คํธ๋ฅผ ์ง์ ๊ทธ๋ ค ๋ฃ์ง ๋ง๋ผ(๊ธ์ ์์ฑ ๊ธ์ง).
|
| 360 |
-
- ๋์ 'ํ
์คํธ๋ฅผ ๋ฃ์ ์๋ฆฌ'๋ฅผ ๊ตฌ๋๋ก ํ๋ณดํด๋ผ(์๋จ/ํ๋จ ์ฌ๋ฐฑ, ์์ ์์ญ).
|
| 361 |
-
- ๊ตญ๊ฐ/๊ตญ๊ธฐ/๋ํต๋ น/์ฒญ์๋/๊ตญํ์์ฌ๋น ๋ฑ ํน์ ๊ตญ๊ฐ ์์ง์ด ์๋์ผ๋ก ๋์ค์ง ์๊ฒ,
|
| 362 |
-
์ ์น ์์ง๋ฌผ์ ์ถ์์ ์์ (์ค๋ฃจ์ฃ, ์กฐ๋ช
, ๊ตฐ์ค, ๋ฌด๋)๋ก ์ฒ๋ฆฌํด๋ผ.
|
| 363 |
-
- ํ๋ฉด๋น๋ {aspect_ratio}.
|
| 364 |
-
- ์ถ๋ ฅ์ "ํ๋กฌํํธ ํ
์คํธ 1๊ฐ"๋ง. JSON/๋งํฌ๋ค์ด ๊ธ์ง.
|
| 365 |
-
|
| 366 |
-
[์ฌ์ฉ์๊ฐ ๋ฃ์ ๋ฉ์ธ ๋ฌธ๊ตฌ(์ฐธ๊ณ ๋ง)]
|
| 367 |
-
{thumb_text}
|
| 368 |
-
""".strip()
|
| 369 |
-
|
| 370 |
-
res = client.models.generate_content(model=text_model_id, contents=prompt)
|
| 371 |
-
thumb_prompt = (getattr(res, "text", "") or "").strip()
|
| 372 |
-
st.session_state["thumb_prompt"] = thumb_prompt
|
| 373 |
-
st.success("์ธ๋ค์ผ ํ๋กฌํํธ ์์ฑ ์๋ฃ!")
|
| 374 |
-
st.text_area("์์ฑ๋ ์ธ๋ค์ผ ํ๋กฌํํธ", value=thumb_prompt, height=180)
|
| 375 |
|
| 376 |
-
|
| 377 |
-
thumb_prompt_cached = st.session_state.get("thumb_prompt", "")
|
| 378 |
-
if thumb_prompt_cached:
|
| 379 |
-
if st.button("๐จ ์ธ๋ค์ผ ์ด๋ฏธ์ง 1์ฅ ์์ฑ", key="thumb_img_btn", type="primary"):
|
| 380 |
if not api_key:
|
| 381 |
st.error("API Key ํ์")
|
|
|
|
|
|
|
| 382 |
else:
|
| 383 |
client = genai.Client(api_key=api_key)
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 394 |
try:
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
except:
|
| 399 |
-
|
| 400 |
else:
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
)
|
| 405 |
-
try:
|
| 406 |
-
cand = img_res.candidates[0]
|
| 407 |
-
part = cand.content.parts[0]
|
| 408 |
-
img_bytes = part.inline_data.data if part.inline_data else None
|
| 409 |
-
except:
|
| 410 |
-
img_bytes = None
|
| 411 |
-
except Exception as e:
|
| 412 |
-
st.error(f"์ด๋ฏธ์ง ์์ฑ ์คํจ: {e}")
|
| 413 |
-
|
| 414 |
-
if img_bytes:
|
| 415 |
-
st.image(Image.open(io.BytesIO(img_bytes)), use_container_width=True)
|
| 416 |
-
st.download_button(
|
| 417 |
-
"โฌ๏ธ ์ธ๋ค์ผ ๋ค์ด๋ก๋",
|
| 418 |
-
data=img_bytes,
|
| 419 |
-
file_name="thumbnail.png",
|
| 420 |
-
mime="image/png",
|
| 421 |
-
use_container_width=True
|
| 422 |
-
)
|
| 423 |
-
else:
|
| 424 |
-
st.error("์ด๋ฏธ์ง ๋ฐ์ดํธ๋ฅผ ์ถ์ถํ์ง ๋ชปํ์ต๋๋ค. (๋ชจ๋ธ ์๋ต ๊ตฌ์กฐ ํ์ธ ํ์)")
|
| 425 |
|
| 426 |
# ----------------------------------------------------------------
|
| 427 |
# [TAB 3] AI ์ฑ์ฐ (TTS)
|
|
@@ -478,4 +460,4 @@ with tab3:
|
|
| 478 |
if final_wav:
|
| 479 |
st.success("์ค๋์ค ์์ฑ ์๋ฃ!")
|
| 480 |
st.audio(final_wav, format="audio/wav")
|
| 481 |
-
st.download_button("๋ค์ด๋ก๋ (WAV)", final_wav, "full_audio.wav", "audio/wav")
|
|
|
|
| 28 |
st.session_state['final_audio'] = None
|
| 29 |
if 'shared_script' not in st.session_state:
|
| 30 |
st.session_state['shared_script'] = ""
|
| 31 |
+
if 'thumbnail_results' not in st.session_state:
|
| 32 |
+
st.session_state['thumbnail_results'] = []
|
| 33 |
|
| 34 |
# [CSS] ๋คํฌ๋ชจ๋ + ์ค๋ ์ง ํฌ์ธํธ ๋์์ธ
|
| 35 |
st.markdown("""
|
|
|
|
| 312 |
seo_result = logic_seo.generate_seo_content(client, text_model_id, seo_script)
|
| 313 |
|
| 314 |
st.session_state["seo_result"] = seo_result
|
| 315 |
+
st.session_state["thumbnail_results"] = []
|
| 316 |
st.success("๋ถ์ ์๋ฃ!")
|
| 317 |
|
| 318 |
c_seo1, c_seo2 = st.columns(2)
|
|
|
|
| 326 |
st.markdown("##### ๐ ์ค๋ช
๋ (Description)")
|
| 327 |
st.text_area("์ค๋ช
๋ ๊ฒฐ๊ณผ", seo_result['description'], height=200)
|
| 328 |
st.divider()
|
|
|
|
| 329 |
|
| 330 |
+
st.subheader("๐ผ๏ธ ์ธ๋ค์ผ ์์ฑ")
|
| 331 |
|
| 332 |
+
seo_cached = st.session_state.get("seo_result")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
|
| 334 |
+
if not seo_cached:
|
| 335 |
+
st.info("SEO ๋ถ์์ ๋จผ์ ์คํํ๋ฉด ์ธ๋ค์ผ ์์ฑ ๋ฒํผ์ด ๋ํ๋ฉ๋๋ค.")
|
| 336 |
+
else:
|
| 337 |
+
default_thumb_text = seo_cached["titles"][0] if seo_cached.get("titles") else ""
|
| 338 |
+
thumb_text = st.text_input("์ธ๋ค์ผ ๋ฉ์ธ ๋ฌธ๊ตฌ(์ฐธ๊ณ ์ฉ)", value=default_thumb_text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
|
| 340 |
+
if st.button("๐จ ์ธ๋ค์ผ 3์ข
๋์ ์์ฑ", key="thumb_img_btn", type="primary"):
|
|
|
|
|
|
|
|
|
|
| 341 |
if not api_key:
|
| 342 |
st.error("API Key ํ์")
|
| 343 |
+
elif not seo_script:
|
| 344 |
+
st.warning("๋๋ณธ ํ์")
|
| 345 |
else:
|
| 346 |
client = genai.Client(api_key=api_key)
|
| 347 |
+
progress_text = "์ธ๋ค์ผ 3์ข
์์ฑ ์ค..."
|
| 348 |
+
my_bar = st.progress(0, text=progress_text)
|
| 349 |
+
|
| 350 |
+
strategy_items = list(THUMBNAIL_STRATEGIES.items())
|
| 351 |
+
temp_results = [None] * len(strategy_items)
|
| 352 |
+
|
| 353 |
+
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
|
| 354 |
+
future_to_idx = {
|
| 355 |
+
executor.submit(
|
| 356 |
+
logic_image.process_thumbnail_task,
|
| 357 |
+
i,
|
| 358 |
+
key,
|
| 359 |
+
strategy_text,
|
| 360 |
+
seo_script,
|
| 361 |
+
thumb_text,
|
| 362 |
+
client,
|
| 363 |
+
text_model_id,
|
| 364 |
+
image_model_id,
|
| 365 |
+
aspect_ratio
|
| 366 |
+
): i
|
| 367 |
+
for i, (key, strategy_text) in enumerate(strategy_items)
|
| 368 |
+
}
|
| 369 |
+
completed = 0
|
| 370 |
+
for future in concurrent.futures.as_completed(future_to_idx):
|
| 371 |
+
idx, prompt, img = future.result()
|
| 372 |
+
strategy_key = strategy_items[idx][0]
|
| 373 |
+
temp_results[idx] = (strategy_key, prompt, img)
|
| 374 |
+
completed += 1
|
| 375 |
+
my_bar.progress(completed / len(strategy_items), text=f"{strategy_key} ์๋ฃ!")
|
| 376 |
+
|
| 377 |
+
st.session_state['thumbnail_results'] = temp_results
|
| 378 |
+
my_bar.empty()
|
| 379 |
+
st.rerun()
|
| 380 |
+
|
| 381 |
+
if st.session_state.get('thumbnail_results'):
|
| 382 |
+
cols = st.columns(3)
|
| 383 |
+
for col, item in zip(cols, st.session_state['thumbnail_results']):
|
| 384 |
+
if item is None:
|
| 385 |
+
continue
|
| 386 |
+
strategy_key, prompt_text, img_data = item
|
| 387 |
+
with col:
|
| 388 |
+
st.markdown(f"**{strategy_key}**")
|
| 389 |
+
if img_data:
|
| 390 |
try:
|
| 391 |
+
image = Image.open(io.BytesIO(img_data))
|
| 392 |
+
st.image(image, use_container_width=True)
|
| 393 |
+
st.download_button(
|
| 394 |
+
label="โฌ๏ธ ๋ค์ด๋ก๋",
|
| 395 |
+
data=img_data,
|
| 396 |
+
file_name=f"thumbnail_{strategy_key.split('.')[0].lower()}.png",
|
| 397 |
+
mime="image/png",
|
| 398 |
+
key=f"thumb_dl_{strategy_key}",
|
| 399 |
+
use_container_width=True
|
| 400 |
+
)
|
| 401 |
except:
|
| 402 |
+
st.error("์ด๋ฏธ์ง ์ค๋ฅ")
|
| 403 |
else:
|
| 404 |
+
st.warning("์ด๋ฏธ์ง ์์")
|
| 405 |
+
with st.expander("ํ๋กฌํํธ ๋ณด๊ธฐ"):
|
| 406 |
+
st.write(prompt_text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
# ----------------------------------------------------------------
|
| 409 |
# [TAB 3] AI ์ฑ์ฐ (TTS)
|
|
|
|
| 460 |
if final_wav:
|
| 461 |
st.success("์ค๋์ค ์์ฑ ์๋ฃ!")
|
| 462 |
st.audio(final_wav, format="audio/wav")
|
| 463 |
+
st.download_button("๋ค์ด๋ก๋ (WAV)", final_wav, "full_audio.wav", "audio/wav")
|
logic_image.py
CHANGED
|
@@ -141,7 +141,8 @@ def process_scene_task(
|
|
| 141 |
img_bytes = None
|
| 142 |
|
| 143 |
return index, final_prompt, img_bytes
|
| 144 |
-
|
|
|
|
| 145 |
index,
|
| 146 |
strategy_key,
|
| 147 |
strategy_text,
|
|
@@ -151,7 +152,7 @@ def process_scene_task(
|
|
| 151 |
text_model_id,
|
| 152 |
image_model_id,
|
| 153 |
aspect_ratio,
|
| 154 |
-
reference_image=None
|
| 155 |
):
|
| 156 |
"""
|
| 157 |
return (idx, final_prompt, image_bytes)
|
|
@@ -177,6 +178,7 @@ def process_scene_task(
|
|
| 177 |
[ํ์ ์กฐ๊ฑด]
|
| 178 |
- ์ถ๋ ฅ์ ๋ฌด์กฐ๊ฑด ํ๊ตญ์ด๋ง. ์์ด/๋ก๋ง์ ๊ธ์ง.
|
| 179 |
- ์ด๋ฏธ์ง ์์ ๊ธ์/์๋ง/๋ฐฐ๋/๋ก๊ณ ์ ๋ ์์ฑ ๊ธ์ง.
|
|
|
|
| 180 |
- ๋์ ํ
์คํธ๋ฅผ ๋์ค์ ๋ฃ์ ์ ์๊ฒ ์๋จ ๋๋ ํ๋จ์ ๋์ ์ฌ๋ฐฑ(์์ ์์ญ)์ ํ๋ณด.
|
| 181 |
- ํน์ ๊ตญ๊ฐ ์์ง ์๋์์ฑ ๊ธ์ง: ํ๊ทน๊ธฐ, ์ฒญ์๋, ๊ตญํ์์ฌ๋น, ๋ํต๋ น, ํ์ฅ/ํ์ฅ, ์ ๊ฑฐ ํฌ์คํฐ, ๊ตญ๊ธฐ๋ฅ ์ ๋ถ ๊ธ์ง.
|
| 182 |
- ์ ์น์ธ์ ์ค์กด ์ธ๋ฌผ์ฒ๋ผ ํน์ ํ์ง ๋ง๊ณ , ์ต๋ช
์บ๋ฆญํฐ/์ค๋ฃจ์ฃ/์์ง์ ์ฐ์ถ๋ก ์ฒ๋ฆฌ.
|
|
@@ -215,4 +217,3 @@ def process_scene_task(
|
|
| 215 |
img_bytes = None
|
| 216 |
|
| 217 |
return index, final_prompt, img_bytes
|
| 218 |
-
|
|
|
|
| 141 |
img_bytes = None
|
| 142 |
|
| 143 |
return index, final_prompt, img_bytes
|
| 144 |
+
|
| 145 |
+
def process_thumbnail_task(
|
| 146 |
index,
|
| 147 |
strategy_key,
|
| 148 |
strategy_text,
|
|
|
|
| 152 |
text_model_id,
|
| 153 |
image_model_id,
|
| 154 |
aspect_ratio,
|
| 155 |
+
reference_image=None,
|
| 156 |
):
|
| 157 |
"""
|
| 158 |
return (idx, final_prompt, image_bytes)
|
|
|
|
| 178 |
[ํ์ ์กฐ๊ฑด]
|
| 179 |
- ์ถ๋ ฅ์ ๋ฌด์กฐ๊ฑด ํ๊ตญ์ด๋ง. ์์ด/๋ก๋ง์ ๊ธ์ง.
|
| 180 |
- ์ด๋ฏธ์ง ์์ ๊ธ์/์๋ง/๋ฐฐ๋/๋ก๊ณ ์ ๋ ์์ฑ ๊ธ์ง.
|
| 181 |
+
- ์ ๋ต์ ํฌํจ๋ ํ
์คํธ ์ค๋ฒ๋ ์ด ์ง์๋ ๋ชจ๋ ๋ฌด์ํ๊ณ , ํ
์คํธ๊ฐ ๋ค์ด๊ฐ์ง ์๊ฒ ๊ตฌ์ฑ.
|
| 182 |
- ๋์ ํ
์คํธ๋ฅผ ๋์ค์ ๋ฃ์ ์ ์๊ฒ ์๋จ ๋๋ ํ๋จ์ ๋์ ์ฌ๋ฐฑ(์์ ์์ญ)์ ํ๋ณด.
|
| 183 |
- ํน์ ๊ตญ๊ฐ ์์ง ์๋์์ฑ ๊ธ์ง: ํ๊ทน๊ธฐ, ์ฒญ์๋, ๊ตญํ์์ฌ๋น, ๋ํต๋ น, ํ์ฅ/ํ์ฅ, ์ ๊ฑฐ ํฌ์คํฐ, ๊ตญ๊ธฐ๋ฅ ์ ๋ถ ๊ธ์ง.
|
| 184 |
- ์ ์น์ธ์ ์ค์กด ์ธ๋ฌผ์ฒ๋ผ ํน์ ํ์ง ๋ง๊ณ , ์ต๋ช
์บ๋ฆญํฐ/์ค๋ฃจ์ฃ/์์ง์ ์ฐ์ถ๋ก ์ฒ๋ฆฌ.
|
|
|
|
| 217 |
img_bytes = None
|
| 218 |
|
| 219 |
return index, final_prompt, img_bytes
|
|
|