### Create Django Project Environment (Bash) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/README.md Sets up a Python virtual environment using venv, activates it, upgrades pip, and installs Django. This ensures a isolated environment for the project dependencies. ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip python -m pip install django ``` -------------------------------- ### Run Django Development Server (Bash) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/README.md Starts Django's built-in development server. The server runs on the default port 8000, but a different port can be specified. This is useful for local development and testing. ```bash python manage.py runserver # To use a different port: # python manage.py runserver 5000 ``` -------------------------------- ### Initialize Node.js Project and Install Dependencies Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/Website(Django)/wa-node/README.md Initializes a new Node.js project and installs essential libraries: axios for HTTP requests, express for creating endpoints, whatsapp-web.js for WhatsApp interaction, and qrcode for QR code generation. These are crucial for building the backend communication layer. ```bash cd wa-node npm init -y npm i axios express whatsapp-web.js qrcode ``` -------------------------------- ### Create Django App (Bash) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/README.md Creates a new application within the Django project. Apps are self-contained modules that perform a specific function for the website. ```bash python manage.py startapp whatsapp ``` -------------------------------- ### Initialize Fine-Tuned and Original TinyLlama Models in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initializes both a fine-tuned TinyLlama model from a local path and the original TinyLlama model from Hugging Face. This setup allows for direct comparison or combined usage of both model versions. ```python FT_MODEL_PATH = "/Users/ransela/merged" fine_tuned_model, fine_tuned_tokenizer = load_model(FT_MODEL_PATH) original_model, original_tokenizer = load_model("TinyLlama/TinyLlama-1.1B-Chat-v1.0") ``` -------------------------------- ### Create Django Project and Initialize Database (Bash) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/README.md Initializes a new Django project in the current directory and creates an initial SQLite database for development. The `startproject` command creates the necessary project structure, and `migrate` sets up the database schema. ```bash django-admin startproject web_project . python manage.py migrate ``` -------------------------------- ### Prepare Context and User Style Data in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Prepares the necessary context and user style strings for generating augmented prompts. It involves building context from a knowledge base and extracting user-specific conversational styles. ```python # build context and user style strings context = build_context(kb_df_all, conv_id='chat:u_barbara_u_maayan', k=10) barbara_messages,user_style = build_user_style(kb_df_all[kb_df_all['conv_id'] == 'chat:u_barbara_u_maayan'], user_id='u_barbara', k=10) query = "i need help with my students, did you taught them already the embeddings ppt?" ``` -------------------------------- ### Augment Examples with Teacher Answers (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Augments the existing list of human-created examples with teacher-generated answers using the RAG system. It randomly samples a fraction of the human examples, generates corresponding answers using `generate_teacher_answer`, and adds them to the `examples` list with `label_source` set to 'teacher'. ```python # randomly sampling rows where we add teacher indices = list(human_df.index) n_aug = int(AUGMENT_FRACTION * len(indices)) augment_indices = set(random.sample(indices, n_aug)) print(f"Will augment {n_aug} rows with teacher answers") for idx in augment_indices: row = human_df.loc[idx] query = str(row["text"]).strip() input_text = build_input_text(row) teacher_answer = generate_teacher_answer(query) if teacher_answer is None: print("Haven't generated answer") continue examples.append({ "input_text": input_text, "target_text": teacher_answer, "label_source": "teacher", }) print(f"Total examples after adding teacher labels: {len(examples)}") ``` -------------------------------- ### Django Usage Example for WhatsApp Models Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Demonstrates how to use the defined Django models to create new sessions, query active and ready sessions, and retrieve unread messages grouped by chat. This example illustrates common ORM operations for interacting with the session and unread message data. ```python # Usage example from whatsapp.models import Session, UnreadSession # Create new session sess = Session.objects.create(is_active=True) # Query active ready sessions active_sess = Session.objects.filter( is_active=True, state=Session.State.READY ).order_by("-started_at").first() # Get unread messages grouped by chat chat_summaries = ( UnreadSession.objects.filter(session=active_sess) .values("chat_id") .annotate( num_unread=models.Count("id"), last_msg_ts=models.Max("msg_ts") ) .order_by("-last_msg_ts") ) for chat in chat_summaries: print(f"Chat: {chat['chat_id']}, Unread: {chat['num_unread']}") ``` -------------------------------- ### Augment Prompt for WhatsApp Replies Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Generates an augmented prompt for an AI model to craft WhatsApp replies. It queries a Pinecone index for relevant past answers and user style examples to mimic the user's tone, vocabulary, and emoji habits. The function takes the user's query, style examples, chat context, and the Pinecone index as input. ```python def augment_prompt( query: str, user_style: str, context: str, model: SentenceTransformer = SentenceTransformer('all-MiniLM-L6-v2'), index=None, ) -> str: results = [float(val) for val in list(model.encode(query))] # get top 10 results from knowledge base query_results = index.query( vector=results, top_k=5, include_values=True, include_metadata=True )['matches'] text_matches = [match['metadata']['answer'] for match in query_results] # get the text from the results answers = "\n\n".join(text_matches) # feed into an augmented prompt improved_prompt = f""" You write WhatsApp replies *exactly as the user would*. Your job: given a new incoming message, write the reply the user is most likely to send. You are given: 1) **query** – the new incoming message you must answer. 2) **similar_past_answers** – real replies the user wrote in the past to similar messages. Use them for tone, vibe, typical phrasing, emojis, and attitude. 3) **user_style_examples** – random messages the user wrote in other chats. Use them to mimic writing style, vocabulary, length, energy level, and emoji habits. 4) **recent_context** – the recent messages in this same chat (both sides). Your reply must fit naturally after this context. ### Rules: - Write the reply **as the user**, in first person. - Match the **language**, **tone**, and **emotion** of the conversation. - Keep it natural for WhatsApp: short to medium length, can include emojis. - If the query contains multiple questions – answer all. - If necessary info is missing – ask a short clarifying question. - **Never** mention examples, past messages, embeddings, or that you're an AI. - **Only output the final WhatsApp-style reply. No explanations.** --- ### query: {query} ### similar_past_answers for similar queries: {answers} ### user_style_examples: {user_style} ### recent_context: {context} """ return improved_prompt, answers ``` -------------------------------- ### Execute RAG Pipeline with Fine-Tuned TinyLlama in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initiates the full Retrieval-Augmented Generation (RAG) pipeline using the fine-tuned TinyLlama model. This involves calling `generate_augmented_answer` with the prepared query, user style, context, and model specifics. ```python # Call the full RAG + Original generation pipeline answer_ft, retrieved_docs_ft = generate_augmented_answer( query=query, user_style=user_style, context=context, model_to_gen=fine_tuned_model, tokenizer_to_gen=fine_tuned_tokenizer, model=model_emb, index=index # Pinecone index ) ``` -------------------------------- ### Consolidate User Styles Dictionary in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Creates a dictionary that maps user IDs to their extracted conversational styles. This consolidated structure simplifies the process of retrieving and applying specific user styles during response generation. ```python users_style ={'u_barbara': barbara_messages, 'u_maayan': maayan_messages} ``` -------------------------------- ### Create Pinecone Vector Database Index (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initializes and creates a Pinecone vector database index if it doesn't already exist. Requires the Pinecone API key to be set in the environment. Specifies index name, vector dimension, and similarity metric. ```python from pinecone import Pinecone, ServerlessSpec # Assume PINECONE_API_KEY is set in environment variables def create_pinecone_index( index_name: str, dimension: int, metric: str = 'cosine', ): """ Create a pinecone index if it does not exist Args: index_name: The name of the index dimension: The dimension of the index metric: The metric to use for the index Returns: Pinecone: A pinecone object which can later be used for upserting vectors and connecting to VectorDBs """ print("Creating a Pinecone index...") pc = Pinecone(api_key=PINECONE_API_KEY) existing_indexes = [index_info["name"] for index_info in pc.list_indexes()] if index_name not in existing_indexes: pc.create_index( name=index_name, dimension=dimension, metric=metric, spec=ServerlessSpec( cloud="aws", region="us-east-1" ) ) print("Done!") return pc ``` -------------------------------- ### Initialize Sentiment Analysis Pipeline with Transformers Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initializes a sentiment analysis pipeline using the transformers library from Hugging Face. It specifies the model 'cardiffnlp/twitter-roberta-base-sentiment-latest' and is configured to return all scores. This pipeline is a core dependency for sentiment-related computations. ```python from transformers import pipeline # list of strings sent_pipe = pipeline( "sentiment-analysis", model="cardiffnlp/twitter-roberta-base-sentiment-latest", return_all_scores=True ) ``` -------------------------------- ### Create Pinecone Index Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initializes and creates a Pinecone index with a specified name and embedding dimension. This is a prerequisite for storing and retrieving vector data. It assumes the Pinecone client is already configured. ```python pc = create_pinecone_index(INDEX_NAME, shape[1]) ``` -------------------------------- ### Initialize SentenceTransformer Embedding Model Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Initializes a pre-trained SentenceTransformer model using the 'all-MiniLM-L6-v2' checkpoint, which is a lightweight, efficient model optimized for sentence embeddings. This model is then used to encode text data into 384-dimensional vector representations. ```python EMBEDDING_MODEL = 'all-MiniLM-L6-v2' model_emb = SentenceTransformer(EMBEDDING_MODEL) ``` -------------------------------- ### Model Loading and QLoRA Fine-tuning Setup in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb This code configures a causal language model for fine-tuning using QLoRA (4-bit quantization). It loads a pre-trained tokenizer and model, sets up 4-bit quantization parameters using `BitsAndBytesConfig`, and applies LoRA configuration using `LoraConfig` from the `peft` library. The model is automatically mapped to the GPU. Dependencies include `transformers`, `torch`, and `peft`. ```python tok = AutoTokenizer.from_pretrained(MODEL_ID) if tok.pad_token is None: tok.pad_token = tok.eos_token # 4-bit quantization (QLoRA style) bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.float16, ) # model in 4-bit, note that automatically is must be placed on GPU base = AutoModelForCausalLM.from_pretrained( MODEL_ID, quantization_config=bnb_config, device_map="auto", ) base.config.pad_token_id = tok.pad_token_id lora_config = LoraConfig( task_type=TaskType.CAUSAL_LM, r=8, lora_alpha=16, lora_dropout=0.05, target_modules=TARGET_MODULES, ) model = get_peft_model(base, lora_config) model.print_trainable_parameters() ``` -------------------------------- ### Generate Augmented Answers with Fine-Tuned TinyLlama in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Generates a response using an augmented prompt, incorporating user style and context, specifically with a fine-tuned TinyLlama model. It utilizes a separate `augment_prompt` function and the `llama_generate` utility. ```python def generate_augmented_answer(query, user_style, context, model_to_gen, tokenizer_to_gen, model=model_emb, index=index): augmented_prompt, source_knowledge = augment_prompt(query, user_style, context,model=model_emb,index=index) answer = llama_generate(augmented_prompt, model_to_gen, tokenizer_to_gen) return answer, source_knowledge ``` -------------------------------- ### Generate Response with Cohere API Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb This snippet demonstrates how to use the Cohere client to generate a chat response. It requires an API key and augments a prompt based on user style, context, and source knowledge before sending it to the Cohere API. ```python import cohere # Assuming 'query', 'user_style', 'context', 'model_emb', 'index', and 'COHERE_API_KEY' are defined elsewhere. # The 'augment_prompt' function is assumed to be available. augmented_prompt, source_knowledge = augment_prompt(query, user_style, context,model=model_emb,index=index) co = cohere.Client(api_key=COHERE_API_KEY) response = co.chat( model='command-a-03-2025', message=augmented_prompt, ) print(response.text) ``` -------------------------------- ### Print Generated Response from Fine-Tuned TinyLlama in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Prints the generated answer from the fine-tuned TinyLlama model to the console. This is typically used to display the final output after the RAG pipeline has completed. ```python print("====== GENERATED Fine-Tuned Tiny Llama ANSWER ======") print(answer_ft) ``` -------------------------------- ### Initialize WhatsApp RAG System with Knowledge Base Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Sets up the RAG system by loading chat history, initializing vector embeddings with sentence transformers, configuring Pinecone index, and preparing user style examples. The system uses these components to generate replies that match the user's writing patterns and communication style. ```python from Website.whatsapp.rag_pipe import WhatsAppRAG # Initialize RAG system with knowledge base rag = WhatsAppRAG( kb_path="./RAG_data/KB_data.csv", receiver_user_id="u_barbara", context_conv_id="chat:u_barbara_u_maayan", index_name="chats-index", embedding_model_name="all-MiniLM-L6-v2", cohere_model_name="command-a-03-2025", k_style_messages=10, k_context_messages=10 ) # Generate a reply to incoming message query = "i need help with my students, did you taught them already the embeddings ppt?" reply = rag.generate_reply( query=query, instructions="Be professional but friendly" ) print(f"Generated reply: {reply}") # Output: A WhatsApp-style response matching Barbara's tone and style ``` -------------------------------- ### WhatsApp Session Management API Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Handles the initialization and management of WhatsApp Web sessions. It includes endpoints to start a new session and wait for QR code authentication. ```APIDOC ## POST /login/start ### Description Initializes a new WhatsApp Web session. This endpoint should be called to begin the login process. ### Method POST ### Endpoint /login/start ### Parameters #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Redirects to the login wait page. #### Response Example Redirects to `/login/wait/` ``` ```APIDOC ## GET /login/wait/ ### Description Displays the QR code for WhatsApp authentication and waits for the user to scan it. It also checks the session state and redirects if the session is ready. ### Method GET ### Endpoint /login/wait/ ### Parameters #### Path Parameters - **session_id** (string) - Required - The unique identifier for the session. #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Renders the login wait template with session details and QR code. #### Response Example (Renders an HTML page with QR code) ``` -------------------------------- ### Setup Vector Database with Embeddings and Pinecone Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Loads WhatsApp chat dataset, generates embeddings using sentence transformers, creates a Pinecone vector index, and upserts embeddings for semantic search. Filters messages by receiver user for personalized indexing. ```python from RAG.RAG_generic_func import ( load_and_embedd_dataset, create_pinecone_index, upsert_vectors ) from sentence_transformers import SentenceTransformer import pandas as pd import os # Load data whatsapp_chats = pd.read_csv("./RAG_data/KB_data.csv") # Embed dataset model = SentenceTransformer("all-MiniLM-L6-v2") kb_df_all, embeddings = load_and_embedd_dataset(whatsapp_chats, model) # Filter for specific user kb_df_to_barbara = kb_df_all[ kb_df_all["receiver_user_id"] == "Barbara" ].sort_values(by="conv_turn") embeddings_to_barbara = embeddings[kb_df_to_barbara.index.to_list()] # Create Pinecone index INDEX_NAME = "chats-index" pc = create_pinecone_index(INDEX_NAME, embeddings_to_barbara.shape[1]) # Upsert vectors index = pc.Index(INDEX_NAME) index_upserted = upsert_vectors(index, kb_df_to_barbara, embeddings_to_barbara) print(f"Upserted {len(kb_df_to_barbara)} vectors to Pinecone") ``` -------------------------------- ### Compute and Display Style Metrics for Users Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Calculates and displays sentiment and style metrics for two users, 'Barbara' and 'Maayan', comparing their messages against a generated response. It uses a pre-initialized sentiment pipeline and a `compute_style_metrics` function. The results are stored in pandas DataFrames for clear visualization. ```python gen_msg = response.text metrics_barbara, barbara_centroid_dict,gen_sent_dict = compute_style_metrics( 'u_barbara', user_messages=barbara_messages, generated_message=gen_msg, sentiment_pipeline=sent_pipe ) metrics_maayan, maayan_centroid_dict,_ = compute_style_metrics( 'u_maayan', user_messages=maayan_messages, generated_message=gen_msg, sentiment_pipeline=sent_pipe ) print("\n--- Sentiment Style Analysis ---\n") sentimend_data = { 'Barbara_Sentiment': barbara_centroid_dict, 'Maayan_Sentiment': maayan_centroid_dict, } metrics_data = { 'Barbara_Metrics': metrics_barbara, 'Maayan_Metrics': metrics_maayan, } df_sentiment = pd.DataFrame(sentimend_data) df_sentiment_transposed = df_sentiment.T display(df_sentiment_transposed) df = pd.DataFrame(metrics_data) df_transposed = df.T display(df_transposed) ``` -------------------------------- ### Save Distillation Dataset (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Saves the compiled list of examples (both human and teacher-generated) into a JSON Lines file. This dataset is intended for distillation training, where the model learns to mimic both human and teacher responses. ```python out_df = pd.DataFrame(examples) out_df.to_json( OUTPUT_KB_JSONL, orient="records", lines=True, force_ascii=False, ) print(f"Saved distillation dataset to {OUTPUT_KB_JSONL}") ``` -------------------------------- ### Import Core Libraries for WhatsApp WebApp (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Imports essential Python libraries for data science, machine learning, and API interactions. This includes pandas for data manipulation, scikit-learn for ML algorithms, and libraries for interacting with external services like Cohere and Pinecone. Warnings are suppressed for cleaner output. ```python import os from typing import List, Dict import re import pandas as pd from pandas import DataFrame import numpy as np import matplotlib.pyplot as plt from sklearn.metrics.pairwise import cosine_similarity from sklearn.decomposition import PCA import warnings warnings.filterwarnings("ignore") import cohere from transformers import AutoTokenizer, AutoModelForCausalLM import torch from sentence_transformers import SentenceTransformer from pinecone import Pinecone, ServerlessSpec from tqdm import tqdm ``` -------------------------------- ### Describe Pinecone Index Statistics Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Retrieves and displays statistics for a Pinecone index. This includes information such as the index dimension, fullness, metric type, namespaces, total vector count, and vector type. ```python index.describe_index_stats() ``` -------------------------------- ### Load TinyLlama Models and Tokenizers in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Loads a specified Hugging Face model and its tokenizer, making them available for text generation. It defaults to using CUDA if available, otherwise falls back to CPU. The model is set to evaluation mode. ```python DEVICE = "cuda" if torch.cuda.is_available() else "cpu" def load_model(model_path: str): tokenizer = AutoTokenizer.from_pretrained(model_path) model = AutoModelForCausalLM.from_pretrained(model_path).to(DEVICE) model.eval() return model, tokenizer ``` -------------------------------- ### Text Tokenization and N-gram Utilities Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Provides utility functions for basic text processing. `_tokenize_words` splits text into words by finding sequences of alphanumeric characters, and `_char_ngrams` generates character n-grams of a specified length from a given text. ```python import re from typing import List # simple word tokenizer def _tokenize_words(text: str) -> List[str]: text = text.lower() # split on non letters or numbers return re.findall(r"\w+", text) # character n grams def _char_ngrams(text: str, n: int = 3) -> List[str]: text = text.replace(" ", "") if len(text) < n: return [] return [text[i:i+n] for i in range(len(text) - n + 1)] ``` -------------------------------- ### Extract User Styles for Multiple Users in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Extracts conversational styles for multiple users ('u_barbara' and 'u_maayan') from a knowledge base. This data is crucial for personalizing responses based on individual user communication patterns. ```python barbara_messages = build_user_style(kb_df_all[kb_df_all['conv_id'] == 'chat:u_barbara_u_maayan'], user_id='u_barbara', k=100)[0] maayan_messages = build_user_style(kb_df_all, user_id='u_maayan', k=100)[0] ``` -------------------------------- ### Fine-Tune LLaMA Model with PEFT and Transformers in Python Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Demonstrates the setup for fine-tuning a TinyLlama model using LoRA adapters. It imports necessary components from the Transformers and PEFT libraries for model loading, tokenizer, dataset preparation, and training configuration. ```python # Fine-tuning script (not included but inferred from project structure) from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer from peft import LoraConfig, get_peft_model from datasets import load_dataset import torch ``` -------------------------------- ### Display First 5 Rows of WhatsApp Chat DataFrame (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Utilizes the `.head()` method of a pandas DataFrame to display the first five rows of the `whatsapp_chats` DataFrame. This is a common practice for quickly inspecting the structure and content of the loaded data. ```python whatsapp_chats.head() ``` -------------------------------- ### Load Environment Variables and API Keys (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Loads sensitive API keys from a .env file using `python-dotenv`. It retrieves Pinecone and Cohere API keys from environment variables, providing default empty strings if they are not found. This is crucial for secure API authentication. ```python from dotenv import load_dotenv load_dotenv(override=True) # Replace with your own PineCone API KEY PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY", "") # Replace with your own Cohere API KEY COHERE_API_KEY = os.environ.get("COHERE_API_KEY", "") ``` -------------------------------- ### Data Splitting and Oversampling in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb This snippet demonstrates how to split a dataset into 'human' and 'teacher' generated examples based on a 'label_source' field. It then oversamples the 'human' generated data to balance the dataset before shuffling and printing the new size. Requires the `datasets` library. ```python train_human = train_ds.filter(lambda ex: ex.get("label_source", "") == "human") train_teacher = train_ds.filter(lambda ex: ex.get("label_source", "") == "teacher") print("Train human:", len(train_human), "| Train teacher:", len(train_teacher)) # oversampling human train_human_oversampled = concatenate_datasets([train_human] * HUMAN_DUP_FACTOR) train_balanced = concatenate_datasets([train_human_oversampled, train_teacher]).shuffle(seed=RANDOM_SEED) train_ds = train_balanced print("New train size after oversampling:", len(train_ds)) ``` -------------------------------- ### Django WhatsApp Session Login Start Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Initializes a new WhatsApp Web session in a Django application. It creates a session record, requests a session ID from a Node.js service, and redirects the user to a waiting page for QR code authentication. Requires a Django ORM model 'Session' and the 'requests' library. ```python # Django views.py from django.shortcuts import render, redirect from .models import Session import requests # Start WhatsApp session def login_start(request): """POST /login/start - Initialize WhatsApp Web session""" sess = Session.objects.create(is_active=True) r = requests.post( "http://localhost:3001/node/session", json={"session_hint": str(sess.id)}, timeout=(3.0, 6.0) ) data = r.json() sess.node_session_id = data.get("session_id", "") sess.state = Session.State.PENDING sess.save() return redirect("login_wait", session_id=sess.id) ``` -------------------------------- ### Load and Prepare Human Examples (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Loads conversation data from a CSV file, filters for rows where a specific user ('Barbara') is the receiver and has provided a non-empty human answer. It then formats these rows into a list of dictionaries, each containing 'input_text' and 'target_text', intended for model training. ```python df = pd.read_csv(KB_PATH) df["answer"] = df["answer"].astype(str) mask_receiver_barbara = df["receiver_user_id"] == USER # rows with non-empty human answer mask_has_human = df["answer"].str.strip().ne("") human_df = df[mask_receiver_barbara & mask_has_human].copy() print(f"Total rows in KB: {len(df)}") print(f"Rows with receiver == {USER!r} and non-empty human answer: {len(human_df)}") examples: List[Dict[str, Any]] = [] for _, row in human_df.iterrows(): input_text = build_input_text(row) human_answer = row["answer"].strip() examples.append({ "input_text": input_text, "target_text": human_answer, "label_source": "human", # used later for sampling/weighting }) print(f"Base human examples: {len(examples)}") ``` -------------------------------- ### Execute Dataset Embedding Pipeline Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Calls the embedding function to process the WhatsApp chat dataset, generating embeddings for all conversation records. The execution includes batch processing with progress visualization, processing 2362 message pairs into 384-dimensional vectors. ```python kb_df_all,embeddings = load_and_embedd_dataset(whatsapp_chats, model_emb) kb_df_all.head() ``` -------------------------------- ### Build User Style Sample from DataFrame (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Creates a string representing a user's messaging style by sampling 'k' messages from a pandas DataFrame. It can either randomly sample messages or take the last 'k' messages, with an option for random seed for reproducibility. Requires sender ID, message text, and timestamp columns. ```python import pandas as pd import numpy as np def build_user_style( df: pd.DataFrame, user_id: str, k: int = 10, text_col: str = "text", random_sample: bool = True, seed: int | None = 42, ) -> str: """ Return a string that represents the typical style of a given user, built from k of their messages. Each line looks like: Args: df: DataFrame with at least ['sender_user_id', text_col]. user_id: The user whose style we want to capture. k: Number of messages to use. text_col: Column with the text of the message. random_sample: If True sample k messages randomly, else take the last k. seed: Random seed for reproducibility when random_sample is True. Returns: A single multi line string with example messages in the user's style. """ user_df = df[df["sender_user_id"] == user_id].copy() if len(user_df) == 0: return "" user_df = user_df.sort_values("sent_at") if random_sample and len(user_df) > k: rng = np.random.default_rng(seed) idx = rng.choice(user_df.index.to_list(), size=k, replace=False) user_df = user_df.loc[idx].sort_values("sent_at") else: user_df = user_df.tail(k) lines = [str(msg) for msg in user_df[text_col].tolist()] user_style = "\n".join(lines) return lines, user_style ``` -------------------------------- ### Load WhatsApp Chat Data from CSV (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Reads a CSV file named 'KB_data.csv' located in the './RAG_data/' directory into a pandas DataFrame. This DataFrame will store the WhatsApp chat history, enabling further analysis and processing within the application. ```python kb_path = './RAG_data/KB_data.csv' whatsapp_chats = pd.read_csv(kb_path) ``` -------------------------------- ### Plot PCA of Style Centroids Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb This function visualizes the stylistic space by plotting the principal components (PC1 and PC2) of text embeddings. It takes a dictionary of centroids (representing user or generated text styles) and uses PCA to reduce dimensionality before plotting. ```python import matplotlib.pyplot as plt from sklearn.decomposition import PCA import numpy as np def plot_centroids_only(centroids: dict, title="Style Space – Centroids Only"): """ centroids: dict { "u_barbara": vec, "u_maayan": vec, "generated": vec } """ # Prepare centroid matrix & labels labels = list(centroids.keys()) vectors = np.vstack([centroids[k] for k in labels]) # Reduce to 2D pca = PCA(n_components=2) vectors_2d = pca.fit_transform(vectors) # Plot plt.figure(figsize=(8, 8)) colors = ['red', 'lightpink', 'lightgreen'] markers = ["X", "X", "X"] for i, label in enumerate(labels): x, y = vectors_2d[i] plt.scatter( x, y, color=colors[i], marker=markers[i], s=250, edgecolor="black" ) plt.text( x + 0.01, y + 0.01, label, fontsize=12, fontweight="bold" ) plt.title(title, fontsize=16) plt.xlabel("PC1") plt.ylabel("PC2") plt.grid(True, linestyle="--", alpha=0.4) # Zoom out so all distances are visible all_x = vectors_2d[:, 0] all_y = vectors_2d[:, 1] padding = 0.15 plt.xlim(all_x.min() - padding, all_x.max() + padding) plt.ylim(all_y.min() - padding, all_y.max() + padding) plt.show() # Example usage (assuming 'centroids' is defined): # plot_centroids_only(centroids, title="Style Space - generate centroid vs users") ``` -------------------------------- ### Generate Text using TinyLlama in Python Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Generates text based on a given prompt using a loaded TinyLlama model and tokenizer. It controls generation parameters like `max_new_tokens`, `temperature`, and `top_p` for diverse outputs. The function also extracts and returns the final relevant reply. ```python def llama_generate(prompt, model, tokenizer, max_new_tokens=80): inputs = tokenizer(prompt, return_tensors="pt").to(model.device) with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=max_new_tokens, temperature=0.8, top_p=0.9, do_sample=True ) input_ids = inputs["input_ids"][0] generated_ids = outputs[0][len(input_ids):] answer = tokenizer.decode(generated_ids, skip_special_tokens=True) clean_answer = _extract_final_reply(answer) return answer.strip() ``` -------------------------------- ### Compute comprehensive style metrics Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Orchestrates calculation of multiple style metrics comparing user messages with a generated message. Computes lexical Jaccard similarity, character 3-gram Jaccard similarity, emoji overlap ratio, and optional sentiment cosine similarity. Returns a dictionary of metric scores. Requires user_messages list and generated_message string; sentiment_pipeline is optional. ```python def compute_style_metrics( user_id: str, user_messages: List[str], generated_message: str, sentiment_pipeline=None ) -> Dict[str, float]: """ Compute several style metrics between a set of user messages and a single generated message. Metrics: - lexical_jaccard: Jaccard overlap of word unigrams - char_3gram_jaccard: Jaccard overlap of character trigrams - emoji_overlap: overlap between emojis of user and generated - sentiment_cosine: cosine similarity between average user sentiment and sentiment of generated message (requires sentiment_pipeline) """ lexical_jaccard = _compute_lexical_jaccard(user_messages, generated_message) char_3gram_jaccard = _compute_char_3gram_jaccard(user_messages, generated_message) emoji_overlap = _compute_emoji_overlap(user_messages, generated_message) sentiment_cos = None ``` -------------------------------- ### GET /chats/{chat_id}/ Source: https://context7.com/brarbrb/whatsapp_webapp_-django-/llms.txt Retrieves messages for a specific chat and generates an AI-powered reply suggestion using the RAG pipeline. ```APIDOC ## GET /chats/{chat_id}/ ### Description Retrieves messages for a specific chat and generates an AI-powered reply suggestion using the RAG pipeline. This endpoint can also handle POST requests to allow users to provide custom instructions for the reply suggestion. ### Method GET, POST ### Endpoint `/chats//` ### Parameters #### Path Parameters - **chat_id** (string) - Required - The unique identifier for the chat. #### Query Parameters None #### Request Body - **prompt** (string) - Optional - Custom instructions provided by the user to guide the AI reply suggestion (used with POST method). ### Request Example ```json { "prompt": "Keep it short and friendly." } ``` ### Response #### Success Response (200) - **session** (object) - Information about the active WhatsApp session. - **chat_id** (string) - The ID of the chat. - **messages_list** (array) - A list of messages in the chat, sorted by timestamp. - **suggestion_text** (string) - The AI-generated reply suggestion. - **prompt_text** (string) - The user-provided prompt text (if any). #### Response Example ```json { "session": { ... }, "chat_id": "some_chat_id", "messages_list": [ { "body": "Hello!", "msg_ts": 1678886400 }, { "body": "Hi there!", "msg_ts": 1678886460 } ], "suggestion_text": "Great to hear from you!", "prompt_text": "" } ``` ``` -------------------------------- ### Configure and Initialize Hugging Face Trainer Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Sets up training arguments for a Hugging Face `Trainer`, including epochs, batch sizes, learning rate, logging, and evaluation strategies. It then initializes the `Trainer` with the model, arguments, datasets, data collator, and tokenizer. ```python args = TrainingArguments( output_dir=output_dir, num_train_epochs=3, per_device_train_batch_size=2, per_device_eval_batch_size=2, gradient_accumulation_steps=16, fp16=True, learning_rate=2e-4, logging_steps=20, eval_strategy="epoch", save_strategy="epoch", save_total_limit=2, report_to="none", gradient_checkpointing=True, gradient_checkpointing_kwargs={"use_reentrant": False}, lr_scheduler_type="cosine", warmup_ratio=0.01, ) trainer = Trainer( model=model, args=args, train_dataset=train_tok, eval_dataset=val_tok, data_collator=default_data_collator, tokenizer=tok, ) trainer.train() ``` -------------------------------- ### Import Required Libraries for LLM Fine-tuning Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/Fine_Tune/fine_tune_tiny_llama.ipynb Imports essential libraries for loading datasets, transformers, LoRA configuration, and GPU computation. Includes Hugging Face datasets and transformers for model loading, PEFT for parameter-efficient fine-tuning, and PyTorch utilities for numerical operations. ```python from datasets import load_dataset from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, DataCollatorForLanguageModeling,Trainer from peft import LoraConfig, get_peft_model, TaskType import torch import numpy as np import math ``` -------------------------------- ### Configure Training Arguments for Hugging Face Transformers Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/Fine_Tune/fine_tune_tiny_llama.ipynb Sets up training arguments for a Hugging Face Transformers model. This includes configurations for output directory, epochs, batch sizes, learning rate, logging, evaluation, saving, and gradient checkpointing. It requires the `transformers` library. ```python args = TrainingArguments( output_dir="./bbt-lora", num_train_epochs=2, per_device_train_batch_size=1, per_device_eval_batch_size=1, gradient_accumulation_steps=16, fp16=True, learning_rate=2e-4, logging_steps=50, evaluation_strategy="steps", eval_steps=200, save_steps=200, save_total_limit=2, report_to="none", gradient_checkpointing=True, gradient_checkpointing_kwargs={\"use_reentrant\": False}, # to avoid warning lr_scheduler_type="cosine", warmup_ratio=0.03 ) ``` -------------------------------- ### Python Configuration for Distillation and Fine-Tuning Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb This snippet sets up essential configuration parameters for the knowledge distillation and fine-tuning process. It defines API keys, output directories, model parameters (like LoRA target modules and embedding models), data paths, training hyperparameters (batch size, learning rate, epochs), and device selection. ```python COHERE_API_KEY = os.environ.get("COHERE_API_KEY_PAY", "") PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY", "") output_dir = "/home/student/Whatsapp_webApp_-Django-/Fine_Tune/distilled/KB_lora" max_len = 800 TARGET_MODULES = ["q_proj", "k_proj", "v_proj", "o_proj"] # full attention # TARGET_MODULES = ["q_proj","v_proj"] # TARGET_MODULES = ["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"] EMBEDDING_MODEL = "all-MiniLM-L6-v2" KB_PATH = r"RAG_data\KB_data_distilled.csv" OUTPUT_KB_JSONL = r"RAG_data\distillation_dataset.jsonl" AUGMENT_FRACTION = 0.3 # fraction of human examples that also get a teacher-label version RANDOM_SEED = 42 random.seed(RANDOM_SEED) USER = "Barbara" # the user whose tone we try to copy INDEX_NAME = "chats-index" # parameters for fine tuning MODEL_ID = "TinyLlama/TinyLlama-1.1B-Chat-v1.0" BATCH_SIZE = 4 MAX_LENGTH = 512 NUM_EPOCHS = 3 LEARNING_RATE = 5e-5 # "Weights" via oversampling: how many times to duplicate human examples HUMAN_DUP_FACTOR = 2 # 2 = roughly double weight vs teacher OUTPUT_JSONL = "RAG_data/distillation_dataset_clean.jsonl" # clean appended file device = "cuda" if torch.cuda.is_available() else "cpu" device ``` -------------------------------- ### Tokenize and Prepare Dataset for Training Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb A Python function `build_example` that tokenizes input and target texts, formats them into input IDs and attention masks, and creates labels for supervised learning by masking the prompt portion. It processes datasets using the Hugging Face `map` function and sets the format to PyTorch tensors. ```python def build_example(ex: Dict[str, Any]) -> Dict[str, Any]: input_text = ex.get("input_text", "") target_text = ex.get("target_text", "") # propmt + full text prompt = input_text + "\n\n### Barbara:\n" x = prompt + target_text # full padded to max_len for batching enc_full = tok( x, max_length=max_len, truncation=True, padding="max_length", ) # prompt onl with NO padding enc_prompt = tok( prompt, truncation=True, padding=False, add_special_tokens=False, ) input_ids = enc_full["input_ids"] labels = input_ids.copy() # asking only pront n_prompt = len(enc_prompt["input_ids"]) n_prompt = min(n_prompt, len(labels)) for i in range(n_prompt): labels[i] = -100 return { "input_ids": input_ids, "attention_mask": enc_full["attention_mask"], "labels": labels, } cols = ["input_ids", "attention_mask", "labels"] train_tok = train_ds.map( build_example, remove_columns=train_ds.column_names, ) val_tok = val_ds.map( build_example, remove_columns=val_ds.column_names, ) train_tok.set_format(type="torch", columns=cols) val_tok.set_format(type="torch", columns=cols) print("Tokenized train size:", len(train_tok), "| val size:", len(val_tok)) ex0 = train_tok[0] print("len(input_ids):", len(ex0["input_ids"])) print("len(labels): ", len(ex0["labels"])) print("num supervised tokens:", sum(1 for t in ex0["labels"].tolist() if t != -100)) ``` -------------------------------- ### Initialize RAG Context and User Style (Python) Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Initializes the Retrieval-Augmented Generation (RAG) context and user style using provided dataframes and conversation IDs. It loads a knowledge base, builds a context based on conversation history, and defines user-specific conversational styles. Dependencies include pandas and potentially custom build functions. ```python context = build_context( kb_df_all, conv_id="chat:u_1_u_2", # adjust conv_id as needed k=10, ) _, user_style = build_user_style( kb_df_all, user_id=USER, k=10, ) print("RAG initialization done!") ``` -------------------------------- ### Verify Embedding Dimensions Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/RAG_architecture.ipynb Displays the shape of the generated embeddings array to confirm successful encoding. The output shape [2362, 384] indicates 2362 message pairs encoded into 384-dimensional vectors by the SentenceTransformer model. ```python shape = embeddings.shape print("Embedding shape:", shape) ``` -------------------------------- ### Initialize Text Generation Pipeline with Character Prompt Engineering Source: https://github.com/brarbrb/whatsapp_webapp_-django-/blob/main/RAG/distillation.ipynb Creates a Hugging Face text generation pipeline using the fine-tuned model and tokenizer, configured with automatic device mapping. Implements a function that generates character-specific responses (Barbara) using structured prompts with query sections and instructions, applying temperature and top-p sampling for controlled randomness. ```python pipe = pipeline( "text-generation", model=output_dir, tokenizer=tok, device_map="auto", ) def generate_barbara_reply(query: str, max_new_tokens: int = 80): input_text = ( "You are Barbara. Answer in her natural WhatsApp style.\n\n" "### QUERY\n" f"{query}\n\n" "### INSTRUCTIONS\n" "Reply as Barbara would reply in WhatsApp." ) prompt = input_text + "\n\n### Barbara:\n" out = pipe( prompt, max_new_tokens=max_new_tokens, do_sample=True, top_p=0.9, temperature=0.7, )[0]["generated_text"] if "### Barbara:" in out: reply = out.split("### Barbara:", 1)[1].strip() else: reply = out.strip() return reply print(generate_barbara_reply("Hi, I'm sick today, can I get an extension?")) ```