22import time
33import json
44import logging
5- from typing import Callable , Generator , Optional , Any
5+ from typing import Callable , Generator , Optional
66from pydantic import BaseModel
7-
87import typer
9- from fastapi import APIRouter , HTTPException , Query
8+ from fastapi import APIRouter , HTTPException
109from fastapi .responses import StreamingResponse
1110from makefun import with_signature
1211from rb .lib .stdout import Capturing # type: ignore
2120 BatchTextResponse ,
2221 BatchDirectoryResponse ,
2322)
24-
23+ from rb . api . models import API_APPMETDATA , API_ROUTES , PLUGIN_SCHEMA_SUFFIX
2524from rescuebox .main import app as rescuebox_app
26-
2725logging .basicConfig (level = logging .DEBUG )
2826logger = logging .getLogger (__name__ )
2927
30- cli_router = APIRouter ()
28+ cli_to_api_router = APIRouter ()
3129
3230
3331def static_endpoint (callback : Callable , * args , ** kwargs ) -> ResponseBody :
@@ -36,14 +34,24 @@ def static_endpoint(callback: Callable, *args, **kwargs) -> ResponseBody:
3634 try :
3735 logger .debug (f"Executing CLI command: { callback .__name__ } with args={ args } , kwargs={ kwargs } " )
3836 result = callback (* args , ** kwargs ) # Ensure this returns a valid Pydantic model
39- logger .debug (f"CLI command output: { result } " )
37+
38+ logger .debug (f"CLI command output type: { type (result )} " )
4039
41- if isinstance (result , BaseModel ): # Ensure it's a valid Pydantic model
40+ if isinstance (result , ResponseBody ): # Ensure it's a valid Pydantic model
41+ return result
42+ if isinstance (result , BaseModel ): # Ensure it's a valid Pydantic model , not sure if this is needed for desktop calls
4243 return ResponseBody (root = result )
44+ if isinstance (result , dict ): # or Ensure it's a valid dict model for desktop app metadata call to work
45+ return result
46+ if isinstance (result , list ): # or Ensure it's a valid str model for routes call
47+ return result
48+ if isinstance (result , str ): # or Ensure it's a valid str model for routes call
49+ return ResponseBody (root = TextResponse (value = result ))
50+ # this has an issue of nor sending back details to desktop ui the api caller ?
4351 raise ValueError (f"Invalid return type from Typer command: { type (result )} " )
4452 except Exception as e :
45- logger .error (f "Error executing CLI command: { e } " )
46- raise HTTPException (
53+ logger .error ("Error executing CLI command: %s" , e )
54+ raise HTTPException ( # pylint: disable=raise-missing-from
4755 status_code = 400 ,
4856 detail = {"error" : f"Typer CLI aborted { e } " , "stdout" : stdout [- 10 :]},
4957 )
@@ -52,7 +60,7 @@ def static_endpoint(callback: Callable, *args, **kwargs) -> ResponseBody:
5260def streaming_endpoint (callback : Callable , * args , ** kwargs ) -> Generator :
5361 """Execute a CLI command and stream the results with proper response handling"""
5462
55- logger .debug (f"🚀 Streaming started for command: { callback .__name__ } with args={ args } , kwargs={ kwargs } " )
63+ logger .debug (f"🚀Streaming started for command: { callback .__name__ } with args={ args } , kwargs={ kwargs } " )
5664
5765 for line in capture_stdout_as_generator (callback , * args , ** kwargs ):
5866 try :
@@ -96,20 +104,11 @@ def streaming_endpoint(callback: Callable, *args, **kwargs) -> Generator:
96104 time .sleep (0.01 )
97105
98106
99-
100107def command_callback (command : typer .models .CommandInfo ):
101108 """Create a FastAPI endpoint handler for a Typer CLI command with `ResponseBody`"""
102109
103110 original_signature = inspect .signature (command .callback )
104- new_params = []
105-
106- # Convert Typer CLI arguments to FastAPI-compatible query/body parameters
107- for param in original_signature .parameters .values ():
108- if param .default is inspect .Parameter .empty : # Required argument
109- param = param .replace (default = Query (..., description = f"Required parameter { param .name } " ))
110- elif param .default is Ellipsis : # Typer required argument
111- param = param .replace (default = Query (..., description = f"Required parameter { param .name } " ))
112- new_params .append (param )
111+ new_params = list (original_signature .parameters .values ())
113112
114113 streaming_param = inspect .Parameter (
115114 "streaming" ,
@@ -144,14 +143,30 @@ def wrapper(*args, **kwargs) -> ResponseBody:
144143 router = APIRouter ()
145144
146145 for command in plugin .typer_instance .registered_commands :
147- logger .debug (f"Registering FastAPI route for CLI command: { command .callback .__name__ } " )
148146
149- router .add_api_route (
150- f"/{ command .callback .__name__ } " ,
151- endpoint = command_callback (command ),
152- methods = ["POST" ],
153- name = command .callback .__name__ ,
154- response_model = ResponseBody ,
155- )
156-
157- cli_router .include_router (router , prefix = f"/{ plugin .name } " , tags = [plugin .name ])
147+
148+ if command .name and (command .name == API_APPMETDATA or
149+ command .name == API_ROUTES or
150+ command .name .endswith (PLUGIN_SCHEMA_SUFFIX )):
151+ logger .debug (f'plugin command name is { command .name } ' )
152+ router .add_api_route (
153+ f"/{ command .callback .__name__ } " ,
154+ endpoint = command_callback (command ),
155+ methods = ["GET" ],
156+ name = command .callback .__name__ ,
157+ )
158+ # FIXME: prefix /api to make desktop call happy for now , eventually this will go away
159+ # GOAL : /audio/routes is valid /api/routes should no longer work
160+ cli_to_api_router .include_router (router ,prefix = f'/api' , tags = [plugin .name ])
161+
162+ logger .debug (f"Registering FastAPI route for { plugin .name } desktop call: { command .callback .__name__ } " )
163+ else :
164+ router .add_api_route (
165+ f"/{ command .callback .__name__ } " ,
166+ endpoint = command_callback (command ),
167+ methods = ["POST" ],
168+ name = command .callback .__name__ ,
169+ response_model = ResponseBody ,
170+ )
171+ logger .debug (f"Registering FastAPI route for { plugin .name } command: { command .callback .__name__ } " )
172+ cli_to_api_router .include_router (router , prefix = f"/{ plugin .name } " , tags = [plugin .name ])
0 commit comments