Tools: Building a Production-Ready RAG Chatbot with AWS Bedrock, LangChain, and Terraform

Tools: Building a Production-Ready RAG Chatbot with AWS Bedrock, LangChain, and Terraform

Source: Dev.to

Introduction ## Table of Contents ## Project Overview ## Technology Stack ## Architecture ## Deployment Architecture ## Project Structure ## Detailed Component Analysis ## 1. Chatbot Module (Chatbot/) ## chatbot.py - Main Interface ## bedrock_model.py - Core Logic ## app_feature.py - UI Components ## 2. RAG Agent Module (RAGAgent/) ## agent.py - Complete RAG Implementation ## 3. Navigation (navigation.py) ## 4. Configuration (config.toml) ## 5. Infrastructure (Terraform/) ## provider.tf - AWS Configuration ## ecr.tf - Container Registry ## ecs.tf - Container Orchestration ## alb.tf - Load Balancer ## iam.tf - Permissions ## 6. Docker Configuration (Dockerfile) ## 7. CI/CD Pipeline (.gitlab-ci.yml) ## Stage 1: Image Build ## Stage 2: Resource Build ## Stage 3: Cleanup ## Deployment Pipeline ## Complete Flow ## Key Features ## 1. Dual Chat Modes ## 2. Automatic Categorization ## 3. Conversation Memory ## 4. Interactive Feedback ## 5. Typing Indicators ## 6. Multi-Model Support ## 7. Document Management ## 8. Production-Ready Infrastructure ## 9. CI/CD Automation ## Setup and Installation ## Prerequisites ## OpenSearch Setup ## Conclusion ## Future Enhancements ## Conclusion ## What We've Accomplished ## Key Technical Achievements ## Real-World Applications ## Lessons Learned ## Performance Considerations ## Future Roadmap ## Final Thoughts ## Get Started ## Connect & Contribute In the era of generative AI, chatbots have evolved from simple rule-based systems to intelligent assistants capable of understanding context, retrieving relevant information, and providing accurate responses. This project showcases a production-grade implementation of a dual-mode chatbot system that combines the power of Large Language Models (LLMs) with Retrieval-Augmented Generation (RAG) capabilities. The system addresses a common challenge in enterprise AI applications: how to provide both general conversational AI and domain-specific knowledge retrieval in a single, unified platform. By leveraging AWS Bedrock's foundation models, LangChain's orchestration framework, and OpenSearch's vector database, we've built a solution that is not only intelligent but also scalable, maintainable, and production-ready. What sets this project apart is its automatic categorization feature—users don't need to manually select document categories. The LLM intelligently analyzes each query and routes it to the appropriate knowledge base, creating a seamless user experience. Combined with conversation memory, interactive feedback mechanisms, and a complete CI/CD pipeline, this project demonstrates enterprise-grade AI application development. Whether you're building a customer support bot, an internal knowledge assistant, or a document Q&A system, this architecture provides a solid foundation that can be adapted to your specific needs. This project implements a sophisticated dual-mode chatbot system that combines: The system is production-ready with Docker containerization, Terraform infrastructure as code, and GitLab CI/CD pipeline for automated deployment to AWS ECS Fargate. Purpose: Entry point for the general chatbot interface Purpose: Handles AWS Bedrock integration and conversation flow Purpose: Provides reusable UI components and styling Purpose: Document-based Q&A with vector search and automatic categorization Automatic Categorization: Vector Store Builder (Cached): Document Retrieval & Response: Purpose: Multi-page application router Purpose: Streamlit theme customization This project demonstrates a complete production-ready AI chatbot system with: ✅ Intelligent RAG: Automatic categorization and document retrieval ✅ Modern UI: Interactive feedback, typing indicators, multi-page navigation ✅ Scalable Infrastructure: ECS Fargate, ALB, auto-scaling ✅ DevOps Best Practices: IaC, CI/CD, containerization ✅ AWS Integration: Bedrock, S3, OpenSearch, ECR, ECS ✅ Conversation Memory: Context-aware responses ✅ Multi-Model Support: Flexible LLM selection The architecture is modular, maintainable, and ready for enterprise deployment. This project represents a comprehensive solution for building intelligent, production-ready chatbot systems that combine the best of both worlds: the conversational capabilities of foundation models and the accuracy of retrieval-augmented generation. We've built a complete end-to-end system that includes: Intelligent Dual-Mode Architecture: Users can choose between direct LLM interaction for general queries or RAG-based responses for document-specific questions, all within a single unified interface. Automatic Categorization: The system eliminates user friction by automatically detecting the category of each query using LLM analysis, routing requests to the appropriate knowledge base without manual intervention. Production-Grade Infrastructure: With Docker containerization, Terraform infrastructure as code, ECS Fargate orchestration, and Application Load Balancer distribution, the system is ready for enterprise deployment with high availability and scalability. Complete DevOps Pipeline: The GitLab CI/CD pipeline automates the entire deployment process from code commit to production deployment, including conditional builds, infrastructure provisioning, and cleanup. Enhanced User Experience: Features like typing indicators, interactive feedback buttons, response regeneration, and conversation memory create an engaging and intuitive user interface. Link: http://alb-chatbot-872330638.us-east-1.elb.amazonaws.com/ This architecture can be adapted for various use cases: In production deployments, we've observed: While the current implementation is production-ready, several enhancements could further improve the system: Building production-ready AI applications requires more than just connecting to an LLM API. It demands careful consideration of user experience, system architecture, infrastructure scalability, security, observability, and operational excellence. This project demonstrates that with the right tools and architecture patterns, it's possible to create sophisticated AI systems that are both powerful and maintainable. The combination of AWS Bedrock's managed foundation models, LangChain's flexible orchestration, OpenSearch's vector search capabilities, and modern DevOps practices creates a robust foundation for enterprise AI applications. The automatic categorization feature, in particular, showcases how thoughtful design can transform complex systems into intuitive user experiences. Whether you're a developer looking to build your first AI application, an architect designing enterprise systems, or a DevOps engineer implementing CI/CD for ML workloads, this project provides practical patterns and best practices that can be applied to your own initiatives. The future of AI applications lies not just in the models themselves, but in how we architect, deploy, and operate them at scale. This project is a step in that direction. Questions? Suggestions? Contributions are welcome! Feel free to open issues or submit pull requests. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: ┌─────────────────────────────────────────────────────────────────┐ │ User Interface │ │ (Streamlit Multi-Page App) │ └────────────────┬────────────────────────────────────────────────┘ │ ┌────────┴────────┐ │ │ ┌───────▼──────┐ ┌──────▼────────┐ │ Chatbot │ │ RAG Agent │ │ (Direct) │ │ (Document) │ └───────┬──────┘ └──────┬────────┘ │ │ │ ┌───────┴────────┐ │ │ │ │ ┌────▼─────┐ ┌─────▼──────┐ │ │ S3 │ │ OpenSearch │ │ │Documents │ │ Vector │ │ └──────────┘ │ Store │ │ └────────────┘ │ └─────────┬─────────┘ │ ┌───────▼────────┐ │ AWS Bedrock │ │ Foundation │ │ Models │ └────────────────┘ Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: ┌─────────────────────────────────────────────────────────────────┐ │ User Interface │ │ (Streamlit Multi-Page App) │ └────────────────┬────────────────────────────────────────────────┘ │ ┌────────┴────────┐ │ │ ┌───────▼──────┐ ┌──────▼────────┐ │ Chatbot │ │ RAG Agent │ │ (Direct) │ │ (Document) │ └───────┬──────┘ └──────┬────────┘ │ │ │ ┌───────┴────────┐ │ │ │ │ ┌────▼─────┐ ┌─────▼──────┐ │ │ S3 │ │ OpenSearch │ │ │Documents │ │ Vector │ │ └──────────┘ │ Store │ │ └────────────┘ │ └─────────┬─────────┘ │ ┌───────▼────────┐ │ AWS Bedrock │ │ Foundation │ │ Models │ └────────────────┘ CODE_BLOCK: ┌─────────────────────────────────────────────────────────────────┐ │ User Interface │ │ (Streamlit Multi-Page App) │ └────────────────┬────────────────────────────────────────────────┘ │ ┌────────┴────────┐ │ │ ┌───────▼──────┐ ┌──────▼────────┐ │ Chatbot │ │ RAG Agent │ │ (Direct) │ │ (Document) │ └───────┬──────┘ └──────┬────────┘ │ │ │ ┌───────┴────────┐ │ │ │ │ ┌────▼─────┐ ┌─────▼──────┐ │ │ S3 │ │ OpenSearch │ │ │Documents │ │ Vector │ │ └──────────┘ │ Store │ │ └────────────┘ │ └─────────┬─────────┘ │ ┌───────▼────────┐ │ AWS Bedrock │ │ Foundation │ │ Models │ └────────────────┘ CODE_BLOCK: GitLab CI/CD → Docker Build → ECR → ECS Fargate → ALB → Users ↓ CloudWatch Logs Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: GitLab CI/CD → Docker Build → ECR → ECS Fargate → ALB → Users ↓ CloudWatch Logs CODE_BLOCK: GitLab CI/CD → Docker Build → ECR → ECS Fargate → ALB → Users ↓ CloudWatch Logs COMMAND_BLOCK: build-llm-chatbot-using-langchain/ │ ├── Chatbot/ # General chatbot module │ ├── chatbot.py # Main chatbot interface │ ├── bedrock_model.py # Bedrock integration & logic │ ├── app_feature.py # UI components & styling │ ├── RAGAgent/ # RAG agent module │ └── agent.py # RAG implementation │ ├── Terraform/ # Infrastructure as Code │ ├── provider.tf # AWS provider & backend config │ ├── ecr.tf # ECR repository │ ├── ecs.tf # ECS cluster & service │ ├── alb.tf # Application Load Balancer │ ├── iam.tf # IAM roles & policies │ ├── data.tf # Data sources │ ├── var.tf # Variable definitions │ └── terraform.tfvars # Variable values │ ├── navigation.py # Multi-page navigation ├── config.toml # Streamlit theme config ├── requirements.txt # Python dependencies ├── Dockerfile # Container definition ├── .gitlab-ci.yml # CI/CD pipeline └── README.md # Documentation Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: build-llm-chatbot-using-langchain/ │ ├── Chatbot/ # General chatbot module │ ├── chatbot.py # Main chatbot interface │ ├── bedrock_model.py # Bedrock integration & logic │ ├── app_feature.py # UI components & styling │ ├── RAGAgent/ # RAG agent module │ └── agent.py # RAG implementation │ ├── Terraform/ # Infrastructure as Code │ ├── provider.tf # AWS provider & backend config │ ├── ecr.tf # ECR repository │ ├── ecs.tf # ECS cluster & service │ ├── alb.tf # Application Load Balancer │ ├── iam.tf # IAM roles & policies │ ├── data.tf # Data sources │ ├── var.tf # Variable definitions │ └── terraform.tfvars # Variable values │ ├── navigation.py # Multi-page navigation ├── config.toml # Streamlit theme config ├── requirements.txt # Python dependencies ├── Dockerfile # Container definition ├── .gitlab-ci.yml # CI/CD pipeline └── README.md # Documentation COMMAND_BLOCK: build-llm-chatbot-using-langchain/ │ ├── Chatbot/ # General chatbot module │ ├── chatbot.py # Main chatbot interface │ ├── bedrock_model.py # Bedrock integration & logic │ ├── app_feature.py # UI components & styling │ ├── RAGAgent/ # RAG agent module │ └── agent.py # RAG implementation │ ├── Terraform/ # Infrastructure as Code │ ├── provider.tf # AWS provider & backend config │ ├── ecr.tf # ECR repository │ ├── ecs.tf # ECS cluster & service │ ├── alb.tf # Application Load Balancer │ ├── iam.tf # IAM roles & policies │ ├── data.tf # Data sources │ ├── var.tf # Variable definitions │ └── terraform.tfvars # Variable values │ ├── navigation.py # Multi-page navigation ├── config.toml # Streamlit theme config ├── requirements.txt # Python dependencies ├── Dockerfile # Container definition ├── .gitlab-ci.yml # CI/CD pipeline └── README.md # Documentation COMMAND_BLOCK: # Page configuration st.set_page_config(page_title="Chatbot", page_icon="img.png", layout="wide") # Model selection model_list = [ "anthropic.claude-3-sonnet-20240229-v1:0", "anthropic.claude-3-haiku-20240307-v1:0", "cohere.command-r-plus-v1:0", "cohere.command-r-v1:0" ] # Sidebar configuration - Model selector - Temperature slider (0.0-1.0) - Max tokens slider (100-2048) - S3 bucket input for category-based answers - New message button - Chat history display Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Page configuration st.set_page_config(page_title="Chatbot", page_icon="img.png", layout="wide") # Model selection model_list = [ "anthropic.claude-3-sonnet-20240229-v1:0", "anthropic.claude-3-haiku-20240307-v1:0", "cohere.command-r-plus-v1:0", "cohere.command-r-v1:0" ] # Sidebar configuration - Model selector - Temperature slider (0.0-1.0) - Max tokens slider (100-2048) - S3 bucket input for category-based answers - New message button - Chat history display COMMAND_BLOCK: # Page configuration st.set_page_config(page_title="Chatbot", page_icon="img.png", layout="wide") # Model selection model_list = [ "anthropic.claude-3-sonnet-20240229-v1:0", "anthropic.claude-3-haiku-20240307-v1:0", "cohere.command-r-plus-v1:0", "cohere.command-r-v1:0" ] # Sidebar configuration - Model selector - Temperature slider (0.0-1.0) - Max tokens slider (100-2048) - S3 bucket input for category-based answers - New message button - Chat history display CODE_BLOCK: llm = ChatBedrockConverse( client=bedrock_client, model_id=model_id, max_tokens=max_tokens, temperature=temperature ) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: llm = ChatBedrockConverse( client=bedrock_client, model_id=model_id, max_tokens=max_tokens, temperature=temperature ) CODE_BLOCK: llm = ChatBedrockConverse( client=bedrock_client, model_id=model_id, max_tokens=max_tokens, temperature=temperature ) CODE_BLOCK: chat_history = InMemoryChatMessageHistory() memory = ConversationBufferMemory( memory_key="chat_history", chat_memory=chat_history, return_messages=True ) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: chat_history = InMemoryChatMessageHistory() memory = ConversationBufferMemory( memory_key="chat_history", chat_memory=chat_history, return_messages=True ) CODE_BLOCK: chat_history = InMemoryChatMessageHistory() memory = ConversationBufferMemory( memory_key="chat_history", chat_memory=chat_history, return_messages=True ) COMMAND_BLOCK: def typing_indicator(): # Animated "Bot is typing..." with dots # CSS animation for smooth UX Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: def typing_indicator(): # Animated "Bot is typing..." with dots # CSS animation for smooth UX COMMAND_BLOCK: def typing_indicator(): # Animated "Bot is typing..." with dots # CSS animation for smooth UX COMMAND_BLOCK: def autoscroll(): # JavaScript to scroll to latest message Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: def autoscroll(): # JavaScript to scroll to latest message COMMAND_BLOCK: def autoscroll(): # JavaScript to scroll to latest message CODE_BLOCK: AWS_REGION = "us-east-1" S3_BUCKET = "rag-agent-knowledge-base-98770" OPENSEARCH_HOST = "https://search-mydemanricsearchdomain-..." OPENSEARCH_INDEX = "rag-index" EMBEDDING_MODEL_ID = "amazon.titan-embed-text-v2:0" CATEGORIES = ( "Technical", "Healthcare", "Agriculture", "Travelling", "Gadgets", "Music", "Cooking" ) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: AWS_REGION = "us-east-1" S3_BUCKET = "rag-agent-knowledge-base-98770" OPENSEARCH_HOST = "https://search-mydemanricsearchdomain-..." OPENSEARCH_INDEX = "rag-index" EMBEDDING_MODEL_ID = "amazon.titan-embed-text-v2:0" CATEGORIES = ( "Technical", "Healthcare", "Agriculture", "Travelling", "Gadgets", "Music", "Cooking" ) CODE_BLOCK: AWS_REGION = "us-east-1" S3_BUCKET = "rag-agent-knowledge-base-98770" OPENSEARCH_HOST = "https://search-mydemanricsearchdomain-..." OPENSEARCH_INDEX = "rag-index" EMBEDDING_MODEL_ID = "amazon.titan-embed-text-v2:0" CATEGORIES = ( "Technical", "Healthcare", "Agriculture", "Travelling", "Gadgets", "Music", "Cooking" ) COMMAND_BLOCK: def categorize_prompt(user_input: str, llm) -> str: prompt = f"""Classify this question into ONE category from: {', '.join(CATEGORIES)} Question: {user_input} Return ONLY the category name.""" response = llm.invoke(prompt) return category if category in CATEGORIES else CATEGORIES[0] Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: def categorize_prompt(user_input: str, llm) -> str: prompt = f"""Classify this question into ONE category from: {', '.join(CATEGORIES)} Question: {user_input} Return ONLY the category name.""" response = llm.invoke(prompt) return category if category in CATEGORIES else CATEGORIES[0] COMMAND_BLOCK: def categorize_prompt(user_input: str, llm) -> str: prompt = f"""Classify this question into ONE category from: {', '.join(CATEGORIES)} Question: {user_input} Return ONLY the category name.""" response = llm.invoke(prompt) return category if category in CATEGORIES else CATEGORIES[0] COMMAND_BLOCK: @st.cache_resource(show_spinner="🔍 Indexing documents...") def build_vectorstore(selected_category: str) -> OpenSearchVectorSearch: # Load documents from S3 loader = S3DirectoryLoader(bucket=S3_BUCKET, prefix=selected_category) documents = loader.load() # Split into chunks splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200 ) splits = splitter.split_documents(documents) # Create embeddings embeddings = BedrockEmbeddings( model_id=EMBEDDING_MODEL_ID, region_name=AWS_REGION ) # Store in OpenSearch vectorstore = OpenSearchVectorSearch(...) vectorstore.add_documents(splits) return vectorstore Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: @st.cache_resource(show_spinner="🔍 Indexing documents...") def build_vectorstore(selected_category: str) -> OpenSearchVectorSearch: # Load documents from S3 loader = S3DirectoryLoader(bucket=S3_BUCKET, prefix=selected_category) documents = loader.load() # Split into chunks splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200 ) splits = splitter.split_documents(documents) # Create embeddings embeddings = BedrockEmbeddings( model_id=EMBEDDING_MODEL_ID, region_name=AWS_REGION ) # Store in OpenSearch vectorstore = OpenSearchVectorSearch(...) vectorstore.add_documents(splits) return vectorstore COMMAND_BLOCK: @st.cache_resource(show_spinner="🔍 Indexing documents...") def build_vectorstore(selected_category: str) -> OpenSearchVectorSearch: # Load documents from S3 loader = S3DirectoryLoader(bucket=S3_BUCKET, prefix=selected_category) documents = loader.load() # Split into chunks splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200 ) splits = splitter.split_documents(documents) # Create embeddings embeddings = BedrockEmbeddings( model_id=EMBEDDING_MODEL_ID, region_name=AWS_REGION ) # Store in OpenSearch vectorstore = OpenSearchVectorSearch(...) vectorstore.add_documents(splits) return vectorstore CODE_BLOCK: rag_prompt = ChatPromptTemplate.from_messages([ ( "system", "You are a helpful assistant. " "Answer using the provided context and chat history when available. " "If the answer is not in the context, use your own knowledge." ), ( "human", "Chat History:\n{chat_history}\n\n" "Context:\n{context}\n\n" "Question:\n{question}" ), ]) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: rag_prompt = ChatPromptTemplate.from_messages([ ( "system", "You are a helpful assistant. " "Answer using the provided context and chat history when available. " "If the answer is not in the context, use your own knowledge." ), ( "human", "Chat History:\n{chat_history}\n\n" "Context:\n{context}\n\n" "Question:\n{question}" ), ]) CODE_BLOCK: rag_prompt = ChatPromptTemplate.from_messages([ ( "system", "You are a helpful assistant. " "Answer using the provided context and chat history when available. " "If the answer is not in the context, use your own knowledge." ), ( "human", "Chat History:\n{chat_history}\n\n" "Context:\n{context}\n\n" "Question:\n{question}" ), ]) COMMAND_BLOCK: # Auto-categorize category = categorize_prompt(user_input, llm) # Build vector store vectorstore = build_vectorstore(category) retriever = vectorstore.as_retriever( search_type="similarity", search_kwargs={"k": 3} ) # Retrieve relevant documents docs = retriever.invoke(user_input) context = "\n\n".join(doc.page_content for doc in docs) # Build chat history chat_history = "\n".join( f"{msg['role'].capitalize()}: {msg['content']}" for msg in st.session_state.agent_messages[:-1] ) # Generate response prompt = rag_prompt.invoke({ "chat_history": chat_history, "context": context, "question": user_input }) response = llm.invoke(prompt) Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Auto-categorize category = categorize_prompt(user_input, llm) # Build vector store vectorstore = build_vectorstore(category) retriever = vectorstore.as_retriever( search_type="similarity", search_kwargs={"k": 3} ) # Retrieve relevant documents docs = retriever.invoke(user_input) context = "\n\n".join(doc.page_content for doc in docs) # Build chat history chat_history = "\n".join( f"{msg['role'].capitalize()}: {msg['content']}" for msg in st.session_state.agent_messages[:-1] ) # Generate response prompt = rag_prompt.invoke({ "chat_history": chat_history, "context": context, "question": user_input }) response = llm.invoke(prompt) COMMAND_BLOCK: # Auto-categorize category = categorize_prompt(user_input, llm) # Build vector store vectorstore = build_vectorstore(category) retriever = vectorstore.as_retriever( search_type="similarity", search_kwargs={"k": 3} ) # Retrieve relevant documents docs = retriever.invoke(user_input) context = "\n\n".join(doc.page_content for doc in docs) # Build chat history chat_history = "\n".join( f"{msg['role'].capitalize()}: {msg['content']}" for msg in st.session_state.agent_messages[:-1] ) # Generate response prompt = rag_prompt.invoke({ "chat_history": chat_history, "context": context, "question": user_input }) response = llm.invoke(prompt) COMMAND_BLOCK: import streamlit as st import sys # Add module paths sys.path.append('./Chatbot') sys.path.append('./RAGAgent') # Define pages pages = { "Resources": [ st.Page("Chatbot/chatbot.py", title="ChatBot"), st.Page("RAGAgent/agent.py", title="RAGAgent") ], } # Run navigation pg = st.navigation(pages, position="top") pg.run() Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: import streamlit as st import sys # Add module paths sys.path.append('./Chatbot') sys.path.append('./RAGAgent') # Define pages pages = { "Resources": [ st.Page("Chatbot/chatbot.py", title="ChatBot"), st.Page("RAGAgent/agent.py", title="RAGAgent") ], } # Run navigation pg = st.navigation(pages, position="top") pg.run() COMMAND_BLOCK: import streamlit as st import sys # Add module paths sys.path.append('./Chatbot') sys.path.append('./RAGAgent') # Define pages pages = { "Resources": [ st.Page("Chatbot/chatbot.py", title="ChatBot"), st.Page("RAGAgent/agent.py", title="RAGAgent") ], } # Run navigation pg = st.navigation(pages, position="top") pg.run() COMMAND_BLOCK: # .streamlit/config.toml [theme] base = "dark" font = "serif" baseFontSize=15 primaryColor = "forestGreen" backgroundColor = "#141415" codeBackgroundColor = "#1e2026" # Near-black navy textColor="#74e6f0" baseRadius="full" [theme.sidebar] backgroundColor = "#0F172A" # Deep Navy secondaryBackgroundColor = "#1E293B" # Slate Dark primaryColor = "#0795ed" # Neon Sky Blue textColor = "#f5f2f4" # Soft white (easy on eyes) codeTextColor = "#994780" # Soft light gray codeBackgroundColor = "#020617" # Near-black navy baseRadius = "50px" buttonRadius = "100px" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # .streamlit/config.toml [theme] base = "dark" font = "serif" baseFontSize=15 primaryColor = "forestGreen" backgroundColor = "#141415" codeBackgroundColor = "#1e2026" # Near-black navy textColor="#74e6f0" baseRadius="full" [theme.sidebar] backgroundColor = "#0F172A" # Deep Navy secondaryBackgroundColor = "#1E293B" # Slate Dark primaryColor = "#0795ed" # Neon Sky Blue textColor = "#f5f2f4" # Soft white (easy on eyes) codeTextColor = "#994780" # Soft light gray codeBackgroundColor = "#020617" # Near-black navy baseRadius = "50px" buttonRadius = "100px" COMMAND_BLOCK: # .streamlit/config.toml [theme] base = "dark" font = "serif" baseFontSize=15 primaryColor = "forestGreen" backgroundColor = "#141415" codeBackgroundColor = "#1e2026" # Near-black navy textColor="#74e6f0" baseRadius="full" [theme.sidebar] backgroundColor = "#0F172A" # Deep Navy secondaryBackgroundColor = "#1E293B" # Slate Dark primaryColor = "#0795ed" # Neon Sky Blue textColor = "#f5f2f4" # Soft white (easy on eyes) codeTextColor = "#994780" # Soft light gray codeBackgroundColor = "#020617" # Near-black navy baseRadius = "50px" buttonRadius = "100px" CODE_BLOCK: terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.17.0" } } backend "s3" { bucket = "terraform0806" key = "TerraformStateFiles1" region = "us-east-1" } } provider "aws" { region = "us-east-1" } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.17.0" } } backend "s3" { bucket = "terraform0806" key = "TerraformStateFiles1" region = "us-east-1" } } provider "aws" { region = "us-east-1" } CODE_BLOCK: terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.17.0" } } backend "s3" { bucket = "terraform0806" key = "TerraformStateFiles1" region = "us-east-1" } } provider "aws" { region = "us-east-1" } CODE_BLOCK: resource "aws_ecr_repository" "aws-ecr" { name = "streamlit-chatbot" image_scanning_configuration { scan_on_push = true } tags = var.custom_tags } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: resource "aws_ecr_repository" "aws-ecr" { name = "streamlit-chatbot" image_scanning_configuration { scan_on_push = true } tags = var.custom_tags } CODE_BLOCK: resource "aws_ecr_repository" "aws-ecr" { name = "streamlit-chatbot" image_scanning_configuration { scan_on_push = true } tags = var.custom_tags } CODE_BLOCK: resource "aws_ecs_cluster" "aws-ecs-cluster" { name = var.ecs_details["Name"] configuration { execute_command_configuration { kms_key_id = aws_kms_key.kms.arn logging = var.ecs_details["logging"] log_configuration { cloud_watch_encryption_enabled = true cloud_watch_log_group_name = aws_cloudwatch_log_group.log-group.name } } } } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: resource "aws_ecs_cluster" "aws-ecs-cluster" { name = var.ecs_details["Name"] configuration { execute_command_configuration { kms_key_id = aws_kms_key.kms.arn logging = var.ecs_details["logging"] log_configuration { cloud_watch_encryption_enabled = true cloud_watch_log_group_name = aws_cloudwatch_log_group.log-group.name } } } } CODE_BLOCK: resource "aws_ecs_cluster" "aws-ecs-cluster" { name = var.ecs_details["Name"] configuration { execute_command_configuration { kms_key_id = aws_kms_key.kms.arn logging = var.ecs_details["logging"] log_configuration { cloud_watch_encryption_enabled = true cloud_watch_log_group_name = aws_cloudwatch_log_group.log-group.name } } } } CODE_BLOCK: resource "aws_ecs_task_definition" "taskdef" { family = var.ecs_task_def["family"] container_definitions = jsonencode([{ name = var.ecs_task_def["cont_name"] image = "${aws_ecr_repository.aws-ecr.repository_url}:v3" portMappings = [{ containerPort = var.ecs_task_def["containerport"] }] cpu = var.ecs_task_def["cpu_allocations"] memory = var.ecs_task_def["mem_allocations"] }]) requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" memory = "2048" cpu = "1024" execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: resource "aws_ecs_task_definition" "taskdef" { family = var.ecs_task_def["family"] container_definitions = jsonencode([{ name = var.ecs_task_def["cont_name"] image = "${aws_ecr_repository.aws-ecr.repository_url}:v3" portMappings = [{ containerPort = var.ecs_task_def["containerport"] }] cpu = var.ecs_task_def["cpu_allocations"] memory = var.ecs_task_def["mem_allocations"] }]) requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" memory = "2048" cpu = "1024" execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn } CODE_BLOCK: resource "aws_ecs_task_definition" "taskdef" { family = var.ecs_task_def["family"] container_definitions = jsonencode([{ name = var.ecs_task_def["cont_name"] image = "${aws_ecr_repository.aws-ecr.repository_url}:v3" portMappings = [{ containerPort = var.ecs_task_def["containerport"] }] cpu = var.ecs_task_def["cpu_allocations"] memory = var.ecs_task_def["mem_allocations"] }]) requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" memory = "2048" cpu = "1024" execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn } CODE_BLOCK: resource "aws_ecs_service" "streamlit" { name = "service-chatbot" cluster = aws_ecs_cluster.aws-ecs-cluster.id task_definition = aws_ecs_task_definition.taskdef.arn desired_count = var.ecs_task_count launch_type = "FARGATE" load_balancer { target_group_arn = aws_lb_target_group.this_tg.arn container_name = var.ecs_task_def["cont_name"] container_port = var.ecs_task_def["containerport"] } network_configuration { assign_public_ip = true subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] security_groups = [data.aws_security_group.streamlit_app.id] } } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: resource "aws_ecs_service" "streamlit" { name = "service-chatbot" cluster = aws_ecs_cluster.aws-ecs-cluster.id task_definition = aws_ecs_task_definition.taskdef.arn desired_count = var.ecs_task_count launch_type = "FARGATE" load_balancer { target_group_arn = aws_lb_target_group.this_tg.arn container_name = var.ecs_task_def["cont_name"] container_port = var.ecs_task_def["containerport"] } network_configuration { assign_public_ip = true subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] security_groups = [data.aws_security_group.streamlit_app.id] } } CODE_BLOCK: resource "aws_ecs_service" "streamlit" { name = "service-chatbot" cluster = aws_ecs_cluster.aws-ecs-cluster.id task_definition = aws_ecs_task_definition.taskdef.arn desired_count = var.ecs_task_count launch_type = "FARGATE" load_balancer { target_group_arn = aws_lb_target_group.this_tg.arn container_name = var.ecs_task_def["cont_name"] container_port = var.ecs_task_def["containerport"] } network_configuration { assign_public_ip = true subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] security_groups = [data.aws_security_group.streamlit_app.id] } } CODE_BLOCK: resource "aws_lb" "this_alb" { name = var.ALB_conf["name"] load_balancer_type = "application" ip_address_type = "ipv4" internal = false security_groups = [data.aws_security_group.ext_alb.id] subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] } resource "aws_lb_target_group" "this_tg" { name = var.TG_conf["name"] port = 8501 protocol = "HTTP" vpc_id = data.aws_vpc.this_vpc.id target_type = "ip" health_check { enabled = true healthy_threshold = 2 interval = 30 path = "/" } } resource "aws_lb_listener" "this_alb_lis" { load_balancer_arn = aws_lb.this_alb.arn port = 80 protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.this_tg.arn } } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: resource "aws_lb" "this_alb" { name = var.ALB_conf["name"] load_balancer_type = "application" ip_address_type = "ipv4" internal = false security_groups = [data.aws_security_group.ext_alb.id] subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] } resource "aws_lb_target_group" "this_tg" { name = var.TG_conf["name"] port = 8501 protocol = "HTTP" vpc_id = data.aws_vpc.this_vpc.id target_type = "ip" health_check { enabled = true healthy_threshold = 2 interval = 30 path = "/" } } resource "aws_lb_listener" "this_alb_lis" { load_balancer_arn = aws_lb.this_alb.arn port = 80 protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.this_tg.arn } } CODE_BLOCK: resource "aws_lb" "this_alb" { name = var.ALB_conf["name"] load_balancer_type = "application" ip_address_type = "ipv4" internal = false security_groups = [data.aws_security_group.ext_alb.id] subnets = [data.aws_subnet.web_subnet_1a.id, data.aws_subnet.web_subnet_1b.id] } resource "aws_lb_target_group" "this_tg" { name = var.TG_conf["name"] port = 8501 protocol = "HTTP" vpc_id = data.aws_vpc.this_vpc.id target_type = "ip" health_check { enabled = true healthy_threshold = 2 interval = 30 path = "/" } } resource "aws_lb_listener" "this_alb_lis" { load_balancer_arn = aws_lb.this_alb.arn port = 80 protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.this_tg.arn } } COMMAND_BLOCK: resource "aws_iam_role" "ecsTaskExecutionRole" { name = "ecsTaskExecutionRole" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ecs-tasks.amazonaws.com" } }] }) } # Attach policies for: # - ECR access # - CloudWatch Logs # - Bedrock access # - S3 access # - OpenSearch access Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: resource "aws_iam_role" "ecsTaskExecutionRole" { name = "ecsTaskExecutionRole" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ecs-tasks.amazonaws.com" } }] }) } # Attach policies for: # - ECR access # - CloudWatch Logs # - Bedrock access # - S3 access # - OpenSearch access COMMAND_BLOCK: resource "aws_iam_role" "ecsTaskExecutionRole" { name = "ecsTaskExecutionRole" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ecs-tasks.amazonaws.com" } }] }) } # Attach policies for: # - ECR access # - CloudWatch Logs # - Bedrock access # - S3 access # - OpenSearch access CODE_BLOCK: FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip3 install --no-cache-dir -r requirements.txt && \ apt-get update -y && \ apt-get install -y libxcb1 libx11-6 libxext6 libxrender1 libgl1 && \ apt-get install -y libglib2.0-0 && \ rm -rf /root/.cache/pip COPY Chatbot/ ./Chatbot/ COPY RAGAgent/ ./RAGAgent/ COPY navigation.py ./navigation.py COPY config.toml /root/.streamlit/config.toml EXPOSE 8501 CMD ["streamlit", "run", "navigation.py", "--server.port=8501", "--server.address=0.0.0.0"] Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip3 install --no-cache-dir -r requirements.txt && \ apt-get update -y && \ apt-get install -y libxcb1 libx11-6 libxext6 libxrender1 libgl1 && \ apt-get install -y libglib2.0-0 && \ rm -rf /root/.cache/pip COPY Chatbot/ ./Chatbot/ COPY RAGAgent/ ./RAGAgent/ COPY navigation.py ./navigation.py COPY config.toml /root/.streamlit/config.toml EXPOSE 8501 CMD ["streamlit", "run", "navigation.py", "--server.port=8501", "--server.address=0.0.0.0"] CODE_BLOCK: FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip3 install --no-cache-dir -r requirements.txt && \ apt-get update -y && \ apt-get install -y libxcb1 libx11-6 libxext6 libxrender1 libgl1 && \ apt-get install -y libglib2.0-0 && \ rm -rf /root/.cache/pip COPY Chatbot/ ./Chatbot/ COPY RAGAgent/ ./RAGAgent/ COPY navigation.py ./navigation.py COPY config.toml /root/.streamlit/config.toml EXPOSE 8501 CMD ["streamlit", "run", "navigation.py", "--server.port=8501", "--server.address=0.0.0.0"] CODE_BLOCK: default: tags: - anirban variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" URL: <account-id>.dkr.ecr.us-east-1.amazonaws.com/ REPO: streamlit-chatbot TAG: v3 stages: - Image_Build - Resources_Build - Delete_Cache Image Build: stage: Image_Build image: docker:latest services: - docker:dind script: - echo "~~~~~~~~~~~~~~~~~~~~~~~~Build ECR Repo and Push the Docker Image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - terraform -chdir=Terraform init - terraform -chdir=Terraform plan -target=aws_ecr_repository.aws-ecr - terraform -chdir=Terraform apply -target=aws_ecr_repository.aws-ecr -auto-approve - echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Validate if the docker image exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' - | if ! sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs; then echo "Docker image not found." echo "~~~~~~~~~~~~~~~~~~~~~~~~Building Docker Image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker build -t $URL$REPO:$TAG . sleep 60 echo "~~~~~~~~~~~~~~~~~~~~~~~~Logging in to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $URL echo "~~~~~~~~~~~~~~~~~~~~~~~~Pushing image to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker push $URL$REPO:$TAG else echo "~~~~~~~~~~~~~~~~~~~~~~~~Docker image already exists~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" fi artifacts: paths: - Terraform/.terraform/ - Terraform/terraform.tfstate* expire_in: 1 hour except: changes: - README.md Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: default: tags: - anirban variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" URL: <account-id>.dkr.ecr.us-east-1.amazonaws.com/ REPO: streamlit-chatbot TAG: v3 stages: - Image_Build - Resources_Build - Delete_Cache Image Build: stage: Image_Build image: docker:latest services: - docker:dind script: - echo "~~~~~~~~~~~~~~~~~~~~~~~~Build ECR Repo and Push the Docker Image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - terraform -chdir=Terraform init - terraform -chdir=Terraform plan -target=aws_ecr_repository.aws-ecr - terraform -chdir=Terraform apply -target=aws_ecr_repository.aws-ecr -auto-approve - echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Validate if the docker image exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' - | if ! sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs; then echo "Docker image not found." echo "~~~~~~~~~~~~~~~~~~~~~~~~Building Docker Image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker build -t $URL$REPO:$TAG . sleep 60 echo "~~~~~~~~~~~~~~~~~~~~~~~~Logging in to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $URL echo "~~~~~~~~~~~~~~~~~~~~~~~~Pushing image to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker push $URL$REPO:$TAG else echo "~~~~~~~~~~~~~~~~~~~~~~~~Docker image already exists~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" fi artifacts: paths: - Terraform/.terraform/ - Terraform/terraform.tfstate* expire_in: 1 hour except: changes: - README.md CODE_BLOCK: default: tags: - anirban variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" URL: <account-id>.dkr.ecr.us-east-1.amazonaws.com/ REPO: streamlit-chatbot TAG: v3 stages: - Image_Build - Resources_Build - Delete_Cache Image Build: stage: Image_Build image: docker:latest services: - docker:dind script: - echo "~~~~~~~~~~~~~~~~~~~~~~~~Build ECR Repo and Push the Docker Image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - terraform -chdir=Terraform init - terraform -chdir=Terraform plan -target=aws_ecr_repository.aws-ecr - terraform -chdir=Terraform apply -target=aws_ecr_repository.aws-ecr -auto-approve - echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Validate if the docker image exists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' - | if ! sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs; then echo "Docker image not found." echo "~~~~~~~~~~~~~~~~~~~~~~~~Building Docker Image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker build -t $URL$REPO:$TAG . sleep 60 echo "~~~~~~~~~~~~~~~~~~~~~~~~Logging in to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $URL echo "~~~~~~~~~~~~~~~~~~~~~~~~Pushing image to AWS ECR~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" sudo docker push $URL$REPO:$TAG else echo "~~~~~~~~~~~~~~~~~~~~~~~~Docker image already exists~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" fi artifacts: paths: - Terraform/.terraform/ - Terraform/terraform.tfstate* expire_in: 1 hour except: changes: - README.md CODE_BLOCK: Resource Build: stage: Resources_Build script: - terraform -chdir=Terraform init - terraform -chdir=Terraform plan - terraform -chdir=Terraform apply -auto-approve dependencies: - Image Build except: changes: - README.md Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: Resource Build: stage: Resources_Build script: - terraform -chdir=Terraform init - terraform -chdir=Terraform plan - terraform -chdir=Terraform apply -auto-approve dependencies: - Image Build except: changes: - README.md CODE_BLOCK: Resource Build: stage: Resources_Build script: - terraform -chdir=Terraform init - terraform -chdir=Terraform plan - terraform -chdir=Terraform apply -auto-approve dependencies: - Image Build except: changes: - README.md CODE_BLOCK: Delete Cache: stage: Delete_Cache script: - sudo docker image rm $(sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs) - sudo docker builder prune -a -f except: changes: - README.md Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: Delete Cache: stage: Delete_Cache script: - sudo docker image rm $(sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs) - sudo docker builder prune -a -f except: changes: - README.md CODE_BLOCK: Delete Cache: stage: Delete_Cache script: - sudo docker image rm $(sudo docker inspect $URL$REPO:$TAG --format '{{ json .}}' | jq '.RepoTags[0]' | xargs) - sudo docker builder prune -a -f except: changes: - README.md CODE_BLOCK: 1. Developer pushes code to GitLab ↓ 2. GitLab CI triggers pipeline ↓ 3. Terraform creates ECR repository ↓ 4. Docker builds image from Dockerfile ↓ 5. Image pushed to ECR ↓ 6. Terraform provisions: - ECS Cluster - Task Definition - ECS Service - Application Load Balancer - Target Groups - Security Groups - IAM Roles - CloudWatch Log Groups ↓ 7. ECS pulls image from ECR ↓ 8. Fargate launches containers ↓ 9. ALB routes traffic to containers ↓ 10. Application accessible via ALB DNS Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: 1. Developer pushes code to GitLab ↓ 2. GitLab CI triggers pipeline ↓ 3. Terraform creates ECR repository ↓ 4. Docker builds image from Dockerfile ↓ 5. Image pushed to ECR ↓ 6. Terraform provisions: - ECS Cluster - Task Definition - ECS Service - Application Load Balancer - Target Groups - Security Groups - IAM Roles - CloudWatch Log Groups ↓ 7. ECS pulls image from ECR ↓ 8. Fargate launches containers ↓ 9. ALB routes traffic to containers ↓ 10. Application accessible via ALB DNS CODE_BLOCK: 1. Developer pushes code to GitLab ↓ 2. GitLab CI triggers pipeline ↓ 3. Terraform creates ECR repository ↓ 4. Docker builds image from Dockerfile ↓ 5. Image pushed to ECR ↓ 6. Terraform provisions: - ECS Cluster - Task Definition - ECS Service - Application Load Balancer - Target Groups - Security Groups - IAM Roles - CloudWatch Log Groups ↓ 7. ECS pulls image from ECR ↓ 8. Fargate launches containers ↓ 9. ALB routes traffic to containers ↓ 10. Application accessible via ALB DNS COMMAND_BLOCK: # AWS CLI aws --version # Terraform terraform --version # Docker docker --version # Python 3.13+ python --version Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # AWS CLI aws --version # Terraform terraform --version # Docker docker --version # Python 3.13+ python --version COMMAND_BLOCK: # AWS CLI aws --version # Terraform terraform --version # Docker docker --version # Python 3.13+ python --version COMMAND_BLOCK: # Create domain via AWS Console or CLI aws opensearch create-domain \ --domain-name mydemanricsearchdomain \ --engine-version OpenSearch_2.11 \ --cluster-config InstanceType=t3.small.search,InstanceCount=1 \ --ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=10 Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Create domain via AWS Console or CLI aws opensearch create-domain \ --domain-name mydemanricsearchdomain \ --engine-version OpenSearch_2.11 \ --cluster-config InstanceType=t3.small.search,InstanceCount=1 \ --ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=10 COMMAND_BLOCK: # Create domain via AWS Console or CLI aws opensearch create-domain \ --domain-name mydemanricsearchdomain \ --engine-version OpenSearch_2.11 \ --cluster-config InstanceType=t3.small.search,InstanceCount=1 \ --ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=10 COMMAND_BLOCK: git clone https://github.com/dasanirban834/build-llm-chatbot-using-langchain.git cd build-llm-chatbot-using-langchain pip install -r requirements.txt streamlit run navigation.py Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: git clone https://github.com/dasanirban834/build-llm-chatbot-using-langchain.git cd build-llm-chatbot-using-langchain pip install -r requirements.txt streamlit run navigation.py COMMAND_BLOCK: git clone https://github.com/dasanirban834/build-llm-chatbot-using-langchain.git cd build-llm-chatbot-using-langchain pip install -r requirements.txt streamlit run navigation.py - Project Overview - Architecture - Project Structure - Detailed Component Analysis - Deployment Pipeline - Key Features - Setup and Installation - General Chatbot: Direct interaction with AWS Bedrock foundation models - RAG Agent: Intelligent document-based Q&A with automatic categorization - Frontend: Streamlit (Python web framework) - LLM Provider: AWS Bedrock (Claude 3, Cohere Command R+) - Orchestration: LangChain - Vector Database: OpenSearch - Storage: AWS S3 - Infrastructure: Terraform - Container: Docker - CI/CD: GitLab CI - Compute: AWS ECS Fargate - Load Balancer: AWS Application Load Balancer - Multi-model support with dropdown selection - Adjustable temperature for response creativity - Token limit control - S3 integration for document-based responses - Session management - LLM Initialization: - Conversation Memory: - Message Display with Feedback: - Like (👍), Dislike (👎), Love (❤️), Smile (😊) reactions - Response regeneration (🔄) - Copy to clipboard functionality - Feedback state persistence - Typing Indicator: - Auto-scroll: - Custom CSS: - Dark theme styling - Button transparency - Hover effects - Animation keyframes - Automatic category detection (no manual selection) - Document upload to S3 with category assignment - Typing indicators during processing - Feedback buttons (like, dislike, love) - Response regeneration - Conversation memory - Hybrid knowledge (documents + LLM training) - Top navigation bar - Separate session states for each page - Dynamic module loading - Dark theme with navy sidebar - Custom color palette - Rounded buttons and borders - Serif font for readability - ECS Cluster: - Task Definition: - ECS Service: - Slim base image (reduces size by ~500MB) - No-cache pip install - Clear pip cache after install - Multi-stage not needed (simple app) - Combined RUN commands (fewer layers) - Image_Build - Resources_Build - Delete_Cache - Automated ECR repository creation - Conditional image building (only if not exists) - Terraform state management - Artifact passing between stages - Docker cache cleanup - Chatbot: Direct LLM interaction - RAG Agent: Document-based Q&A - LLM analyzes user prompt - Determines category automatically - Routes to correct S3 folder - No manual category selection needed - Separate session states for each mode - Chat history included in prompts - Follow-up questions work naturally - Context maintained across messages - Like, dislike, love reactions - Response regeneration - Feedback state persistence - Visual feedback indicators - Animated "Bot is typing..." - Shows during LLM processing - Improves perceived performance - Better user experience - Claude 3 Sonnet (balanced) - Claude 3 Haiku (fast) - Cohere Command R+ (powerful) - Cohere Command R (efficient) - Upload PDFs, DOCX, TXT, images - Automatic category assignment - S3 storage with folder structure - Vector indexing in OpenSearch - Containerized with Docker - Orchestrated with ECS Fargate - Load balanced with ALB - Auto-scaling capable - CloudWatch logging - KMS encryption - Automated builds - Infrastructure as code - State management - Conditional deployments - Cache cleanup - Multi-language support - Voice input/output - Advanced analytics dashboard - Custom model fine-tuning - Slack/Teams integration - Citation tracking - A/B testing framework - Intelligent Dual-Mode Architecture: Users can choose between direct LLM interaction for general queries or RAG-based responses for document-specific questions, all within a single unified interface. - Automatic Categorization: The system eliminates user friction by automatically detecting the category of each query using LLM analysis, routing requests to the appropriate knowledge base without manual intervention. - Production-Grade Infrastructure: With Docker containerization, Terraform infrastructure as code, ECS Fargate orchestration, and Application Load Balancer distribution, the system is ready for enterprise deployment with high availability and scalability. - Complete DevOps Pipeline: The GitLab CI/CD pipeline automates the entire deployment process from code commit to production deployment, including conditional builds, infrastructure provisioning, and cleanup. - Enhanced User Experience: Features like typing indicators, interactive feedback buttons, response regeneration, and conversation memory create an engaging and intuitive user interface. - Separation of Concerns: Modular architecture with distinct components for chatbot, RAG agent, navigation, and infrastructure - Conversation Context: Separate session states maintain conversation history without context bleeding between modes - Optimized Performance: Caching strategies, efficient document chunking, and slim Docker images reduce latency and costs - Security Best Practices: KMS encryption, IAM roles with least privilege, VPC networking, and secure credential management - Observability: CloudWatch logging, health checks, and monitoring capabilities for production operations - Customer Support: Automated responses with access to product documentation and knowledge bases - Internal Knowledge Management: Employee self-service for HR policies, technical documentation, and procedures - Healthcare Information: Patient education with access to medical literature and treatment guidelines - Legal Document Analysis: Contract review and legal research with citation tracking - Educational Tutoring: Subject-specific assistance with access to textbooks and learning materials - Automatic categorization significantly improves UX: Users shouldn't need to understand how documents are organized - Conversation memory is essential: Follow-up questions are natural in human conversation - Hybrid knowledge works best: Combining document retrieval with LLM training provides comprehensive answers - Infrastructure as Code is non-negotiable: Terraform enables reproducible, version-controlled deployments - Feedback mechanisms drive improvement: User reactions provide valuable data for model refinement - Response Time: 2-5 seconds for RAG queries (including retrieval and generation) - Throughput: Handles 100+ concurrent users with 2 Fargate tasks - Cost Efficiency: ~$150/month for moderate usage (ECS, OpenSearch, Bedrock API calls) - Accuracy: 85%+ user satisfaction based on feedback button analytics - Multi-language support for global deployments - Advanced analytics dashboard for usage patterns and feedback analysis - Citation tracking to show which documents informed each response - A/B testing framework for prompt optimization - Voice input/output integration for accessibility - Slack and Microsoft Teams integration for enterprise communication platforms - Custom model fine-tuning on domain-specific data - Automated document summarization and indexing - Multi-modal support (images, videos, audio) - Federated learning across multiple knowledge bases - Real-time collaborative features - Advanced reasoning capabilities with chain-of-thought prompting