Redis

Getting Started with Redis and Redis Insight

What is Redis

Redis is an in-memory key-value store often used for caching and real-time processing. It supports various data structures and is known for its speed and flexibility.

Install Redis on Docker

To install Redis using Docker, follow the steps below.

  1. Install Docker: First, make sure you have Docker installed on your operating system. You can download and install Docker from the official Docker website.

  2. Pull the Redis Image: Open a terminal or command prompt and run the following command to pull the Redis Docker image: docker pull redis.This downloads the official Redis image from Docker Hub.

  3. Run Redis Container: Once the Redis image is downloaded, you can start a Redis container using the following commands. You can also change the mapped port if needed by replacing 6379:6379 with your preferred port. Redis uses port 6379 by default: # Run Redis with no password (accessible via any network interface)

    docker run --name my-redis -p 6379:6379 -d redis

    # Run Redis with password (local access only)

    docker run --name my-redis -p 127.0.0.1:6379:6379 -d redis redis-server --requirepass yourpassword

    This command creates and starts a container named "my-redis" using the Redis image. The container will run in the background.

  4. Verify Redis is Running: Open a terminal or command prompt and run the following command to verify the Redis container is running. docker ps You should see a container named “my-redis” running.

What is Redis Insight

RedisInsight is a desktop GUI for Redis. Download it at: https://redis.io/downloads/#Redis_Insight

Sample Use Case

LLM ChatBot (Gemini + Redis)

LLM ChatBot (Gemini + Redis) is an AI-powered chatbot application designed with a Vue.js frontend and PHP backend. It integrates Google's Gemini API to provide intelligent natural language responses and uses Redis to efficiently queue and manage chatbot requests.

LLM ChatBot

Architecture Overview

Prerequisites

Install php_redis.dll on Windows

  1. Find your PHP version:

    1. Run this in Command Prompt or PowerShell: php -v

    2. Look for something like: PHP 8.2.12 (cli) …

    3. Note if it is Thread Safe (TS) or Non-Thread Safe (NTS).

  2. Download php_redis.dll:

  3. Install the DLL:

    1. Extract the .dll file.

    2. Copy it into your PHP ext directory (usually C:\xampp\php\ext or C:\php\ext).

  4. Edit php.ini:

    1. Open your php.ini (often in C:\xampp\php or C:\php).

    2. Add this line at the bottom: extension=php_redis.dll

    3. Then save and close.

  5. Restart Your Server:

    • If you're using XAMPP:

      1. Open the XAMPP Control Panel

      2. Stop and start Apache

    • Or, restart any PHP service you’re using.

  6. Verify Redis Extension is Loaded:

    • Run: php -m You should see redis in the list of loaded modules.

    • Or, use: php -i | findstr redis

      You should see info about the redis extension.

Get a Gemini API Key

  1. Prepare a Google Account: Make sure you're signed in with a Google account.

  2. Visit Google AI Studio: Go to aistudio.google.com and sign in.

  3. Access the API Key Section: Use the left sidebar to navigate to API Keys or click Get API Key.

  4. Create an API Key:

    1. Choose to create the key in a new project (recommended) or an existing GCP project.

    2. Click Create API Key after selecting your option.

  5. Copy and Store the Key:

    1. Once generated, copy the API key immediately.

    2. Store it securely.

Environment Configuration

Create a .env file:

GOOGLE_API_KEY=your_gemini_api_key_here
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0

Backend Code

FuzzyCacheManager.php

Intelligent response caching with fallback strategies

// Level 1: Exact Match Cache (Fastest)
$exactKey = "exact_cache:" . md5(trim($prompt));
$exactResponse = $this->redis->get($exactKey);

// Level 2: Normalized Text Cache
$normalizedKey = "normalized_cache:" . md5($normalizedPrompt);
$normalizedResponse = $this->redis->get($normalizedKey);

// Level 3: Fuzzy Matching (Most Intelligent)
$keys = $this->redis->keys("fuzzy_cache:*");
// Complex similarity calculation...

Similarity Calculation Algorithm

private function calculateSimilarity($str1, $str2) {
    // Method 1: Levenshtein Distance
    $distance = levenshtein($str1, $str2, 1, 1, 1);
    $levenshteinSimilarity = 1.0 - ($distance / $maxLen);
    
    // Method 2: Keyword Overlap (Jaccard Index)
    $keywordSimilarity = $this->keywordSimilarity($str1, $str2);
    
    // Method 3: N-gram Analysis
    $ngramSimilarity = $this->ngramSimilarity($str1, $str2);
    
    // Weighted combination for optimal results
    return ($levenshteinSimilarity * 0.4) + 
           ($keywordSimilarity * 0.4) + 
           ($ngramSimilarity * 0.2);
}

Text Normalization

private function normalizeText($text) {
    $text = strtolower(trim($text));
    $text = preg_replace('/[^\w\s]/', '', $text);  // Remove punctuation
    $text = preg_replace('/\s+/', ' ', $text);      // Normalize spaces
    return $text;
}

Keyword Extraction

private function extractKeywords($text) {
    $stopWords = ['what', 'how', 'the', 'is', 'are', ...];
    
    $words = explode(' ', $this->normalizeText($text));
    $keywords = array_filter($words, function($word) use ($stopWords) {
        return strlen($word) > 2 && !in_array($word, $stopWords);
    });
    
    return array_values(array_unique($keywords));
}

chat.php

Redis Setup and Connection

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

The script connects to a Redis server running locally on the default port 6379. Redis serves as both a cache storage and job queue system.

Response Caching (Cache Hit Scenario)

When a similar prompt is found in the cache:

// Initialize fuzzy cache manager
$cacheManager = new FuzzyCacheManager();
// Check for similar responses using fuzzy matching
$similarResponse = $cacheManager->findSimilarResponse($prompt);
if ($similarResponse) {
    // Generate a job ID for consistency with frontend expectations
    $jobId = uniqid('chat_', true);
       
    // Store the cached response with the job ID format
    $redis->set("chatbot_response:$jobId", $similarResponse['response']);
       
    // Return job ID so frontend can poll normally
    echo json_encode([
        "message" => "Request processed from cache",
        "job_id" => $jobId,
        "cached" => true,
        "cache_type" => $similarResponse['type'],
        "similarity" => round($similarResponse['similarity'], 3),
        "original_prompt" => $similarResponse['original_prompt'] ?? null
    ]);
    exit;
}
  • Stores the cached response with a key pattern chatbot_response:{job_id}

  • This allows the frontend to retrieve the response using the same polling mechanism it would use for new requests

  • The job ID maintains consistency with the normal workflow

Job Queue System (Cache Miss Scenario)

When no similar response exists:

// If no similar response found, proceed with normal queue processing
$job = [
    'id' => uniqid('chat_', true),
    'prompt' => $prompt,
    'timestamp' => time()
 ];
   
// Push job to Redis queue
$redis->lPush('chatbot_queue', json_encode($job));
  • Uses Redis list data structure as a job queue

  • lPush adds the job to the left side of the list chatbot_queue

  • This creates a FIFO (First In, First Out) queue for background processing

Redis Data Flow

  • Cache Hit Path:

    1. Check fuzzy cache for similar prompts

    2. If found → Store response in Redis with job ID key

    3. Return job ID to frontend (appears like normal processing)

  • Cache Miss Path:

    1. No similar prompt found

    2. Create job object with unique ID

    3. Push job to Redis queue for background worker processing

    4. Return job ID to frontend

worker.php

Initialization Phase

// Load environment configuration
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
$apiKey = $_ENV['GOOGLE_API_KEY'];


// Establish Redis connection
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);


// Initialize fuzzy cache management
$cacheManager = new FuzzyCacheManager();

Job Processing Loop

The main processing loop implements the following workflow:

Job Retrieval

$jobJson = $redis->rPop('chatbot_queue');
if (!$jobJson) {
    sleep(1);
    continue;
}

$job = json_decode($jobJson, true);
$prompt = $job['prompt'];
$jobId = $job['id'];

echo "Processing job: {$jobId}\n";
echo "Prompt: " . substr($prompt, 0, 100) . "...\n";
  • Uses blocking pop operation from Redis queue

  • Implements 1-second polling interval when queue is empty

  • Ensures graceful handling of queue downtime

Fuzzy Cache Lookup

// Double-check cache in case it was added while job was in queue
$similarResponse = $cacheManager->findSimilarResponse($prompt);
if ($similarResponse) {
    echo "Found {$similarResponse['type']} match with similarity {$similarResponse['similarity']} for job: {$jobId}\n";
    $redis->set("chatbot_response:$jobId", $similarResponse['response']);
    continue;
}
  • Searches for semantically similar previous responses

  • Returns match type, similarity score, and cached response

  • Avoids duplicate API calls for similar queries

API Integration

When no cache hit occurs, the worker:

echo "Making API call to Gemini for job: {$jobId}\n";

$postData = [
    "contents" => [[ "parts" => [[ "text" => $prompt ]] ]]
];


$gemini_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={$apiKey}";
$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\n",
        'content' => json_encode($postData)
    ]
]);

$result = file_get_contents($gemini_url, false, $context);

if ($result === false) {
    throw new Exception("Failed to get response from Gemini API");
}

$parsed = json_decode($result, true);

if (!$parsed || !isset($parsed['candidates'][0]['content']['parts'][0]['text'])) {
    throw new Exception("Invalid response format from Gemini API");
}

$responseText = $parsed['candidates'][0]['content']['parts'][0]['text'];
  • Sends HTTP POST request with JSON payload

  • Handles API errors and network failures

  • Parses response and extracts generated text

Store Value in Redis

// Store response for this specific job
$redis->set("chatbot_response:$jobId", $responseText);

Response Caching

// Cache the response using fuzzy matching system
$cacheManager->cacheResponse($prompt, $responseText, 3600); // 1 hour expiry
  • Stores new responses with 1-hour expiration

  • Enables fuzzy matching for future similar queries

  • Maintains cache efficiency and relevance

get_response.php

Redis Setup and Connection

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

Check if response exists

$response = $redis->get("chatbot_response:$jobId");

Frontend

Frontend Architecture

Core Frontend Components

Vue.js Template Structure

<template>
  <div class="chat-container">
    <h1 class="chat-title">Chat with AI</h1>


    <div class="chat-messages" ref="chatBody">
      <div
        v-for="(msg, index) in messages"
        :key="index"
        :class="['chat-bubble', msg.sender]"
      >
        <span class="icon" :title="msg.sender === 'user' ? 'You' : 'Bot'">
          {{ msg.sender === 'user' ? '🗨️' : '🤖' }}
        </span>
        <div class="text" v-html="msg.text"></div>
      </div>
    </div>


    <div class="chat-input">
      <label for="prompt" class="input-label">Your Message</label>
      <input
        id="prompt"
        v-model="prompt"
        placeholder="Type your message here..."
        @keydown.enter.exact.prevent="sendPrompt"
        :disabled="loading"
        autocomplete="off"
      />


      <button
        @click="sendPrompt"
        :disabled="loading || !prompt.trim()"
        aria-label="Send message"
      >

      </button>
    </div>
  </div>
</template>

Vue.js Reactive State Management

import { ref, nextTick } from 'vue'

// Reactive state variables
const prompt = ref('')           // Current input text
const loading = ref(false)       // Loading state for UI feedback
const messages = ref([])         // Chat message history
const chatBody = ref(null)       // Reference to scrollable chat area

Asynchronous Communication Flow

Message Submission

const sendPrompt = async () => {
const input = prompt.value.trim()
if (!input) return

messages.value.push({ sender: 'user', text: input })
prompt.value = ''
loading.value = true
scrollToBottom()

const loadingMsg = { sender: 'bot', text: '<i>Typing...</i>' }
messages.value.push(loadingMsg)
scrollToBottom()

Job Queue Submission

try {
  const res = await fetch('http://localhost:8000/chat.php', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ prompt: input }),
  })


  const { job_id } = await res.json()
  if (!job_id) throw new Error("Job not queued.")


  // Step 3: Polling Implementation


  poll()
} catch (err) {
  loadingMsg.text = `<span class="error">Error: ${err.message}</span>`
  loading.value = false
}

Polling Implementation

const poll = async () => {
  const pollRes = await fetch(`http://localhost:8000/get_response.php?job_id=${job_id}`);
  const pollData = await pollRes.json()


  if (pollData.status === 'done') {
    loadingMsg.text = pollData.response.replace(/\n/g, '<br>')
    loading.value = false
  } else {
    setTimeout(poll, 2000)
  }
}

Last updated