77
88from io import BytesIO
99import logging
10- from typing import Optional , TypeVar
10+ from typing import Optional
1111
1212import torch
1313
1414from typing_extensions import override
1515from comfy_api .latest import ComfyExtension , IO
1616from comfy_api .input_impl .video_types import VideoCodec , VideoContainer , VideoInput
17- from comfy_api_nodes .apis import pika_defs
18- from comfy_api_nodes .apis .client import (
17+ from comfy_api_nodes .apis import pika_api as pika_defs
18+ from comfy_api_nodes .util import (
19+ validate_string ,
20+ download_url_to_video_output ,
21+ tensor_to_bytesio ,
1922 ApiEndpoint ,
20- EmptyRequest ,
21- HttpMethod ,
22- PollingOperation ,
23- SynchronousOperation ,
23+ sync_op ,
24+ poll_op ,
2425)
25- from comfy_api_nodes .util import validate_string , download_url_to_video_output , tensor_to_bytesio
2626
27- R = TypeVar ("R" )
2827
2928PATH_PIKADDITIONS = "/proxy/pika/generate/pikadditions"
3029PATH_PIKASWAPS = "/proxy/pika/generate/pikaswaps"
4039
4140
4241async def execute_task (
43- initial_operation : SynchronousOperation [R , pika_defs .PikaGenerateResponse ],
44- auth_kwargs : Optional [dict [str , str ]] = None ,
45- node_id : Optional [str ] = None ,
42+ task_id : str ,
43+ cls : type [IO .ComfyNode ],
4644) -> IO .NodeOutput :
47- task_id = (await initial_operation .execute ()).video_id
48- final_response : pika_defs .PikaVideoResponse = await PollingOperation (
49- poll_endpoint = ApiEndpoint (
50- path = f"{ PATH_VIDEO_GET } /{ task_id } " ,
51- method = HttpMethod .GET ,
52- request_model = EmptyRequest ,
53- response_model = pika_defs .PikaVideoResponse ,
54- ),
55- completed_statuses = ["finished" ],
56- failed_statuses = ["failed" , "cancelled" ],
45+ final_response : pika_defs .PikaVideoResponse = await poll_op (
46+ cls ,
47+ ApiEndpoint (path = f"{ PATH_VIDEO_GET } /{ task_id } " ),
48+ response_model = pika_defs .PikaVideoResponse ,
5749 status_extractor = lambda response : (response .status .value if response .status else None ),
5850 progress_extractor = lambda response : (response .progress if hasattr (response , "progress" ) else None ),
59- auth_kwargs = auth_kwargs ,
60- result_url_extractor = lambda response : (response .url if hasattr (response , "url" ) else None ),
61- node_id = node_id ,
6251 estimated_duration = 60 ,
6352 max_poll_attempts = 240 ,
64- ). execute ()
53+ )
6554 if not final_response .url :
6655 error_msg = f"Pika task { task_id } succeeded but no video data found in response:\n { final_response } "
6756 logging .error (error_msg )
@@ -124,23 +113,15 @@ async def execute(
124113 resolution = resolution ,
125114 duration = duration ,
126115 )
127- auth = {
128- "auth_token" : cls .hidden .auth_token_comfy_org ,
129- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
130- }
131- initial_operation = SynchronousOperation (
132- endpoint = ApiEndpoint (
133- path = PATH_IMAGE_TO_VIDEO ,
134- method = HttpMethod .POST ,
135- request_model = pika_defs .PikaBodyGenerate22I2vGenerate22I2vPost ,
136- response_model = pika_defs .PikaGenerateResponse ,
137- ),
138- request = pika_request_data ,
116+ initial_operation = await sync_op (
117+ cls ,
118+ ApiEndpoint (path = PATH_IMAGE_TO_VIDEO , method = "POST" ),
119+ response_model = pika_defs .PikaGenerateResponse ,
120+ data = pika_request_data ,
139121 files = pika_files ,
140122 content_type = "multipart/form-data" ,
141- auth_kwargs = auth ,
142123 )
143- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
124+ return await execute_task (initial_operation . video_id , cls )
144125
145126
146127class PikaTextToVideoNode (IO .ComfyNode ):
@@ -183,29 +164,21 @@ async def execute(
183164 duration : int ,
184165 aspect_ratio : float ,
185166 ) -> IO .NodeOutput :
186- auth = {
187- "auth_token" : cls .hidden .auth_token_comfy_org ,
188- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
189- }
190- initial_operation = SynchronousOperation (
191- endpoint = ApiEndpoint (
192- path = PATH_TEXT_TO_VIDEO ,
193- method = HttpMethod .POST ,
194- request_model = pika_defs .PikaBodyGenerate22T2vGenerate22T2vPost ,
195- response_model = pika_defs .PikaGenerateResponse ,
196- ),
197- request = pika_defs .PikaBodyGenerate22T2vGenerate22T2vPost (
167+ initial_operation = await sync_op (
168+ cls ,
169+ ApiEndpoint (path = PATH_TEXT_TO_VIDEO , method = "POST" ),
170+ response_model = pika_defs .PikaGenerateResponse ,
171+ data = pika_defs .PikaBodyGenerate22T2vGenerate22T2vPost (
198172 promptText = prompt_text ,
199173 negativePrompt = negative_prompt ,
200174 seed = seed ,
201175 resolution = resolution ,
202176 duration = duration ,
203177 aspectRatio = aspect_ratio ,
204178 ),
205- auth_kwargs = auth ,
206179 content_type = "application/x-www-form-urlencoded" ,
207180 )
208- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
181+ return await execute_task (initial_operation . video_id , cls )
209182
210183
211184class PikaScenes (IO .ComfyNode ):
@@ -309,24 +282,16 @@ async def execute(
309282 duration = duration ,
310283 aspectRatio = aspect_ratio ,
311284 )
312- auth = {
313- "auth_token" : cls .hidden .auth_token_comfy_org ,
314- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
315- }
316- initial_operation = SynchronousOperation (
317- endpoint = ApiEndpoint (
318- path = PATH_PIKASCENES ,
319- method = HttpMethod .POST ,
320- request_model = pika_defs .PikaBodyGenerate22C2vGenerate22PikascenesPost ,
321- response_model = pika_defs .PikaGenerateResponse ,
322- ),
323- request = pika_request_data ,
285+ initial_operation = await sync_op (
286+ cls ,
287+ ApiEndpoint (path = PATH_PIKASCENES , method = "POST" ),
288+ response_model = pika_defs .PikaGenerateResponse ,
289+ data = pika_request_data ,
324290 files = pika_files ,
325291 content_type = "multipart/form-data" ,
326- auth_kwargs = auth ,
327292 )
328293
329- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
294+ return await execute_task (initial_operation . video_id , cls )
330295
331296
332297class PikAdditionsNode (IO .ComfyNode ):
@@ -383,24 +348,16 @@ async def execute(
383348 negativePrompt = negative_prompt ,
384349 seed = seed ,
385350 )
386- auth = {
387- "auth_token" : cls .hidden .auth_token_comfy_org ,
388- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
389- }
390- initial_operation = SynchronousOperation (
391- endpoint = ApiEndpoint (
392- path = PATH_PIKADDITIONS ,
393- method = HttpMethod .POST ,
394- request_model = pika_defs .PikaBodyGeneratePikadditionsGeneratePikadditionsPost ,
395- response_model = pika_defs .PikaGenerateResponse ,
396- ),
397- request = pika_request_data ,
351+ initial_operation = await sync_op (
352+ cls ,
353+ ApiEndpoint (path = PATH_PIKADDITIONS , method = "POST" ),
354+ response_model = pika_defs .PikaGenerateResponse ,
355+ data = pika_request_data ,
398356 files = pika_files ,
399357 content_type = "multipart/form-data" ,
400- auth_kwargs = auth ,
401358 )
402359
403- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
360+ return await execute_task (initial_operation . video_id , cls )
404361
405362
406363class PikaSwapsNode (IO .ComfyNode ):
@@ -472,23 +429,15 @@ async def execute(
472429 seed = seed ,
473430 modifyRegionRoi = region_to_modify if region_to_modify else None ,
474431 )
475- auth = {
476- "auth_token" : cls .hidden .auth_token_comfy_org ,
477- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
478- }
479- initial_operation = SynchronousOperation (
480- endpoint = ApiEndpoint (
481- path = PATH_PIKASWAPS ,
482- method = HttpMethod .POST ,
483- request_model = pika_defs .PikaBodyGeneratePikaswapsGeneratePikaswapsPost ,
484- response_model = pika_defs .PikaGenerateResponse ,
485- ),
486- request = pika_request_data ,
432+ initial_operation = await sync_op (
433+ cls ,
434+ ApiEndpoint (path = PATH_PIKASWAPS , method = "POST" ),
435+ response_model = pika_defs .PikaGenerateResponse ,
436+ data = pika_request_data ,
487437 files = pika_files ,
488438 content_type = "multipart/form-data" ,
489- auth_kwargs = auth ,
490439 )
491- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
440+ return await execute_task (initial_operation . video_id , cls )
492441
493442
494443class PikaffectsNode (IO .ComfyNode ):
@@ -528,28 +477,20 @@ async def execute(
528477 negative_prompt : str ,
529478 seed : int ,
530479 ) -> IO .NodeOutput :
531- auth = {
532- "auth_token" : cls .hidden .auth_token_comfy_org ,
533- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
534- }
535- initial_operation = SynchronousOperation (
536- endpoint = ApiEndpoint (
537- path = PATH_PIKAFFECTS ,
538- method = HttpMethod .POST ,
539- request_model = pika_defs .PikaBodyGeneratePikaffectsGeneratePikaffectsPost ,
540- response_model = pika_defs .PikaGenerateResponse ,
541- ),
542- request = pika_defs .PikaBodyGeneratePikaffectsGeneratePikaffectsPost (
480+ initial_operation = await sync_op (
481+ cls ,
482+ ApiEndpoint (path = PATH_PIKAFFECTS , method = "POST" ),
483+ response_model = pika_defs .PikaGenerateResponse ,
484+ data = pika_defs .PikaBodyGeneratePikaffectsGeneratePikaffectsPost (
543485 pikaffect = pikaffect ,
544486 promptText = prompt_text ,
545487 negativePrompt = negative_prompt ,
546488 seed = seed ,
547489 ),
548490 files = {"image" : ("image.png" , tensor_to_bytesio (image ), "image/png" )},
549491 content_type = "multipart/form-data" ,
550- auth_kwargs = auth ,
551492 )
552- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
493+ return await execute_task (initial_operation . video_id , cls )
553494
554495
555496class PikaStartEndFrameNode (IO .ComfyNode ):
@@ -592,18 +533,11 @@ async def execute(
592533 ("keyFrames" , ("image_start.png" , tensor_to_bytesio (image_start ), "image/png" )),
593534 ("keyFrames" , ("image_end.png" , tensor_to_bytesio (image_end ), "image/png" )),
594535 ]
595- auth = {
596- "auth_token" : cls .hidden .auth_token_comfy_org ,
597- "comfy_api_key" : cls .hidden .api_key_comfy_org ,
598- }
599- initial_operation = SynchronousOperation (
600- endpoint = ApiEndpoint (
601- path = PATH_PIKAFRAMES ,
602- method = HttpMethod .POST ,
603- request_model = pika_defs .PikaBodyGenerate22KeyframeGenerate22PikaframesPost ,
604- response_model = pika_defs .PikaGenerateResponse ,
605- ),
606- request = pika_defs .PikaBodyGenerate22KeyframeGenerate22PikaframesPost (
536+ initial_operation = await sync_op (
537+ cls ,
538+ ApiEndpoint (path = PATH_PIKAFRAMES , method = "POST" ),
539+ response_model = pika_defs .PikaGenerateResponse ,
540+ data = pika_defs .PikaBodyGenerate22KeyframeGenerate22PikaframesPost (
607541 promptText = prompt_text ,
608542 negativePrompt = negative_prompt ,
609543 seed = seed ,
@@ -612,9 +546,8 @@ async def execute(
612546 ),
613547 files = pika_files ,
614548 content_type = "multipart/form-data" ,
615- auth_kwargs = auth ,
616549 )
617- return await execute_task (initial_operation , auth_kwargs = auth , node_id = cls . hidden . unique_id )
550+ return await execute_task (initial_operation . video_id , cls )
618551
619552
620553class PikaApiNodesExtension (ComfyExtension ):
0 commit comments