magic_hour 0.9.5__py3-none-any.whl → 0.44.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. magic_hour/README.md +34 -0
  2. magic_hour/__init__.py +1 -1
  3. magic_hour/client.py +8 -17
  4. magic_hour/environment.py +13 -1
  5. magic_hour/helpers/__init__.py +4 -0
  6. magic_hour/helpers/download.py +77 -0
  7. magic_hour/helpers/logger.py +8 -0
  8. magic_hour/resources/v1/README.md +32 -0
  9. magic_hour/resources/v1/ai_clothes_changer/README.md +94 -5
  10. magic_hour/resources/v1/ai_clothes_changer/client.py +161 -16
  11. magic_hour/resources/v1/ai_face_editor/README.md +195 -0
  12. magic_hour/resources/v1/ai_face_editor/__init__.py +4 -0
  13. magic_hour/resources/v1/ai_face_editor/client.py +324 -0
  14. magic_hour/resources/v1/ai_gif_generator/README.md +116 -0
  15. magic_hour/resources/v1/ai_gif_generator/__init__.py +4 -0
  16. magic_hour/resources/v1/ai_gif_generator/client.py +257 -0
  17. magic_hour/resources/v1/ai_headshot_generator/README.md +81 -3
  18. magic_hour/resources/v1/ai_headshot_generator/client.py +167 -18
  19. magic_hour/resources/v1/ai_image_editor/README.md +125 -0
  20. magic_hour/resources/v1/ai_image_editor/__init__.py +4 -0
  21. magic_hour/resources/v1/ai_image_editor/client.py +290 -0
  22. magic_hour/resources/v1/ai_image_generator/README.md +99 -5
  23. magic_hour/resources/v1/ai_image_generator/client.py +170 -24
  24. magic_hour/resources/v1/ai_image_upscaler/README.md +89 -3
  25. magic_hour/resources/v1/ai_image_upscaler/client.py +173 -20
  26. magic_hour/resources/v1/ai_meme_generator/README.md +129 -0
  27. magic_hour/resources/v1/ai_meme_generator/__init__.py +4 -0
  28. magic_hour/resources/v1/ai_meme_generator/client.py +253 -0
  29. magic_hour/resources/v1/ai_photo_editor/README.md +119 -4
  30. magic_hour/resources/v1/ai_photo_editor/client.py +199 -18
  31. magic_hour/resources/v1/ai_qr_code_generator/README.md +84 -3
  32. magic_hour/resources/v1/ai_qr_code_generator/client.py +140 -18
  33. magic_hour/resources/v1/ai_talking_photo/README.md +137 -0
  34. magic_hour/resources/v1/ai_talking_photo/__init__.py +4 -0
  35. magic_hour/resources/v1/ai_talking_photo/client.py +326 -0
  36. magic_hour/resources/v1/ai_voice_cloner/README.md +62 -0
  37. magic_hour/resources/v1/ai_voice_cloner/__init__.py +4 -0
  38. magic_hour/resources/v1/ai_voice_cloner/client.py +272 -0
  39. magic_hour/resources/v1/ai_voice_generator/README.md +112 -0
  40. magic_hour/resources/v1/ai_voice_generator/__init__.py +4 -0
  41. magic_hour/resources/v1/ai_voice_generator/client.py +241 -0
  42. magic_hour/resources/v1/animation/README.md +128 -6
  43. magic_hour/resources/v1/animation/client.py +247 -22
  44. magic_hour/resources/v1/audio_projects/README.md +135 -0
  45. magic_hour/resources/v1/audio_projects/__init__.py +12 -0
  46. magic_hour/resources/v1/audio_projects/client.py +310 -0
  47. magic_hour/resources/v1/audio_projects/client_test.py +520 -0
  48. magic_hour/resources/v1/auto_subtitle_generator/README.md +128 -0
  49. magic_hour/resources/v1/auto_subtitle_generator/__init__.py +4 -0
  50. magic_hour/resources/v1/auto_subtitle_generator/client.py +346 -0
  51. magic_hour/resources/v1/client.py +75 -1
  52. magic_hour/resources/v1/face_detection/README.md +157 -0
  53. magic_hour/resources/v1/face_detection/__init__.py +12 -0
  54. magic_hour/resources/v1/face_detection/client.py +380 -0
  55. magic_hour/resources/v1/face_swap/README.md +137 -9
  56. magic_hour/resources/v1/face_swap/client.py +329 -38
  57. magic_hour/resources/v1/face_swap_photo/README.md +118 -3
  58. magic_hour/resources/v1/face_swap_photo/client.py +199 -14
  59. magic_hour/resources/v1/files/README.md +39 -0
  60. magic_hour/resources/v1/files/client.py +351 -1
  61. magic_hour/resources/v1/files/client_test.py +414 -0
  62. magic_hour/resources/v1/files/upload_urls/README.md +38 -17
  63. magic_hour/resources/v1/files/upload_urls/client.py +38 -34
  64. magic_hour/resources/v1/image_background_remover/README.md +96 -5
  65. magic_hour/resources/v1/image_background_remover/client.py +151 -16
  66. magic_hour/resources/v1/image_projects/README.md +82 -10
  67. magic_hour/resources/v1/image_projects/__init__.py +10 -2
  68. magic_hour/resources/v1/image_projects/client.py +154 -16
  69. magic_hour/resources/v1/image_projects/client_test.py +527 -0
  70. magic_hour/resources/v1/image_to_video/README.md +96 -11
  71. magic_hour/resources/v1/image_to_video/client.py +282 -38
  72. magic_hour/resources/v1/lip_sync/README.md +112 -9
  73. magic_hour/resources/v1/lip_sync/client.py +288 -34
  74. magic_hour/resources/v1/photo_colorizer/README.md +107 -0
  75. magic_hour/resources/v1/photo_colorizer/__init__.py +4 -0
  76. magic_hour/resources/v1/photo_colorizer/client.py +248 -0
  77. magic_hour/resources/v1/text_to_video/README.md +96 -7
  78. magic_hour/resources/v1/text_to_video/client.py +204 -18
  79. magic_hour/resources/v1/video_projects/README.md +81 -9
  80. magic_hour/resources/v1/video_projects/__init__.py +10 -2
  81. magic_hour/resources/v1/video_projects/client.py +151 -14
  82. magic_hour/resources/v1/video_projects/client_test.py +527 -0
  83. magic_hour/resources/v1/video_to_video/README.md +119 -15
  84. magic_hour/resources/v1/video_to_video/client.py +299 -46
  85. magic_hour/types/models/__init__.py +92 -56
  86. magic_hour/types/models/v1_ai_clothes_changer_create_response.py +33 -0
  87. magic_hour/types/models/v1_ai_face_editor_create_response.py +33 -0
  88. magic_hour/types/models/v1_ai_gif_generator_create_response.py +33 -0
  89. magic_hour/types/models/v1_ai_headshot_generator_create_response.py +33 -0
  90. magic_hour/types/models/v1_ai_image_editor_create_response.py +33 -0
  91. magic_hour/types/models/v1_ai_image_generator_create_response.py +33 -0
  92. magic_hour/types/models/v1_ai_image_upscaler_create_response.py +33 -0
  93. magic_hour/types/models/v1_ai_meme_generator_create_response.py +33 -0
  94. magic_hour/types/models/v1_ai_photo_editor_create_response.py +33 -0
  95. magic_hour/types/models/v1_ai_qr_code_generator_create_response.py +33 -0
  96. magic_hour/types/models/v1_ai_talking_photo_create_response.py +35 -0
  97. magic_hour/types/models/v1_ai_voice_cloner_create_response.py +27 -0
  98. magic_hour/types/models/v1_ai_voice_generator_create_response.py +27 -0
  99. magic_hour/types/models/v1_animation_create_response.py +35 -0
  100. magic_hour/types/models/v1_audio_projects_get_response.py +72 -0
  101. magic_hour/types/models/v1_audio_projects_get_response_downloads_item.py +19 -0
  102. magic_hour/types/models/{get_v1_image_projects_id_response_error.py → v1_audio_projects_get_response_error.py} +2 -2
  103. magic_hour/types/models/v1_auto_subtitle_generator_create_response.py +35 -0
  104. magic_hour/types/models/v1_face_detection_create_response.py +25 -0
  105. magic_hour/types/models/v1_face_detection_get_response.py +45 -0
  106. magic_hour/types/models/v1_face_detection_get_response_faces_item.py +25 -0
  107. magic_hour/types/models/v1_face_swap_create_response.py +35 -0
  108. magic_hour/types/models/v1_face_swap_photo_create_response.py +33 -0
  109. magic_hour/types/models/v1_files_upload_urls_create_response.py +24 -0
  110. magic_hour/types/models/{post_v1_files_upload_urls_response_items_item.py → v1_files_upload_urls_create_response_items_item.py} +2 -2
  111. magic_hour/types/models/v1_image_background_remover_create_response.py +33 -0
  112. magic_hour/types/models/{get_v1_image_projects_id_response.py → v1_image_projects_get_response.py} +20 -18
  113. magic_hour/types/models/{get_v1_video_projects_id_response_downloads_item.py → v1_image_projects_get_response_downloads_item.py} +1 -1
  114. magic_hour/types/models/{get_v1_video_projects_id_response_error.py → v1_image_projects_get_response_error.py} +2 -2
  115. magic_hour/types/models/v1_image_to_video_create_response.py +35 -0
  116. magic_hour/types/models/v1_lip_sync_create_response.py +35 -0
  117. magic_hour/types/models/v1_photo_colorizer_create_response.py +33 -0
  118. magic_hour/types/models/v1_text_to_video_create_response.py +35 -0
  119. magic_hour/types/models/{get_v1_video_projects_id_response.py → v1_video_projects_get_response.py} +26 -23
  120. magic_hour/types/models/{get_v1_video_projects_id_response_download.py → v1_video_projects_get_response_download.py} +1 -1
  121. magic_hour/types/models/{get_v1_image_projects_id_response_downloads_item.py → v1_video_projects_get_response_downloads_item.py} +1 -1
  122. magic_hour/types/models/v1_video_projects_get_response_error.py +25 -0
  123. magic_hour/types/models/v1_video_to_video_create_response.py +35 -0
  124. magic_hour/types/params/__init__.py +422 -176
  125. magic_hour/types/params/v1_ai_clothes_changer_create_body.py +40 -0
  126. magic_hour/types/params/v1_ai_clothes_changer_create_body_assets.py +58 -0
  127. magic_hour/types/params/v1_ai_clothes_changer_generate_body_assets.py +33 -0
  128. magic_hour/types/params/v1_ai_face_editor_create_body.py +52 -0
  129. magic_hour/types/params/v1_ai_face_editor_create_body_assets.py +33 -0
  130. magic_hour/types/params/v1_ai_face_editor_create_body_style.py +137 -0
  131. magic_hour/types/params/v1_ai_face_editor_generate_body_assets.py +17 -0
  132. magic_hour/types/params/v1_ai_gif_generator_create_body.py +47 -0
  133. magic_hour/types/params/{post_v1_ai_image_generator_body_style.py → v1_ai_gif_generator_create_body_style.py} +5 -5
  134. magic_hour/types/params/v1_ai_headshot_generator_create_body.py +49 -0
  135. magic_hour/types/params/v1_ai_headshot_generator_create_body_assets.py +33 -0
  136. magic_hour/types/params/v1_ai_headshot_generator_create_body_style.py +27 -0
  137. magic_hour/types/params/v1_ai_headshot_generator_generate_body_assets.py +17 -0
  138. magic_hour/types/params/v1_ai_image_editor_create_body.py +49 -0
  139. magic_hour/types/params/v1_ai_image_editor_create_body_assets.py +47 -0
  140. magic_hour/types/params/v1_ai_image_editor_create_body_style.py +41 -0
  141. magic_hour/types/params/v1_ai_image_editor_generate_body_assets.py +28 -0
  142. magic_hour/types/params/{post_v1_ai_image_generator_body.py → v1_ai_image_generator_create_body.py} +17 -11
  143. magic_hour/types/params/v1_ai_image_generator_create_body_style.py +127 -0
  144. magic_hour/types/params/v1_ai_image_upscaler_create_body.py +59 -0
  145. magic_hour/types/params/v1_ai_image_upscaler_create_body_assets.py +33 -0
  146. magic_hour/types/params/{post_v1_ai_image_upscaler_body_style.py → v1_ai_image_upscaler_create_body_style.py} +4 -4
  147. magic_hour/types/params/v1_ai_image_upscaler_generate_body_assets.py +17 -0
  148. magic_hour/types/params/v1_ai_meme_generator_create_body.py +37 -0
  149. magic_hour/types/params/v1_ai_meme_generator_create_body_style.py +73 -0
  150. magic_hour/types/params/{post_v1_ai_photo_editor_body.py → v1_ai_photo_editor_create_body.py} +15 -15
  151. magic_hour/types/params/v1_ai_photo_editor_create_body_assets.py +33 -0
  152. magic_hour/types/params/{post_v1_ai_photo_editor_body_style.py → v1_ai_photo_editor_create_body_style.py} +20 -4
  153. magic_hour/types/params/v1_ai_photo_editor_generate_body_assets.py +17 -0
  154. magic_hour/types/params/v1_ai_qr_code_generator_create_body.py +45 -0
  155. magic_hour/types/params/{post_v1_ai_qr_code_generator_body_style.py → v1_ai_qr_code_generator_create_body_style.py} +4 -4
  156. magic_hour/types/params/v1_ai_talking_photo_create_body.py +68 -0
  157. magic_hour/types/params/v1_ai_talking_photo_create_body_assets.py +46 -0
  158. magic_hour/types/params/v1_ai_talking_photo_create_body_style.py +44 -0
  159. magic_hour/types/params/v1_ai_talking_photo_generate_body_assets.py +26 -0
  160. magic_hour/types/params/v1_ai_voice_cloner_create_body.py +49 -0
  161. magic_hour/types/params/v1_ai_voice_cloner_create_body_assets.py +33 -0
  162. magic_hour/types/params/v1_ai_voice_cloner_create_body_style.py +28 -0
  163. magic_hour/types/params/v1_ai_voice_cloner_generate_body_assets.py +28 -0
  164. magic_hour/types/params/v1_ai_voice_generator_create_body.py +40 -0
  165. magic_hour/types/params/v1_ai_voice_generator_create_body_style.py +440 -0
  166. magic_hour/types/params/{post_v1_animation_body.py → v1_animation_create_body.py} +16 -16
  167. magic_hour/types/params/{post_v1_animation_body_assets.py → v1_animation_create_body_assets.py} +15 -5
  168. magic_hour/types/params/{post_v1_animation_body_style.py → v1_animation_create_body_style.py} +13 -10
  169. magic_hour/types/params/v1_animation_generate_body_assets.py +39 -0
  170. magic_hour/types/params/v1_auto_subtitle_generator_create_body.py +78 -0
  171. magic_hour/types/params/v1_auto_subtitle_generator_create_body_assets.py +33 -0
  172. magic_hour/types/params/v1_auto_subtitle_generator_create_body_style.py +56 -0
  173. magic_hour/types/params/v1_auto_subtitle_generator_create_body_style_custom_config.py +86 -0
  174. magic_hour/types/params/v1_auto_subtitle_generator_generate_body_assets.py +17 -0
  175. magic_hour/types/params/v1_face_detection_create_body.py +44 -0
  176. magic_hour/types/params/v1_face_detection_create_body_assets.py +33 -0
  177. magic_hour/types/params/v1_face_detection_generate_body_assets.py +17 -0
  178. magic_hour/types/params/v1_face_swap_create_body.py +92 -0
  179. magic_hour/types/params/v1_face_swap_create_body_assets.py +91 -0
  180. magic_hour/types/params/v1_face_swap_create_body_assets_face_mappings_item.py +44 -0
  181. magic_hour/types/params/v1_face_swap_create_body_style.py +33 -0
  182. magic_hour/types/params/v1_face_swap_generate_body_assets.py +56 -0
  183. magic_hour/types/params/v1_face_swap_generate_body_assets_face_mappings_item.py +25 -0
  184. magic_hour/types/params/v1_face_swap_photo_create_body.py +40 -0
  185. magic_hour/types/params/v1_face_swap_photo_create_body_assets.py +76 -0
  186. magic_hour/types/params/v1_face_swap_photo_create_body_assets_face_mappings_item.py +44 -0
  187. magic_hour/types/params/v1_face_swap_photo_generate_body_assets.py +47 -0
  188. magic_hour/types/params/v1_face_swap_photo_generate_body_assets_face_mappings_item.py +25 -0
  189. magic_hour/types/params/v1_files_upload_urls_create_body.py +36 -0
  190. magic_hour/types/params/v1_files_upload_urls_create_body_items_item.py +38 -0
  191. magic_hour/types/params/v1_image_background_remover_create_body.py +40 -0
  192. magic_hour/types/params/v1_image_background_remover_create_body_assets.py +49 -0
  193. magic_hour/types/params/v1_image_background_remover_generate_body_assets.py +27 -0
  194. magic_hour/types/params/v1_image_to_video_create_body.py +101 -0
  195. magic_hour/types/params/v1_image_to_video_create_body_assets.py +33 -0
  196. magic_hour/types/params/v1_image_to_video_create_body_style.py +53 -0
  197. magic_hour/types/params/v1_image_to_video_generate_body_assets.py +17 -0
  198. magic_hour/types/params/v1_lip_sync_create_body.py +100 -0
  199. magic_hour/types/params/{post_v1_lip_sync_body_assets.py → v1_lip_sync_create_body_assets.py} +15 -5
  200. magic_hour/types/params/v1_lip_sync_create_body_style.py +37 -0
  201. magic_hour/types/params/v1_lip_sync_generate_body_assets.py +36 -0
  202. magic_hour/types/params/v1_photo_colorizer_create_body.py +40 -0
  203. magic_hour/types/params/v1_photo_colorizer_create_body_assets.py +33 -0
  204. magic_hour/types/params/v1_photo_colorizer_generate_body_assets.py +17 -0
  205. magic_hour/types/params/v1_text_to_video_create_body.py +78 -0
  206. magic_hour/types/params/v1_text_to_video_create_body_style.py +43 -0
  207. magic_hour/types/params/v1_video_to_video_create_body.py +101 -0
  208. magic_hour/types/params/{post_v1_video_to_video_body_assets.py → v1_video_to_video_create_body_assets.py} +9 -4
  209. magic_hour/types/params/{post_v1_video_to_video_body_style.py → v1_video_to_video_create_body_style.py} +68 -26
  210. magic_hour/types/params/v1_video_to_video_generate_body_assets.py +27 -0
  211. magic_hour-0.44.0.dist-info/METADATA +328 -0
  212. magic_hour-0.44.0.dist-info/RECORD +231 -0
  213. magic_hour/core/__init__.py +0 -52
  214. magic_hour/core/api_error.py +0 -56
  215. magic_hour/core/auth.py +0 -314
  216. magic_hour/core/base_client.py +0 -618
  217. magic_hour/core/binary_response.py +0 -23
  218. magic_hour/core/query.py +0 -106
  219. magic_hour/core/request.py +0 -156
  220. magic_hour/core/response.py +0 -293
  221. magic_hour/core/type_utils.py +0 -28
  222. magic_hour/core/utils.py +0 -55
  223. magic_hour/types/models/post_v1_ai_clothes_changer_response.py +0 -25
  224. magic_hour/types/models/post_v1_ai_headshot_generator_response.py +0 -25
  225. magic_hour/types/models/post_v1_ai_image_generator_response.py +0 -25
  226. magic_hour/types/models/post_v1_ai_image_upscaler_response.py +0 -25
  227. magic_hour/types/models/post_v1_ai_photo_editor_response.py +0 -25
  228. magic_hour/types/models/post_v1_ai_qr_code_generator_response.py +0 -25
  229. magic_hour/types/models/post_v1_animation_response.py +0 -25
  230. magic_hour/types/models/post_v1_face_swap_photo_response.py +0 -25
  231. magic_hour/types/models/post_v1_face_swap_response.py +0 -25
  232. magic_hour/types/models/post_v1_files_upload_urls_response.py +0 -21
  233. magic_hour/types/models/post_v1_image_background_remover_response.py +0 -25
  234. magic_hour/types/models/post_v1_image_to_video_response.py +0 -25
  235. magic_hour/types/models/post_v1_lip_sync_response.py +0 -25
  236. magic_hour/types/models/post_v1_text_to_video_response.py +0 -25
  237. magic_hour/types/models/post_v1_video_to_video_response.py +0 -25
  238. magic_hour/types/params/post_v1_ai_clothes_changer_body.py +0 -40
  239. magic_hour/types/params/post_v1_ai_clothes_changer_body_assets.py +0 -45
  240. magic_hour/types/params/post_v1_ai_headshot_generator_body.py +0 -40
  241. magic_hour/types/params/post_v1_ai_headshot_generator_body_assets.py +0 -28
  242. magic_hour/types/params/post_v1_ai_image_upscaler_body.py +0 -57
  243. magic_hour/types/params/post_v1_ai_image_upscaler_body_assets.py +0 -28
  244. magic_hour/types/params/post_v1_ai_photo_editor_body_assets.py +0 -28
  245. magic_hour/types/params/post_v1_ai_qr_code_generator_body.py +0 -45
  246. magic_hour/types/params/post_v1_face_swap_body.py +0 -72
  247. magic_hour/types/params/post_v1_face_swap_body_assets.py +0 -52
  248. magic_hour/types/params/post_v1_face_swap_photo_body.py +0 -40
  249. magic_hour/types/params/post_v1_face_swap_photo_body_assets.py +0 -36
  250. magic_hour/types/params/post_v1_files_upload_urls_body.py +0 -31
  251. magic_hour/types/params/post_v1_files_upload_urls_body_items_item.py +0 -38
  252. magic_hour/types/params/post_v1_image_background_remover_body.py +0 -40
  253. magic_hour/types/params/post_v1_image_background_remover_body_assets.py +0 -28
  254. magic_hour/types/params/post_v1_image_to_video_body.py +0 -73
  255. magic_hour/types/params/post_v1_image_to_video_body_assets.py +0 -28
  256. magic_hour/types/params/post_v1_image_to_video_body_style.py +0 -37
  257. magic_hour/types/params/post_v1_lip_sync_body.py +0 -80
  258. magic_hour/types/params/post_v1_text_to_video_body.py +0 -57
  259. magic_hour/types/params/post_v1_text_to_video_body_style.py +0 -28
  260. magic_hour/types/params/post_v1_video_to_video_body.py +0 -93
  261. magic_hour-0.9.5.dist-info/METADATA +0 -133
  262. magic_hour-0.9.5.dist-info/RECORD +0 -132
  263. {magic_hour-0.9.5.dist-info → magic_hour-0.44.0.dist-info}/LICENSE +0 -0
  264. {magic_hour-0.9.5.dist-info → magic_hour-0.44.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,380 @@
1
+ import asyncio
2
+ import os
3
+ import pydantic
4
+ import time
5
+ import typing
6
+
7
+ from magic_hour.helpers.download import download_files_async, download_files_sync
8
+ from magic_hour.helpers.logger import get_sdk_logger
9
+ from magic_hour.resources.v1.files import AsyncFilesClient, FilesClient
10
+ from magic_hour.types import models, params
11
+ from make_api_request import (
12
+ AsyncBaseClient,
13
+ RequestOptions,
14
+ SyncBaseClient,
15
+ default_request_options,
16
+ to_encodable,
17
+ type_utils,
18
+ )
19
+
20
+
21
+ logger = get_sdk_logger(__name__)
22
+
23
+
24
+ class V1FaceDetectionGetResponseWithDownloads(models.V1FaceDetectionGetResponse):
25
+ downloaded_paths: typing.Optional[typing.List[str]] = pydantic.Field(
26
+ default=None, alias="downloaded_paths"
27
+ )
28
+ """
29
+ The paths to the downloaded face images.
30
+
31
+ This field is only populated if `download_outputs` is True and the face detection is complete.
32
+ """
33
+
34
+
35
+ class FaceDetectionClient:
36
+ def __init__(self, *, base_client: SyncBaseClient):
37
+ self._base_client = base_client
38
+
39
+ def generate(
40
+ self,
41
+ *,
42
+ assets: params.V1FaceDetectionCreateBodyAssets,
43
+ confidence_score: typing.Union[
44
+ typing.Optional[float], type_utils.NotGiven
45
+ ] = type_utils.NOT_GIVEN,
46
+ wait_for_completion: bool = True,
47
+ download_outputs: bool = True,
48
+ download_directory: typing.Optional[str] = None,
49
+ request_options: typing.Optional[RequestOptions] = None,
50
+ ) -> V1FaceDetectionGetResponseWithDownloads:
51
+ """
52
+ Generate face detection results with optional waiting and downloading.
53
+
54
+ This method creates a face detection task and optionally waits for completion
55
+ and downloads the detected face images.
56
+
57
+ Args:
58
+ assets: Provide the assets for face detection
59
+ confidence_score: Confidence threshold for filtering detected faces
60
+ wait_for_completion: Whether to wait for the face detection task to complete
61
+ download_outputs: Whether to download the detected face images
62
+ download_directory: The directory to download the face images to. If not provided,
63
+ the images will be downloaded to the current working directory
64
+ request_options: Additional options to customize the HTTP request
65
+
66
+ Returns:
67
+ V1FaceDetectionGetResponseWithDownloads: The face detection response with optional
68
+ downloaded face image paths included
69
+ """
70
+ # Handle file upload if needed
71
+ file_client = FilesClient(base_client=self._base_client)
72
+ target_file_path = assets["target_file_path"]
73
+ assets["target_file_path"] = file_client.upload_file(file=target_file_path)
74
+
75
+ create_response = self.create(
76
+ assets=assets,
77
+ confidence_score=confidence_score,
78
+ request_options=request_options,
79
+ )
80
+
81
+ task_id = create_response.id
82
+
83
+ api_response = self.get(id=task_id)
84
+ if not wait_for_completion:
85
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
86
+
87
+ poll_interval = float(os.getenv("MAGIC_HOUR_POLL_INTERVAL", "0.5"))
88
+
89
+ while api_response.status not in ["complete", "error"]:
90
+ api_response = self.get(id=task_id)
91
+ time.sleep(poll_interval)
92
+
93
+ if api_response.status != "complete":
94
+ log = logger.error if api_response.status == "error" else logger.info
95
+ log(f"Face detection {task_id} has status {api_response.status}")
96
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
97
+
98
+ if not download_outputs or not api_response.faces:
99
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
100
+
101
+ face_downloads = [
102
+ models.V1ImageProjectsGetResponseDownloadsItem(
103
+ url=face.url,
104
+ expires_at="ignore",
105
+ )
106
+ for face in api_response.faces
107
+ ]
108
+ downloaded_paths = download_files_sync(
109
+ downloads=face_downloads,
110
+ download_directory=download_directory,
111
+ )
112
+
113
+ return V1FaceDetectionGetResponseWithDownloads(
114
+ **api_response.model_dump(), downloaded_paths=downloaded_paths
115
+ )
116
+
117
+ def get(
118
+ self, *, id: str, request_options: typing.Optional[RequestOptions] = None
119
+ ) -> models.V1FaceDetectionGetResponse:
120
+ """
121
+ Get face detection details
122
+
123
+ Get the details of a face detection task.
124
+
125
+ Use this API to get the list of faces detected in the image or video to use in the [face swap photo](/api-reference/face-swap-photo/face-swap-photo) or [face swap video](/api-reference/face-swap/face-swap-video) API calls for multi-face swaps.
126
+
127
+ GET /v1/face-detection/{id}
128
+
129
+ Args:
130
+ id: The id of the task. This value is returned by the [face detection API](/api-reference/files/face-detection#response-id).
131
+ request_options: Additional options to customize the HTTP request
132
+
133
+ Returns:
134
+ 200
135
+
136
+ Raises:
137
+ ApiError: A custom exception class that provides additional context
138
+ for API errors, including the HTTP status code and response body.
139
+
140
+ Examples:
141
+ ```py
142
+ client.v1.face_detection.get(id="uuid-example")
143
+ ```
144
+ """
145
+ return self._base_client.request(
146
+ method="GET",
147
+ path=f"/v1/face-detection/{id}",
148
+ auth_names=["bearerAuth"],
149
+ cast_to=models.V1FaceDetectionGetResponse,
150
+ request_options=request_options or default_request_options(),
151
+ )
152
+
153
+ def create(
154
+ self,
155
+ *,
156
+ assets: params.V1FaceDetectionCreateBodyAssets,
157
+ confidence_score: typing.Union[
158
+ typing.Optional[float], type_utils.NotGiven
159
+ ] = type_utils.NOT_GIVEN,
160
+ request_options: typing.Optional[RequestOptions] = None,
161
+ ) -> models.V1FaceDetectionCreateResponse:
162
+ """
163
+ Face Detection
164
+
165
+ Detect faces in an image or video.
166
+
167
+ Use this API to get the list of faces detected in the image or video to use in the [face swap photo](/api-reference/face-swap-photo/face-swap-photo) or [face swap video](/api-reference/face-swap/face-swap-video) API calls for multi-face swaps.
168
+
169
+ Note: Face detection is free to use for the near future. Pricing may change in the future.
170
+
171
+ POST /v1/face-detection
172
+
173
+ Args:
174
+ confidence_score: Confidence threshold for filtering detected faces.
175
+ * Higher values (e.g., 0.9) include only faces detected with high certainty, reducing false positives.
176
+ * Lower values (e.g., 0.3) include more faces, but may increase the chance of incorrect detections.
177
+ assets: Provide the assets for face detection
178
+ request_options: Additional options to customize the HTTP request
179
+
180
+ Returns:
181
+ 200
182
+
183
+ Raises:
184
+ ApiError: A custom exception class that provides additional context
185
+ for API errors, including the HTTP status code and response body.
186
+
187
+ Examples:
188
+ ```py
189
+ client.v1.face_detection.create(
190
+ assets={"target_file_path": "api-assets/id/1234.png"}, confidence_score=0.5
191
+ )
192
+ ```
193
+ """
194
+ _json = to_encodable(
195
+ item={"confidence_score": confidence_score, "assets": assets},
196
+ dump_with=params._SerializerV1FaceDetectionCreateBody,
197
+ )
198
+ return self._base_client.request(
199
+ method="POST",
200
+ path="/v1/face-detection",
201
+ auth_names=["bearerAuth"],
202
+ json=_json,
203
+ cast_to=models.V1FaceDetectionCreateResponse,
204
+ request_options=request_options or default_request_options(),
205
+ )
206
+
207
+
208
+ class AsyncFaceDetectionClient:
209
+ def __init__(self, *, base_client: AsyncBaseClient):
210
+ self._base_client = base_client
211
+
212
+ async def generate(
213
+ self,
214
+ *,
215
+ assets: params.V1FaceDetectionCreateBodyAssets,
216
+ confidence_score: typing.Union[
217
+ typing.Optional[float], type_utils.NotGiven
218
+ ] = type_utils.NOT_GIVEN,
219
+ wait_for_completion: bool = True,
220
+ download_outputs: bool = True,
221
+ download_directory: typing.Optional[str] = None,
222
+ request_options: typing.Optional[RequestOptions] = None,
223
+ ) -> V1FaceDetectionGetResponseWithDownloads:
224
+ """
225
+ Generate face detection results with optional waiting and downloading.
226
+
227
+ This method creates a face detection task and optionally waits for completion
228
+ and downloads the detected face images.
229
+
230
+ Args:
231
+ assets: Provide the assets for face detection
232
+ confidence_score: Confidence threshold for filtering detected faces
233
+ wait_for_completion: Whether to wait for the face detection task to complete
234
+ download_outputs: Whether to download the detected face images
235
+ download_directory: The directory to download the face images to. If not provided,
236
+ the images will be downloaded to the current working directory
237
+ request_options: Additional options to customize the HTTP request
238
+
239
+ Returns:
240
+ V1FaceDetectionGetResponseWithDownloads: The face detection response with optional
241
+ downloaded face image paths included
242
+ """
243
+ # Handle file upload if needed
244
+ file_client = AsyncFilesClient(base_client=self._base_client)
245
+ target_file_path = assets["target_file_path"]
246
+ assets["target_file_path"] = await file_client.upload_file(
247
+ file=target_file_path
248
+ )
249
+
250
+ create_response = await self.create(
251
+ assets=assets,
252
+ confidence_score=confidence_score,
253
+ request_options=request_options,
254
+ )
255
+
256
+ task_id = create_response.id
257
+
258
+ api_response = await self.get(id=task_id)
259
+ if not wait_for_completion:
260
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
261
+
262
+ poll_interval = float(os.getenv("MAGIC_HOUR_POLL_INTERVAL", "0.5"))
263
+
264
+ while api_response.status not in ["complete", "error"]:
265
+ api_response = await self.get(id=task_id)
266
+ await asyncio.sleep(poll_interval)
267
+
268
+ if api_response.status != "complete":
269
+ log = logger.error if api_response.status == "error" else logger.info
270
+ log(f"Face detection {task_id} has status {api_response.status}")
271
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
272
+
273
+ if not download_outputs or not api_response.faces:
274
+ return V1FaceDetectionGetResponseWithDownloads(**api_response.model_dump())
275
+
276
+ face_downloads = [
277
+ models.V1ImageProjectsGetResponseDownloadsItem(
278
+ url=face.url,
279
+ expires_at="ignore",
280
+ )
281
+ for face in api_response.faces
282
+ ]
283
+ downloaded_paths = await download_files_async(
284
+ downloads=face_downloads,
285
+ download_directory=download_directory,
286
+ )
287
+
288
+ return V1FaceDetectionGetResponseWithDownloads(
289
+ **api_response.model_dump(), downloaded_paths=downloaded_paths
290
+ )
291
+
292
+ async def get(
293
+ self, *, id: str, request_options: typing.Optional[RequestOptions] = None
294
+ ) -> models.V1FaceDetectionGetResponse:
295
+ """
296
+ Get face detection details
297
+
298
+ Get the details of a face detection task.
299
+
300
+ Use this API to get the list of faces detected in the image or video to use in the [face swap photo](/api-reference/face-swap-photo/face-swap-photo) or [face swap video](/api-reference/face-swap/face-swap-video) API calls for multi-face swaps.
301
+
302
+ GET /v1/face-detection/{id}
303
+
304
+ Args:
305
+ id: The id of the task. This value is returned by the [face detection API](/api-reference/files/face-detection#response-id).
306
+ request_options: Additional options to customize the HTTP request
307
+
308
+ Returns:
309
+ 200
310
+
311
+ Raises:
312
+ ApiError: A custom exception class that provides additional context
313
+ for API errors, including the HTTP status code and response body.
314
+
315
+ Examples:
316
+ ```py
317
+ await client.v1.face_detection.get(id="uuid-example")
318
+ ```
319
+ """
320
+ return await self._base_client.request(
321
+ method="GET",
322
+ path=f"/v1/face-detection/{id}",
323
+ auth_names=["bearerAuth"],
324
+ cast_to=models.V1FaceDetectionGetResponse,
325
+ request_options=request_options or default_request_options(),
326
+ )
327
+
328
+ async def create(
329
+ self,
330
+ *,
331
+ assets: params.V1FaceDetectionCreateBodyAssets,
332
+ confidence_score: typing.Union[
333
+ typing.Optional[float], type_utils.NotGiven
334
+ ] = type_utils.NOT_GIVEN,
335
+ request_options: typing.Optional[RequestOptions] = None,
336
+ ) -> models.V1FaceDetectionCreateResponse:
337
+ """
338
+ Face Detection
339
+
340
+ Detect faces in an image or video.
341
+
342
+ Use this API to get the list of faces detected in the image or video to use in the [face swap photo](/api-reference/face-swap-photo/face-swap-photo) or [face swap video](/api-reference/face-swap/face-swap-video) API calls for multi-face swaps.
343
+
344
+ Note: Face detection is free to use for the near future. Pricing may change in the future.
345
+
346
+ POST /v1/face-detection
347
+
348
+ Args:
349
+ confidence_score: Confidence threshold for filtering detected faces.
350
+ * Higher values (e.g., 0.9) include only faces detected with high certainty, reducing false positives.
351
+ * Lower values (e.g., 0.3) include more faces, but may increase the chance of incorrect detections.
352
+ assets: Provide the assets for face detection
353
+ request_options: Additional options to customize the HTTP request
354
+
355
+ Returns:
356
+ 200
357
+
358
+ Raises:
359
+ ApiError: A custom exception class that provides additional context
360
+ for API errors, including the HTTP status code and response body.
361
+
362
+ Examples:
363
+ ```py
364
+ await client.v1.face_detection.create(
365
+ assets={"target_file_path": "api-assets/id/1234.png"}, confidence_score=0.5
366
+ )
367
+ ```
368
+ """
369
+ _json = to_encodable(
370
+ item={"confidence_score": confidence_score, "assets": assets},
371
+ dump_with=params._SerializerV1FaceDetectionCreateBody,
372
+ )
373
+ return await self._base_client.request(
374
+ method="POST",
375
+ path="/v1/face-detection",
376
+ auth_names=["bearerAuth"],
377
+ json=_json,
378
+ cast_to=models.V1FaceDetectionCreateResponse,
379
+ request_options=request_options or default_request_options(),
380
+ )
@@ -1,14 +1,118 @@
1
+ # v1.face_swap
1
2
 
2
- ### create <a name="create"></a>
3
- Face Swap video
3
+ ## Module Functions
4
+
5
+ <!-- CUSTOM DOCS START -->
6
+
7
+ ### Face Swap Generate Workflow <a name="generate"></a>
8
+
9
+ The workflow performs the following action
10
+
11
+ 1. upload local assets to Magic Hour storage. So you can pass in a local path instead of having to upload files yourself
12
+ 2. trigger a generation
13
+ 3. poll for a completion status. This is configurable
14
+ 4. if success, download the output to local directory
15
+
16
+ > [!TIP]
17
+ > This is the recommended way to use the SDK unless you have specific needs where it is necessary to split up the actions.
18
+
19
+ #### Parameters
20
+
21
+ In Additional to the parameters listed in the `.create` section below, `.generate` introduces 3 new parameters:
22
+
23
+ - `wait_for_completion` (bool, default True): Whether to wait for the project to complete.
24
+ - `download_outputs` (bool, default True): Whether to download the generated files
25
+ - `download_directory` (str, optional): Directory to save downloaded files (defaults to current directory)
26
+
27
+ #### Synchronous Client
28
+
29
+ ```python
30
+ from magic_hour import Client
31
+ from os import getenv
32
+
33
+ client = Client(token=getenv("API_TOKEN"))
34
+ res = client.v1.face_swap.generate(
35
+ assets={
36
+ "face_mappings": [
37
+ {
38
+ "new_face": "/path/to/1234.png",
39
+ "original_face": "api-assets/id/0-0.png",
40
+ }
41
+ ],
42
+ "face_swap_mode": "all-faces",
43
+ "image_file_path": "image/id/1234.png",
44
+ "video_file_path": "/path/to/1234.mp4",
45
+ "video_source": "file",
46
+ },
47
+ end_seconds=15.0,
48
+ start_seconds=0.0,
49
+ name="Face Swap video",
50
+ style={"version": "default"},
51
+ wait_for_completion=True,
52
+ download_outputs=True,
53
+ download_directory="outputs"
54
+ )
55
+ ```
56
+
57
+ #### Asynchronous Client
58
+
59
+ ```python
60
+ from magic_hour import AsyncClient
61
+ from os import getenv
62
+
63
+ client = AsyncClient(token=getenv("API_TOKEN"))
64
+ res = await client.v1.face_swap.generate(
65
+ assets={
66
+ "face_mappings": [
67
+ {
68
+ "new_face": "/path/to/1234.png",
69
+ "original_face": "api-assets/id/0-0.png",
70
+ }
71
+ ],
72
+ "face_swap_mode": "all-faces",
73
+ "image_file_path": "image/id/1234.png",
74
+ "video_file_path": "/path/to/1234.mp4",
75
+ "video_source": "file",
76
+ },
77
+ end_seconds=15.0,
78
+ start_seconds=0.0,
79
+ name="Face Swap video",
80
+ style={"version": "default"},
81
+ wait_for_completion=True,
82
+ download_outputs=True,
83
+ download_directory="outputs"
84
+ )
85
+ ```
86
+
87
+ <!-- CUSTOM DOCS END -->
88
+
89
+ ### Face Swap Video <a name="create"></a>
4
90
 
5
91
  Create a Face Swap video. The estimated frame cost is calculated using 30 FPS. This amount is deducted from your account balance when a video is queued. Once the video is complete, the cost will be updated based on the actual number of frames rendered.
6
-
7
- Get more information about this mode at our [product page](/products/face-swap).
8
-
92
+
93
+ Get more information about this mode at our [product page](https://magichour.ai/products/face-swap).
9
94
 
10
95
  **API Endpoint**: `POST /v1/face-swap`
11
96
 
97
+ #### Parameters
98
+
99
+ | Parameter | Required | Deprecated | Description | Example |
100
+ | -------------------- | :------: | :--------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
101
+ | `assets` | ✓ | ✗ | Provide the assets for face swap. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used | `{"face_mappings": [{"new_face": "api-assets/id/1234.png", "original_face": "api-assets/id/0-0.png"}], "face_swap_mode": "all-faces", "image_file_path": "image/id/1234.png", "video_file_path": "api-assets/id/1234.mp4", "video_source": "file"}` |
102
+ | `└─ face_mappings` | ✗ | — | This is the array of face mappings used for multiple face swap. The value is required if `face_swap_mode` is `individual-faces`. | `[{"new_face": "api-assets/id/1234.png", "original_face": "api-assets/id/0-0.png"}]` |
103
+ | `└─ face_swap_mode` | ✗ | — | The mode of face swap. * `all-faces` - Swap all faces in the target image or video. `source_file_path` is required. * `individual-faces` - Swap individual faces in the target image or video. `source_faces` is required. | `"all-faces"` |
104
+ | `└─ image_file_path` | ✗ | — | The path of the input image with the face to be swapped. The value is required if `face_swap_mode` is `all-faces`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). Please refer to the [Input File documentation](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) to learn more. | `"image/id/1234.png"` |
105
+ | `└─ video_file_path` | ✗ | — | Required if `video_source` is `file`. This value is either - a direct URL to the video file - `file_path` field from the response of the [upload urls API](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls). Please refer to the [Input File documentation](https://docs.magichour.ai/api-reference/files/generate-asset-upload-urls#input-file) to learn more. | `"api-assets/id/1234.mp4"` |
106
+ | `└─ video_source` | ✓ | — | | `"file"` |
107
+ | `└─ youtube_url` | ✗ | — | Using a youtube video as the input source. This field is required if `video_source` is `youtube` | `"http://www.example.com"` |
108
+ | `end_seconds` | ✓ | ✗ | The end time of the input video in seconds. This value is used to trim the input video. The value must be greater than 0.1, and more than the start_seconds. | `15.0` |
109
+ | `start_seconds` | ✓ | ✗ | The start time of the input video in seconds. This value is used to trim the input video. The value must be greater than 0. | `0.0` |
110
+ | `height` | ✗ | ✓ | `height` is deprecated and no longer influences the output video's resolution. Output resolution is determined by the **minimum** of: - The resolution of the input video - The maximum resolution allowed by your subscription tier. See our [pricing page](https://magichour.ai/pricing) for more details. This field is retained only for backward compatibility and will be removed in a future release. | `123` |
111
+ | `name` | ✗ | ✗ | The name of video. This value is mainly used for your own identification of the video. | `"Face Swap video"` |
112
+ | `style` | ✗ | ✗ | Style of the face swap video. | `{"version": "default"}` |
113
+ | `└─ version` | ✗ | — | * `v1` - May preserve skin detail and texture better, but weaker identity preservation. * `v2` - Faster, sharper, better handling of hair and glasses. stronger identity preservation. * `default` - Use the version we recommend, which will change over time. This is recommended unless you need a specific earlier version. This is the default behavior. | `"default"` |
114
+ | `width` | ✗ | ✓ | `width` is deprecated and no longer influences the output video's resolution. Output resolution is determined by the **minimum** of: - The resolution of the input video - The maximum resolution allowed by your subscription tier. See our [pricing page](https://magichour.ai/pricing) for more details. This field is retained only for backward compatibility and will be removed in a future release. | `123` |
115
+
12
116
  #### Synchronous Client
13
117
 
14
118
  ```python
@@ -18,15 +122,21 @@ from os import getenv
18
122
  client = Client(token=getenv("API_TOKEN"))
19
123
  res = client.v1.face_swap.create(
20
124
  assets={
125
+ "face_mappings": [
126
+ {
127
+ "new_face": "api-assets/id/1234.png",
128
+ "original_face": "api-assets/id/0-0.png",
129
+ }
130
+ ],
131
+ "face_swap_mode": "all-faces",
21
132
  "image_file_path": "image/id/1234.png",
22
133
  "video_file_path": "api-assets/id/1234.mp4",
23
134
  "video_source": "file",
24
135
  },
25
136
  end_seconds=15.0,
26
- height=960,
27
137
  start_seconds=0.0,
28
- width=512,
29
138
  name="Face Swap video",
139
+ style={"version": "default"},
30
140
  )
31
141
  ```
32
142
 
@@ -39,14 +149,32 @@ from os import getenv
39
149
  client = AsyncClient(token=getenv("API_TOKEN"))
40
150
  res = await client.v1.face_swap.create(
41
151
  assets={
152
+ "face_mappings": [
153
+ {
154
+ "new_face": "api-assets/id/1234.png",
155
+ "original_face": "api-assets/id/0-0.png",
156
+ }
157
+ ],
158
+ "face_swap_mode": "all-faces",
42
159
  "image_file_path": "image/id/1234.png",
43
160
  "video_file_path": "api-assets/id/1234.mp4",
44
161
  "video_source": "file",
45
162
  },
46
163
  end_seconds=15.0,
47
- height=960,
48
164
  start_seconds=0.0,
49
- width=512,
50
165
  name="Face Swap video",
166
+ style={"version": "default"},
51
167
  )
52
168
  ```
169
+
170
+ #### Response
171
+
172
+ ##### Type
173
+
174
+ [V1FaceSwapCreateResponse](/magic_hour/types/models/v1_face_swap_create_response.py)
175
+
176
+ ##### Example
177
+
178
+ ```python
179
+ {"credits_charged": 450, "estimated_frame_cost": 450, "id": "cuid-example"}
180
+ ```