--- license: other pipeline_tag: text-to-image --- # Mongle RunPod Test Package RunPod에서 Mongle 캐릭터 생성과 피드 이미지 생성을 테스트하기 위한 패키지입니다. 이 repo는 현재 로직을 RunPod에서 바로 검증하기 위한 테스트 패키지입니다. 아래 두 가지 방식으로 사용할 수 있습니다. ```text 1. end-to-end 테스트 파일로 전체 흐름 검증 - test_text2feed_pipeline.py - test_image2feed_pipeline.py 2. RunPod serverless handler로 캐릭터/피드 분리 실행 - handler_character.py - handler_feed.py ``` ## 전체 구조 현재 로직은 크게 두 단계로 나뉩니다. ```text 1. 캐릭터 생성 - 텍스트로 캐릭터를 만들거나 - 이미지로 캐릭터를 만들 수 있음 - 결과로 character.png와 appearance.json을 만듦 2. 피드 생성 - 1단계에서 나온 appearance.json - 사용자의 quest text - 위 두 개를 사용해서 feed.png를 만듦 ``` 서비스 관점에서는 아래처럼 분리해서 사용합니다. ```text handler_character 입력: - character_ko 또는 character_image 출력: - character.png - appearance.json handler_feed 입력: - appearance.json - quest_ko 출력: - feed.png - quest_en ``` 이 repo에는 위 구조를 실제로 나눈 handler 파일도 들어 있습니다. ```text handler_character.py 텍스트 branch와 이미지 branch를 모두 처리 character.png와 appearance.json을 반환 handler_feed.py appearance.json과 quest_ko를 받아 feed.png를 반환 ``` 그리고 아래 두 테스트 파일은 두 단계를 한 번에 이어서 돌려보기 위한 end-to-end 테스트 파일입니다. ```text test_text2feed_pipeline.py 텍스트 캐릭터 설명에서 시작해서 character.png, appearance.json, feed.png까지 생성 test_image2feed_pipeline.py 입력 캐릭터 이미지에서 시작해서 character.png, appearance.json, feed.png까지 생성 ``` ## 분기 기준 캐릭터 생성 입력이 텍스트인지 이미지인지에 따라 파일을 다르게 사용합니다. ```text 텍스트로 캐릭터 생성 테스트 -> test_text2feed_pipeline.py 이미지로 캐릭터 생성 테스트 -> test_image2feed_pipeline.py ``` 두 파일 모두 마지막에는 피드 생성까지 실행합니다. ```text appearance.json + quest_ko -> Qwen2.5-7B로 quest_en 생성 -> SDXL + lora_v3_32bit + lora_bg_v1로 feed.png 생성 ``` ## 포함된 LoRA 아래 두 LoRA는 이 repo에 포함되어 있습니다. 따로 업로드하거나 별도로 받을 필요가 없습니다. ```text models/lora_v3_32bit/pytorch_lora_weights.safetensors models/lora_bg_v1/pytorch_lora_weights.safetensors ``` 코드는 위 경로를 그대로 사용합니다. ```text 캐릭터 생성: models/lora_v3_32bit 피드 생성: models/lora_v3_32bit/pytorch_lora_weights.safetensors models/lora_bg_v1/pytorch_lora_weights.safetensors ``` ## 실행 중 자동 다운로드되는 베이스 모델 아래 모델들은 이 repo에 포함하지 않습니다. RunPod에서 처음 실행할 때 Hugging Face에서 자동으로 다운로드됩니다. ```text stabilityai/stable-diffusion-xl-base-1.0 Qwen/Qwen2.5-7B-Instruct Qwen/Qwen2.5-VL-7B-Instruct ``` 용도는 아래와 같습니다. ```text stabilityai/stable-diffusion-xl-base-1.0 - character.png 생성 - feed.png 생성 Qwen/Qwen2.5-7B-Instruct - 한국어 캐릭터 설명 -> 영어 캐릭터 프롬프트 - 한국어 퀘스트 -> 영어 장면 프롬프트 Qwen/Qwen2.5-VL-7B-Instruct - 캐릭터 이미지 -> appearance.json 추출 ``` `rembg`도 첫 실행 시 배경 제거용 모델을 캐시에 다운로드할 수 있습니다. ## 포함된 코드 ```text test_text2feed_pipeline.py test_image2feed_pipeline.py handler_character.py handler_feed.py test_qwen25_vl_extract.py src/pipeline/persona2prompt.py src/feed/feed_generator_1.py src/feed/feed_generator_2.py requirements.txt ``` ## 포함하지 않은 것 ```text .env HF_TOKEN outputs/ data/ image/ grid/ logs caches ``` ## RunPod에서 받기 LoRA가 Git LFS로 올라가 있으므로 반드시 `git lfs`를 먼저 켭니다. ```bash git lfs install git clone https://huggingface.co/Hadimeeee/mongle-hf-package cd mongle-hf-package git lfs pull ``` LoRA가 실제 파일로 받아졌는지 확인합니다. ```bash du -sh models/lora_v3_32bit/pytorch_lora_weights.safetensors du -sh models/lora_bg_v1/pytorch_lora_weights.safetensors ``` 각각 약 `177M` 정도로 보여야 정상입니다. 몇 KB로 보이면 LFS pointer만 받은 상태입니다. ## 패키지 설치 ```bash pip install -r requirements.txt ``` RunPod CUDA 이미지에 따라 `torch`, `torchvision`, `xformers`, `bitsandbytes` 버전 충돌이 날 수 있습니다. 그 경우 RunPod 이미지의 CUDA/PyTorch 버전에 맞춰 먼저 설치한 뒤 `requirements.txt`를 조정하세요. ## 테스트 1: 텍스트에서 캐릭터와 피드 생성 텍스트 캐릭터 설명만으로 캐릭터를 만들고, 이어서 피드 이미지까지 생성합니다. ```bash python test_text2feed_pipeline.py \ --name runpod_text_test \ --character-ko "이 친구는 부드러운 체리핑크색 곰 인형이에요. 크림색 배를 가지고 있고 작은 둥근 귀와 분홍색 코가 있어요." \ --quest-ko "공원에서 30분 달리기를 완료했어요!" \ --force ``` 실행 흐름: ```text character_ko -> Qwen2.5-7B -> English character prompt -> SDXL + lora_v3_32bit -> character.png -> Qwen2.5-VL -> appearance.json -> quest_ko를 Qwen2.5-7B로 quest_en 변환 -> SDXL + lora_v3_32bit + lora_bg_v1 -> feed.png ``` 출력: ```text outputs/text2feed/runpod_text_test/ character.png appearance_raw.txt appearance.json character_prompt.json quest.json feed.png results.json ``` 이미 영어 캐릭터 프롬프트가 있으면 Qwen 캐릭터 번역 단계를 건너뛸 수 있습니다. ```bash python test_text2feed_pipeline.py \ --name runpod_text_fast \ --character-text "soft cherry pink bear plush mascot with a cream belly, tiny pink nose, rounded ears" \ --quest-ko "공원에서 30분 달리기를 완료했어요!" \ --force ``` 이미 영어 퀘스트 장면이 있으면 Qwen 퀘스트 번역 단계도 건너뛸 수 있습니다. ```bash python test_text2feed_pipeline.py \ --name runpod_text_fastest \ --character-text "soft cherry pink bear plush mascot with a cream belly, tiny pink nose, rounded ears" \ --quest-en "running with arms swinging along a fluffy cloud meadow path" \ --force ``` ## Handler 1: 캐릭터 생성 RunPod serverless에서 캐릭터 생성 전용 worker로 쓸 파일입니다. ```text handler_character.py ``` 이 handler는 입력에 따라 내부에서 두 branch로 나뉩니다. ```text mode = "text" character_ko 또는 character_text 사용 -> character.png -> appearance.json mode = "image" character_image base64 사용 -> rembg -> appearance.json -> character.png ``` 텍스트 branch 입력 예시: ```json { "input": { "mode": "text", "name": "char_text_01", "character_ko": "이 친구는 부드러운 체리핑크색 곰 인형이에요. 크림색 배와 작은 둥근 귀가 있어요.", "seed": 42, "character_steps": 30 } } ``` 이미지 branch 입력 예시: ```json { "input": { "mode": "image", "name": "char_image_01", "character_image": "", "seed": 42, "character_steps": 30 } } ``` 출력 예시: ```json { "name": "char_text_01", "mode": "text", "character_image": "", "appearance": { "animal_type": "bear", "body_color": "soft cherry pink" }, "appearance_raw": "..." } ``` RunPod serverless entrypoint 예시: ```bash python handler_character.py ``` ## 테스트 2: 이미지에서 캐릭터와 피드 생성 입력 캐릭터 이미지를 사용해서 appearance를 추출하고, 픽셀 캐릭터와 피드 이미지를 생성합니다. 먼저 테스트 이미지를 준비합니다. ```bash mkdir -p image # image/01.jpg 위치에 캐릭터 이미지를 업로드 ``` 실행: ```bash python test_image2feed_pipeline.py \ --name runpod_image_test \ --character-image image/01.jpg \ --quest-ko "공원에서 30분 달리기를 완료했어요!" \ --force ``` 실행 흐름: ```text character_image -> rembg -> input_nobg.png -> Qwen2.5-VL -> appearance.json -> SDXL + lora_v3_32bit -> character.png -> quest_ko를 Qwen2.5-7B로 quest_en 변환 -> SDXL + lora_v3_32bit + lora_bg_v1 -> feed.png ``` 출력: ```text outputs/image2feed/runpod_image_test/ input_nobg.png appearance_raw.txt appearance.json character.png quest.json feed.png results.json ``` 이미 영어 퀘스트 장면이 있으면 번역 단계를 건너뛸 수 있습니다. ```bash python test_image2feed_pipeline.py \ --name runpod_image_fast \ --character-image image/01.jpg \ --quest-en "running with arms swinging along a fluffy cloud meadow path" \ --force ``` ## Handler 2: 피드 생성 RunPod serverless에서 피드 생성 전용 worker로 쓸 파일입니다. ```text handler_feed.py ``` 이 handler는 캐릭터 생성 handler에서 나온 `appearance`와 퀘스트 텍스트를 받아서 피드 이미지를 만듭니다. 입력 예시: ```json { "input": { "name": "feed_01", "appearance": { "animal_type": "bear", "body_color": "soft cherry pink", "body_shape": "round plush body", "eye_style": "small black bead eyes" }, "quest_ko": "공원에서 30분 달리기를 완료했어요!", "feed_seed": 123 } } ``` 이미 영어 장면 프롬프트가 있으면 `quest_en`을 넣어서 Qwen 번역 단계를 건너뛸 수 있습니다. ```json { "input": { "name": "feed_fast_01", "appearance": { "animal_type": "bear", "body_color": "soft cherry pink" }, "quest_en": "running with arms swinging along a fluffy cloud meadow path", "feed_seed": 123 } } ``` 출력 예시: ```json { "name": "feed_01", "quest": { "quest_ko": "공원에서 30분 달리기를 완료했어요!", "quest_en": "running with arms swinging along a fluffy cloud meadow path" }, "feed_image": "" } ``` RunPod serverless entrypoint 예시: ```bash python handler_feed.py ``` ## 서비스 코드로 분리할 때 현재 테스트 파일은 end-to-end 검증용이고, 실제 서비스에서는 `handler_character.py`와 `handler_feed.py`를 나누어 사용하는 것이 자연스럽습니다. ```text handler_character.py - 앱에서 캐릭터 생성 요청을 받음 - 텍스트 입력이면 text branch 사용 - 이미지 입력이면 image branch 사용 - character.png와 appearance.json 반환 - 서버는 character.png를 S3에 업로드하고 appearance를 DB에 저장 handler_feed.py - 앱에서 quest 완료 요청을 받음 - 서버가 DB에서 character_id로 appearance를 조회 - appearance + quest_ko를 RunPod에 전달 - feed.png와 quest_en 반환 - 서버는 feed.png를 S3에 업로드하고 feed record를 DB에 저장 ``` 서비스 흐름: ```text 캐릭터 생성 요청 -> handler_character -> character.png + appearance.json -> S3 + DB 저장 퀘스트 완료 요청 -> DB에서 appearance 조회 -> handler_feed -> feed.png + quest_en -> S3 + DB 저장 ``` 즉, `appearance.json`이 캐릭터 생성과 피드 생성을 이어주는 중간 산출물입니다.