Friday, March 21, 2025

#1 K8S Intro -Lab


GCP Kubernetes Hands-on Lab

Objective

By the end of this lab, students will be able to:

  • Log in to Google Cloud Platform (GCP)
  • Create a Kubernetes cluster using Google Kubernetes Engine (GKE)
  • Deploy and manage nodes
  • Deploy and manage pods
  • Run and expose an application

Prerequisites

  • A Google Cloud Platform (GCP) account
  • Billing enabled for the GCP project
  • Google Cloud SDK installed (or use Google Cloud Shell)
  • Basic understanding of Kubernetes concepts

Step 1: Log in to GCP

  1. Open Google Cloud Console.
  2. Click on Select a project and create a new project (or use an existing one).
  3. Enable the Kubernetes Engine API:
    • Navigate to APIs & Services > Library.
    • Search for Kubernetes Engine API and enable it.
  4. Open Cloud Shell (recommended) or install and configure gcloud CLI:
    gcloud auth login
    gcloud config set project [PROJECT_ID]
    




Step 2: Create a Kubernetes Cluster

  1. In the Google Cloud Console, navigate to the left panel and select Kubernetes Engine.
  2. Click on Create and choose either Auto Pilot or Standard (configure as needed).
  3. Select Zonal as the location type.
  4. Use the Release Channel (default) setting.
  5. (Optional) Use the Setup Guide from the left menu for guided setup.
  6. In the Default-pool section, configure:
    • Number of Nodes (e.g., 3)
    • Machine Configuration:
      • Nodes: E2
      • E2-micro instance type
  7. Click Create Cluster.
  8. Configure kubectl to use the cluster:
    gcloud container clusters get-credentials my-cluster --zone us-central1-a
    
  9. Verify the cluster status:
    kubectl get nodes
    

Step 3: Deploy a Pod

  1. Create a deployment running an Nginx container:
    kubectl create deployment niginx --image=nginx
    
  2. Check the status of the pod:
    kubectl get pods
    
    Output should show running if successful.

Step 4: Expose the Deployment

  1. Expose the deployment as a service:
    kubectl expose deployment my-nginx --type=LoadBalancer --port=80
    
  2. Get the external IP of the service:
    kubectl get services
    
  3. Open a web browser and enter the external IP to verify that Nginx is running.

Step 5: Scale the Deployment

  1. Scale the deployment to 3 replicas:
    kubectl scale deployment my-nginx --replicas=3
    
  2. Verify the number of pods:
    kubectl get pods
    

Step 6: Clean Up

  1. Delete the service:
    kubectl delete service my-nginx
    
  2. Delete the deployment:
    kubectl delete deployment my-nginx
    
  3. Delete the cluster:
    gcloud container clusters delete my-cluster --zone us-central1-a
    

    Note: If you do not delete the cluster and pods, you may continue to incur charges while they are running.


Additional Resources


Conclusion

In this lab, students learned how to create a Kubernetes cluster on GCP, deploy an application, expose it to the internet, scale it, and clean up resources. This provides a basic understanding of Kubernetes operations on Google Cloud.

Thursday, March 20, 2025

For Demo - Discussion?

25.03.2025

Let me explain how to create docker conatiner to run Document processing Agent by AI-Team :

Step 1:  

In Visual code editor create Agent-Doc folder

Please generate all the necessary files one by one:

  1. Agent.py - The Flask backend with Llama3.2 integration, EasyOCR document processing, and AI-based name suggestions.

  2. index.html - The frontend for user interaction with AI-generated data and document processing.

  3. Dockerfile - A Dockerfile to containerize the application.

  4. requirements.txt - Dependencies for the Flask server.

Let us generate these now.

Agent.py (backend)

from flask import Flask, jsonify, request
from flask_cors import CORS  # Import CORS
import requests
from functools import lru_cache
import asyncio
import easyocr
from PIL import Image
import io
import re
 

app = Flask(__name__)
CORS(app)  # Enable CORS globally for all routes

reader = easyocr.Reader(['en'])

# Mock database (replace with real database later)
mock_user_data = {
    "userId": 1,
    "panNumber": "ABCDE1234F",
    "registeredAddress": "123 Business Park, Mumbai, Maharashtra, India"
}

# Cache LLM responses for frequently asked questions
@lru_cache(maxsize=128)
def get_llm_response(prompt):
    full_prompt = f"{prompt} Please provide a short and relevant answer (max 10 words)."
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "llama3.2",
        "prompt": full_prompt,
        "stream": False
    }
    response = requests.post(url, json=payload)
    if response.status_code == 200:
        llm_response = response.json().get("response", "I am not sure about this.")
        if len(llm_response.split()) > 10:  # Limit to 10 words
            llm_response = " ".join(llm_response.split()[:10]) + "..."
        return llm_response
    return "Error communicating with LLM."

# Endpoint for basic and generic data
@app.route('/api/auto-fill', methods=['GET'])
async def auto_fill():
    user_data = mock_user_data

    business_activity_prompt = "Describe the primary business activity for a company in India."
    ownership_type_prompt = "What are common ownership types for Indian companies?"

    business_activity_task = asyncio.to_thread(get_llm_response, business_activity_prompt)
    ownership_type_task = asyncio.to_thread(get_llm_response, ownership_type_prompt)

    business_activity, ownership_type = await asyncio.gather(business_activity_task, ownership_type_task)

    return jsonify({
        "panNumber": user_data["panNumber"],
        "registeredAddress": user_data["registeredAddress"],
        "businessActivity": business_activity,
        "ownershipType": ownership_type
    })


# Other endpoints remain unchanged...
# Initialize EasyOCR reader
# English language

# Endpoint for document processing


@app.route('/api/process-documents', methods=['POST'])
def process_documents():
    try:
        print("Processing uploaded documents...")  # Log the start of the process

        files = request.files.getlist('documents')
        if not files:
            return jsonify({"error": "No files uploaded"}), 400

        extracted_data = {"gstNumber": "", "directorAadhaar": ""}

        for file in files:
            print(f"Processing file: {file.filename}")  # Log the file name

            # Check file type
            if file.filename.lower().endswith(('.png', '.jpg', '.jpeg')):
                print("Detected image file.")  # Log file type
                try:
                    image = Image.open(io.BytesIO(file.read()))
                    # Convert image to bytes for EasyOCR
                    image_bytes = io.BytesIO()
                    image.save(image_bytes, format='PNG')
                    image_bytes.seek(0)

                    # Extract text using EasyOCR
                    result = reader.readtext(image_bytes.getvalue())
                    text = " ".join([item[1] for item in result])  # Join all detected text
                    print(f"Extracted text from image: {text[:100]}...")  # Log extracted text
                except Exception as e:
                    print(f"Error processing image: {e}")
                    return jsonify({"error": f"Failed to process image file: {file.filename}"}), 500

            elif file.filename.lower().endswith('.pdf'):
                print("Detected PDF file.")  # Log file type
                try:
                    from pdf2image import convert_from_bytes
                    images = convert_from_bytes(file.read())
                    text = ""
                    for img in images:
                        # Convert each page to bytes for EasyOCR
                        img_byte_arr = io.BytesIO()
                        img.save(img_byte_arr, format='PNG')
                        img_byte_arr.seek(0)

                        # Extract text using EasyOCR
                        result = reader.readtext(img_byte_arr.getvalue())
                        text += " ".join([item[1] for item in result])  # Join all detected text
                    print(f"Extracted text from PDF: {text[:100]}...")  # Log extracted text
                except Exception as e:
                    print(f"Error processing PDF: {e}")
                    return jsonify({"error": f"Failed to process PDF file: {file.filename}"}), 500

            else:
                return jsonify({"error": f"Unsupported file type: {file.filename}"}), 400

            # Extract GST and Aadhaar numbers using regex
            gst_match = re.search(r'\b\d{2}[A-Z]{5}\d{4}[A-Z]{1}[A-Z\d]{1}[Z]{1}[A-Z\d]{1}\b', text)
            aadhaar_match = re.search(r'\b\d{4}-\d{4}-\d{4}\b', text)

            if gst_match:
                extracted_data["gstNumber"] = gst_match.group(0)
                print(f"Extracted GST Number: {gst_match.group(0)}")  # Log GST number
            if aadhaar_match:
                extracted_data["directorAadhaar"] = aadhaar_match.group(0)
                print(f"Extracted Aadhaar Number: {aadhaar_match.group(0)}")  # Log Aadhaar number

        return jsonify(extracted_data)

    except Exception as e:
        print(f"Unexpected error: {e}")  # Log unexpected errors
        return jsonify({"error": "An unexpected error occurred while processing the documents."}), 500


# Mock function to validate company names against Indian naming conventions
def validate_company_name(name):
    prohibited_words = ["bank", "government", "reserve"]  # Example prohibited words
    if any(word in name.lower() for word in prohibited_words):
        return False
    return True


# Function to generate AI-based name suggestions
def get_ai_suggestions(firstName):
    # Craft a prompt for the LLM
    prompt = f"Generate 5 creative and unique company name suggestions based on '{firstName}' that adhere to Indian company naming conventions."

    # Call the LLM via Ollama
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "llama3.2",
        "prompt": prompt,
        "stream": False
    }
    response = requests.post(url, json=payload)
    if response.status_code == 200:
        llm_response = response.json().get("response", "")
        suggestions = [name.strip() for name in llm_response.split("\n") if name.strip()]
        return suggestions[:5]  # Return only 5 suggestions
    return []


# Endpoint for AI-based name suggestions
@app.route('/api/suggest-names', methods=['POST'])
def suggest_names():
    try:
        data = request.get_json()
        firstName = data.get("firstName", "").strip()

        if not firstName:
            return jsonify({"error": "First name preference is required."}), 400

        # Validate the first preference
        if not validate_company_name(firstName):
            return jsonify({"error": "The provided name does not meet Indian company naming conventions."}), 400

        # Generate AI-based suggestions
        suggestions = get_ai_suggestions(firstName)

        if not suggestions:
            return jsonify({"error": "Failed to generate name suggestions."}), 500

        return jsonify({"suggestions": suggestions})

    except Exception as e:
        print(f"Unexpected error: {e}")
        return jsonify({"error": "An unexpected error occurred while generating name suggestions."}), 500


if __name__ == '__main__':
    app.run(debug=True, port=3000)

Now, let's generate the remaining files:

index.html (Frontend)

This file provides a simple interface to interact with the backend.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI-Powered Form Generator</title>
</head>
<body>
    <h2>Generate Name Suggestions</h2>
    <input type="text" id="prompt" placeholder="Enter your prompt">
    <button onclick="generateText()">Generate</button>
    <p id="generatedResponse"></p>

    <h2>Process Document</h2>
    <input type="file" id="fileInput">
    <button onclick="processDoc()">Upload & Process</button>
    <p id="processedText"></p>

    <script>
        async function generateText() {
            let prompt = document.getElementById("prompt").value;
            let response = await fetch("/generate", {
                method: "POST",
                headers: {"Content-Type": "application/json"},
                body: JSON.stringify({ prompt })
            });
            let data = await response.json();
            document.getElementById("generatedResponse").innerText = data.generated_text;
        }

        async function processDoc() {
            let fileInput = document.getElementById("fileInput").files[0];
            let formData = new FormData();
            formData.append("file", fileInput);

            let response = await fetch("/process-doc", {
                method: "POST",
                body: formData
            });
            let data = await response.json();
            document.getElementById("processedText").innerText = data.text.join(", ");
        }
    </script>
</body>
</html>

Dockerfile

This file creates a containerized environment for the Flask application.

# Use official Python image as a base
FROM python:3.10

# Set working directory
WORKDIR /app

# Copy project files
COPY . .

# Install dependencies
RUN pip install -r requirements.txt

# Expose Flask port
EXPOSE 5000

# Run the Flask app
CMD ["python", "Agent.py"]

requirements.txt

This file lists all dependencies.

Flask
easyocr
ollama

Please install ollama from https://ollama.com/

Please pull llama3.2 from ollama by : 

ollama run llama3.2

Now you have everything to run your AI-powered form generator and document processor inside a Docker container! Let me know if you need any modifications. ๐Ÿš€ 

MCP Agent for Name Checking MCA Portal

Perfect โ€” if you're using Ollama to run local LLMs (like llama3 , mistral , or custom models), you can absolutely build an agent-based ...