This is the main endpoint that calls the TinyAgent to generate a response to the given query.
(request: TinyAgentRequest)
| 59 | |
| 60 | @app.post("/generate") |
| 61 | async def execute_command(request: TinyAgentRequest) -> StreamingResponse: |
| 62 | """ |
| 63 | This is the main endpoint that calls the TinyAgent to generate a response to the given query. |
| 64 | """ |
| 65 | log(f"\n\n====\nReceived request: {request.query}") |
| 66 | |
| 67 | # First, ensure the queue is empty |
| 68 | empty_queue(streaming_queue) |
| 69 | |
| 70 | query = request.query |
| 71 | |
| 72 | if not query or len(query) <= 0: |
| 73 | raise HTTPException( |
| 74 | status_code=HTTPStatus.BAD_REQUEST, detail="No query provided" |
| 75 | ) |
| 76 | |
| 77 | try: |
| 78 | tiny_agent_config = get_tiny_agent_config(config_path=CONFIG_PATH) |
| 79 | tiny_agent = TinyAgent(tiny_agent_config) |
| 80 | except Exception as e: |
| 81 | raise HTTPException( |
| 82 | status_code=HTTPStatus.INTERNAL_SERVER_ERROR, |
| 83 | detail=f"Error: {e}", |
| 84 | ) |
| 85 | |
| 86 | async def generate(): |
| 87 | try: |
| 88 | response_task = asyncio.create_task(tiny_agent.arun(query)) |
| 89 | |
| 90 | while True: |
| 91 | # Await a small timeout to periodically check if the task is done |
| 92 | try: |
| 93 | token = await asyncio.wait_for(streaming_queue.get(), timeout=1.0) |
| 94 | if token is None: |
| 95 | break |
| 96 | if token.startswith(LLM_ERROR_TOKEN): |
| 97 | raise Exception(token[len(LLM_ERROR_TOKEN) :]) |
| 98 | yield token |
| 99 | except asyncio.TimeoutError: |
| 100 | pass # No new token, check task status |
| 101 | |
| 102 | # Check if the task is done to handle any potential exception |
| 103 | if response_task.done(): |
| 104 | break |
| 105 | |
| 106 | # Task created with asyncio.create_task() do not propagate exceptions |
| 107 | # to the calling context. Instead, the exception remains encapsulated within |
| 108 | # the task object itself until the task is awaited or its result is explicitly retrieved. |
| 109 | # Hence, we check here if the task has an exception set by awaiting it, which will |
| 110 | # raise the exception if it exists. If it doesn't, we just yield the result. |
| 111 | await response_task |
| 112 | response = response_task.result() |
| 113 | yield f"\n\n{response}" |
| 114 | except Exception as e: |
| 115 | # You cannot raise HTTPExceptions in an async generator, it doesn't |
| 116 | # get caught by the FastAPI exception handling middleware. Hence, |
| 117 | # we are manually catching the exceptions and yielding/logging them. |
| 118 | yield f"Error: {e}" |
nothing calls this directly
no test coverage detected