×
Community Blog Model Studio에서 Wan 2.5 Preview 모델을 사용하여 텍스트 프롬프트로 이미지 및 비디오 생성

Model Studio에서 Wan 2.5 Preview 모델을 사용하여 텍스트 프롬프트로 이미지 및 비디오 생성

이 글에서는 Alibaba Cloud ECS에서 Gradio를 사용하여 API 키 통합을 통해 Model Studio의 Wan 2.5 모델로 이미지와 비디오를 생성하는 데모를 소개합니다.

작성: Ferdin Joe

이 데모에서는 Alibaba Cloud Elastic Compute Service(ECS)에서 Gradio 인터페이스를 만들고 Gradio를 활성화하여 API 키를 통해 Alibaba Cloud Model Studio의 Wan 2.5 미리보기 모델과 연결하고 입력으로 주어진 텍스트 프롬프트에 대한 사진과 비디오를 생성합니다. 이 데모는 다음과 같은 부분으로 구성되어 있습니다.

● ECS 인스턴스 생성

● Gradio를 위한 코드 개발

● Bash 스크립트를 사용하여 ECS에 코드 설치

● 솔루션 사용을 위한 탐색 가이드

ECS 인스턴스 생성

공용 IP 주소 또는 EIP가 있는 일반 구성으로 ECS 인스턴스를 만듭니다. 공용 IP는 적절한 대역폭이 할당되어 있어야 합니다. 인바운드 연결에서 포트 7860을 허용하는 보안 그룹에 해당 인스턴스를 추가합니다.

image

인바운드 및 아웃바운드 규칙에 대한 다른 규칙은 평소와 같습니다.

Gradio용 코드 개발

Gradio는 Python을 사용하며 필요한 종속성을 설치해야 합니다. Model Studio API 키가 필요합니다. Model Studio 콘솔에서 생성합니다. 다음과 같은 코드 구성 요소가 필요합니다.

Filename: .env

요청을 가져오기 위한 API 키를 저장하는 데 사용됩니다.

DASHSCOPE_API_KEY=<Model Studio API 키>

Filename: gradio_wan_app.py

#!/usr/bin/env python3
"""
WAN 텍스트-이미지 생성을 위한 Gradio 웹 인터페이스
DashScope Model Studio API 사용
"""

from http import HTTPStatus
from urllib.parse import urlparse, unquote
from pathlib import PurePosixPath
import requests
from dashscope import ImageSynthesis, VideoSynthesis
from dashscope.audio.tts_v2 import SpeechSynthesizer
import os
import dashscope
import gradio as gr
from dotenv import load_dotenv
from PIL import Image
from io import BytesIO
import logging
import json

# 로깅 설정
logging.basicConfig(
  level=logging.INFO,
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 환경 변수 로드
load_dotenv()

# 구성 - 싱가포르 리전 API 사용
dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

# 환경에서 API 키 가져오기
DASHSCOPE_API_KEY = os.getenv("DASHSCOPE_API_KEY", "<Model Studio API>")
dashscope.api_key = DASHSCOPE_API_KEY

logger.info(f"🚀 Gradio WAN Image Generator starting...")
logger.info(f"API Endpoint: {dashscope.base_http_api_url}")


def generate_image(
  prompt: str,
  negative_prompt: str = "",
  num_images: int = 1,
  size: str = "1024*1024",
  seed: int = None,
  prompt_extend: bool = True,
  watermark: bool = False
):
  """
    WAN 2.5 모델을 사용하여 이미지 생성
    
    Args:
        prompt: 생성할 이미지의 텍스트 설명
        negative_prompt: 이미지에서 피해야 할 것
        num_images: 생성할 이미지 수(1~4개)
        size: 이미지 크기(1024*1024, 720*1280, 1280*720)
        seed: 재현성을 위한 무작위 시드(선택 사항)
        prompt_extend: 프롬프트를 자동으로 확장할지 여부
        watermark: 워터마크 추가 여부
    
    반환:
        PIL 이미지 또는 오류 메시지 목록
    """
  if not prompt or prompt.strip() == "":
    return None, None, " 프롬프트 설명을 제공하십시오!"

    try:
      logger.info(f"🎨 Generating image with prompt: {prompt}")

      # 매개변수 준비
      params = {
        'api_key': DASHSCOPE_API_KEY,
        'model': 'wan2.5-t2i-preview',
        'prompt': prompt,
        'negative_prompt': negative_prompt,
        'n': num_images,
        'size': size,
        'prompt_extend': prompt_extend,
        'watermark': watermark
      }

      # 제공되는 경우 시드 추가
      if seed is not None and seed > 0:
        params['seed'] = seed

        # WAN API 호출
        logger.info(f"Calling WAN 2.5 API with parameters: {params}")
      rsp = ImageSynthesis.call(**params)

      logger.info(f"Response status: {rsp.status_code}")

      if rsp.status_code == HTTPStatus.OK:
        images = []

        # 생성된 각 이미지 다운로드 및 변환
        for idx, result in enumerate(rsp.output.results):
          logger.info(f"Downloading image {idx + 1}: {result.url}")

          # 이미지 데이터 다운로드
          image_data = requests.get(result.url).content

          # PIL 이미지로 변환
          image = Image.open(BytesIO(image_data))
          images.append(image)

          logger.info(f"✅ Image {idx + 1} downloaded successfully")

          success_msg = f"✅ {len(images)}개의 이미지를 성공적으로 생성했습니다!"
        # 항상 갤러리 구성 요소에 대한 목록으로 반환
        return images, None, success_msg
      else:
        error_msg = f"❌ 생성에 실패했습니다!\n\n상태: {rsp.status_code}\n코드: {rsp.code}\n메시지: {rsp.message}"
        logger.error(error_msg)
        return None, None, error_msg

    except Exception as e:
      error_msg = f"❌ 이미지 생성 중 오류 발생:\n\n{str(e)}"
      logger.error(f"Error in generate_image: {e}", exc_info=True)
      return None, None, error_msg


def generate_video(
  prompt: str,
  resolution: str = "1280*720",
  duration: str = "5s",
  enable_audio: bool = False
):
  """
    WAN 2.5 T2V Preview 모델을 사용하여 비디오 생성
    
    Args:
        prompt: 생성할 비디오의 텍스트 설명
        resolution: 비디오 해상도(1280*720, 960*960, 1280*768, 768*1280)
        duration: 비디오 길이(5초 또는 10초)
        enable_audio: 비디오용 오디오 생성 여부
    
    반환:
        비디오 파일 경로 및 상태 메시지
    """
  if not prompt or prompt.strip() == "":
    return None, None, " 프롬프트 설명을 제공하십시오!"

    try:
      logger.info(f"🎬 Generating video with prompt: {prompt}")
      logger.info(f"Using WAN 2.5 T2V Preview model with resolution: {resolution}")
      logger.info(f"Duration: {duration}")
      logger.info(f"Audio enabled: {enable_audio}")

      # VideoSynthesis를 사용하여 WAN 2.5 T2V Preview API 호출
      # 참고: 오디오 생성은 별도의 매개변수를 통해 수행됩니다.
      logger.info("Calling VideoSynthesis API...")

      # 길이 문자열을 초로 변환(예: "10초" -> 10)
      duration_seconds = int(duration.replace('s', ''))

      if enable_audio:
        # 오디오 지원이 있는 모델 사용
        rsp = VideoSynthesis.call(
          model='wan2.5-t2v-preview',
          prompt=prompt,
          size=resolution,
          duration=duration_seconds,
          audio=True  # 오디오 생성 활성화
        )
      else:
        # 오디오가 없는 표준 비디오
        rsp = VideoSynthesis.call(
          model='wan2.5-t2v-preview',
          prompt=prompt,
          size=resolution,
          duration=duration_seconds
        )

        logger.info(f"Response status: {rsp.status_code}")

      if rsp.status_code == HTTPStatus.OK:
        video_url = rsp.output.video_url
        logger.info(f"Video URL received: {video_url}")

        # 비디오 다운로드
        logger.info("Downloading video...")
        video_data = requests.get(video_url).content

        # 파일에 저장
        import time
        video_filename = f"generated_video_{int(time.time())}.mp4"
        with open(video_filename, 'wb') as f:
          f.write(video_data)

          logger.info(f"✅ Video downloaded successfully: {video_filename}")
        audio_status = " with audio" if enable_audio else " (no audio)"
        success_msg = f"✅ 비디오를 성공적으로 생성했습니다{audio_status}!\n\n길이: {duration}\n해상도: {resolution}\n모델: WAN 2.5 T2V Preview"
        return None, video_filename, success_msg
      else:
        error_msg = f"❌ 비디오 생성에 실패했습니다!\n\n상태: {rsp.status_code}\n코드: {rsp.code}\n메시지: {rsp.message}\n\n참고: 현재 API 키로는 비디오 생성을 사용하지 못할 수 있습니다."
        logger.error(error_msg)
        logger.error(f"Full response: status_code={rsp.status_code}, code={rsp.code}, message={rsp.message}")
        return None, None, error_msg

    except Exception as e:
      error_msg = f"❌ 비디오 생성 중 오류 발생:\n\n{str(e)}\n\n참고: 비디오 생성에는 WAN T2V 모델에 대한 API 액세스가 필요합니다."
      logger.error(f"Error in generate_video: {e}", exc_info=True)
      return None, None, error_msg


def generate_content(
  mode: str,
  prompt: str,
  negative_prompt: str,
  num_images: int,
  image_size: str,
  video_resolution: str,
  video_duration: str,
  enable_audio: bool,
  seed: int,
  prompt_extend: bool,
  watermark: bool
):
  """
    모드에 따라 적절한 생성 기능으로 라우팅
    """
  if mode == "Text to Image":
    return generate_image(
      prompt=prompt,
      negative_prompt=negative_prompt,
      num_images=num_images,
      size=image_size,
      seed=seed,
      prompt_extend=prompt_extend,
      watermark=watermark
    )
  else:  # 텍스트-비디오
    return generate_video(
      prompt=prompt,
      resolution=video_resolution,
      duration=video_duration,
      enable_audio=enable_audio
    )


# Gradio 인터페이스 만들기
def create_interface():
  """Gradio 인터페이스 만들기 및 구성"""

  with gr.Blocks(
    title="WAN 텍스트-이미지 및 텍스트-비디오 생성기",
    theme=gr.themes.Soft()
  ) as demo:
    gr.Markdown(
      """
            # 🎨 WAN 2.5 텍스트-이미지 및 텍스트-비디오 생성기
            
            Alibaba Cloud의 WAN 모델을 사용하여 텍스트 설명으로 멋진 이미지 또는 비디오를 생성합니다.
            
            ### 사용 방법:
            1.  생성 모드 선택(이미지 또는 비디오)
            2.  자세한 설명 입력
            3.  (선택 사항) 설정 조정
            4.  **생성** 버튼 클릭
            5.  생성 기다리기  🎞️
            """
    )

    with gr.Row():
      with gr.Column(scale=1):
        # 모드 선택
        mode_radio = gr.Radio(
          choices=["텍스트-이미지", "텍스트-비디오"],
          value="텍스트-이미지",
          label="🎭 생성 모드",
          info="생성하려는 것을 선택하십시오"
        )

        # 입력 컨트롤
        prompt_input = gr.Textbox(
          label="✏️ 프롬프트",
          placeholder="생성하려는 것을 설명하십시오...(예: '산 위의 아름다운 일몰')",
          lines=3,
          max_lines=5
        )

        # 이미지별 설정
        with gr.Group(visible=True) as image_settings:
          gr.Markdown("### 🖼️ 이미지 설정")

          negative_prompt_input = gr.Textbox(
            label="🚫 제외 프롬프트(선택 사항)",
            placeholder="피해야 할 것...(예: '흐릿함, 낮은 품질')",
            lines=2,
            max_lines=3
          )

          num_images_slider = gr.Slider(
            minimum=1,
            maximum=4,
            value=1,
            step=1,
            label="이미지 수"
          )

          image_size_dropdown = gr.Dropdown(
            choices=["1024*1024", "720*1280", "1280*720"],
            value="1024*1024",
            label="이미지 크기"
          )

          seed_number = gr.Number(
            label="시드(선택 사항)",
            value=None,
            precision=0,
            info="재현 가능한 결과를 위해서는 동일한 시드를 사용하십시오"
          )

          prompt_extend_checkbox = gr.Checkbox(
            label="프롬프트 자동 확장",
            value=True,
            info="AI로 프롬프트를 확장하십시오"
          )

          watermark_checkbox = gr.Checkbox(
            label="워터마크 추가",
            value=False
          )

          # 비디오별 설정
          with gr.Group(visible=False) as video_settings:
            gr.Markdown("### 🎬 비디오 설정")

            video_resolution_dropdown = gr.Dropdown(
              choices=["1280*720", "960*960", "1280*768", "768*1280"],
              value="1280*720",
              label="비디오 해상도"
            )

            video_duration_radio = gr.Radio(
              choices=["5초", "10초"],
              value="5초",
              label="비디오 길이",
              info="더 긴 비디오는 생성하는 데 더 많은 시간이 걸립니다"
            )

            enable_audio_checkbox = gr.Checkbox(
              label="🔊 오디오 활성화",
              value=False,
              info="비디오용 오디오를 생성합니다(참고: 오디오 지원은 API 가용성에 따라 다름)"
            )

            generate_btn = gr.Button(
              "🎨 생성",
              variant="primary",
              size="lg"
            )

        status_output = gr.Textbox(
          label="상태",
          interactive=False,
          show_label=True
        )

        with gr.Column(scale=1):
          # 출력 디스플레이
          image_output = gr.Gallery(
            label="생성된 이미지",
            show_label=True,
            visible=True,
            columns=2,
            rows=2,
            object_fit="contain"
          )

          video_output = gr.Video(
            label="생성된 비디오",
            show_label=True,
            visible=False
          )

      # 예시 프롬프트
      gr.Markdown("### 💡 예시 프롬프트")

    with gr.Tab("이미지 예시"):
      gr.Examples(
        examples=[
          ["벚꽃, 잉어 연못, 전통 탑이 있는 해질녘의 고요한 일본 정원"],
          ["네온 불빛, 날아 다니는 자동차, 우뚝 솟은 고층 건물이 있는 미래형 사이버 펑크 도시"],
          ["따뜻한 조명, 목재 가구 및 식물이 있는 아늑한 카페 내부"],
          ["북극광 아래에서 눈 덮인 산 위를 날아가는 장엄한 용"],
          ["고대 책으로 가득 찬 도서관에서 책을 읽는 귀여운 로봇"],
        ],
        inputs=[prompt_input]
      )

      with gr.Tab("비디오 예시"):
        gr.Examples(
          examples=[
            ["산 풍경 위로 푸른 하늘을 가로질러 가는 구름의 타임랩스"],
            ["해질녘에 모래사장에 부드럽게 밀려오는 파도"],
            ["꽃에 내려앉아 천천히 날개를 펼치는 나비"],
            ["도시 배경이 흐릿하게 보이는 창문에 떨어지는 빗방울"],
            ["눈 덮인 풍경 위로 밤하늘에서 춤추는 북극광"],
          ],
          inputs=[prompt_input]
        )

        # 모드에 따라 가시성 전환
        def update_visibility(mode):
          if mode == "Text to Image":
            return (
              gr.update(visible=True),   # image_settings
              gr.update(visible=False),  # video_settings
              gr.update(visible=True),   # image_output
              gr.update(visible=False),  # video_output
              gr.update(value="🎨 이미지 생성")  # 버튼 텍스트
            )
          else:
            return (
              gr.update(visible=False),  # image_settings
              gr.update(visible=True),   # video_settings
              gr.update(visible=False),  # image_output
              gr.update(visible=True),   # video_output
              gr.update(value="🎬 비디오 생성")  # 버튼 텍스트
            )

    mode_radio.change(
      fn=update_visibility,
      inputs=[mode_radio],
      outputs=[image_settings, video_settings, image_output, video_output, generate_btn]
    )

    # 생성 버튼 연결
    generate_btn.click(
      fn=generate_content,
      inputs=[
        mode_radio,
        prompt_input,
        negative_prompt_input,
        num_images_slider,
        image_size_dropdown,
        video_resolution_dropdown,
        video_duration_radio,
        enable_audio_checkbox,
        seed_number,
        prompt_extend_checkbox,
        watermark_checkbox
      ],
      outputs=[image_output, video_output, status_output]
    )

    return demo


if __name__ == "__main__":
  # API 키 검증
  if not DASHSCOPE_API_KEY or DASHSCOPE_API_KEY == "":
    logger.error("❌ DASHSCOPE_API_KEY not found in environment variables!")
    print("\n⚠️  Please set DASHSCOPE_API_KEY in your .env file\n")
    exit(1)

    # 인터페이스 만들기 및 실행
    demo = create_interface()

  logger.info("🌐 Launching Gradio interface...")
  demo.launch(
    server_name="0.0.0.0",
    server_port=7860,
    share=False,
    show_error=True
  )

Filename: deploy_to_ecs.sh

#!/bin/bash
# Alibaba Cloud ECS의 Gradio WAN 앱 배포 스크립트
# 파일을 전송한 후 ECS 인스턴스에서 이 스크립트를 실행하십시오.

set -e  # 오류 시 종료

echo "🚀Gradio WAN 앱 배포 시작 중..."

# 출력 색상
GREEN='\033[0;32m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # 색상 없음

# 구성
APP_DIR="/root/financeapp"
SERVICE_NAME="gradio-wan"

echo -e "${BLUE}📦 1단계: 시스템 종속성 설치...${NC}"
if command -v apt &> /dev/null; then
    # Ubuntu/Debian
    sudo apt update
    sudo apt install -y python3 python3.12-venv python3-pip git build-essential
elif command -v yum &> /dev/null; then
    # CentOS/RHEL
    sudo yum update -y
    sudo yum install -y python39 python39-pip git gcc gcc-c++ make
fi

echo -e "${BLUE}📂 2단계: 애플리케이션 디렉토리 설정...${NC}"
cd $APP_DIR

echo -e "${BLUE}🐍 3단계: Python 가상 환경 만들기...${NC}"
python3 -m venv .venv
source .venv/bin/activate

echo -e "${BLUE}📥 4단계: Python 종속성 설치...${NC}"
pip install --upgrade pip
pip install gradio==4.16.0 gradio-client==0.8.1
pip install dashscope>=1.23.4
pip install python-dotenv>=1.0.0
pip install requests>=2.31.0
pip install pillow>=10.0.0
pip install "huggingface_hub<1.0.0"
pip install numpy>=1.24.0

echo -e "${BLUE}⚙️  5단계: systemd 서비스 만들기...${NC}"
sudo tee /etc/systemd/system/${SERVICE_NAME}.service > /dev/null <<EOF
[단위]
Description=Gradio WAN 이미지 및 비디오 생성기
After=network.target

[서비스]
Type=simple
User=root
WorkingDirectory=$APP_DIR
Environment="PATH=$APP_DIR/.venv/bin"
ExecStart=$APP_DIR/.venv/bin/python gradio_wan_app.py
Restart=always
RestartSec=10
StandardOutput=append:/var/log/${SERVICE_NAME}.log
StandardError=append:/var/log/${SERVICE_NAME}.error.log

[설치]
WantedBy=multi-user.target
EOF

echo -e "${BLUE}🔄 6단계: 서비스 활성화 및 시작...${NC}"
sudo systemctl daemon-reload
sudo systemctl enable ${SERVICE_NAME}
sudo systemctl restart ${SERVICE_NAME}

echo -e "${GREEN}✅ 배포가 성공적으로 완료되었습니다!${NC}"
echo ""
echo "📊 서비스 상태:"
sudo systemctl status ${SERVICE_NAME} --no-pager

echo ""
echo "🌐 이제 다음 위치에서 Gradio 앱에 액세스할 수 있습니다."
echo "   http://$(curl -s ifconfig.me):7860"
echo ""
echo "📝 유용한 명령:"
echo "   로그 보기:     sudo journalctl -u ${SERVICE_NAME} -f"
echo "   서비스 중지:  sudo systemctl stop ${SERVICE_NAME}"
echo "   서비스 시작: sudo systemctl start ${SERVICE_NAME}"
echo "   다시 시작:       sudo systemctl restart ${SERVICE_NAME}"
echo "   상태:        sudo systemctl status ${SERVICE_NAME}"
echo ""
echo "⚠️  중요: 포트 7860 이 ECS 보안 그룹에 열려 있는지 확인하십시오!"

위의 3개 파일을 가상 환경 .venv가 있는 지정된 루트 폴더에 로드하십시오. 필요한 모든 것을 설치하기 위한 명령은 다음 섹션에 나와 있습니다.

Bash 스크립트를 사용하여 ECS에 코드 설치

로컬 터미널에서 다음 명령을 사용하여 파일을 ECS에 업로드하십시오.

# 필요한 모든 파일 전송(<ECS_IP>를 실제 ECS 공용 IP로 대체)
scp gradio_wan_app.py root@<ECS_IP>:/root/targetfolder/
scp .env root@<ECS_IP>:/root/targetfolder/
scp deploy_to_ecs.sh root@<ECS_IP>:/root/targetfolder/

Python, pip, 가상 환경 및 필수 라이브러리에서 시작하는 데 필요한 모든 것을 설치하려면 다음 명령을 실행하십시오.

cd /root/targetfolder
chmod +x deploy_to_ecs.sh
./deploy_to_ecs.sh

그러면 셸 스크립트가 실행되고 다음 주소로 인터페이스를 실행할 수 있습니다. http://ECS-Public-IP:7860

blog1

텍스트에서 이미지를 생성하는 경우 동시에 4개의 이미지를 만들 수 있습니다. 텍스트에서 비디오를 생성하는 경우 다양한 해상도로 wan 비디오를 만들고 오디오를 활성화/비활성화하고 5초 또는 10초 길이의 비디오를 생성할 수 있습니다. 이 애플리케이션은 에이전트 모드를 사용하여 Qoder IDE를 사용하여 개발됩니다.


이 문서는 원본 영어 버전을 번역한 것입니다. 소스 콘텐츠는 다음을 방문하십시오. https://www.alibabacloud.com/blog/image-and-video-generation-from-text-prompts-using-wan-2-5-preview-model-from-model-studio_602726

0 0 0
Share on

Regional Content Hub

127 posts | 4 followers

You may also like

Comments

Regional Content Hub

127 posts | 4 followers

Related Products