{"slug": "buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this", "title": "Buddy Base:Built an LLM Powered Group Chat for My Friends to Make Plans This Weekend", "summary": "A developer built BuddyBase, a private, offline Django web application that gives a friend group a shared AI assistant running entirely on a laptop over a local network. The app uses a locally loaded Qwen model via HuggingFace with lru_cache and ThreadPoolExecutor timeout handling, and offers four features: group chat with an @buddy AI summon, an AI-assisted decision maker, smart shared lists, and per-user personal assistants with persistent preference memory. The developer says the project is not production-ready but plans to enhance it.", "body_md": "*This is a submission for the [Hacktoberfest Weekend Challenge: Build for a Friend](https://dev.to/challenges/hacktoberfest-weekend-2026-10-01)*\n\nBuddyBase — a private, offline web application that gives your friend group a shared AI assistant. It runs entirely on your laptop. Friends connect through your local network (WiFi, Bluetooth tethering, or mobile hotspot). No data ever leaves your machine.\n\n**Four Features, All AI-Powered**\n\nGroup Chat with AIA real-time chatroom where anyone can summon the AI by typing [@buddy](https://dev.to/buddy). It knows your group name, all members, and the last 20 messages for context. It responds like a friend who's always around — casual, funny, and actually helpful.\n\nDecision MakerCreate a question with options. AI immediately gives a recommendation with reasoning. Everyone votes. After each vote, AI updates its recommendation considering the majority. No more 40-minute indecision loops.\n\nSmart Shared ListsCollaborative lists where anyone can add items. Ask the AI to \"suggest 5 more movies like these\" or \"what are we forgetting for the road trip?\" It reads the list and gives real suggestions.\n\nPersonal BuddyEach friend gets a private AI assistant that learns their preferences. Tell it \"I love spicy food\" and next time someone asks about dinner, your buddy already knows. Memories persist in the database forever.\n\ncannot make it in production but will be surely enhanced it and make it to production\n\ngithub link : [https://github.com/sanjaynep/django-websocket](https://github.com/sanjaynep/django-websocket)\n\nThis is the core — loads Qwen once using `lru_cache`, generates responses using the same `apply_chat_template` pattern from HuggingFace, with timeout handling via `ThreadPoolExecutor`:\n\n``` python\n@lru_cache(maxsize=1)\ndef _load_llm():\n    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)\n    model = AutoModelForCausalLM.from_pretrained(\n        MODEL_NAME,\n        torch_dtype=torch.float32,\n        device_map={\"\": \"cpu\"},\n    )\n    model.eval()\n    return tokenizer, model\n\ndef _generate(messages):\n    tokenizer, model = _load_llm()\n    text = tokenizer.apply_chat_template(\n        messages, tokenize=False, add_generation_prompt=True\n    )\n    model_inputs = tokenizer([text], return_tensors=\"pt\").to(\"cpu\")\n    generated_ids = model.generate(**model_inputs, max_new_tokens=256, do_sample=True)\n    output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()\n    return tokenizer.decode(output_ids, skip_special_tokens=True).strip()\n\ndef chat(messages):\n    with ThreadPoolExecutor(max_workers=1) as executor:\n        future = executor.submit(_generate, messages)\n        return future.result(timeout=60)\n```\n\n**Key Code: WebSocket Consumer**\n\n``` python\nclass GroupChatConsumer(AsyncWebsocketConsumer):\n    async def receive(self, text_data):\n        message = json.loads(text_data).get('message', '').strip()\n        user = self.scope['user']\n\n        chat_msg = await self._save_message(user, message, is_ai=False)\n        await self.channel_layer.group_send(self.room_group_name, {\n            'type': 'chat_message',\n            'message': message,\n            'username': user.username,\n            'is_ai': False,\n            'time': chat_msg.created_at.strftime('%H:%M'),\n        })\n\n        if '@buddy' in message.lower():\n            await self.channel_layer.group_send(self.room_group_name, {\n                'type': 'typing_indicator',\n            })\n            ai_response = await self._get_ai_response()\n            ai_msg = await self._save_message(None, ai_response, is_ai=True)\n            await self.channel_layer.group_send(self.room_group_name, {\n                'type': 'chat_message',\n                'message': ai_response,\n                'username': 'Buddy',\n                'is_ai': True,\n                'time': ai_msg.created_at.strftime('%H:%M'),\n            })\n```\n\n**Key Code: Preference Memory**\n\n``` python\ndef _try_save_memory(user, message):\n    prefixes = {\n        'i love': 'loves', 'i hate': 'hates', 'i like': 'likes',\n        \"i don't like\": 'dislikes', 'my favorite': 'favorite',\n    }\n    for prefix, key_prefix in prefixes.items():\n        if prefix in message.lower():\n            value = message[message.lower().index(prefix) + len(prefix):].strip()\n            BuddyMemory.objects.update_or_create(\n                user=user, key=f\"{key_prefix}_{value[:20]}\",\n                defaults={'value': value}\n            )\n```\n\n**Tech Stack**\n\nLayer       Technology            Why\n\nBackend     Django 4.2      Clean MVC, auth, ORM, admin panel out of the box\n\nReal-Time   Django Channels + WebSocket Messages appear instantly, no page reload\n\nAI Model    Qwen2.5-1.5B-Instruct via HuggingFace Transformers  Runs locally on CPU, 3GB RAM, good chat quality\n\nFrontend    Vanilla JS + CSS    Zero dependencies, works offline, no CDN needed\n\nDatabase    SQLite  Local file, zero setup, perfect for small group\n\nServer  Daphne (ASGI)   Supports both HTTP and WebSocket\n\n**Open-Source AI I Used**\n\nComponent                   What\n\nLLM             Qwen2.5-1.5B-Instruct by Alibaba\n\nInference       HuggingFace Transformers\n\nPyTorch PyTorch     (CPU build) \n\nFramework       Django\n\nWebSocket       Django Channels \n\n**Privacy is not a feature, it's a fundamental right.**\n\nIf I used OpenAI's API or Google's Gemini API for this project, every message my friends send — their food preferences, their votes, their inside jokes, their travel plans — would be sent to a third-party server. That data would be logged, possibly used for training, and stored in someone else's database forever.\n\nWith open-weight models like Qwen, that doesn't happen.\n\nMy friends' data stays on my laptop. In a SQLite file that I control. I can delete it, back it up, or move it. Nobody else has access.\n\nNo API keys to leak. There are no API keys in the code. No .env file with secrets. No billing account to worry about.\n\nNo internet dependency. We used this at a cabin with no WiFi. I turned on mobile hotspot, everyone connected, and the AI still worked because Qwen runs locally.\n\nNo usage limits. No \"you've exceeded your quota\" errors at 3 AM when we're still planning. The model runs as long as my laptop is on.\n\nFull customization. I can change the AI's personality, what it remembers, how it makes decisions. Try getting ChatGPT to always pick a restaurant based on your group's dietary restrictions. With open models, I just edit the system prompt.\n\nZero cost. Running Qwen2.5-1.5B on my laptop costs exactly $0. Forever. For unlimited messages, unlimited friends, unlimited decisions.\n\nOpen innovation made this possible because:\n\nQwen's Apache 2.0 license lets me use it commercially or personally without restrictions\n\nHuggingFace Transformers provides the inference engine for free\n\nDjango's BSD license gives me a production-grade web framework for free\n\nDjango Channels adds real-time capabilities for free\n\nA closed API would make this project either impossible (no offline mode), expensive (paying per message for 5 friends chatting all weekend), or privacy-violating (sending personal preferences to the cloud). Open models make it free, private, and offline.", "url": "https://wpnews.pro/news/buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this", "canonical_source": "https://dev.to/sanjaynep/buddy-basebuilt-an-llm-powered-group-chat-for-my-friends-to-make-plans-this-weekend-1ic2", "published_at": "2026-10-05 12:10:28+00:00", "updated_at": "2026-10-05 12:19:44.341237+00:00", "lang": "en", "topics": ["large-language-models", "ai-agents", "ai-tools", "developer-tools"], "entities": ["BuddyBase", "Qwen", "HuggingFace", "Django", "sanjaynep"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this", "markdown": "https://wpnews.pro/news/buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this.md", "text": "https://wpnews.pro/news/buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this.txt", "jsonld": "https://wpnews.pro/news/buddy-base-built-an-llm-powered-group-chat-for-my-friends-to-make-plans-this.jsonld"}}