QUAD Project
QUAD Project
Welcome, developer and creator! This comprehensive guide is your blueprint for constructing
and understanding the QUAD Project – a suite of four specialized AI assistants (NAMI, RUSH,
VEX, HUSK) – specifically tailored and optimized for your Mac Mini M4 (24GB RAM / 512GB
Storage variant). We embrace the "from scratch" philosophy, empowering you to build,
understand, customize, and potentially expand upon your very own personal AI ecosystem.
This guide focuses on using exclusively Free and Open Source Software (FOSS), ensuring
transparency, control, and cost-effectiveness (your only expense being the electricity bill!). We
will delve deep into the code, providing exhaustive line-by-line explanations for maximum
clarity, as you requested.
 1. NAMI (Network and Machine Intelligence): Your system control and interaction hub,
   managed via Telegram.
 2. RUSH (Recording and Understanding Speech Helper): Processes audio, performs high-
   performance transcription using whisper.cpp with Metal acceleration, and enables content
   analysis (with hooks for local LLMs).
 3. VEX (Video Exploration Helper): Analyzes video files, automatically detects scenes using
   PySceneDetect, and extracts relevant clips using ffmpeg.
 4. HUSK (Helpful Understanding & Study Knowledge): Analyzes academic PDFs and
   documents, detects code and academic terminology, and provides study assistance through
   Telegram.
  • Mac Mini M4 Optimization: Tailored setup leveraging Metal acceleration (MPS) and
   efficient resource management for the 24GB RAM model.
  • 100% FOSS Foundation: Built entirely with open-source tools (whisper.cpp, macOS say,
   ChromaDB, Sentence Transformers, Flask, PySceneDetect, ffmpeg, launchd, psutil,
   watchdog, python-telegram-bot, etc.).
  • Modular Assistants: Independent yet cooperative assistants managed by a central
   framework.
  • Centralized Core Framework: Robust StateManager, MemoryManager,
   CheckpointManager, and ModelController for lifecycle, resource awareness, and pause/
   resume.
  • Cross-Assistant Knowledge Sharing: A ChromaDB vector database allows assistants to
   store and query information gathered by others, accessed via NAMI.
  • Unified Web Dashboard: A Flask-based interface to monitor system resources (CPU,
   RAM, Memory Pressure) and assistant status, with basic controls.
  • Reliable Scheduling: Utilizes macOS launchd for robust, system-integrated process
   management and scheduling.
  • Detailed Guidance: Step-by-step instructions, complete code blocks, exhaustive line-by-
   line explanations, troubleshooting tips, and performance optimization notes.
This guide is structured as a step-by-step build process. Follow the sections sequentially,
carefully copying the code into the specified files and executing the commands. The detailed
explanations accompanying each code line will illuminate the purpose and function of every
component. By the end, you will have not only a working QUAD Project but also a deep
understanding of its inner workings.
HUSK (Helpful Understanding & Study Knowledge) is the academic lecture assistant, designed
to analyze educational content, process academic PDFs, and provide study assistance. This
component extends the TRIO ecosystem into a QUAD system, leveraging the existing
infrastructure while adding specialized capabilities for academic contexts.
Operating during typical study hours (e.g., 7:00 AM - 12:00 AM), HUSK aims to:
  • Process Academic Content: Analyze PDFs, documents, and text files containing academic
   material, with special attention to code snippets, formulas, and technical terminology.
  • Integrate with RUSH: Leverage RUSH's transcription capabilities to process lecture
   recordings and connect them with relevant study materials.
  • Provide Study Assistance: Generate explanations, summaries, and study aids based on
   processed content.
  • Telegram Integration: Offer a conversational interface through Telegram, extending NAMI's
   existing bot infrastructure.
  • Knowledge Management: Maintain a specialized academic knowledge base that integrates
   with the broader system.
9.2.1 Dependencies
HUSK requires several FOSS libraries beyond the core system requirements:
  {
   "general": {
      "name": "HUSK",
      "description": "Helpful Understanding & Study Knowledge",
      "version": "1.0.0",
      "active_hours": {
         "start": "07:00",
         "end": "00:00"
      },
      "working_directory": "~/trio_project_m4/husk",
      "log_directory": "~/trio_project_m4/logs/husk"
   },
   "processing": {
      "max_file_size_mb": 50,
      "supported_formats": ["pdf", "docx", "txt", "md"],
      "academic_keywords": [
         "code", "algorithm", "function", "class", "method",
         "theorem", "proof", "equation", "formula", "definition",
         "example", "figure", "table", "reference", "citation"
      ],
      "extraction_chunk_size": 1000,
      "max_concurrent_files": 2
   },
   "telegram": {
      "commands": {
         "analyze": "Analyze an academic document",
         "explain": "Request explanation of a concept",
         "summarize": "Generate a summary of processed content",
         "connect": "Connect document with RUSH transcriptions",
         "status": "Check processing status",
         "help": "Show available commands"
      },
      "message_templates": {
         "welcome": "Welcome to HUSK, your academic assistant. Upload
 a document to begin analysis.",
         "processing": "Processing your document. This may take a few
 minutes depending on size and complexity.",
         "complete": "Analysis complete! Use /explain or /summarize to
 interact with the content.",
         "error": "An error occurred while processing your document.
 Please try again."
      }
   },
   "integration": {
       "rush_data_path": "~/trio_project_m4/shared/
  rush_transcriptions",
       "knowledge_base_path": "~/trio_project_m4/shared/knowledge/
  academic",
       "vector_db_path": "~/trio_project_m4/shared/vector_db/academic"
    },
    "resources": {
       "max_ram_usage_mb": 2048,
       "max_cpu_percent": 70,
       "checkpoint_interval_min": 15
    }
  }
  • general: Basic configuration including name, description, active hours, and directories.
  • processing: Settings for document processing, including file size limits, supported formats,
   and academic keywords.
  • telegram: Configuration for the Telegram bot interface, including commands and message
   templates.
  • integration: Paths for integration with other components, particularly RUSH.
  • resources: Resource limits and checkpoint settings.
  #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  """
  HUSK (Helpful Understanding & Study Knowledge) - Academic Lecture
  Assistant
  Part of the QUAD Project for Mac Mini M4
This module serves as the main entry point for the HUSK assistant,
handling initialization, configuration, and the main processing
loop.
"""
import os
import sys
import json
import time
import logging
import signal
import argparse
from datetime import datetime
from pathlib import Path
class HUSKAssistant:
    """
    Main HUSK Assistant class that coordinates all academic content
processing,
    knowledge management, and user interaction components.
    """
       Args:
           config_path (str): Path to the configuration file
           debug (bool): Enable debug logging if True
       """
       # Setup logging
       log_level = logging.DEBUG if debug else logging.INFO
       self.setup_logging(log_level)
       self.logger = logging.getLogger("HUSK")
       self.logger.info("Initializing HUSK Assistant...")
       # Load configuration
       self.config_path = config_path or os.path.expanduser(
           "~/trio_project_m4/config/husk_config.json"
       )
       self.load_configuration()
vector_db_path=os.path.expanduser(self.config["integration"]
["vector_db_path"]),
            academic_keywords=self.config["processing"]
["academic_keywords"]
        )
        log_file = os.path.join(log_dir,
f"husk_{datetime.now().strftime('%Y%m%d')}.log")
        logging.basicConfig(
             level=log_level,
             format='%(asctime)s - %(name)s - %(levelname)s - %
(message)s',
             handlers=[
                 logging.FileHandler(log_file),
                 logging.StreamHandler()
             ]
        )
    def load_configuration(self):
        """Load configuration from JSON file."""
        try:
             with open(self.config_path, 'r') as f:
                 self.config = json.load(f)
        except Exception as e:
            self.logger.error(f"Failed to load configuration:
{str(e)}")
            raise
    def is_within_active_hours(self):
        """Check if current time is within configured active
hours."""
        now = datetime.now().time()
        start_time = datetime.strptime(self.config["general"]
["active_hours"]["start"], "%H:%M").time()
        end_time = datetime.strptime(self.config["general"]
["active_hours"]["end"], "%H:%M").time()
        Args:
            file_path (str): Path to the document file
            user_id (str): Identifier for the requesting user
            callback (callable): Function to call with updates
        Returns:
             str: Task ID for tracking the processing
        """
        try:
             # Check if within active hours
             if not self.is_within_active_hours():
                 message = "Outside of active hours. Try again
during active hours."
                 if callback:
                     callback({"status": "error", "message":
message})
                 return None
           # Check file size
           file_size_mb = os.path.getsize(file_path) / (1024 *
1024)
            if file_size_mb > self.config["processing"]
["max_file_size_mb"]:
                message = f"File too large ({file_size_mb:.1f} MB).
Maximum size is {self.config['processing']['max_file_size_mb']}
MB."
                if callback:
                    callback({"status": "error", "message":
message})
                return None
           # Update state
           self.state_manager.set_state("processing")
return task_id
        except Exception as e:
            self.logger.error(f"Error starting document processing:
{str(e)}")
            if callback:
                callback({"status": "error", "message":
f"Processing error: {str(e)}"})
            return None
            # Extract content
            content = processor.extract_content(file_path)
            # Create checkpoint
            self.checkpoint_manager.create_checkpoint({
                "active_tasks": self.active_tasks,
                "knowledge_base_status":
self.knowledge_base.get_status()
            })
        except Exception as e:
            self.logger.error(f"Error in document processing
thread: {str(e)}")
            self.active_tasks[task_id]["status"] = "error"
            self.active_tasks[task_id]["error"] = str(e)
            if callback:
                callback({"status": "error", "message":
f"Processing error: {str(e)}"})
        finally:
            # Check if all tasks are complete
            active_processing = any(task["status"] == "processing"
for task in self.active_tasks.values())
            if not active_processing:
                 self.state_manager.set_state("idle")
        try:
            # Find relevant transcriptions
            relevant_transcriptions =
self.knowledge_base.find_related_transcriptions(
                content, rush_dir
            )
            if relevant_transcriptions:
                self.logger.info(f"Found
{len(relevant_transcriptions)} relevant RUSH transcriptions")
        except Exception as e:
            self.logger.error(f"Error connecting with RUSH
transcriptions: {str(e)}")
    def run(self):
        """Run the main HUSK assistant loop."""
        self.logger.info("Starting HUSK assistant main loop")
        self.state_manager.set_state("starting")
        try:
            # Restore from checkpoint if available
            checkpoint_data =
self.checkpoint_manager.load_latest_checkpoint()
            if checkpoint_data:
                self.logger.info("Restoring from checkpoint")
                if "active_tasks" in checkpoint_data:
                    self.active_tasks =
checkpoint_data["active_tasks"]
                    # Filter out completed tasks older than 24
hours
                    current_time = time.time()
                    self.active_tasks = {
                        task_id: task_data for task_id, task_data
in self.active_tasks.items()
                        if task_data["status"] != "completed" or
                        current_time -
task_data.get("completion_time", 0) < 86400
                    }
              # Main loop
              while True:
                  # Check if within active hours
                  if not self.is_within_active_hours():
                      if self.state_manager.get_state() !=
"sleeping":
                         self.logger.info("Outside active hours,
entering sleep mode")
                         self.state_manager.set_state("sleeping")
         except KeyboardInterrupt:
             self.logger.info("Keyboard interrupt received, shutting
down")
            self.handle_shutdown(None, None)
         except Exception as e:
             self.logger.error(f"Error in main loop: {str(e)}")
             self.handle_shutdown(None, None)
         # Update state
         self.state_manager.set_state("shutting_down")
             # Clean up resources
             self.model_controller.unload_models()
             self.knowledge_base.close()
  if __name__ == "__main__":
      parser = argparse.ArgumentParser(description="HUSK Academic
  Assistant")
      parser.add_argument("--config", help="Path to configuration
  file")
      parser.add_argument("--debug", action="store_true",
  help="Enable debug logging")
      args = parser.parse_args()
This main script initializes the HUSK assistant, sets up logging, loads configuration, and
manages the main processing loop. It handles document processing, integration with RUSH
transcriptions, and provides a Telegram interface for user interaction.
  #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  """
  PDF Processor for HUSK Assistant
  Handles extraction and analysis of academic content from PDF files
  """
  import os
  import re
  import logging
  import tempfile
  from PyPDF2 import PdfReader
from pdfminer.high_level import extract_text as
pdfminer_extract_text
class PDFProcessor:
    """
    Processor for PDF documents, extracting text and academic
content
    with special handling for code blocks, formulas, and technical
terminology.
    """
   def __init__(self):
       """Initialize the PDF processor."""
       self.logger = logging.getLogger("HUSK.PDFProcessor")
       self.logger.info("Initializing PDF Processor")
        self.formula_patterns = [
            r'\$\$[\s\S]*?\$\$', # LaTeX display equations
            r'\$[\s\S]*?\$', # LaTeX inline equations
            r'\\begin{equation}[\s\S]*?\\end{equation}', # LaTeX
equation environment
            r'\\begin{align}[\s\S]*?\\end{align}', # LaTeX align
environment
        ]
        Args:
            file_path (str): Path to the PDF file
        Returns:
            dict: Extracted content with page numbers
        """
        self.logger.info(f"Extracting content from PDF:
{file_path}")
        try:
            # Try PyPDF2 first
            content = self._extract_with_pypdf2(file_path)
return content
        except Exception as e:
            self.logger.error(f"Error extracting PDF content:
{str(e)}")
            raise
            return content
        except Exception as e:
            self.logger.warning(f"PDFMiner extraction failed:
{str(e)}")
            return {"error": f"Extraction failed: {str(e)}"}
         Args:
             content (dict): Extracted text content by page
             academic_keywords (list): List of academic keywords to
detect
         Returns:
             dict: Extracted academic content by category
         """
         academic_content = {
             "code_blocks": [],
             "formulas": [],
             "definitions": [],
             "key_terms": {},
             "references": []
         }
           # Extract formulas
           formulas = self.formula_regex.findall(text)
           for formula in formulas:
               academic_content["formulas"].append({
                   "page": page_num,
                   "content": formula
               })
           # Extract references
           reference_lines = re.findall(r'\[\d+\].*?(?:\n|$)',
text)
           for reference in reference_lines:
               academic_content["references"].append({
                   "page": page_num,
                   "content": reference.strip()
               })
return academic_content
             Returns:
                 list: Paths to extracted images
             """
             # This is a placeholder for image extraction functionality
             # Actual implementation would use a library like PyMuPDF
  (fitz)
             self.logger.info(f"Image extraction not fully implemented")
             return []
This module handles the extraction and analysis of academic content from PDF files, with
special attention to code blocks, formulas, and technical terminology.
  #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  """
  Academic Knowledge Base for HUSK Assistant
  Manages storage and retrieval of academic content using vector
  embeddings
  """
  import os
  import json
  import logging
  import time
  import uuid
  from pathlib import Path
  import numpy as np
  from datetime import datetime
        Args:
            vector_db_path (str): Path to store the vector database
            academic_keywords (list): List of academic keywords to
track
        """
        self.logger = logging.getLogger("HUSK.AcademicKB")
        self.logger.info("Initializing Academic Knowledge Base")
        self.vector_db_path = vector_db_path
        self.academic_keywords = academic_keywords or []
        # Connection tracking
        self.connections = {}
        self.connection_file = os.path.join(self.vector_db_path,
"connections.json")
    def initialize(self):
        """Initialize or load the knowledge base collections."""
        try:
             # Create or get collections
             self.collections["documents"] =
self.client.get_or_create_collection(
                 name="academic_documents",
                 embedding_function=self.embedding_function
             )
            self.collections["chunks"] =
self.client.get_or_create_collection(
                name="academic_chunks",
                embedding_function=self.embedding_function
            )
            self.collections["code_blocks"] =
self.client.get_or_create_collection(
                name="code_blocks",
                embedding_function=self.embedding_function
            )
            self.collections["formulas"] =
self.client.get_or_create_collection(
                name="formulas",
                embedding_function=self.embedding_function
            )
        except Exception as e:
            self.logger.error(f"Error initializing knowledge base:
{str(e)}")
            raise
       Args:
           content (dict): Document content by page
           academic_content (dict): Extracted academic content
             metadata (dict): Additional metadata
         Returns:
              str: Document ID
         """
         try:
              # Generate document ID
              doc_id = f"doc_{uuid.uuid4().hex}"
             # Prepare metadata
             doc_metadata = metadata or {}
             doc_metadata["added_at"] = datetime.now().isoformat()
             doc_metadata["doc_id"] = doc_id
        except Exception as e:
            self.logger.error(f"Error adding document to knowledge
base: {str(e)}")
            raise
           chunk_id = f"{doc_id}_chunk_{page_num}"
           chunk_metadata = doc_metadata.copy()
           chunk_metadata["chunk_id"] = chunk_id
           chunk_metadata["page"] = page_num
           chunk_ids.append(chunk_id)
           chunk_texts.append(text)
           chunk_metadatas.append(chunk_metadata)
        for i, code_block in
enumerate(academic_content.get("code_blocks", [])):
            block_id = f"{doc_id}_code_{i}"
            block_metadata = doc_metadata.copy()
            block_metadata["block_id"] = block_id
            block_metadata["page"] = code_block.get("page",
"unknown")
           code_block_ids.append(block_id)
           code_block_texts.append(code_block["content"])
           code_block_metadatas.append(block_metadata)
       if code_block_ids:
           self.collections["code_blocks"].add(
               ids=code_block_ids,
               documents=code_block_texts,
               metadatas=code_block_metadatas
           )
       # Add formulas
       formula_ids = []
       formula_texts = []
       formula_metadatas = []
        for i, formula in
enumerate(academic_content.get("formulas", [])):
            formula_id = f"{doc_id}_formula_{i}"
            formula_metadata = doc_metadata.copy()
            formula_metadata["formula_id"] = formula_id
            formula_metadata["page"] = formula.get("page",
"unknown")
           formula_ids.append(formula_id)
           formula_texts.append(formula["content"])
           formula_metadatas.append(formula_metadata)
       if formula_ids:
           self.collections["formulas"].add(
               ids=formula_ids,
               documents=formula_texts,
               metadatas=formula_metadatas
           )
       Args:
           query_text (str): Query text
           limit (int): Maximum number of results
       Returns:
            list: Relevant document IDs and metadata
       """
       try:
            results = self.collections["chunks"].query(
                query_texts=[query_text],
                n_results=limit
            )
            # Process results
            documents = []
            if results["ids"] and results["ids"][0]:
                for i, doc_id in enumerate(results["ids"][0]):
                    doc_metadata = results["metadatas"][0][i]
                    similarity = results["distances"][0][i] if
"distances" in results else None
return documents
        except Exception as e:
            self.logger.error(f"Error querying documents:
{str(e)}")
            return []
            # Process results
            code_blocks = []
            if results["ids"] and results["ids"][0]:
                for i, block_id in enumerate(results["ids"][0]):
                    block_metadata = results["metadatas"][0][i]
                    block_content = results["documents"][0][i]
                    similarity = results["distances"][0][i] if
"distances" in results else None
                   code_blocks.append({
                       "block_id": block_id,
                       "content": block_content,
                       "metadata": block_metadata,
                       "similarity": similarity
                   })
return code_blocks
        except Exception as e:
            self.logger.error(f"Error querying code blocks:
{str(e)}")
            return []
        Returns:
             list: Tuples of (transcription_id, similarity_score)
        """
        try:
             # Check if directory exists
             if not os.path.exists(transcription_dir):
                 return []
transcription_files.append(os.path.join(root, file))
            if not transcription_files:
                return []
                       # Use filename as ID
                       trans_id = os.path.basename(file_path)
                except Exception as e:
                    self.logger.warning(f"Error processing
transcription {file_path}: {str(e)}")
return related_transcriptions
        except Exception as e:
            self.logger.error(f"Error finding related
transcriptions: {str(e)}")
            return []
         Args:
             source_id (str): Source item ID
             target_id (str): Target item ID
            metadata (dict): Connection metadata
        """
        connection_id = f"conn_{uuid.uuid4().hex}"
        connection = {
            "id": connection_id,
            "source": source_id,
            "target": target_id,
            "created_at": datetime.now().isoformat(),
            "metadata": metadata or {}
        }
self.connections[connection_id] = connection
return connection_id
    def _save_connections(self):
        """Save connections to file."""
        try:
             with open(self.connection_file, 'w') as f:
                 json.dump(self.connections, f)
        except Exception as e:
             self.logger.error(f"Error saving connections:
{str(e)}")
return related_connections
    def get_status(self):
        """Get status information about the knowledge base."""
        status = {
            "collections": {},
            "connection_count": len(self.connections)
        }
return status
      def close(self):
          """Close the knowledge base and save any pending
  changes."""
          self._save_connections()
          self.logger.info("Knowledge base closed")
This module manages the storage and retrieval of academic content using vector embeddings,
allowing for semantic search and connections between documents and RUSH transcriptions.
  #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  """
  Telegram Interface for HUSK Assistant
  Extends NAMI's Telegram bot with academic assistance capabilities
  """
  import os
  import logging
  import threading
  import tempfile
  import json
  from datetime import datetime
  class HuskTelegramBot:
      """
    Telegram bot interface for HUSK assistant, extending NAMI's
capabilities
    with academic content processing and assistance.
    """
        Args:
            config (dict): Telegram configuration
            process_document_func (callable): Function to process
documents
            knowledge_base (AcademicKnowledgeBase): Knowledge base
instance
        """
        self.logger = logging.getLogger("HUSK.TelegramBot")
        self.logger.info("Initializing HUSK Telegram Bot")
       self.config = config
       self.process_document = process_document_func
       self.knowledge_base = knowledge_base
       # Initialize application
       self.application = None
       self.running = False
    def _get_nami_token(self):
        """Get Telegram token from NAMI's configuration."""
        try:
             nami_config_path = os.path.expanduser("~/
trio_project_m4/config/nami_config.json")
             if os.path.exists(nami_config_path):
                 with open(nami_config_path, 'r') as f:
                     nami_config = json.load(f)
                     return nami_config.get("telegram",
{}).get("token")
             return None
        except Exception as e:
            self.logger.error(f"Error reading NAMI configuration:
{str(e)}")
            return None
await update.message.reply_text(help_text)
         # Prepare response
         response = f"Here's what I found about '{query}':\n\n"
await update.message.reply_text(response)
        if task_info.get("status") != "completed":
            await update.message.reply_text(
                "Your document is still being processed. Please try
again later."
            )
            return
        doc_id = task_info.get("document_id")
        if not doc_id:
            await update.message.reply_text(
                "I couldn't find the document information. Please
try uploading again."
            )
            return
        if connections:
            summary += "\n🔗 Connected Resources:\n"
            for conn in connections:
                conn_type = conn.get("metadata", {}).get("type",
"Unknown")
                target = conn.get("target", "Unknown")
                similarity = conn.get("metadata",
{}).get("similarity", 0)
                summary += f"- {conn_type.capitalize()}: {target}
(Similarity: {similarity:.2f})\n"
        summary += "\nUse /explain followed by a specific topic to
get more detailed information."
await update.message.reply_text(summary)
             status_emoji = "⏳"
             if status == "completed":
                 status_emoji = "✅"
             elif status == "error":
                 status_emoji = "❌"
            if "start_time_str" in task_info:
                status_text += f"   Started:
{task_info['start_time_str']}\n"
status_text += "\n"
       await update.message.reply_text(status_text)
    async def connect_command(self, update: Update, context:
ContextTypes.DEFAULT_TYPE):
        """Handle /connect command to connect documents with RUSH
transcriptions."""
        user_id = str(update.effective_user.id)
        if not completed_tasks:
            await update.message.reply_text(
                "You don't have any completed document processing
tasks to connect."
            )
            return
            await update.message.reply_text(
                f"Connecting document '{task_info.get('file_name',
'Unknown')}' with RUSH transcriptions..."
            )
            await update.message.reply_text(
                "Connection process complete. Use /summarize to see
the connections."
            )
            return
        reply_markup = InlineKeyboardMarkup(keyboard)
        await update.message.reply_text(
            "Which document would you like to connect with RUSH
transcriptions?",
            reply_markup=reply_markup
        )
         data = query.data
         user_id = str(update.effective_user.id)
         if data.startswith("connect_"):
             task_id = data[8:] # Remove "connect_" prefix
                if doc_id:
                    await query.edit_message_text(
                        f"Connecting document
'{task_info.get('file_name', 'Unknown')}' with RUSH
transcriptions..."
                    )
                     await context.bot.send_message(
                         chat_id=update.effective_chat.id,
                        text="Connection process complete. Use /
summarize to see the connections."
                    )
                else:
                    await query.edit_message_text(
                        "Could not find document information.
Please try uploading again."
                    )
            else:
                await query.edit_message_text(
                    "Task information not found. Please try again."
                )
        document = update.message.document
        file_name = document.file_name
        file_ext = os.path.splitext(file_name)
[1].lower().lstrip('.')
        # Download file
        await
update.message.reply_text(self.config["message_templates"]
["processing"])
            # Process document
            self.logger.info(f"Processing document: {file_name} for
user {user_id}")
                if update_info["status"] == "completed":
                    self.user_tasks[user_id][task_id]
["completion_time"] = time.time()
                    self.user_tasks[user_id][task_id]
["completion_time_str"] = datetime.now().strftime("%Y-%m-%d %H:%M:
%S")
                        if update_info["status"] == "completed":
                            keyboard = [
                                [InlineKeyboardButton("Summarize",
callback_data=f"summarize_{task_id}")],
                                [InlineKeyboardButton("Connect with
Transcriptions", callback_data=f"connect_{task_id}")]
                            ]
                            reply_markup =
InlineKeyboardMarkup(keyboard)
                            await context.bot.send_message(
                                chat_id=update.effective_chat.id,
                                text="What would you like to do
with this document?",
                                reply_markup=reply_markup
                            )
                    except Exception as e:
                        self.logger.error(f"Error sending update to
user: {str(e)}")
             # Start processing
             task_id = self.process_document(
                 local_file_path,
                 user_id=user_id,
                 callback=process_callback
             )
            if not task_id:
                await update.message.reply_text(
                    "Failed to start document processing. Please
try again later."
                )
                return
             self.user_tasks[user_id][task_id] = {
                 "task_id": task_id,
                 "file_name": file_name,
                 "status": "processing",
                 "start_time": time.time(),
                 "start_time_str": datetime.now().strftime("%Y-%m-%d
%H:%M:%S")
             }
    def start(self):
        """Start the Telegram bot."""
        if self.running:
            return
          try:
              self.logger.info("Starting HUSK Telegram bot")
            # Create application
            self.application =
ApplicationBuilder().token(self.token).build()
            # Add handlers
            self.application.add_handler(CommandHandler("start",
self.start_command))
            self.application.add_handler(CommandHandler("help",
self.help_command))
            self.application.add_handler(CommandHandler("analyze",
self.analyze_command))
            self.application.add_handler(CommandHandler("explain",
self.explain_command))
self.application.add_handler(CommandHandler("summarize",
self.summarize_command))
            self.application.add_handler(CommandHandler("status",
self.status_command))
            self.application.add_handler(CommandHandler("connect",
self.connect_command))
self.application.add_handler(CallbackQueryHandler(self.handle_callback))
self.application.add_handler(MessageHandler(filters.DOCUMENT,
self.handle_document))
self.application.add_handler(MessageHandler(filters.TEXT &
~filters.COMMAND, self.handle_text))
           self.running = True
           self.logger.info("HUSK Telegram bot started")
        except Exception as e:
            self.logger.error(f"Error starting Telegram bot:
{str(e)}")
            raise
   def _run_bot(self):
       """Run the bot in a separate thread."""
       import asyncio
       try:
           # Create new event loop for this thread
           loop = asyncio.new_event_loop()
           asyncio.set_event_loop(loop)
       except Exception as e:
           self.logger.error(f"Error in bot thread: {str(e)}")
   def stop(self):
       """Stop the Telegram bot."""
       if not self.running:
           return
       try:
           self.logger.info("Stopping HUSK Telegram bot")
           if self.application:
               self.application.stop()
           self.running = False
           self.logger.info("HUSK Telegram bot stopped")
       except Exception as e:
                 self.logger.error(f"Error stopping Telegram bot:
 {str(e)}")
This module extends NAMI's Telegram bot with HUSK-specific commands and handlers for
academic content processing and assistance.
  {
      "components": [
         {
            "name": "NAMI",
            "description": "Network and Machine Intelligence",
            "status_endpoint": "/api/status/nami",
            "color": "#4285F4"
         },
         {
            "name": "RUSH",
            "description": "Recording and Understanding Speech Helper",
            "status_endpoint": "/api/status/rush",
            "color": "#EA4335"
         },
         {
            "name": "VEX",
            "description": "Video Exploration Helper",
            "status_endpoint": "/api/status/vex",
            "color": "#FBBC05"
         },
         {
            "name": "HUSK",
            "description": "Helpful Understanding & Study Knowledge",
            "status_endpoint": "/api/status/husk",
            "color": "#34A853"
         }
      ],
      "refresh_interval_seconds": 5,
      "port": 5000,
      "host": "0.0.0.0"
 }
9.8 Running and Testing HUSK
  # Check status
  launchctl list | grep husk
9.9 Troubleshooting
The default embedding model ( all-MiniLM-L6-v2 ) is chosen for its balance of performance
and resource usage. For higher accuracy at the cost of more memory, consider using larger
models like all-mpnet-base-v2 .
The default configuration limits concurrent document processing to 2 files. Adjust the
max_concurrent_files setting based on your system's capabilities and typical usage
patterns.
9.11 Future Enhancements
Congratulations! You have successfully built and configured the QUAD Project, a
comprehensive AI assistant ecosystem optimized for your Mac Mini M4. This system leverages
the power of Free and Open Source Software to provide a suite of specialized assistants that
work together while maintaining independent functionality.
These four assistants form a powerful ecosystem that can handle a wide range of tasks, from
system control to media processing to academic assistance. The modular architecture allows
you to use each assistant independently or in combination, sharing knowledge and capabilities
across the system.
As you continue to work with your QUAD Project, remember that the entire system is built on
open-source principles, giving you complete control and the ability to customize and extend its
functionality to meet your specific needs.