RecipAI is available at https://recipai.student.k8s.aet.cit.tum.de (k8s) and deployable at https://recipai.duckdns.org (aws)
For running it on docker please see dockerized-deployment and .env.template.
The primary functionality of the application is to enable users to generate and explore recipes through a natural language interface powered by a LLM. The application allows users to search for recipes based on ingredients, generate meal plans, and receive step-by-step cooking instructions tailored to their preferences and dietary requirements.
The application is designed for home cooks, culinary enthusiasts, individuals with dietary restrictions, and anyone interested in exploring or generating recipes in an intuitive and flexible manner. It is particularly useful for users who wish to interact with a recipe database using natural language queries.
Generative AI is integrated meaningfully through a dedicated LLM microservice developed in Python. This service processes user inputs in natural language, generates recipes based on the provided ingredients, modifies existing recipes according to user needs, and provides meal suggestions based on the user dietary preferences. The use of GenAI enhances the user experience by offering a personalized RAG system that emphasizes user-specific recipe collections. Through the use of a conversational AI system, we provide to the users with a multi-turn chat with context preservation.
RecipAI provides an intuitive chat-based interface for generating recipes, meal plans, and managing dietary preferences. Here's how to use the application:
- Login: Access the application at the deployed URL and sign in using your GitLab LRZ credentials
- Set Preferences: Configure your dietary restrictions and preferences (vegan, gluten-free, diabetic, etc.) in the user settings
- Start Chatting: Use the main chat interface to interact with the AI recipe assistant
- Be specific about dietary restrictions, cooking time, or cuisine preferences
- Include the number of servings when requesting recipes
- Mention available cooking equipment or preferred cooking methods
- Ask follow-up questions to refine or modify generated recipes
-
Ingredient-Based Recipe Generation: A user inputs, "Suggest a quick dinner recipe with chicken and broccoli." The system uses the LLM to generate a relevant recipe, which is presented to the user through the user interface.
-
Recipe Modification: A user submits a traditional recipe and requests, "Make this vegan." The LLM identifies non-vegan ingredients and substitutes them with plant-based alternatives, returning a modified version of the recipe.
-
Meal Planning with User Preferences: A user defines his/her dietary preferences in the web application and asks for a weekly meal plan in the chat. The LLM generates a diverse and nutritionally balanced plan, based on dietary restrictions or cuisine preferences.
-
Ingredient-Limited Cooking: A user specifies available ingredients, such as "eggs, spinach, and cheese," and the system suggests recipes that can be prepared using those ingredients, optimizing for simplicity and flavor.
Responsible Students:
- Mehmed Esad Akcam & Ege Dogu Kaya
Responsibilities:
- Provide a chat-based UI for interaction.
- Handle authentication with GitLab LRZ via OAuth2/OpenID.
- Allow users to input prompts and view generated responses.
- Let users manage and update their dietary preferences.
- Display recipe history and allow revisiting past conversations.
Core Features:
- Login with GitLab LRZ SSO
- Chat interface (user prompt + LLM response)
- Preference settings (gluten-free, diabetic, vegan, etc.)
- Recipe document upload
- Recipe history viewer
Responsible Student:
- Mehmed Esad Akcam
Responsibilities:
- Authenticate and authorize users via GitLab LRZ.
- Manage user profiles and dietary preferences.
- Route prompts to the GenAI service and handle responses.
- Store and retrieve chat and recipe history from MongoDB.
- Expose REST endpoints for client-side operations.
Responsible Student:
- Ege Dogu Kaya
Responsibilities:
- Process incoming prompts and preferences.
- Use LLM (e.g., GPT via LangChain or Llama3) to generate, modify, and plan recipes.
- Fetch additional data from a well known recipe source stored in the vector database Qdrant to enable document retrieval for answering recipe document based questions.
- Structure outputs into JSON responses and provide endpoints via FastAPI for server module.
Design:
- LangChain chains/tools for recipe generation and transformation
- Prompt templates that incorporate user reqeusts, preferences and dietary constraints
- Qdrant vector database to store embedded documents for similarity search
Collections:
user-preferences– Stores user data and dietary preferenceschats– Stores user messages and GenAI responses
Data Considerations:
- Preferences are indexed for fast lookup
Collections:
recipes– Stores user specific embedded recipe documents which are uploaded by the user
Responsible Students:
- Mehmed Esad Akcam & Ege Dogu Kaya
Responsibilites
- Each service is dockerized and has its own image in github registry
- CI/CD pipelines to deploy on student cluster in Rancher and AWS
- Helm charts for k8s deployment
- Docker compose for AWS deployment
Flow:
- React initiates OAuth2 login with GitLab LRZ
- GitLab redirects with authorization code
- Spring Boot backend exchanges code for tokens
- Backend creates or updates the user profile in MongoDB
- Tokens used for secure communication between frontend and backend
- User logs in via GitLab LRZ → token returned.
- User select his/her didtary preferences.
- User types: "Suggest a dinner with lentils."
- React sends prompt + preferences to Spring Boot API.
- API calls GenAI microservice with combined data.
- GenAI returns structured recipe.
- API stores recipe + chat history in MongoDB.
- Response returned to frontend and rendered in chat UI.
| Component | Technology |
|---|---|
| Frontend | React, TypeScript |
| Backend | Spring Boot, Java |
| GenAI Service | Python, LangChain |
| Database | MongoDB |
| Vector Database | Qdrant |
| Auth | GitLab LRZ SSO |
We fulfilled all the project requirements for RecipAI. You can find our project requirements checklist here: Project Requirements Checklist
- Node.js (v22 or later)
- Java JDK 21+
- Python 3.11
- Gradle
- Docker and Docker Compose
- Git
- Kubernetes and Helm (for Kubernetes deployment)
git clone https://github.com/AET-DevOps25/team-continuous-disappointment.git
cd team-continuous-disappointment- Navigate to the
clientdirectory:cd client - Install dependencies:
npm install
Note: Please be aware that you need to manually add the GITLAB_CLIENT_SECRET from the .env file (see .env.template) to the application.yaml file for the field client-secret for local development.
spring:
profiles:
active: dev
application:
name: api-gw
cloud:
gateway:
mvc:
routes:
- id: user
uri: http://user-service:8081
predicates:
- Path=/user/**
- id: chat
uri: http://chat-service:8082
predicates:
- Path=/chat/**
security:
oauth2:
resourceserver:
opaquetoken:
client-id: ${GITLAB_CLIENT_ID:60a9e442420a386f2ddff0f60ed0801dd7e826f0710507e982d5afe6aa054334}
client-secret: -> PUT HERE <-
introspection-uri: https://gitlab.lrz.de/oauth/introspect
server:
port: 8080
management:
endpoints:
web:
exposure:
include:
- health
- info
- metrics
- prometheus- Navigate to the
serverdirectory:cd server - Build the project:
./gradlew build
- Navigate to the
genaidirectory:cd genai - Install dependencies:
python3 -m venv .venv source .venv/bin/activate pip3 install -r requirements.txt
- Navigate to the
serverdirectory:cd server - Test the microservice - API Gateway:
./gradlew :api-gw:test
- Test the microservice - User:
./gradlew :user:test
- Test the microservice - Chat:
./gradlew :chat:test
- Navigate to the
genaidirectory:cd genai - Test the microservice - GenAI:
pytest
Sidenote: In order to pass all genai tests, you need to have a Qdrant instance running on your local machine, because one of the integration tests requires a running Qdrant instance.
- Navigate to the
clientdirectory:cd client - Test the microservice - Client:
npm run test -- --run
docker compose -f docker-compose-dev.yml up -dcd client
npm run devThe client will be available at http://localhost:5173.
cd server./gradlew :api-gw:bootRunThe API-Gateway Service API will be available at http://localhost:8080.
./gradlew :user:bootRunThe User Service API will be available at http://localhost:8081.
./gradlew :chat:bootRunThe Chat Service API will be available at http://localhost:8082.
cd genai
uvicorn main:app --reload --host 0.0.0.0 --port 8000The LLM service will be available at http://localhost:8000.
- Built with React + Vite and TypeScript for a modern, reactive UI.
- TailwindCSS for styling.
- Components, routes, pages, hooks, types, and services are organized in the
client/srcdirectory. - Features user preferences, file uploading, and a modern chat with history.
- Built with Spring Boot for scalable and maintainable server services.
- Includes REST communication with the GenAI service.
- MongoDB integration for user preferences and chat history storage.
- RESTful APIs for user and chat management, with a unified entry point for all services.
- Gradle is used for dependency management and building.
- Source code is in the
server/src/main/javadirectory. - Tests are in the
server/src/test/javadirectory.
- Built with FastAPI for AI-powered recipe recommendations.
- Integrates with local and cloud LLMs for generating suggestions based on the given ingredients.
- Stores embedded documents in a vector database to be able to make similarity search and document retrieval.
- Source code is in the
genaidirectory. - Tests are in the
genai/testsdirectory.
- The GenAI service is responsible for all interactions with the language model used to generate and modify recipes in RecipAI. It receives user inputs as free-text prompts and responds with structured outputs such as complete recipes, meal plans, or modified instructions. It is implemented using FastAPI, LangChain, and integrates with local and cloud large language models.
- The GenAI service uses Qdrant as a vector store to retrieve relevant documents before querying the LLM. It adds the retrieved context to the prompt to improve the relevance of answers.
- The client UI sends user requests to the API gateway, which forwards them to the chat service. Chat service forwards them to the GenAI service along with the user’s query and chat history to support multi-turn conversations. GenAI service then makes a similarity search in the vector database with the given query, and generates a respective answer. GenAI service is able to provide a proper answer altough no similar context is found in the vector database. (Endpoint: POST -
genai/generate) - If the user wants to upload a recipe file, client UI sends the file content directly to the API gateway, which forwards to the GenAI service, where the content of the file is chunked, embedded, and stored in the vector database. (Endpoint: POST -
genai/upload) - For using/testing the upload functionality, you can find some recipe PDFs to test the upload under
recipe_pdfsfolder. If you want, you can also modify the content of the script to generate your own recipe PDFs which can be found underrecipe_pdfs/scriptsfolder. You can run the script from the root folder like:-
python recipe_pdfs/scripts/basic_recipes.py
-
We use Qdrant as the vector database to enable semantic search and retrieval-augmented generation (RAG) in RecipAI. Embeddings are generated using OpenAI’s small embedding model text-embedding-3-small.
# Example: Creating OpenAI embeddings for ingestion
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
openai_api_key=Config.api_key_openai
)- If you want to use cloud and local based LLM models, you need to set the respective api key in your
.envfile. Required.envvariables:
# Cloud based LLM models
API_OPENAI="your openai key"
API_ANTHROPIC="your anthropic key"
API_MISTRAL="your mistral key"
API_HUGGINGFACEHUB="your huggingface api token"
# Local Models
API_OPENWEBUI="your openwebui key"
# Base URL for calling local models
BASE_URL="base url where openwebui is hosted"-
However, you do not need to set all of these fields in your
.envfile. To run the GenAI module, you need at least the API_OPENAI, API_OPENWEBUI, and BASE_URL variables. You can find more information in the .env.template file. -
Example for Cloud LLM Models (defined in
genai/service/llm_service.py):
llm_cloud_anthropic = CloudLLM(
model_name="claude-3-sonnet-20240229",
model_provider="anthropic",
api_key=Config.api_key_anthropic,
)
llm_cloud_openai = CloudLLM(
model_name="gpt-4-1106-preview",
model_provider="openai",
api_key=Config.api_key_openai,
)
llm_cloud_mistral = CloudLLM(
model_name="mistral-medium",
model_provider="mistral",
api_key=Config.api_key_mistral,
)
# If no parameters are provided, the default cloud model will be openai.
# Example:
# llm = CloudLLM() # same as llm_cloud_openai- Example for Local LLM Models (defined in
genai/service/llm_service.py):
# Make calls to local models in openwebui (model can be changed by giving a different model_name as parameter)
llm = ChatModel(model_name="llama3.3:latest")cd client
npm run build prodcd server
./gradlew clean buildThe project includes Docker configurations for containerized deployment.
- Build and start all services:
docker compose -f docker-compose.yml up -d
- Access the application:
- Client: http://localhost:5173
- API Gateway Service: http://localhost:8080
- User Service: http://localhost:8081
- Chat Service: http://localhost:8082
- GenAI Service: http://localhost:8000
- Database: MongoDB on port 27017, Mongo Express is accessible at http://localhost:8083
- Vector Database: Qdrant on port 6333, Web UI is accessible at http://localhost:6333/dashboard
- Grafana Dashboard: http://localhost:3001
- Prometheus: http://localhost:9090
- Loki runs on port 3100
- Cadvisor runs on port 8003
The project includes Helm charts for Kubernetes deployment in the infra/recipai-chart directory.
- Install the Helm chart:
helm -n <your namespace> install recip-ai ./infra/recipai-chart \ --set secrets.gitlabClientSecret="your gitlab client secret" \ --set secrets.mongodbAdminPassword="your mongodb admin password" \ --set secrets.apiOpenAi="your open ai api key" \ --set secrets.apiOpenWebUi="your open web ui api key" --set secrets.discordWebhookUrl="${{ your discord webhook url }}"
- Change the host name of the server on inventory.ini and ansible-manual to the server or ip address of VM.
- Update
recipai.duckdns.orgDNS record on DuckDNS to point new VM IP address - The application is now deployable through github actions with the following steps
- Run Manual Ansible Playbook Execution action install_docker.yml as input
- Run Manual Ansible Playbook Execution action with docker_compose_up.yml
- Run Manual Ansible Playbook Execution action with install_caddy.yml
The project includes a GitHub Actions workflow ci-cd.yml for:
- Building Docker Images: Automatically builds and pushes Docker images to GitHub Container Registry.
- Deploying Docker Images: Automatically deploys the application to a production environment by using deployment manifests in helm for K8s cluster.
- Running Server Tests: For each push, server tests on server microservices are run.
- Running GenAI Tests: Automatically runs the tests defined in the
genai/testsdirectory on every code push in genai module. - Running Client Tests: Automatically runs the UI tests defined in the
client/src/components/__tests__directory on every code push in client module.
Triggers:
- Push to
mainorfeature/**branches - Changes in
genai/**,server/**,client/**, or workflow files
Features:
- Change Detection: Uses
dorny/paths-filterto detect which services have changed - Conditional Builds: Only builds and tests services that have been modified
- Multi-stage Pipeline: Build → Test → Docker → Deploy
Jobs:
detect-changes: Identifies which services need building/testingbuild-genai: Python linting, dependency installation, and genai testsbuild-server: Java microservices build and test (API Gateway, Chat, User)build-client: Node.js build and testdocker-release-*: Builds and pushes Docker images to GitHub Container Registryhelm-deploy: Deploys to Kubernetes using Helm charts
The project includes a GitHub Actions workflow helm-manual.yml for:
- Deploying Docker Images: Manually deploys the application to a production environment by using deployment manifests in helm for K8s cluster.
The project includes a GitHub Actions workflow ansible-manual.yml for:
- Running Ansible Playbook: Manually runs any Ansible playbook defined in the
infra/ansible/playbooksdirectory against an EC2 instance securely using SSH and Ansible Vault.
REST API documentation for User, Chat, API Gateway, and GenaAI is available in the api/openapi.yaml file.
We also publish our REST API documentation via Github Pages automatically:
📄 Swagger UI: https://aet-devops25.github.io/team-continuous-disappointment/api-documentation/
- Recipe Generation: The system must allow users to input a description or ingredients and receive a complete recipe in response.
- Meal Planning: The system must allow users to request a meal plan for a specified number of days and meals per day.
- Chat-Based Interaction: The user must be able to interact with the application via a conversational interface and therefore the system must preserve context in multi-turn conversations.
- Document Upload: The user must be able to upload their own recipe files in a PDF format for analysis or transformation into a structured recipe.
- RAG Integration: The LLM must be able to retrieve information from an internal vector store when generating responses.
- Chat History: The user must be able to view and revisit previous recipe requests and conversations.
- Performance: The system must generate a recipe in response to a user query within 15 seconds in 95% of cases.
- Scalability: The architecture must allow horizontal scaling of microservices.
- Availability: The system must maintain 99.5% uptime during working hours.
- Reliability: In case of failure in the GenAI service, users must receive a clear error message without crashing the app.
- Security: The system must restrict access to service endpoints from outside world.
- Security: Only authenticated users must be allowed to use the application.
- Modularity: Each microservice must be independently deployable.
- Maintainability: Codebase must follow clean architecture principles and use OpenAPI documentation for APIs.
- Deployability: The system must be deployable via Docker Compose locally and to a Kubernetes cluster via Helm charts.
- Portability: All services must run correctly in both local and cloud environments with minimal configuration.
- Usability: The chat interface must be responsive and intuitive.
- Observability & Monitoring: The system must expose Prometheus metrics for all critical services. Dashboards must be created in Grafana to visualize response latency, error rates, and user request volume. Besides that, at least one alert must be defined.
The following UML component diagram shows the details of the RecipAI application architecture and provides a comprehensive overview of the interfaces offered by the genai, chat, user, and API gateway services.

The following UML class diagram shows the details of the RecipAI application server’s repository layer, service layer, and controller layer.

The following UML class diagram shows the details of the RecipAI GenAI module's repository layer, service layer, and controller layer.

The following UML use case diagram shows the use cases and the participating actors of the RecipAI web application.

RecipAI is equipped with a monitoring stack powered by Prometheus and Grafana, deployed in a Kubernetes environment. This setup enables real-time observability across all microservices, including the GenAI service, user and chat services, and the API gateway.
Prometheus is configured via a Kubernetes ConfigMap named prometheus-config at infra/recipai-chart/templates/prometheus/prometheus-configmap.yml. The configuration defines scrape jobs for each service, enabling Prometheus to collect metrics every 15 seconds.
All services expose Prometheus-compatible metrics:
- GenAI service uses a standard
/metricsendpoint. - Server (Spring Boot) services (e.g., chat, user, api-gw) expose metrics via
/actuator/prometheus.
For dockerized setup, respective prometheus config is also defined at monitoring/prometheus/prometheus.yml
Grafana is used to visualize metrics collected by Prometheus. It is deployed via Helm and configured with:
- Dashboards for GenAI and chat service latency, error rates, and request counts.
- Dashboard for general system metrics of the cluster
- Contact points for alerting (Discord Webhook)
- system-dasboard.json: Infrastructure-level metrics (CPU, memory, nodes)
- For dockerized setup:
monitoring/grafana/dashboards/system-dashboard.json - For helm setup:
infra/recipai-chart/dashboards/system-dashboard.json 
- For dockerized setup:
- genai-dashboard.json: latency, error rates, and request counts
- For dockerized setup:
monitoring/grafana/dashboards/genai-dashboard.json - For helm setup:
infra/recipai-chart/dashboards/genai-dashboard.json 
- For dockerized setup:
- chat-dashboard.json: latency, error rates, and request counts
- For dockerized setup:
monitoring/grafana/dashboards/chat-dashboard.json - For helm setup:
infra/recipai-chart/dashboards/chat-dashboard.json 
- For dockerized setup:
RecipAI collects all service logs via Loki and Promtail for centralized logging. Promtail is configured to scrape logs from all services running in the cluster and forwards them to Loki for storage. This enables log aggregation and visualization through Grafana's built-in log viewer.
Example - Logs from the GenAI Service:
-
To access Grafana locally from the cluster, we can do port-forwarding:
kubectl port-forward svc/grafana 3000:3000
Then, it should be available at
http://localhost:3000 -
Or you can access it directly via our ingress in the cluster:
https://grafana-tcd.student.k8s.aet.cit.tum.de -
Grafana Credentials:
- Username:
admin - Password:
admin
- Username:
Alerts are configured using Grafana’s Unified Alerting system. It defines our Discord webhook as the receiver for high response generation duration in the GenAI service (for >15 seconds).
-
Contact points are defined:
- For dockerized setup:
monitoring/grafana/provisioning/alerting/contact-points.yaml - For helm setup:
infra/recipai-chart/templates/grafana/grafana-alerting.yml
- For dockerized setup:
-
Discord webhook as our contact point:
This project is licensed under the MIT License.



