Skip to main content

Contributing to ChatbotAI-Free

Thank you for your interest in contributing to ChatbotAI-Free! This guide will help you get started with development, understand the codebase structure, and submit your contributions.

Getting Started

Fork and Clone

1

Fork the repository

Go to ChatbotAI-Free on GitHub and click the Fork button to create your own copy.
2

Clone your fork

git clone https://github.com/YOUR_USERNAME/ChatbotAI-Free
cd ChatbotAI-Free
3

Create a feature branch

git checkout -b feature/AmazingFeature
Use descriptive branch names:
  • feature/add-voice-cloning for new features
  • fix/mic-device-selection for bug fixes
  • docs/update-installation for documentation
  • refactor/tts-manager for code improvements
4

Set up development environment

python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install -r requirements.txt
For GPU development:
pip install onnxruntime-gpu torch --index-url https://download.pytorch.org/whl/cu118

Development Setup

Make sure you have Ollama installed and at least one model pulled before running the app:
ollama pull llama3.1:8b
Download the Kokoro model files for TTS testing:
  1. Visit kokoro-onnx releases
  2. Download kokoro-v1.0.onnx and voices-v1.0.bin
  3. Place in voices/kokoro-v1.0/

Code Structure Overview

Understanding the codebase architecture will help you navigate and make effective contributions.

File Organization

ChatbotAI-Free/
├── main.py              # Main application, UI, event handlers, threading
├── ai_manager.py        # AI orchestration (Whisper, Ollama, TTS coordination)
├── tts_manager.py       # TTS routing (Kokoro vs Sherpa-ONNX)
├── audio_utils.py       # Audio I/O (AudioRecorder, AudioPlayer, VAD)
├── chat_history.py      # Markdown persistence, chat management
├── preferences.py       # Settings serialization (preferences.json)
├── styles.py            # PyQt6 stylesheets (Gemini-inspired dark theme)
├── kokoro_wrapper.py    # Kokoro ONNX interface
├── sherpa_wrapper.py    # Sherpa-ONNX interface (external voice packs)
├── voice_scanner.py     # Voice pack detection and classification
├── voice_detector.py    # Voice selection and mapping logic
├── voices/              # TTS model directory
│   └── kokoro-v1.0/     # Kokoro models
├── chats/               # Saved conversations (Markdown)
└── requirements.txt     # Python dependencies

Key Modules

main.py

UI Layer (1300+ lines)
  • ChatbotWindow: Main window class
  • ManualRecorderThread: Recording thread
  • WorkerThread: Classic chat pipeline
  • LiveWorkerThread: Live mode with barge-in
  • MarkdownRenderer: HTML conversion
  • ThinkingWidget: Collapsible reasoning panel
  • ContextDonut: Token usage indicator

ai_manager.py

AI Coordination (543 lines)
  • Model initialization (Whisper, Ollama, TTS)
  • transcribe(): STT with VAD filtering
  • get_llm_response_streaming(): Streaming LLM with thinking support
  • text_to_speech(): TTS generation
  • Conversation history management
  • Token tracking and context size queries

tts_manager.py

TTS Router (151 lines)
  • Kokoro/Sherpa voice detection (_is_sherpa_voice())
  • Engine lazy loading and caching
  • create(): Unified synthesis interface
  • Language code mapping
  • Speed adjustment support

audio_utils.py

Audio I/O (298 lines)
  • AudioRecorder: VAD-based recording
  • Sample rate detection and resampling
  • AudioPlayer: PipeWire playback via paplay
  • Queue-based buffering
  • Pause/resume for feedback prevention

Adding New Features

Example: Adding a New TTS Engine

Let’s walk through adding support for a new TTS engine called “NeoTTS”.
1

Create a wrapper module

Create neotts_wrapper.py:
import numpy as np

class NeoTTSWrapper:
    def __init__(self, model_path: str):
        # Initialize your TTS engine
        self.model = load_neotts(model_path)
        self.sample_rate = 22050

    def create(self, text: str, speed: float = 1.0):
        """Generate speech from text.
        
        Returns:
            tuple: (numpy.ndarray of float32 samples, sample_rate)
        """
        samples = self.model.synthesize(text, speed=speed)
        return samples.astype(np.float32), self.sample_rate
2

Update TTSManager routing

Edit tts_manager.py:
def _is_neotts_voice(voice_name: str) -> bool:
    # Define how to detect NeoTTS voices
    return voice_name.startswith("neo_")

class TTSManager:
    def __init__(self, ...):
        # Add NeoTTS initialization
        self.neotts = None
        self._init_neotts()

    def _init_neotts(self):
        try:
            from neotts_wrapper import NeoTTSWrapper
            self.neotts = NeoTTSWrapper("models/neotts.onnx")
        except Exception as e:
            print(f"NeoTTS not available: {e}")

    def create(self, text: str, speed: float = 1.0):
        # Add routing logic
        if _is_neotts_voice(self.voice_name):
            return self.neotts.create(text, speed=speed)
        # ... existing Sherpa/Kokoro routing
3

Add voice detection

Edit voice_scanner.py to detect NeoTTS voice packs in the voices/ directory.
4

Test your changes

python main.py
  • Select a NeoTTS voice from the dropdown
  • Send a message and verify audio plays correctly

Example: Adding a New UI Feature

Let’s add a “Copy to Clipboard” button for bot messages.
1

Modify BotMessageWidget

Edit main.py, locate the BotMessageWidget class:
class BotMessageWidget(QFrame):
    def __init__(self, text, font_size=15):
        super().__init__()
        # ... existing code ...

        # Add copy button
        self.copy_btn = QPushButton("📋 Copy")
        self.copy_btn.setStyleSheet("""
            QPushButton {
                background: transparent;
                color: #8AB4F8;
                border: none;
                font-size: 11px;
            }
            QPushButton:hover { color: #A8C7FA; }
        """)
        self.copy_btn.clicked.connect(self._copy_to_clipboard)
        text_layout.addWidget(self.copy_btn)

    def _copy_to_clipboard(self):
        from PyQt6.QtWidgets import QApplication
        QApplication.clipboard().setText(self._raw_text)
        print("Copied to clipboard!")
2

Test the new button

Run the app and verify:
  • Button appears below bot messages
  • Clicking copies raw markdown text
  • Styling matches the app theme

Code Style Guidelines

Python Conventions

  • PEP 8 compliance: Use 4 spaces for indentation, max line length 100 characters
  • Type hints: Add type hints for function parameters and return values where helpful
  • Docstrings: Use triple-quoted docstrings for classes and non-obvious functions
def transcribe(self, audio_data: np.ndarray, sample_rate: int = 16000) -> str:
    """
    Transcribe audio to text using Whisper.
    
    Args:
        audio_data: numpy array of float32 audio samples
        sample_rate: audio sample rate in Hz
        
    Returns:
        Transcribed text string or empty string if filtered out
    """
    # Implementation...

PyQt6 Best Practices

  • Use signals/slots for thread communication: Never update UI directly from worker threads
  • Clean up threads: Always call thread.wait() or use daemon threads
  • Avoid blocking the UI: Move long operations to QThread subclasses
# Good: Non-blocking
class WorkerThread(QThread):
    result_ready = pyqtSignal(str)
    
    def run(self):
        result = expensive_operation()
        self.result_ready.emit(result)

# Bad: Blocks UI
def button_clicked(self):
    result = expensive_operation()  # UI freezes!
    self.update_display(result)

Naming Conventions

  • Classes: PascalCase (e.g., AIManager, AudioRecorder)
  • Functions/methods: snake_case (e.g., transcribe(), get_llm_response())
  • Constants: UPPER_SNAKE_CASE (e.g., LANG_CODES, THINK_OPEN)
  • Private methods: Prefix with _ (e.g., _process_stream(), _emit_thinking())

Testing Your Changes

Manual Testing Checklist

Before submitting a PR, test these scenarios:
  • App starts without errors
  • Classic Chat mode: Record → Transcribe → LLM → TTS works
  • Live Mode: Continuous conversation works
  • Barge-in interruption works in Live Mode
  • Voice selection changes TTS output
  • Language switching works (English ↔ Spanish)
  • Settings dialog saves and loads preferences
  • Font size changes apply to existing messages
  • Voice speed adjustment works
  • Audio device selection works
  • Chat history sidebar shows saved chats
  • Rename/delete chat operations work
  • Context donut shows correct token usage
  • Empty/silent recordings are handled gracefully
  • Very long messages don’t crash the app
  • Switching models mid-conversation works
  • PDF attachment with large documents shows warning
  • Markdown rendering handles code blocks and tables

Automated Testing (Future)

Currently, the project doesn’t have automated tests. Contributions to add unit tests (pytest) or integration tests are highly welcome!
If you want to add tests:
pip install pytest pytest-qt
Example test structure:
# tests/test_audio_utils.py
import pytest
import numpy as np
from audio_utils import AudioRecorder

def test_audio_recorder_initialization():
    recorder = AudioRecorder(sample_rate=16000)
    assert recorder.sample_rate == 16000
    assert recorder.silence_threshold == 0.03

def test_vad_detection():
    recorder = AudioRecorder()
    # Add VAD logic tests

Submitting Your Contribution

1

Commit your changes

Write clear, descriptive commit messages:
git add .
git commit -m "Add copy-to-clipboard button for bot messages

- Add copy button to BotMessageWidget
- Style button to match app theme
- Copy raw markdown text to clipboard
"
Good commit message format:
  • First line: Brief summary (50 chars max)
  • Blank line
  • Detailed explanation of what and why
  • List of specific changes
2

Push to your fork

git push origin feature/AmazingFeature
3

Open a Pull Request

  1. Go to your fork on GitHub
  2. Click “Compare & pull request”
  3. Fill out the PR template:
Title: Clear, descriptive summaryDescription:
## Summary
- Adds copy-to-clipboard button for bot messages
- Improves user experience by allowing easy text copying

## Changes
- Modified `BotMessageWidget` to include copy button
- Added clipboard integration via `QApplication.clipboard()`
- Styled button to match Gemini theme

## Testing
- [x] Tested on Ubuntu 22.04 with PyQt6
- [x] Verified button appears and functions correctly
- [x] Confirmed styling matches app theme

## Screenshots
[Attach screenshot of the new button]
4

Respond to feedback

Maintainers may request changes:
# Make requested changes
git add .
git commit -m "Address PR feedback: improve button placement"
git push origin feature/AmazingFeature
The PR will automatically update.

Development Tips

Debugging PyQt6 Applications

Enable verbose output:
python main.py 2>&1 | tee debug.log
Use PyQt6 debugging tools:
# In main.py, add to button handler:
def debug_state(self):
    print(f"Current model: {self.ai_manager.ollama_model}")
    print(f"History: {len(self.ai_manager.conversation_history)} messages")
    print(f"Recording: {self.recorder.is_recording}")

Working with Audio

Test audio pipeline in isolation:
# test_audio.py
from audio_utils import AudioRecorder, AudioPlayer
import numpy as np

# Test recording
recorder = AudioRecorder()
recorder.start_stream()
audio = recorder.record_until_silence()
print(f"Recorded {len(audio)} samples")

# Test playback
player = AudioPlayer()
test_tone = np.sin(2 * np.pi * 440 * np.arange(24000) / 24000).astype(np.float32)
player.play(test_tone, 24000)

Profiling Performance

Time critical operations:
import time

start = time.time()
result = self.ai_manager.transcribe(audio_data)
print(f"Transcription took {time.time() - start:.2f}s")
Monitor GPU memory:
watch -n 1 nvidia-smi

Contribution Ideas

Looking for ways to contribute? Here are some areas that need work:

High Priority

  • Add automated tests (pytest)
  • Implement voice cloning support
  • Add RAG (Retrieval-Augmented Generation) for long documents
  • Create a packaging script (PyInstaller, AppImage)
  • Add support for more TTS engines (Coqui, Tortoise)

Medium Priority

  • Improve markdown rendering (syntax highlighting for code)
  • Add conversation export (PDF, HTML)
  • Implement conversation search
  • Add hotkey support for recording
  • Create a system tray icon

Documentation

  • Add video tutorials
  • Create architecture diagrams
  • Write API documentation for modules
  • Translate README to other languages

Community Guidelines

  • Be respectful: Treat all contributors with kindness and professionalism
  • Stay on topic: Keep discussions focused on the project
  • Ask questions: If you’re unsure about something, ask in the issue comments
  • Share knowledge: Help other contributors by answering questions

License

By contributing to ChatbotAI-Free, you agree that your contributions will be licensed under The Unlicense. This means your code becomes public domain and can be used by anyone for any purpose.
Read the full license at UNLICENSE.org

Getting Help

If you need help with development:
  1. Check existing issues: Someone may have already solved your problem
  2. Search the codebase: Use grep or IDE search to find similar implementations
  3. Ask in discussions: Open a GitHub Discussion for general questions
  4. Open an issue: For bugs or specific technical questions
Thank you for contributing to ChatbotAI-Free! 🎉

Build docs developers (and LLMs) love