Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service and sandbox orchestrator #7

Merged
merged 17 commits into from
May 16, 2024
Merged

Service and sandbox orchestrator #7

merged 17 commits into from
May 16, 2024

Conversation

jenniferjiangkells
Copy link
Member

@jenniferjiangkells jenniferjiangkells commented May 15, 2024

What is the purpose of this PR?

This PR adds the sandbox and service orchestration layer through the use of decorators @api and @sandbox.

Users can decorate their function with the @api decorator to mark it as the primary A/LLM processing function of their service. The decorator will mark the function as a route to a FastAPI app and mount it to the correct endpoint as defined in the UseCase.

The @sandbox decorator marks the entire class as a sandbox orchestrator. It will set up the client and service with the configurations defined in Service, Client, and UseCase. The class must be derived from BaseUseCase, i.e. inherit fromClinicalDecisionSupport. Typically, The @ehr function will define the synthetic data the users want to test with, and @api function will be where the actual processing logic lies. .start_sabdbox() will then start the service and client on separate async threads.

Example use:

@sandbox
class myCDS(ClinicalDecisionSupport):
        def __init__(self) -> None:
            self.data_generator = DataGenerator()

        @ehr(workflow="encounter-discharge", num=3)
        def load_data(self):
            data = self.data_generator.generate()
            return data

        @api
        def llm(self, text: str):
            chain = prompt | llm | JsonOutputParser()
            result = chain.invoke(text)
            return result

cds = myCDS()
cds.start_sandbox()
print(cds.responses)

Next steps

Integrating with actual data generator (it needs to also include meta data for the CDSRequest)
Export request/responses to a directory, or visualise through a streamlit dashboard

@jenniferjiangkells jenniferjiangkells linked an issue May 15, 2024 that may be closed by this pull request
@jenniferjiangkells jenniferjiangkells self-assigned this May 15, 2024
@jenniferjiangkells jenniferjiangkells changed the title Feature/service Service and sandbox orchestrator May 15, 2024
Copy link
Contributor

@adamkells adamkells left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I need a refresher on how exactly all this code fits together but overall LGTM.


return wrapper

if func is None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the use case where func is None. When would this come up?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just means when the decorator is called on its own it doesn't throw an error. I don't know when it would come up either 🤷‍♀️

log.warning(
f"{list(kwargs.keys())} is not a valid argument and will not be used; use 'service_config'."
)
service_config = arg if arg is not None else kwargs.get("service_config", {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any additional check regarding the form of arg if we are going to use it as service_config?

service_route_count = 0
client_count = 0

for name in dir(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit heavily nested. Ideally, I'd prefer to use a list comprehension to work out what should go in the for loop and avoid the nested if.
called_attrs= [getattr(self, name) for name in dir(self) if callable(getattr(self, name)]
But this isn't essential.

@adamkells adamkells merged commit 14fc41b into main May 16, 2024
2 checks passed
@adamkells adamkells deleted the feature/service branch May 16, 2024 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Write service layer and sandbox orchestrator v1
2 participants