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.
Install Docker: First, make sure you have Docker installed on your operating system. You can download and install Docker from the official Docker website.
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.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.
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.

Architecture Overview

Prerequisites
Install php_redis.dll on Windows
Find your PHP version:
Run this in Command Prompt or PowerShell:
php -v
Look for something like:
PHP 8.2.12 (cli) …
Note if it is Thread Safe (TS) or Non-Thread Safe (NTS).
Download php_redis.dll:
You can download the PHP Redis extension from the official PECL page:
The PHP Redis extension can also be downloaded directly from the official GitHub releases page at https://github.com/phpredis/phpredis/releases. Download the version that matches your PHP version and thread-safety (TS/NTS) setting.
Install the DLL:
Extract the .dll file.
Copy it into your PHP ext directory (usually C:\xampp\php\ext or C:\php\ext).
Edit php.ini:
Open your php.ini (often in C:\xampp\php or C:\php).
Add this line at the bottom:
extension=php_redis.dll
Then save and close.
Restart Your Server:
If you're using XAMPP:
Open the XAMPP Control Panel
Stop and start Apache
Or, restart any PHP service you’re using.
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
Prepare a Google Account: Make sure you're signed in with a Google account.
Visit Google AI Studio: Go to aistudio.google.com and sign in.
Access the API Key Section: Use the left sidebar to navigate to API Keys or click Get API Key.
Create an API Key:
Choose to create the key in a new project (recommended) or an existing GCP project.
Click Create API Key after selecting your option.
Copy and Store the Key:
Once generated, copy the API key immediately.
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:
Check fuzzy cache for similar prompts
If found → Store response in Redis with job ID key
Return job ID to frontend (appears like normal processing)
Cache Miss Path:
No similar prompt found
Create job object with unique ID
Push job to Redis queue for background worker processing
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