Skip to content

Latest commit

 

History

History
236 lines (193 loc) · 6.23 KB

README.md

File metadata and controls

236 lines (193 loc) · 6.23 KB

uOttaChat

chat

uOttaChat is a chatbot service built by the uOttaHack team (the University of Ottawa's hackathon) and released as an open-source project for the hackathon community. It enables participants to ask questions about the event and receive real-time, context-aware responses through live sites & Discord integration.

Note: Anyone implementing this service should include a disclaimer stating that LLMs can make mistakes and that critical information should be double-checked.

Table of Contents

Features

  • Real-Time Information: Dynamic event details, FAQs, and schedules
  • Context-Aware Responses: Intelligent handling of follow-up questions
  • Custom Chained Prompts: Two-step response system for accuracy
  • Reference Data Injection: Dynamic event data integration
  • Discord Integration: Native Discord bot functionality
  • NGINX & SSL Support: Production-ready deployment scripts

Architecture

  1. FastAPI Chat API:

    • /chat endpoint for query processing
    • In-memory session store with TTL
    • Cohere API integration with reflection step
  2. Discord Bot:

    • WebSocket-based Discord integration
    • Mention/command listening
    • Synchronized responses with API

Local Development & Setup

  1. Clone the repository:
git clone https://github.com/uOttaHack/uotta-chatbot.git
cd uotta-chatbot
  1. Set up Python virtual environment:
python3 -m venv venv
source venv/bin/activate  # On Windows, use: venv\Scripts\activate
  1. Install dependencies:
pip install -r requirements.txt
  1. Configure environment variables:
cp .env.example .env
# Open .env file and update with your credentials
  1. Start the server:
uvicorn app:app --reload

Usage

API Endpoint

POST /chat
{
    "userMessage": "What time does opening ceremonies start?"
}

Discord Commands

Mention the bot in your specified server: @uOttaHack_bot your question here

Configuration

Key environment variables:

PORT=8000
COHERE_API_KEY_TRIAL=your_key_here
REF_DATA_API_URL=your_hackathon_api_data_reference_url
ALLOWED_ORIGIN=your_hackathon_live_site_url (any front-end url using the chatbot)

Prompt Engineering & Customization

The chatbot uses a two-step prompting system with dynamic reference data injection:

Reference Data Integration

# Fetch your hackathon's "source of truth"
reference_data = {
    "schedule": [...],
    "faq": [...],
    "venue": {...}
}

Two-Step Prompting

  1. Initial Response:
{
    "messages": [
        {
            "role": "system",
            "content": "You are the official hackathon assistant..."
        },
        {
            "role": "user",
            "content": user_message
        }
    ],
    "documents": [reference_data]
}
  1. Reflection Step:
{
    "messages": [
        # Previous context
        {
            "role": "system",
            "content": "Review and improve the previous response..."
        }
    ],
    "documents": [reference_data]
}

Frontend Integration

Here's an example React component we built and integrated into our live site (live.uottahack.ca/chat):

import React, { useState } from 'react';
import axios from 'axios';

interface Message {
    text: string;
    from: 'user' | 'chatbot';
}

const Chat: React.FC = () => {
    const [message, setMessage] = useState('');
    const [messages, setMessages] = useState<Message[]>([]);
    const [isSending, setIsSending] = useState(false);

    const sendMessage = async (e: React.FormEvent) => {
        e.preventDefault();
        if (message.trim()) {
            // Add user message to chat
            setMessages(prev => [...prev, { text: message, from: 'user' }]);
            setMessage('');
            setIsSending(true);

            try {
                // Send message to API
                const response = await axios.post('https://api.uottahack.ca/chat', {
                    userMessage: message
                });

                // Add bot response to chat
                if (response.data.botMessage) {
                    setMessages(prev => [...prev, {
                        text: response.data.botMessage,
                        from: 'chatbot'
                    }]);
                }
            } catch (error) {
                console.error('Error:', error);
                setMessages(prev => [...prev, {
                    text: 'Sorry, something went wrong. Please try again.',
                    from: 'chatbot'
                }]);
            }

            setIsSending(false);
        }
    };

    return (
        <div className="chat-container">
            {/* Messages Display */}
            <div className="messages-list">
                {messages.map((msg, index) => (
                    <div key={index} className={`message ${msg.from}`}>
                        {msg.text}
                    </div>
                ))}
            </div>

            {/* Message Input Form */}
            <form onSubmit={sendMessage}>
                <input
                    type="text"
                    value={message}
                    onChange={(e) => setMessage(e.target.value)}
                    placeholder="Message uOttaChat"
                    disabled={isSending}
                />
                <button type="submit" disabled={isSending}>
                    Send
                </button>
            </form>
        </div>
    );
};

export default Chat;

Contributing

  1. Fork the repository
  2. Create your feature branch
  3. Commit your changes
  4. Open a pull request

License

MIT License - see LICENSE for details.

Support

Join our uOttaHack general community Discord, feel free to ask us questions about uOttaChat! Join Discord