Create the Flask App (backend/app.py):

Python

# backend/app.py
from flask import Flask, request
from flask_restful import Resource, Api
from flask_cors import CORS
from pymongo import MongoClient
from langchain import LLMChain
from langchain.chains import SimpleSequentialChain
from langchain.prompts import ChatPromptTemplate
from rag_model import generate_response

app = Flask(__name__)
CORS(app)
api = Api(app)

# Connect to MongoDB
client = MongoClient("mongodb://localhost:27017/")
db = client["rag_chatbot"]

# Initialize LangChain (using a simple prompt for now, RAG will handle the core response)
prompt_template = ChatPromptTemplate.from_template("The user said: {user_message}\nThe bot should respond with:")
llm_chain = LLMChain(prompt=prompt_template)
overall_chain = SimpleSequentialChain(chains=[llm_chain])

class Message(Resource):
    def get(self):
        messages = list(db.messages.find({}, {'_id': 0})) # Exclude _id from response
        return {'messages': messages}, 200

    def post(self):
        user_message = request.json['message']
        db.messages.insert_one({'sender': 'user', 'message': user_message})

        bot_response = generate_response(user_message)
        db.messages.insert_one({'sender': 'bot', 'message': bot_response})

        return {'message': bot_response}, 201

api.add_resource(Message, '/message')

if __name__ == '__main__':
    app.run(debug=True)
Create RAG Model Script (backend/rag_model.py):

Python

# backend/rag_model.py
from transformers import RagTokenizer, RagRetriever, RagSequenceForGeneration
import torch
import json
import faiss
import numpy as np

# Load the custom knowledge base
with open('data/knowledge_base.json', 'r') as f:
    knowledge_data = json.load(f)

# Initialize the tokenizer and model
tokenizer = RagTokenizer.from_pretrained("facebook/rag-sequence-nq")
retriever = RagRetriever.from_pretrained("facebook/rag-sequence-nq", index_name="custom")
model = RagSequenceForGeneration.from_pretrained("facebook/rag-sequence-nq")

# Create embeddings for the custom knowledge base
embeddings = []
for doc in knowledge_data:
    inputs = tokenizer(doc['text'], return_tensors="pt")
    outputs = model.retrieval_embeddings(**inputs).detach().cpu().numpy() # Move to CPU for FAISS
    embeddings.append(outputs)
embeddings = np.vstack(embeddings)
embedding_dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(embedding_dimension)
index.add(embeddings)
retriever.retrieval_index = index

def generate_response(query):
    input_ids = tokenizer(query, return_tensors="pt").input_ids.to(model.device)
    question_hidden_states = model.question_encoder(input_ids)[0].unsqueeze(0) # Add batch dimension
    docs_dict = retriever(input_ids.cpu().numpy(), question_hidden_states.cpu().numpy(), return_tensors="pt") # Move to CPU for retrieval
    context_input_ids = docs_dict["context_input_ids"].to(model.device)
    context_attention_mask = docs_dict["context_attention_mask"].to(model.device)
    outputs = model.generate(input_ids=input_ids, context_input_ids=context_input_ids, context_attention_mask=context_attention_mask, max_length=200)
    response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
    return response

if __name__ == '__main__':
    query = "What is the capital of France?"
    response = generate_response(query)
    print(f"Question: {query}")
    print(f"Answer: {response}")
Create Knowledge Base (backend/data/knowledge_base.json):

JSON

# backend/data/knowledge_base.json
[
  {"title": "Document 1", "text": "This is the content of document 1. It discusses important information."},
  {"title": "Document 2", "text": "This is the content of document 2. It provides further details and examples."},
  {"title": "Lahore Information", "text": "Lahore is the second-largest city in Pakistan and the capital of the Punjab province. It is known for its rich history and cultural heritage."}
]
Run the Flask App:
Navigate to the backend directory in your terminal and run:

Bash

cd backend
python app.py
Step 2: Frontend Setup

Initialize the Frontend:
Open a new terminal or command prompt. Navigate to your project root directory.

Bash

npx create-react-app frontend
cd frontend
npm install axios three @react-three/fiber @react-three/drei
Create Avatar Component (frontend/src/Avatar.js):

JavaScript

// frontend/src/Avatar.js
import React, { useRef, useEffect } from 'react';
import { useFrame, useLoader, Canvas } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { OrbitControls } from '@react-three/drei';
import * as THREE from 'three';

function Avatar({ gltfPath }) {
    const gltf = useLoader(GLTFLoader, gltfPath);
    const sceneRef = useRef();

    useEffect(() => {
        if (gltf && sceneRef.current) {
            sceneRef.current.add(gltf.scene);
        }
    }, [gltf]);

    useFrame(() => {
        // Optional: Add subtle rotation or other animations here if your GLB doesn't have any
        if (sceneRef.current) {
            // sceneRef.current.rotation.y += 0.005;
        }
    });

    return <group ref={sceneRef} />;
}

function AvatarCanvas({ glbPath }) {
    return (
        <Canvas style={{ width: '300px', height: '300px' }}>
            <ambientLight intensity={0.7} />
            <directionalLight position={[0, 1, 1]} intensity={0.6} />
            <directionalLight position={[0, -1, -1]} intensity={0.6} />
            <OrbitControls /> {/* Optional: For interactive control during development */}
            <Avatar gltfPath={glbPath} />
        </Canvas>
    );
}

export default AvatarCanvas;
Modify Chat Component (frontend/src/App.js):

JavaScript

// frontend/src/App.js
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import AvatarCanvas from './Avatar';

const App = () => {
    const [messages, setMessages] = useState([]);
    const [input, setInput] = useState('');
    const chatContainerRef = useRef(null);
    const avatarGlbPath = '/models/your_avatar.glb'; // Ensure your GLB is in public/models

    useEffect(() => {
        fetchMessages();
    }, []);

    useEffect(() => {
        if (chatContainerRef.current) {
            chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
        }
    }, [messages]);

    const fetchMessages = async () => {
        try {
            const response = await axios.get('http://localhost:5000/message');
            setMessages(response.data.messages);
        } catch (error) {
            console.error("Error fetching messages:", error);
        }
    };

    const speak = (text) => {
        if ('speechSynthesis' in window) {
            const utterance = new SpeechSynthesisUtterance(text);
            speechSynthesis.speak(utterance);
        } else {
            console.warn('Speech synthesis is not supported in this browser.');
        }
    };

    const sendMessage = async () => {
        if (input.trim()) {
            const userMessage = { sender: 'user', message: input };
            setMessages(prevMessages => [...prevMessages, userMessage]);
            setInput('');

            try {
                const response = await axios.post('http://localhost:5000/message', { message: input });
                const botResponse = { sender: 'bot', message: response.data.message };
                setMessages(prevMessages => [...prevMessages, botResponse]);
                speak(response.data.message);
            } catch (error) {
                console.error("Error sending message:", error);
                const errorMessage = { sender: 'bot', message: "Sorry, there was an error processing your request." };
                setMessages(prevMessages => [...prevMessages, errorMessage]);
                speak(errorMessage.message);
            }
        }
    };

    const handleInputChange = (e) => {
        setInput(e.target.value);
    };

    const handleKeyDown = (e) => {
        if (e.key === 'Enter') {
            sendMessage();
        }
    };

    return (
        <div style={{ display: 'flex', flexDirection: 'column', height: '100vh', padding: '20px' }}>
            <h1>AI Chatbot with Avatar</h1>
            <div style={{ display: 'flex', flexGrow: 1, marginBottom: '10px' }}>
                <div ref={chatContainerRef} style={{ flex: 1, overflowY: 'auto', padding: '10px', border: '1px solid #ccc', borderRadius: '5px', marginRight: '20px' }}>
                    {messages.map((msg, index) => (
                        <p key={index} style={{ textAlign: msg.sender === 'user' ? 'right' : 'left', marginBottom: '5px' }}>
                            <strong>{msg.sender}:</strong> {msg.message}
                        </p>
                    ))}
                </div>
                <div style={{ flexBasis: '300px', height: '300px' }}>
                    <AvatarCanvas glbPath={avatarGlbPath} />
                </div>
            </div>
            <div style={{ display: 'flex' }}>
                <input
                    style={{ flexGrow: 1, padding: '8px', borderRadius: '5px 0 0 5px', border: '1px solid #ccc' }}
                    value={input}
                    onChange={handleInputChange}
                    onKeyDown={handleKeyDown}
                    type="text"
                    placeholder="Type a message"
                />
                <button
                    style={{ padding: '8px 15px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '0 5px 5px 0', cursor: 'pointer' }}
                    onClick={sendMessage}
                >
                    Send
                </button>
            </div>
        </div>
    );
};

export default App;
Place Your GLB File:
Create a public/models folder in your frontend directory and put your your_avatar.glb file inside it.

Run the React App:
Navigate to the frontend directory in your terminal and run:

Bash

cd frontend
npm start
Now you should have a basic AI RAG chatbot with a 3D avatar displayed. The bot's text responses will also be spoken by the browser. The avatar will be statically rendered (you'll need to add animations to your GLB file and potentially control them in the Avatar component for more dynamic behavior).