ONEBADEV

SERVER NOTE:
GPU not found. Falling back to hope, a single vCPU and 4GB RAM.
Like good BBQ, LLM responses on the VPS can take time.
* Known cold-start issue: the first request can fail while the model loads. Try once more. Fix in progress and notes below in 'journal'. *

Skills & Stack

Technical Skills

Web & Backend Development
  • Languages: Python, JavaScript, HTML5, CSS3
  • Frameworks: Node.js, Express.js, Flask, FastAPI, Django
  • REST API Design and Integration
  • Server-Side Application Development
Artificial Intellegence & Machine Learning
  • Model Development & Evaluation
  • Data Preprocessing & Feature Engineering
  • PyTorch, TensorFlow, Scitkit-Learn, Pandas, Numpy
  • Data Visualization: Matplotlib, Seaborn, Plotly
LLM Applications & Retrieval Systems
  • Retrieval-Augmented Generation (RAG) Architecture
  • LangChain, LangGraph, Ollama
  • Embedding Pipelines & Vector Storage
  • LLM Integration & API Development
  • Rule-Based & LLM Powered Systems
Infrastructure & Deployment
  • Linux (Ubuntu), NGINX, PM2, systemd
  • Docker, Azure Container Apps, VPS Hosting
  • Git, GitHub, CI/CD
  • Database Intergration
  • Server Configuration & Application Deployment

It's Me!

Cartoon portrait of Andy drawn in the style of The Simpsons.

Applied Systems

onebadev.com - VPS Infrastructure & Deployment

The portfolio site itself is not hosted on a managed platform, it runs on a self-configured Ubuntu VPS, handled end-to-end from initial setup through production deployment. This includes provisioning the server environment, configuring NGINX as a reverse proxy to route traffic to a Node.js backend (Python in development), and managing the application processes with PM2 to ensure uptime and automatic restarts on failure.

SSL/TLS termination is handled at the NGINX layer via Let's Encrypt, keeping the backend service unexposed to the public internet. Static assets are served directly through NGINX while API traffic is proxied to the appropriate internal port.

The server also runs UFW-based firewall rules with only necessary ports exposed, and auth.log monitoring as an ongoing exercise in understanding what a live public-facing server actually looks like under real traffic conditions.

Tech Stack:
  • OS & Hosting: Ubuntu VPS, self-managed
  • Web Server: NGINX - reverse proxy, static asset serving, SSL termination
  • Process Management: PM2 - process persistence, auto-restart, log management
  • Security: UFW firewall, Let's Encrypt (Certbot)
  • Backend: Node.js + Express proxied via NGINX

BadBot: Production RAG Chatbot (onebadev.com)

Originally developed as a rule-based Python chatbot for a Natural Language Processing course, this assistant began as a structured Q&A system built to recognize predefined prompts and return custom responses. While the early version relied on pattern matching and scripted logic, the broader goal became a bit more ambitious: evolve the chatbot into a system capable of intelligently answering questions about my background, projects, and technical experience.

To support that idea, the project was rewritten in JavaScript to align with my website's backend architecture. This transition established the foundation for integrating large language models and retrieval-based techniques, with the long-term objective of building a Retrieval-Augmented Generation (RAG) system. The intent is for the chatbot to move beyond fixed responses and instead dynamically retrieve relevant information about my work, education, and portfolio, enabling a more natural, accurate, and context-aware interactions. At its core, the project represents a shift from static question-answer logic toward an intelligent, searchable knowledge assistant built around my personal technical ecosystem.

Tech Stack:
  • Backend:Node.js + Express.js
  • LLM:Ollama (Gemma model)
  • Ingestion:DirectoryLoader (PDFLoader + TextLoader)
  • Chunking / Retrieval:RecursiveCharacterTextSplitter + Top-k retrieval
  • Embeddings:OllamaEmbeddings
  • Vector Store:FAISS vector store, with on-disk persistence

Journal | Notes:

  • The site itself has been up and running (and will continue to be), but after deploying BadBot to my VPS I have encountered a performance bottleneck. While responses were fast on my personal PC, the minimal, CPU only server (no GPU) has been struggling under the load. The model, Gemma3:1b, is too heavy for the available hardware, pushing the CPU to max out causing response times to rise. To hopefully solve this, I am currently downsizing the LLM to a leaner Gemma3:270M and reimplementing a lightweight, rule-based system to handle common questions quicker. In this hybrid setup, the AI model is only invoked for more complex queries, helping balance model capability with hardware constraints, keeping the site fast and responsive. Barring any issues with the updated model, (or anything else) upcoming improvements include lightweight in-session memory to further improve flow while maintaining hardware efficiency.

  • It has been a while but after continuing to work through the limitations of CPU-bound performance on the VPS, the approach has recently shifted towards cloud-based models. The current model is still Gemma3 but has been upgraded to 27b-cloud, trying to ease the hardware bottleneck that had been limiting response quality and speed. The local model experiments, showed that lighter models had a tendency to hallucinate more frequently while heavier ones pushed the vCPU to its limits. Additional improvements include a server-side response cache to help reduce redundant calls for repeated questions and refined document chunking with natural text boundary separators for cleaner retrieval.

  • Currently exploring model quantization as another approach to running LLMs within the limited CPU and memory resources of the VPS. Rather than only reducing model size by moving to models with fewer parameters, quantization reduces the numerical precision used to represent a models's weights, such as converting higher-precision weights to 8-bit or 4-bit representations.
    The goal is to better understand the tradeoff between model size, memory usage, inference speed, and response quality. For BadBot, this could potentially allow a more capable model to run locally without the same resource requirements as its higher-precision version. I'm currently experimenting with different quantzation levels and learning how formats such as GGUF and Ollama's model ecosystem fit into that process.

Education & Certifications