Prodia.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from __future__ import annotations
  2. from aiohttp import ClientSession
  3. import asyncio
  4. import random
  5. from ..typing import AsyncResult, Messages
  6. from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
  7. from ..image import ImageResponse
  8. class Prodia(AsyncGeneratorProvider, ProviderModelMixin):
  9. url = "https://app.prodia.com"
  10. api_endpoint = "https://api.prodia.com/generate"
  11. working = True
  12. default_model = 'absolutereality_v181.safetensors [3d9d4d2b]'
  13. default_image_model = default_model
  14. image_models = [
  15. '3Guofeng3_v34.safetensors [50f420de]',
  16. 'absolutereality_V16.safetensors [37db0fc3]',
  17. default_image_model,
  18. 'amIReal_V41.safetensors [0a8a2e61]',
  19. 'analog-diffusion-1.0.ckpt [9ca13f02]',
  20. 'aniverse_v30.safetensors [579e6f85]',
  21. 'anythingv3_0-pruned.ckpt [2700c435]',
  22. 'anything-v4.5-pruned.ckpt [65745d25]',
  23. 'anythingV5_PrtRE.safetensors [893e49b9]',
  24. 'AOM3A3_orangemixs.safetensors [9600da17]',
  25. 'blazing_drive_v10g.safetensors [ca1c1eab]',
  26. 'breakdomain_I2428.safetensors [43cc7d2f]',
  27. 'breakdomain_M2150.safetensors [15f7afca]',
  28. 'cetusMix_Version35.safetensors [de2f2560]',
  29. 'childrensStories_v13D.safetensors [9dfaabcb]',
  30. 'childrensStories_v1SemiReal.safetensors [a1c56dbb]',
  31. 'childrensStories_v1ToonAnime.safetensors [2ec7b88b]',
  32. 'Counterfeit_v30.safetensors [9e2a8f19]',
  33. 'cuteyukimixAdorable_midchapter3.safetensors [04bdffe6]',
  34. 'cyberrealistic_v33.safetensors [82b0d085]',
  35. 'dalcefo_v4.safetensors [425952fe]',
  36. 'deliberate_v2.safetensors [10ec4b29]',
  37. 'deliberate_v3.safetensors [afd9d2d4]',
  38. 'dreamlike-anime-1.0.safetensors [4520e090]',
  39. 'dreamlike-diffusion-1.0.safetensors [5c9fd6e0]',
  40. 'dreamlike-photoreal-2.0.safetensors [fdcf65e7]',
  41. 'dreamshaper_6BakedVae.safetensors [114c8abb]',
  42. 'dreamshaper_7.safetensors [5cf5ae06]',
  43. 'dreamshaper_8.safetensors [9d40847d]',
  44. 'edgeOfRealism_eorV20.safetensors [3ed5de15]',
  45. 'EimisAnimeDiffusion_V1.ckpt [4f828a15]',
  46. 'elldreths-vivid-mix.safetensors [342d9d26]',
  47. 'epicphotogasm_xPlusPlus.safetensors [1a8f6d35]',
  48. 'epicrealism_naturalSinRC1VAE.safetensors [90a4c676]',
  49. 'epicrealism_pureEvolutionV3.safetensors [42c8440c]',
  50. 'ICantBelieveItsNotPhotography_seco.safetensors [4e7a3dfd]',
  51. 'indigoFurryMix_v75Hybrid.safetensors [91208cbb]',
  52. 'juggernaut_aftermath.safetensors [5e20c455]',
  53. 'lofi_v4.safetensors [ccc204d6]',
  54. 'lyriel_v16.safetensors [68fceea2]',
  55. 'majicmixRealistic_v4.safetensors [29d0de58]',
  56. 'mechamix_v10.safetensors [ee685731]',
  57. 'meinamix_meinaV9.safetensors [2ec66ab0]',
  58. 'meinamix_meinaV11.safetensors [b56ce717]',
  59. 'neverendingDream_v122.safetensors [f964ceeb]',
  60. 'openjourney_V4.ckpt [ca2f377f]',
  61. 'pastelMixStylizedAnime_pruned_fp16.safetensors [793a26e8]',
  62. 'portraitplus_V1.0.safetensors [1400e684]',
  63. 'protogenx34.safetensors [5896f8d5]',
  64. 'Realistic_Vision_V1.4-pruned-fp16.safetensors [8d21810b]',
  65. 'Realistic_Vision_V2.0.safetensors [79587710]',
  66. 'Realistic_Vision_V4.0.safetensors [29a7afaa]',
  67. 'Realistic_Vision_V5.0.safetensors [614d1063]',
  68. 'Realistic_Vision_V5.1.safetensors [a0f13c83]',
  69. 'redshift_diffusion-V10.safetensors [1400e684]',
  70. 'revAnimated_v122.safetensors [3f4fefd9]',
  71. 'rundiffusionFX25D_v10.safetensors [cd12b0ee]',
  72. 'rundiffusionFX_v10.safetensors [cd4e694d]',
  73. 'sdv1_4.ckpt [7460a6fa]',
  74. 'v1-5-pruned-emaonly.safetensors [d7049739]',
  75. 'v1-5-inpainting.safetensors [21c7ab71]',
  76. 'shoninsBeautiful_v10.safetensors [25d8c546]',
  77. 'theallys-mix-ii-churned.safetensors [5d9225a4]',
  78. 'timeless-1.0.ckpt [7c4971d4]',
  79. 'toonyou_beta6.safetensors [980f6b15]'
  80. ]
  81. models = [*image_models]
  82. @classmethod
  83. def get_model(cls, model: str) -> str:
  84. if model in cls.models:
  85. return model
  86. elif model in cls.model_aliases:
  87. return cls.model_aliases[model]
  88. else:
  89. return cls.default_model
  90. @classmethod
  91. async def create_async_generator(
  92. cls,
  93. model: str,
  94. messages: Messages,
  95. proxy: str = None,
  96. negative_prompt: str = "",
  97. steps: str = 20, # 1-25
  98. cfg: str = 7, # 0-20
  99. seed: Optional[int] = None,
  100. sampler: str = "DPM++ 2M Karras", # "Euler", "Euler a", "Heun", "DPM++ 2M Karras", "DPM++ SDE Karras", "DDIM"
  101. aspect_ratio: str = "square", # "square", "portrait", "landscape"
  102. **kwargs
  103. ) -> AsyncResult:
  104. model = cls.get_model(model)
  105. if seed is None:
  106. seed = random.randint(0, 10000)
  107. headers = {
  108. "accept": "*/*",
  109. "accept-language": "en-US,en;q=0.9",
  110. "origin": cls.url,
  111. "referer": f"{cls.url}/",
  112. "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
  113. }
  114. async with ClientSession(headers=headers) as session:
  115. prompt = messages[-1]['content'] if messages else ""
  116. params = {
  117. "new": "true",
  118. "prompt": prompt,
  119. "model": model,
  120. "negative_prompt": negative_prompt,
  121. "steps": steps,
  122. "cfg": cfg,
  123. "seed": seed,
  124. "sampler": sampler,
  125. "aspect_ratio": aspect_ratio
  126. }
  127. async with session.get(cls.api_endpoint, params=params, proxy=proxy) as response:
  128. response.raise_for_status()
  129. job_data = await response.json()
  130. job_id = job_data["job"]
  131. image_url = await cls._poll_job(session, job_id, proxy)
  132. yield ImageResponse(image_url, alt=prompt)
  133. @classmethod
  134. async def _poll_job(cls, session: ClientSession, job_id: str, proxy: str, max_attempts: int = 30, delay: int = 2) -> str:
  135. for _ in range(max_attempts):
  136. async with session.get(f"https://api.prodia.com/job/{job_id}", proxy=proxy) as response:
  137. response.raise_for_status()
  138. job_status = await response.json()
  139. if job_status["status"] == "succeeded":
  140. return f"https://images.prodia.xyz/{job_id}.png"
  141. elif job_status["status"] == "failed":
  142. raise Exception("Image generation failed")
  143. await asyncio.sleep(delay)
  144. raise Exception("Timeout waiting for image generation")