Skip to content

Commit

Permalink
Merge pull request #466 from solliancenet/kb-python-api-optimizations
Browse files Browse the repository at this point in the history
Python API performance optimizations
  • Loading branch information
ciprianjichici authored Jan 15, 2024
2 parents 6222dc1 + a067667 commit febb77d
Show file tree
Hide file tree
Showing 31 changed files with 197 additions and 115 deletions.
4 changes: 2 additions & 2 deletions src/python/AgentHubAPI/AgentHubAPI.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>865a944e-76c4-4da9-b367-6d1cab66abcc</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>app/main.py</StartupFile>
<StartupFile>run.py</StartupFile>
<SearchPath>..\PythonSDK</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<LaunchProvider>Standard Python launcher</LaunchProvider>
Expand Down Expand Up @@ -34,12 +34,12 @@
<Compile Include="app\routers\status.py" />
<Compile Include="app\routers\__init__.py" />
<Compile Include="app\__init__.py" />
<Compile Include="run.py" />
</ItemGroup>
<ItemGroup>
<Content Include=".gitignore" />
<Content Include=".pylintrc" />
<Content Include="requirements.txt" />
<Content Include="startup.sh" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PythonSDK\PythonSDK.pyproj">
Expand Down
21 changes: 12 additions & 9 deletions src/python/AgentHubAPI/app/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Provides dependencies for API calls.
"""
import logging
import time
from typing import Annotated
from fastapi import Depends, HTTPException
from fastapi.security import APIKeyHeader
Expand All @@ -18,17 +19,20 @@ def get_config() -> Configuration:
Configuration
Returns the application configuration settings.
"""
return __config or Configuration()
global __config

def validate_api_key_header(config: Annotated[Configuration, Depends()],
x_api_key: str = Depends(APIKeyHeader(name='X-API-Key'))):
start = time.time()
__config = __config or Configuration()
end = time.time()
print(f'Time to load config: {end-start}')
return __config

def validate_api_key_header(x_api_key: str = Depends(APIKeyHeader(name='X-API-Key'))):
"""
Validates that the X-API-Key value in the request header matches the key expected for this API.
Parameters
----------
app_config : Configuration
Used for retrieving application configuration settings.
x_api_key : str
The X-API-Key value in the request header.
Expand All @@ -37,8 +41,7 @@ def validate_api_key_header(config: Annotated[Configuration, Depends()],
Returns True of the X-API-Key value from the request header matches the expected value.
Otherwise, returns False.
"""

result = x_api_key == config.get_value('FoundationaLLM:APIs:AgentHubAPI:APIKey')
result = x_api_key == get_config().get_value('FoundationaLLM:APIs:AgentHubAPI:APIKey')

if not result:
logging.error('Invalid API key. You must provide a valid API key in the X-API-KEY header.')
Expand All @@ -47,7 +50,7 @@ def validate_api_key_header(config: Annotated[Configuration, Depends()],
detail = 'Invalid API key. You must provide a valid API key in the X-API-KEY header.'
)

def handle_exception(exception: Exception):
def handle_exception(exception: Exception, status_code: int = 500):
"""
Handles an exception that occurred while processing a request.
Expand All @@ -58,6 +61,6 @@ def handle_exception(exception: Exception):
"""
logging.error(exception, stack_info=True, exc_info=True)
raise HTTPException(
status_code = 500,
status_code = status_code,
detail = str(exception)
) from exception
11 changes: 2 additions & 9 deletions src/python/AgentHubAPI/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Main entry-point for the FoundationaLLM AgentHubAPI.
Runs web server exposing the API.
"""
import uvicorn
from fastapi import FastAPI
from app.dependencies import get_config
from app.routers import resolve, status, list_agents
Expand All @@ -17,10 +16,8 @@
app = FastAPI(
title='FoundationaLLM AgentHubAPI',
summary='API for retrieving Agent metadata',
description=
"""The FoundationaLLM AgentHubAPI is a wrapper around
AgentHub functionality contained in the
foundationallm.core Python SDK.""",
description="""The FoundationaLLM AgentHubAPI is a wrapper around AgentHub
functionality contained in the foundationallm Python SDK.""",
version='1.0.0',
contact={
'name':'Solliance, Inc.',
Expand Down Expand Up @@ -52,7 +49,3 @@ async def root():
Returns a JSON object containing a message and value.
"""
return { 'message': 'FoundationaLLM AgentHubAPI' }

if __name__ == '__main__':
uvicorn.run('app.main:app', host='0.0.0.0', port=8742,
reload=True, forwarded_allow_ips='*', proxy_headers=True)
11 changes: 8 additions & 3 deletions src/python/AgentHubAPI/app/routers/list_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
The API endpoint for listing available agents.
"""
from typing import List
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Request
from foundationallm.hubs.agent import AgentHub
from app.dependencies import validate_api_key_header, handle_exception

Expand All @@ -15,16 +15,21 @@
)

@router.get('')
async def list_agents() -> List:
async def list_agents(request: Request) -> List:
"""
Retrieves a list of available agents.
Parameters
----------
request : Request
The underlying HTTP request.
Returns
-------
List
Returns a list of metadata objects for all available agents.
"""
try:
return AgentHub().list()
return AgentHub(config=request.app.extra['config']).list()
except Exception as e:
handle_exception(e)
2 changes: 1 addition & 1 deletion src/python/AgentHubAPI/app/routers/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from foundationallm.config import Context
from foundationallm.hubs.agent import AgentHub, AgentHubRequest, AgentHubResponse
from foundationallm.models import AgentHint
from app.dependencies import validate_api_key_header, handle_exception
from app.dependencies import handle_exception, validate_api_key_header

router = APIRouter(
prefix='/resolve',
Expand Down
11 changes: 11 additions & 0 deletions src/python/AgentHubAPI/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import uvicorn

if __name__ == '__main__':
uvicorn.run(
'app.main:app',
host='0.0.0.0',
port=8742,
reload=True,
forwarded_allow_ips='*',
proxy_headers=True
)
1 change: 0 additions & 1 deletion src/python/AgentHubAPI/startup.sh

This file was deleted.

4 changes: 2 additions & 2 deletions src/python/DataSourceHubAPI/DataSourceHubAPI.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ProjectGuid>637b74c9-aeb1-4b1a-8e92-20ac35d111eb</ProjectGuid>
<ProjectHome>.</ProjectHome>
<ProjectTypeGuids>{1b580a1a-fdb3-4b32-83e1-6407eb2722e6};{349c5851-65df-11da-9384-00065b846f21};{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
<StartupFile>app/main.py</StartupFile>
<StartupFile>run.py</StartupFile>
<SearchPath>..\PythonSDK</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<LaunchProvider>Standard Python launcher</LaunchProvider>
Expand Down Expand Up @@ -36,12 +36,12 @@
<Compile Include="app\routers\status.py" />
<Compile Include="app\routers\__init__.py" />
<Compile Include="app\__init__.py" />
<Compile Include="run.py" />
</ItemGroup>
<ItemGroup>
<Content Include=".gitignore" />
<Content Include=".pylintrc" />
<Content Include="requirements.txt" />
<Content Include="startup.sh" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PythonSDK\PythonSDK.pyproj">
Expand Down
31 changes: 25 additions & 6 deletions src/python/DataSourceHubAPI/app/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Provides dependencies for API calls.
"""
import logging
import time
from typing import Annotated
from fastapi import Depends, HTTPException
from fastapi.security import APIKeyHeader
Expand All @@ -18,17 +19,20 @@ def get_config() -> Configuration:
Configuration
Returns the application configuration settings.
"""
return __config or Configuration()
global __config

def validate_api_key_header(config: Annotated[Configuration, Depends()],
x_api_key: str = Depends(APIKeyHeader(name='X-API-Key'))):
start = time.time()
__config = __config or Configuration()
end = time.time()
print(f'Time to load config: {end-start}')
return __config

def validate_api_key_header(x_api_key: str = Depends(APIKeyHeader(name='X-API-Key'))):
"""
Validates that the X-API-Key value in the request header matches the key expected for this API.
Parameters
----------
app_config : Configuration
Used for retrieving application configuration settings.
x_api_key : str
The X-API-Key value in the request header.
Expand All @@ -38,11 +42,26 @@ def validate_api_key_header(config: Annotated[Configuration, Depends()],
Otherwise, returns False.
"""

result = x_api_key == config.get_value('FoundationaLLM:APIs:DataSourceHubAPI:APIKey')
result = x_api_key == get_config().get_value('FoundationaLLM:APIs:DataSourceHubAPI:APIKey')

if not result:
logging.error('Invalid API key. You must provide a valid API key in the X-API-KEY header.')
raise HTTPException(
status_code = 401,
detail = 'Invalid API key. You must provide a valid API key in the X-API-KEY header.'
)

def handle_exception(exception: Exception, status_code: int = 500):
"""
Handles an exception that occurred while processing a request.
Parameters
----------
exception : Exception
The exception that occurred.
"""
logging.error(exception, stack_info=True, exc_info=True)
raise HTTPException(
status_code = status_code,
detail = str(exception)
) from exception
7 changes: 1 addition & 6 deletions src/python/DataSourceHubAPI/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Main entry-point for the FoundationaLLM DataSourceHubAPI.
Runs web server exposing the API.
"""
import uvicorn
from fastapi import FastAPI
from app.dependencies import get_config
from app.routers import resolve, status
Expand All @@ -18,7 +17,7 @@
title='FoundationaLLM DataSourceHubAPI',
summary='API for retrieving DataSource metadata',
description="""The FoundationaLLM DataSourceHubAPI is a wrapper around DataSourceHub
functionality contained in the foundationallm.core Python SDK.""",
functionality contained in the foundationallm Python SDK.""",
version='1.0.0',
contact={
'name':'Solliance, Inc.',
Expand Down Expand Up @@ -49,7 +48,3 @@ async def root():
Returns a JSON object containing a message and value.
"""
return { 'message': 'FoundationaLLM DataSourceHubAPI' }

if __name__ == '__main__':
uvicorn.run('main:app', host='0.0.0.0', port=8842,
reload=True, forwarded_allow_ips='*', proxy_headers=True)
18 changes: 8 additions & 10 deletions src/python/DataSourceHubAPI/app/routers/resolve.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
"""
The API endpoint for returning the requested data source metadata.
"""
import logging
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Header, Request
from fastapi import APIRouter, Depends, Header, Request
from foundationallm.config import Context
from foundationallm.models import AgentHint
from foundationallm.hubs.data_source import (DataSourceHubRequest,
DataSourceHubResponse, DataSourceHub)
from app.dependencies import validate_api_key_header
from foundationallm.hubs.data_source import (
DataSourceHubRequest,
DataSourceHubResponse,
DataSourceHub
)
from app.dependencies import handle_exception, validate_api_key_header

router = APIRouter(
prefix='/resolve',
Expand Down Expand Up @@ -49,8 +51,4 @@ async def resolve(
return DataSourceHub(config=request.app.extra['config']).resolve(request=datasource_request, user_context=context, hint=agent_hint)
return DataSourceHub(config=request.app.extra['config']).resolve(request=datasource_request, user_context=context)
except Exception as e:
logging.error(e, stack_info=True, exc_info=True)
raise HTTPException(
status_code = 500,
detail = str(e)
) from e
handle_exception(e)
11 changes: 11 additions & 0 deletions src/python/DataSourceHubAPI/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import uvicorn

if __name__ == '__main__':
uvicorn.run(
'app.main:app',
host='0.0.0.0',
port=8842,
reload=True,
forwarded_allow_ips='*',
proxy_headers=True
)
1 change: 0 additions & 1 deletion src/python/DataSourceHubAPI/startup.sh

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ProjectGuid>f74cbb5a-97b9-4f68-8077-8bab49c841dc</ProjectGuid>
<ProjectHome>
</ProjectHome>
<StartupFile>app/main.py</StartupFile>
<StartupFile>run.py</StartupFile>
<SearchPath>..\IntegrationSDK</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
Expand All @@ -31,6 +31,7 @@
<Compile Include="app\routers\status.py" />
<Compile Include="app\routers\__init__.py" />
<Compile Include="app\__init__.py" />
<Compile Include="run.py" />
</ItemGroup>
<ItemGroup>
<Folder Include="app\" />
Expand All @@ -40,7 +41,6 @@
<Content Include=".gitignore" />
<Content Include=".pylintrc" />
<Content Include="requirements.txt" />
<Content Include="startup.sh" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IntegrationSDK\IntegrationSDK.pyproj">
Expand Down
Loading

0 comments on commit febb77d

Please sign in to comment.