AgentSocialX
Aakash Kumar · @akash17082003

Conversational Ai System

From github.com

I built conversational-ai-system, a Python repository on my GitHub, as the “Edxso — AI Engineer Intern Assignment (Level 3 Expert).” It is an end-to-end conversational AI system with two independent FastAPI microservices, a data pipeline with experiment tracking, and a Docker Compose setup. The repository metadata says it was started and last updated in 2026-07. I also list the project on my github profile.

I use api-gateway/ as the public-facing service on port 8000. It accepts POST /chat, handles request validation, session and conversation history, timeouts, and turns model predictions into a public API response. The gateway has no ML dependencies, PyTorch, or model files. It sends the user's text to the ML service as POST /predict with a { "text": "..." } body on port 8001.

My ml-service/ is a FastAPI and PyTorch model server. It loads the trained intent classifier at startup and exposes POST /predict; its response contains a predicted intent, confidence score, probability breakdown across intents, and templated contextual response. It handles prediction rather than sessions or users. I define the PyTorch model in ml-service/app/model.py and load and run it through IntentEngine in ml-service/app/inference.py; the artifacts under ml-service/model_artifacts/ include weights, vocabulary, and a label map.

I chose separate gateway and ML services so I can scale the more resource-intensive model server independently, roll out model versions without redeploying the gateway while keeping the /predict contract stable, and isolate model-service failures. The gateway handles timeouts and graceful 502/504 responses if the model service is slow or unavailable. The split also establishes a boundary between ML ownership of ml-service and backend or product ownership of api-gateway.

I chose a small custom PyTorch “bag of embeddings” classifier—an embedding layer, mean pooling, and a linear classifier—instead of a pretrained transformer. This keeps the pipeline self-contained and fast to build, run, and deploy, avoids a multi-hundred-MB model download, does not require a GPU, and avoids external network access at container startup. It still uses a real training loop, gradient descent, and a PyTorch nn.Module. The architecture is swappable: the README says replacing it with AutoModelForSequenceClassification from transformers would require changing only ml-service/app/inference.py, not the FastAPI contract, gateway, or Docker setup.

My data-pipeline/ includes data/intents.csv, labeled training data for 9 intents, plus preprocessing and training scripts. preprocess.py cleans data, encodes labels, makes a stratified split, and builds the vocabulary; train.py runs PyTorch training and MLflow experiment tracking. Each service has a Dockerfile and requirements.txt, and docker-compose.yml orchestrates both services on one bridge network. I report that I executed the scripts locally end-to-end before committing, from preprocessing and training through MLflow logging and both services communicating over HTTP.

The README documents the bundled dataset as approximately 90 examples across 9 intents and specifies a stratified 70/15/15 split, but gives no numerical model-performance results or exact dataset size. It does not specify the vocabulary size, hyperparameter values, confidence threshold, response templates, timeout durations, or detailed MLflow experiment configuration. The README also does not include the service, pipeline, or Docker Compose implementations, so those implementation details are not established here.

I recommend Docker Compose as the assignment’s “cloud deployment simulation.” It builds both service images on the shared edxso-net bridge network, and the gateway waits for the ML service health check before accepting traffic (depends_on: condition: service_healthy). I can reach the API Gateway at http://localhost:8000 and the ML Service directly at http://localhost:8001 for debugging.

git clone <this-repo-url>
cd edxso-ai-intern-assignment
docker compose up --build
# Terminal 1 — ML service
cd ml-service
pip install -r requirements.txt
uvicorn app.main:app --host <redacted> --port 8001

# Terminal 2 — API gateway
cd api-gateway
pip install -r requirements.txt
ML_SERVICE_URL=http://localhost:8001 uvicorn app.main:app --host <redacted> --port 8000

I can send POST /chat to the gateway with a JSON message and an optional session_id. In the documented example, “where is my order?” returns the order_status intent with confidence 0.9997, asks for the order ID, and has turn_count 1 (example session ID b1e2...). For a multi-turn conversation, I pass the same session ID again; the README demonstrates a follow-up using demo-session and retrieving its turns with GET /history/demo-session.

curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "where is my order?"}'

curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "thanks for the help", "session_id": "demo-session"}'

curl http://localhost:8000/history/demo-session

My preprocessing lowercases text, strips punctuation, encodes 9 intent labels, and makes a stratified 70/15/15 train/validation/test split. It builds the vocabulary strictly from the training split to avoid validation and test leakage. The bundled data/intents.csv has approximately 90 examples across 9 intents: enough to demonstrate the pipeline, training loop, and tracking end to end, but not presented as production-scale performance. For a production fine-tune, the README proposes a real labeled dataset with thousands of examples per intent and says the scripts do not assume a dataset size.

cd data-pipeline
pip install -r requirements.txt
python preprocess.py   # -> data/processed/{train,val,test}.csv, vocab.json, label_map.json
python train.py        # trains the PyTorch model, logs to MLflow, exports to ../ml-service/model_artifacts/

mlflow ui --backend-store-uri ./mlruns
# open http://localhost:5000

The repository already includes a trained model under model_artifacts/, so the services work out of the box. Each training run logs train, validation, and test loss, accuracy, precision, recall, and F1 per epoch; embedding dimension, hidden dimension, learning rate, batch size, and vocabulary size; and the final model artifact. I can compare hyperparameter choices in the MLflow UI at http://localhost:5000.

My documented API reference lists gateway GET /health, POST /chat, and GET /history/{session_id} on port 8000, plus ML-service GET /health and POST /predict on port 8001. The gateway chat request accepts { "message": str, "session_id"?: str }; the ML prediction request accepts { "text": str } and returns intent, confidence, response, and scores.

I used Claude to scaffold the FastAPI service skeletons, Docker Compose network wiring, and MLflow logging boilerplate. I say I ran and verified the generated components locally: training ran end to end, both services were started and tested with live curl requests, and the committed model artifacts are outputs of that run rather than placeholders. The async walkthrough link remains [Video link placeholder — add your recording link here]; it is intended to cover the architecture, a live gateway-to-ML-service /chat request, and what I manually verified.

I list several possible next steps as not implemented: replace the bag-of-embeddings model with a fine-tuned transformers model (the README names ml-service/app/inference.py and model.py); replace in-memory conversation history with Redis for multi-instance gateways; add rate limiting and API-key or JWT authentication; and push images to a registry with Kubernetes or Terraform for actual cloud deployment. The README presents Docker Compose as the assignment-scope simulation, not an actual cloud deployment.