| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- import os
- import sys
- import time
- import requests
- import json
- from typing import Dict, Any
- sys.path.append(os.path.join(os.path.dirname(__file__), '../tools/local/liblibai_controlnet'))
- from liblibai_client import LibLibAIClient
- # 常量配置 (根据文档)
- TEMPLATE_UUID = "e10adc3949ba59abbe56e057f20f883e" # SD1.5 & SDXL 通用自定义参数模板
- # 请确保这是一个有效的 SDXL 模型,这样才能匹配底下的 SDXL Canny 模型
- # 这里用的是代码里原本的 Checkpoint ID,请根据你们自己的 Liblib 模型库调整!
- DEFAULT_CHECKPOINT_ID = "0ea388c7eb854be3ba3c6f65aac6bfd3"
- class LibLibTestRunner:
- def __init__(self):
- self.client = LibLibAIClient()
- self.models = self._load_models_from_json()
-
- # 动态匹配基础算法 XL 的各种控制网模型
- self.sdxl_canny = self._get_model_uuid("线稿类", "Canny(硬边缘)", xl_only=True) or "b6806516962f4e1599a93ac4483c3d23"
- self.sdxl_softedge = self._get_model_uuid("线稿类", "SoftEdge(软边缘)", xl_only=True) or "dda1a0c480bfab9833d9d9a1e4a71fff"
- self.sdxl_lineart = self._get_model_uuid("线稿类", "Lineart(线稿)", xl_only=True) or "a0f01da42bf48b0ba02c86b6c26b5699"
- self.sdxl_openpose = self._get_model_uuid("姿态类", "OpenPose(姿态)", xl_only=True) or "2fe4f992a81c5ccbdf8e9851c8c96ff2"
-
- self._verify_models()
-
- def _load_models_from_json(self):
- json_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/liblibai_controlnet_models.json"))
- if os.path.exists(json_path):
- with open(json_path, "r", encoding="utf-8") as f:
- return json.load(f)
- return {}
- def _get_model_uuid(self, category, subtype, xl_only=True):
- if category in self.models and subtype in self.models[category]:
- for model in self.models[category][subtype]:
- if xl_only and model["base_algorithm"] != "基础算法 XL":
- continue
- return model["uuid"]
- return None
- def _verify_models(self):
- print("="*50)
- print("校验底模信息 (使用 api/model/version/get)")
- print("="*50)
-
- models_to_verify = {
- "CheckPoint / 底模": DEFAULT_CHECKPOINT_ID,
- }
-
- for name, uuid in models_to_verify.items():
- info = self.client.get_model_version_info(uuid)
- status = f"{info.get('model_name', 'Unknown')} (Base: {info.get('baseAlgo', 'Unknown')})" if info else "Failed to verify"
- print(f"- {name}: [{uuid}] -> {status}")
- print("\n")
-
- def _submit_task(self, payload: dict) -> str:
- url = self.client.generate_auth_url("/api/generate/webui/text2img")
- print(f"Submitting payload...")
- resp = requests.post(url, json=payload, timeout=10)
- data = resp.json()
- if data.get("code") != 0:
- raise Exception(f"Submit task failed: {data.get('msg')} (code: {data.get('code')})")
- return data["data"]["generateUuid"]
- def _wait_and_print_result(self, task_id: str):
- print(f"Task submitted successfully! Task ID: {task_id}")
- print("Waiting for result...")
- timeout = 300
- start_time = time.time()
- while time.time() - start_time < timeout:
- task_data = self.client.query_task_status(task_id)
- status = task_data.get("generateStatus")
-
- if status == 5: # Success
- images = [img["imageUrl"] for img in task_data.get("images", [])]
- print(f"\n[SUCCESSS] Generated images: {images}")
-
- # --- 新增: 自动下载图片 ---
- output_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "output"))
- os.makedirs(output_dir, exist_ok=True)
- for i, img_url in enumerate(images):
- try:
- img_resp = requests.get(img_url)
- img_resp.raise_for_status()
- timestamp = int(time.time())
- filename = f"workflow_result_{timestamp}_{i}.png"
- filepath = os.path.join(output_dir, filename)
- with open(filepath, "wb") as f:
- f.write(img_resp.content)
- print(f"[{i}] 已自动保存到本地: {filepath}")
- except Exception as e:
- print(f"图片自动下载失败: {e}")
- return
- elif status in [6, 7]: # Failed or Cancelled
- print(f"\n[FAILED] Task failed. Audit status: {task_data.get('auditStatus')}")
- return
-
- print(".", end="", flush=True)
- time.sleep(5)
-
- print("\n[TIMEOUT] Wait for task timed out.")
- # 1. 纯文生图测试
- def test_text2img(self):
- print("\n" + "="*50)
- print("TEST 1: 纯文生图 (Text to Image)")
- print("="*50)
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "prompt": "1girl, cute, beautiful landscape, masterpiece",
- "negativePrompt": "lowres, bad anatomy, text, error",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 2. 纯图生图测试
- def test_img2img(self):
- print("\n" + "="*50)
- print("TEST 2: 纯图生图 (Image to Image)")
- print("="*50)
-
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "mode": 0, # 0 代表图生图
- "sourceImage": test_img_url,
- "denoisingStrength": 0.75, # 去噪强度
- "prompt": "white line art, cat",
- "negativePrompt": "lowres, bad anatomy, error",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 3. 文生图 + ControlNet (Canny) 测试
- def test_text2img_controlnet(self):
- print("\n" + "="*50)
- print("TEST 3: 文生图 + ControlNet (Text2Img with ControlNet Canny)")
- print("="*50)
- print("注意: 如果默认 Checkpoint 是 SD1.5, 下面配置的 SDXL Canny 模型可能会导致访问拒绝!")
-
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "prompt": "simple white line art, cat, black background",
- "negativePrompt": "lowres, bad anatomy",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1,
- "controlNet": [{
- "unitOrder": 1,
- "sourceImage": test_img_url,
- "width": 512,
- "height": 512,
- "preprocessor": 1, # 1 = Canny
- "model": self.sdxl_canny,
- "controlWeight": 1.0,
- "startingControlStep": 0.0,
- "endingControlStep": 1.0,
- "pixelPerfect": 1,
- "controlMode": 0,
- "annotationParameters": {
- "canny": {
- "preprocessorResolution": 512,
- "lowThreshold": 100,
- "highThreshold": 200
- }
- }
- }]
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 4. 文生图 + 边缘 (SoftEdge/HED)
- def test_text2img_softedge(self):
- print("\n" + "="*50)
- print("TEST 4: 文生图 + SoftEdge (软边缘 控制网)")
- print("="*50)
-
- # 测试用图片
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "prompt": "Soft edge artwork, beautiful soft lighting, cat",
- "negativePrompt": "lowres, bad anatomy",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1,
- "controlNet": [{
- "unitOrder": 1,
- "sourceImage": test_img_url,
- "width": 512,
- "height": 512,
- "preprocessor": 5, # 5 = HED / 软边缘
- "model": self.sdxl_softedge,
- "controlWeight": 1.0,
- "startingControlStep": 0.0,
- "endingControlStep": 1.0,
- "pixelPerfect": 1,
- "controlMode": 0,
- "annotationParameters": {
- "hed": {
- "preprocessorResolution": 512
- }
- }
- }]
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 5. 文生图 + 线稿 (Lineart)
- def test_text2img_lineart(self):
- print("\n" + "="*50)
- print("TEST 5: 文生图 + Lineart (线稿 控制网)")
- print("="*50)
-
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "prompt": "Detailed coloring, colorful fantasy style, masterpiece, cat",
- "negativePrompt": "lowres",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1,
- "controlNet": [{
- "unitOrder": 1,
- "sourceImage": test_img_url,
- "width": 512,
- "height": 512,
- "preprocessor": 32, # 32 = Lineart Standard
- "model": self.sdxl_lineart,
- "controlWeight": 1.0,
- "startingControlStep": 0.0,
- "endingControlStep": 1.0,
- "pixelPerfect": 1,
- "controlMode": 0,
- "annotationParameters": {
- "lineart": {
- "preprocessorResolution": 512
- }
- }
- }]
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 6. 文生图 + 骨骼 (OpenPose)
- def test_text2img_openpose(self):
- print("\n" + "="*50)
- print("TEST 6: 文生图 + OpenPose (骨骼 控制网)")
- print("="*50)
-
- # 测试用图片(最好使用含有人物动作的图)
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
-
- payload = {
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "prompt": "1girl, dancing pose, beautiful dress",
- "negativePrompt": "lowres",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1,
- "controlNet": [{
- "unitOrder": 1,
- "sourceImage": test_img_url,
- "width": 512,
- "height": 512,
- "preprocessor": 14, # 14 = OpenPose Full
- "model": self.sdxl_openpose,
- "controlWeight": 1.0,
- "startingControlStep": 0.0,
- "endingControlStep": 1.0,
- "pixelPerfect": 1,
- "controlMode": 0,
- "annotationParameters": {
- "openposeFull": {
- "preprocessorResolution": 512
- }
- }
- }]
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 7. 局部重绘 (Inpaint Mode 4)
- def test_inpaint_mode4(self):
- print("\n" + "="*50)
- print("TEST 7: 局部重绘 (Inpaint Mode 4 蒙版重绘)")
- print("="*50)
-
- test_img_url = "https://liblibai-airship-temp.oss-cn-beijing.aliyuncs.com/aliyun-cn-prod/73ed6ae42b144d21bf566e05b5a6c138.png"
- test_mask_url = test_img_url # 仅作演示,实际应用中应当是一个黑底白色的蒙版图片
-
- payload = {
- # Inpainting 可能需要特殊模板,如不兼容请参考文档
- "templateUuid": TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID,
- "mode": 4, # 4 = Inpaint 蒙版重绘
- "sourceImage": test_img_url,
- "denoisingStrength": 0.5,
- "prompt": "A completely different background, sci-fi city",
- "negativePrompt": "lowres",
- "sampler": 15,
- "steps": 20,
- "cfgScale": 7.0,
- "width": 512,
- "height": 512,
- "imgCount": 1,
- "inpaintParam": {
- "maskImage": test_mask_url,
- "maskBlur": 4,
- "inpaintArea": 0
- }
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- # 8. 人像换脸 (InstantID)
- def test_instantid_faceswap(self):
- print("\n" + "="*50)
- print("TEST 8: 人像换脸 (InstantID)")
- print("="*50)
-
- # Note: InstantID faceswap uses a UNIQUE templateUuid
- INSTANT_ID_TEMPLATE_UUID = "7d888009f81d4252a7c458c874cd017f"
-
- face_img_url = "https://liblibai-online.liblib.cloud/img/081e9f07d9bd4c2ba090efde163518f9/49943c0b-4d79-4e2f-8c55-bc1e5b8c69d8.png"
- pose_img_url = "https://liblibai-online.liblib.cloud/img/081e9f07d9bd4c2ba090efde163518f9/e713676d-baaa-4dac-99b9-d5d814a29f9f.png"
-
- payload = {
- "templateUuid": INSTANT_ID_TEMPLATE_UUID,
- "generateParams": {
- "checkPointId": DEFAULT_CHECKPOINT_ID, # 仅 XL模型支持人像换脸
- "prompt": "Asian portrait,A young woman wearing a green baseball cap, close shot, background is coffee store, masterpiece, best quality, ultra resolution",
- "width": 768,
- "height": 1152,
- "sampler": 20,
- "steps": 35,
- "cfgScale": 2.0,
- "imgCount": 1,
- "controlNet": [
- {
- "unitOrder": 1, # 第一步:先识别要用的人像人脸
- "sourceImage": face_img_url,
- "width": 1080,
- "height": 1432
- },
- {
- "unitOrder": 2, # 第二步:再识别要参考的人物面部朝向
- "sourceImage": pose_img_url,
- "width": 1024,
- "height": 1024
- }
- ]
- }
- }
- task_id = self._submit_task(payload)
- self._wait_and_print_result(task_id)
- if __name__ == "__main__":
- try:
- runner = LibLibTestRunner()
-
- print("选择要测试的模式:")
- print("1. 纯文生图 (Text2Img)")
- print("2. 纯图生图 (Img2Img)")
- print("3. 硬边缘控制 (Canny ControlNet)")
- print("4. 软边缘控制 (SoftEdge ControlNet)")
- print("5. 线稿控制 (Lineart ControlNet)")
- print("6. 骨骼控制 (OpenPose ControlNet)")
- print("7. 局部重绘 (Inpaint Mode=4)")
- print("8. 人像换脸 (InstantID)")
- print("9. 全部测试 (All)")
-
- if len(sys.argv) > 1:
- choice = sys.argv[1]
- else:
- # 默认测试文生图以验证 API Key 最基本权限
- choice = "1"
-
- if choice == "1":
- runner.test_text2img()
- elif choice == "2":
- runner.test_img2img()
- elif choice == "3":
- runner.test_text2img_controlnet()
- elif choice == "4":
- runner.test_text2img_softedge()
- elif choice == "5":
- runner.test_text2img_lineart()
- elif choice == "6":
- runner.test_text2img_openpose()
- elif choice == "7":
- runner.test_inpaint_mode4()
- elif choice == "8":
- runner.test_instantid_faceswap()
- elif choice == "9":
- runner.test_text2img()
- runner.test_img2img()
- runner.test_text2img_controlnet()
- # 省略后面的测试避免同时发生太多请求...
- else:
- print("Unknown choice.")
-
- except Exception as e:
- print(f"\n[FATAL ERROR] {e}")
|