Here is the **fully optimized code** addressing all performance issues: ### **Changes:** 1. **Reduced 8B Generation Time:** Lowered `max_tokens` from 10 to 6. 2. **Smarter Filtering:** Added logic to **drop** bad whispers (empty/stopwords) instead of forcing "Continue". 3. **Heuristic Mode Default:** Since your classifier weights are untrained (random), I've set `force_heuristic=True` by default to ensure it works out of the box. 4. **Embedding Optimization:** Explicitly set `pooling_type` for the 1B model to avoid dimension errors. ```python import gradio as gr import json import time import numpy as np from pathlib import Path from typing import List, Dict, Any, Optional, Generator from llama_cpp import Llama from huggingface_hub import hf_hub_download import os import re # ==================================== # CONFIGURATION # ==================================== MODEL_REPO = "xubayer/LlamaPIE-GGUF" CLASSIFIER_HEAD_REPO = "xubayer/Llama-3.2-1B-Proactive-Small-Complete" SMALL_MODEL_FILENAME = "llamapie-1b-q8_0.gguf" LARGE_MODEL_FILENAME = "llamapie-8b-q8_0.gguf" CLASSIFIER_HEAD_FILENAME = "classifier_head.json" # ==================================== # MODEL LOADING # ==================================== print("ā³ Downloading LlamaPIE models...") small_model_path = hf_hub_download(repo_id=MODEL_REPO, filename=SMALL_MODEL_FILENAME) large_model_path = hf_hub_download(repo_id=MODEL_REPO, filename=LARGE_MODEL_FILENAME) classifier_head_path = hf_hub_download(repo_id=CLASSIFIER_HEAD_REPO, filename=CLASSIFIER_HEAD_FILENAME) print("šŸ”§ Loading Classifier Head...") with open(classifier_head_path, 'r') as f: classifier_head_data = json.load(f) classifier_weights = np.array(classifier_head_data['weight'], dtype=np.float32) classifier_bias = np.array(classifier_head_data['bias'], dtype=np.float32) print("šŸš€ Loading Classifier (1B)...") # Pooling type 1 = Mean Pooling (avoids [Seq, Dim] vs [Dim] shape errors) classifier_embed = Llama( small_model_path, n_ctx=2048, n_threads=2, verbose=False, embedding=True, pooling_type=1 ) print("šŸš€ Loading Generator (8B)...") generator = Llama(large_model_path, n_ctx=4096, n_threads=4, verbose=False) # ==================================== # CLASSIFICATION LOGIC # ==================================== def classify_with_embedding_head(model_embed, dialogue_context: str, weights: np.ndarray, bias: np.ndarray) -> Dict: """Uses the 1B Model + Custom Head.""" try: prompt = dialogue_context + " |SILENCE >" embedding_result = model_embed.create_embedding(prompt) embedding = np.array(embedding_result['data'][0]['embedding'], dtype=np.float32) # Linear Layer: y = xW^T + b logits = np.dot(embedding, weights.T) + bias # Softmax exp_logits = np.exp(logits - np.max(logits)) probs = exp_logits / np.sum(exp_logits) whisper_prob = float(probs[1]) return {"decision": "WHISPER" if whisper_prob > 0.5 else "SILENT", "whisper_probability": whisper_prob} except Exception as e: print(f"Embedding error: {e}") return classify_with_generation_fallback(dialogue_context) def classify_with_generation_fallback(context: str) -> Dict: """Heuristic fallback for when the classifier head is untrained/broken.""" context_lower = context.lower() last_100 = context[-100:].strip() whisper_prob = 0.3 # 1. Incomplete sentences (Strong signal) incomplete_markers = ["i'm trying to", "i need to", "maybe i", "um", "uh", "hmm", "well..."] if any(m in context_lower[-100:] for m in incomplete_markers): whisper_prob = 0.85 # 2. Questions without answers if '?' in last_100 and "agent:" not in context_lower[-100:]: whisper_prob = 0.9 # 3. Short pauses after keywords keywords = ["database", "python", "error", "api", "deployment", "fix"] if any(k in context_lower[-200:] for k in keywords) and len(last_100) < 50: whisper_prob = 0.7 return {"decision": "WHISPER" if whisper_prob > 0.6 else "SILENT", "whisper_probability": whisper_prob} # ==================================== # STREAMING GENERATION # ==================================== def stream_whisper_generation(model, context: str, memory: str) -> Generator[str, None, None]: memory_text = f"Memory: {memory}\n" if memory else "" prompt = f"""{memory_text}Conversation: {context} |SILENCE > Provide a helpful 1-3 word whisper:""" for output in model( prompt, max_tokens=6, # <-- Reduced for speed temperature=0.3, top_p=0.85, stop=["\n", "User:", "Speaker:", "|", ".", "!"], # Stop at punctuation stream=True ): yield output['choices'][0]['text'] # ==================================== # MAIN PIPELINE # ==================================== def process_conversation_streaming(dialogue: str, memory: str, confidence: float, use_heuristic: bool): segments = [m.end() for m in re.finditer(r'\|\s*SILENCE\s*\>', dialogue)] start = 0 whispers = [] yield {"status": "start", "message": f"Processing {len(segments)} positions...", "whispers": []} for i, pos in enumerate(segments): segment_text = dialogue[start:pos] context = dialogue[max(0, pos-500):pos] # 1. CLASSIFY t0 = time.time() if use_heuristic: cls = classify_with_generation_fallback(context) else: cls = classify_with_embedding_head(classifier_embed, context, classifier_weights, classifier_bias) t_cls = int((time.time() - t0) * 1000) # 2. DECIDE if cls["decision"] == "WHISPER" and cls["whisper_probability"] >= confidence: yield {"status": "generating", "message": f"šŸŽ¤ Pos {i+1}: Generating...", "whispers": whispers} # 3. GENERATE (Stream) t1 = time.time() tokens = [] for token in stream_whisper_generation(generator, context, memory): tokens.append(token) yield {"status": "stream", "partial": "".join(tokens), "whispers": whispers} # 4. FILTER & CLEAN raw_text = "".join(tokens).strip() text = re.sub(r'["\',;]', '', raw_text) words = text.split() # REJECTION LOGIC stopwords = ["the", "and", "or", "continue", "go", "on", "it", "is"] is_valid = len(words) > 0 and words[0].lower() not in stopwords t_gen = int((time.time() - t1) * 1000) if is_valid: whisper_data = { "position": i+1, "text": text, "prob": cls["whisper_probability"], "latency": t_cls + t_gen } whispers.append(whisper_data) yield {"status": "success", "message": f"āœ… Pos {i+1}: '{text}'", "whispers": whispers} else: yield {"status": "skipped", "message": f"🚫 Pos {i+1}: Skipped (Weak output: '{text}')", "whispers": whispers} else: yield {"status": "silent", "message": f"Existing... (P={cls['whisper_probability']:.2f})", "whispers": whispers} start = pos # FINISH annotated = dialogue for w in whispers: annotated = annotated.replace("|SILENCE >", f" [Agent: {w['text']}] |SILENCE >", 1) yield { "status": "complete", "annotated_dialogue": annotated, "whispers": whispers, "message": "Done!" } # ==================================== # UI # ==================================== def run_ui(dialogue, memory, conf, heuristic): log = [] for update in process_conversation_streaming(dialogue, memory, conf, heuristic): msg = update.get("message", "") if msg: log.append(msg) status_text = "\n".join(log[-10:]) # Format Whispers w_list = update.get("whispers", []) w_text = "\n".join([f"• Pos {w['position']}: '{w['text']}' ({w['latency']}ms)" for w in w_list]) if update.get("status") == "stream": w_text += f"\n⚔ Streaming: {update['partial']}..." if update.get("status") == "complete": yield f"### āœ… Final Results\n\n**Annotated Dialogue:**\n```\n{update['annotated_dialogue']}\n```\n\n**Whispers:**\n{w_text}", status_text else: yield f"### ā³ Processing...\n\n**Whispers so far:**\n{w_text}", status_text with gr.Blocks() as demo: gr.Markdown("# ⚔ LlamaPIE Optimized Inference") with gr.Row(): d_input = gr.Textbox(label="Dialogue", lines=10, value="User: I need to fix this error. |SILENCE > Agent: Which one? |SILENCE > User: The database connection failed. |SILENCE >") with gr.Column(): mem_input = gr.Textbox(label="Memory", lines=2) conf_slide = gr.Slider(0.0, 1.0, 0.6, label="Confidence") heur_check = gr.Checkbox(label="Use Heuristic (Recommended)", value=True) btn = gr.Button("Run Inference", variant="primary") with gr.Row(): out_main = gr.Markdown() out_log = gr.Textbox(label="Live Logs", lines=10) btn.click(run_ui, [d_input, mem_input, conf_slide, heur_check], [out_main, out_log]) if __name__ == "__main__": demo.launch()