Contributor: Regina Huang
Email: huang.rong@northeastern.edu
Github profile: https://github.com/RongHuang14
LinkedIn: https://www.linkedin.com/in/ronghuang14/
Mentor: Jooho Lee
GraphQL Convertor is a GraphQL generation agent application built with Chainlit and FastAPI that converts natural language queries into GraphQL queries.
Overview: This project is a GraphQL generation agent that converts human language queries into GraphQL queries using AI. Below is the project workflow and code structure:
├── README.md
├── frontend_requirements.txt
├── backend_requirements.txt
├── .env # OpenAI key & postgresql url
│
├── src/
│ ├── frontend/
│ │ ├── chainlit_app.py # Main Chainlit application
│ │ ├── chainlit.md # Welcome page
│ │ └── run.sh # Frontend startup script
│ │
│ ├── backend/
│ │ ├── app.py # Main FastAPI application
│ │ ├── start.sh # Backend startup script
│ │ ├── interactive_demo.sh
│ │ └── utils/
│ │ ├── nested_graphql_helper.py # utils for generating nested graphql
│ │ ├── prompt_builder.py
│ │ ├── filter_utils.py
│ │ ├── credential_helper.py # Generate token for guppy/graphql API
│ │ ├── schema_parser.py
│ │ ├── query_builder.py
│ │ └── context_manager.py
│ │
│ └── tests/
│ ├── test_db.py
│ ├── test_queries.py
│ ├── test_filter_utils.py
│ ├── validate_graphql_generation.py
│ └── test_setup.py
│
├── schema/
│ ├── gitops.json # GraphQL schema content
│ ├── pcdc-schema-prod-*.json
│ └── subject.json
│
├── assets/
- After cloning the project, install dependencies:
You need to build frontend env and backend env seperately, becausegen3andchainlithave version conflict onaiofiles.
Build frontend venv
python3 -m venv frontend_env
source frontend_env/bin/activate
pip install --upgrade pip
pip install -r frontend_requirements.txtBuild backend venv
python3 -m venv backend_env
source backend_env/bin/activate
pip install --upgrade pip
pip install -r backend_requirements.txt- Set up your OpenAI API key in the
.envfile:
OPENAI_API_KEY=your_api_key_here
DATABASE_URL=postgresql://postgres:your_postgresql_address
First, make sure you start the backend server in backend_env:
source backend_env/bin/activate
cd src/backend/
python -m uvicorn app:app --reloadThe backend API will run at http://localhost:8000
cd src/backend/curl -X POST "http://localhost:8000/flat_graphql" \
-H "Content-Type: application/json" \
-d '{"text": "I want to query all male patients"}'{
"query": "query ($filter: JSON) { _aggregation { subject(accessibility: all, filter: $filter) { consortium { histogram { key count } } race { histogram { key count } } _totalCount } } }",
"variables": "{'AND': [{'IN': {'race': ['Asian']}}]}"
}curl -X POST "http://localhost:8000/nested_graphql" \
-H "Content-Type: application/json" \
-d '{"text": "The cohort consists of participants from the INRG consortium who have metastatic tumors. Specifically, these tumors are classified as absent and are located on the skin."}'{
"AND": [
{
"IN": {
"consortium": [
"INRG"
]
}
},
{
"nested": {
"AND": [
{
"IN": {
"tumor_classification": [
"Metastatic"
]
}
},
{
"IN": {
"tumor_state": [
"Absent"
]
}
},
{
"IN": {
"tumor_site": [
"Skin"
]
}
}
],
"path": "tumor_assessments"
}
}
]
}curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "query ($filter: JSON) { _aggregation { subject(accessibility: all, filter: $filter) { consortium { histogram { key count } } sex { histogram { key count } } _totalCount } } }",
"variables": {"filter": {"AND": [{"IN": {"sex": ["Male"]}}]}}
}'{"data":{"_aggregation":{"subject":{"consortium":{"histogram":[{"key":"INSTRuCT","count":52},{"key":"NODAL","count":44},{"key":"INRG","count":42},{"key":"INTERACT","count":38},{"key":"HIBISCUS","count":37},{"key":"MaGIC","count":33},{"key":"ALL","count":32}]},"sex":{"histogram":[{"key":"Other","count":60},{"key":"Male","count":48},{"key":"Undifferentiated","count":45},{"key":"Female","count":43},{"key":"Unknown","count":35},{"key":"Not Reported","count":31},{"key":"no data","count":57}]},"_totalCount":319}}}}curl -X POST http://localhost:8000/query \
-H "Content-Type: application/json" \
-d '{
"query": "query GetAggregation($filter: JSON) { _aggregation { subject(accessibility: all, filter: $filter) { _totalCount } } }",
"variables": {
"filter": {
"AND": [
{
"IN": {
"consortium": [
"INRG"
]
}
},
{
"nested": {
"path": "tumor_assessments",
"AND": [
{
"IN": {
"tumor_classification": [
"Metastatic"
]
}
},
{
"IN": {
"tumor_state": [
"Absent"
]
}
},
{
"IN": {
"tumor_site": [
"Skin"
]
}
}
]
}
}
]
}
}
}'Example Response (via https://portal.pedscommons.org/query)
{
"data": {
"_aggregation": {
"subject": {
"_totalCount": 8508
}
}
}
}First, make sure you start the frontend server in frontend_env:
source frontend_env/bin/activate
bash src/frontend/run.shIt will run at http://localhost:8082
To login, you can use any of follwing accounts: username: test password: test username: admin password: admin username: user password: user123
create table public."Element" (
id uuid not null default extensions.uuid_generate_v4 (),
"threadId" uuid null,
type text null,
url text null,
"chainlitKey" text null,
name text not null,
display text null,
"objectKey" text null,
size text null,
page integer null,
"forIds" text[] null,
mime text null,
"updatedAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"deletedAt" timestamp with time zone null,
"createdAt" timestamp with time zone null default CURRENT_TIMESTAMP,
constraint Element_pkey primary key (id),
constraint Element_threadId_fkey foreign KEY ("threadId") references "Thread" (id) on delete CASCADE
) TABLESPACE pg_default;
create index IF not exists idx_element_threadid on public."Element" using btree ("threadId") TABLESPACE pg_default;
create table public."Feedback" (
id uuid not null default extensions.uuid_generate_v4 (),
"forId" uuid not null,
"threadId" uuid not null,
value integer not null,
comment text null,
"createdAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"updatedAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"deletedAt" timestamp with time zone null,
constraint Feedback_pkey primary key (id),
constraint Feedback_threadId_fkey foreign KEY ("threadId") references "Thread" (id) on delete CASCADE
) TABLESPACE pg_default;
create index IF not exists idx_feedback_threadid on public."Feedback" using btree ("threadId") TABLESPACE pg_default;
create index IF not exists idx_feedback_forid on public."Feedback" using btree ("forId") TABLESPACE pg_default;
create table public."Step" (
id uuid not null default extensions.uuid_generate_v4 (),
name text null default 'step'::text,
type text not null,
"threadId" uuid null,
"parentId" uuid null,
streaming boolean null default false,
"waitForAnswer" boolean null default false,
"isError" boolean null default false,
metadata jsonb null default '{}'::jsonb,
tags text[] null,
input text null,
output text null,
"createdAt" timestamp with time zone null default CURRENT_TIMESTAMP,
command text null,
start timestamp with time zone null,
"end" timestamp with time zone null,
generation jsonb null,
"showInput" text null,
language text null,
indent integer null default 0,
"updatedAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"deletedAt" timestamp with time zone null,
"startTime" timestamp with time zone null,
"endTime" timestamp with time zone null,
"completionStartTime" timestamp with time zone null,
"completionEndTime" timestamp with time zone null,
"disableFeedback" boolean null default false,
constraint Step_pkey primary key (id),
constraint Step_parentId_fkey foreign KEY ("parentId") references "Step" (id) on delete CASCADE,
constraint Step_threadId_fkey foreign KEY ("threadId") references "Thread" (id) on delete CASCADE
) TABLESPACE pg_default;
create index IF not exists idx_step_threadid on public."Step" using btree ("threadId") TABLESPACE pg_default;
create index IF not exists idx_step_parentid on public."Step" using btree ("parentId") TABLESPACE pg_default;
create index IF not exists idx_step_createdat on public."Step" using btree ("createdAt" desc) TABLESPACE pg_default;
create table public."User" (
id uuid not null default extensions.uuid_generate_v4 (),
identifier text not null,
metadata jsonb null default '{}'::jsonb,
"createdAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"updatedAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"deletedAt" timestamp with time zone null,
constraint User_pkey primary key (id),
constraint User_identifier_key unique (identifier)
) TABLESPACE pg_default;
create index IF not exists idx_user_identifier on public."User" using btree (identifier) TABLESPACE pg_default;
create table public."Thread" (
id uuid not null default extensions.uuid_generate_v4 (),
"createdAt" timestamp with time zone null default CURRENT_TIMESTAMP,
name text null,
"userId" uuid null,
"userIdentifier" text null,
tags text[] null,
metadata jsonb null default '{}'::jsonb,
"updatedAt" timestamp with time zone null default CURRENT_TIMESTAMP,
"deletedAt" timestamp with time zone null,
participant jsonb null,
constraint Thread_pkey primary key (id),
constraint Thread_userId_fkey foreign KEY ("userId") references "User" (id) on delete CASCADE
) TABLESPACE pg_default;
create index IF not exists idx_thread_userid on public."Thread" using btree ("userId") TABLESPACE pg_default;
create index IF not exists idx_thread_useridentifier on public."Thread" using btree ("userIdentifier") TABLESPACE pg_default;
create index IF not exists idx_thread_createdat on public."Thread" using btree ("createdAt" desc) TABLESPACE pg_default;
{"query":"query ($filter: JSON) { _aggregation { subject (filter: $filter, accessibility: all) { sex { histogram { key count } } race { histogram { key count } } ethnicity { histogram { key count } } consortium { histogram { key count } } } } }","variables":{"filter":{"AND":[{"nested":{"path":"tumor_assessments","AND":[{"AND":[{"IN":{"disease_phase":["Initial Diagnosis"]}},{"AND":[{"IN":{"tumor_classification":["Metastatic"]}},{"IN":{"tumor_site":["Bone"]}}]}]}]}}]}}}{
"filter_main": {
"AND": [
{
"nested": {
"path": "tumor_assessments",
"AND": [
{
"AND": [
{
"GTE": {
"age_at_tumor_assessment": 0
}
},
{
"LTE": {
"age_at_tumor_assessment": 100
}
}
]
}
]
}
}
]
}
}


