Add 'llm' bot: OpenAI-compatible chat (Ollama-ready)
New 'llm' bot type that takes a startup context (system prompt) and replies to each message via an OpenAI-compatible endpoint — works with a local Ollama (ollama serve, http://localhost:11434/v1), OpenAI, Grok, etc. Generalize the support LLM handler into _handle_llm_message (shared by support + llm) with a per-bot default prompt. Create form reuses the LLM fields (URL/key/model/context) for both support and llm. Adds llm_test.py (mock OpenAI backend) — passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
<h2 style="font-size:15px;margin-bottom:12px;">Available bot types</h2>
|
||||
<table>
|
||||
<tr><td><span class="tag">echo</span></td><td class="muted">Repeats every message back to the sender — handy for testing a connection end to end.</td></tr>
|
||||
<tr><td><span class="tag">llm</span></td><td class="muted">Chat with a local or remote LLM (OpenAI-compatible, e.g. Ollama). Give it context, it replies to your messages.</td></tr>
|
||||
<tr><td><span class="tag">broadcast</span></td><td class="muted">Relays messages from authorized publishers out to all of the bot's contacts.</td></tr>
|
||||
<tr><td><span class="tag">support</span></td><td class="muted">Business inbox — auto-replies with a welcome message and collects incoming inquiries.</td></tr>
|
||||
<tr><td><span class="tag">directory</span></td><td class="muted">Directory service for discovering and listing groups or contacts.</td></tr>
|
||||
@@ -150,24 +151,26 @@
|
||||
<div id="support-fields" style="display:none;">
|
||||
<div style="border-top:1px solid var(--border);margin:4px 0 14px;padding-top:14px;">
|
||||
<p class="muted" style="margin-bottom:12px;">
|
||||
LLM backend (OpenAI-compatible). Leave the URL blank for a static welcome-only bot.
|
||||
LLM backend (OpenAI-compatible — works with a local Ollama via <code>ollama serve</code>,
|
||||
OpenAI, Grok…). The LLM bot needs the URL; support bots may leave it blank for a
|
||||
welcome-only inbox.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>API Base URL</label>
|
||||
<input type="text" name="api_base" placeholder="https://api.x.ai/v1 (Ollama: http://localhost:11434/v1)">
|
||||
<input type="text" name="api_base" placeholder="http://localhost:11434/v1 (Ollama) · https://api.x.ai/v1">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>API Key</label>
|
||||
<input type="password" name="api_key" placeholder="xai-… (any value for Ollama)">
|
||||
<label>API Key <span class="muted" style="font-weight:400;">(any value for Ollama)</span></label>
|
||||
<input type="password" name="api_key" placeholder="ollama · xai-…">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Model</label>
|
||||
<input type="text" name="model" placeholder="grok-2 (Ollama: llama3.2)">
|
||||
<input type="text" name="model" placeholder="llama3.2 (Ollama) · grok-2">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>System Prompt</label>
|
||||
<textarea name="system_prompt" rows="3" placeholder="You are a helpful customer-support assistant…"></textarea>
|
||||
<label>Context <span class="muted" style="font-weight:400;">(system prompt given on start-up)</span></label>
|
||||
<textarea name="system_prompt" rows="3" placeholder="You are a helpful assistant…"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="deadmans-fields" style="display:none;">
|
||||
@@ -289,7 +292,7 @@ function copyAddr(ev, btn, addr) {
|
||||
function onTypeChange() {
|
||||
const val = document.getElementById('type-select').value;
|
||||
document.getElementById('welcome-field').style.display = (val === 'echo') ? 'none' : '';
|
||||
document.getElementById('support-fields').style.display = (val === 'support') ? 'block' : 'none';
|
||||
document.getElementById('support-fields').style.display = (val === 'support' || val === 'llm') ? 'block' : 'none';
|
||||
document.getElementById('deadmans-fields').style.display = (val === 'deadmans') ? 'block' : 'none';
|
||||
document.getElementById('directory-fields').style.display = (val === 'directory') ? 'block' : 'none';
|
||||
document.getElementById('broadcast-fields').style.display = (val === 'broadcast') ? 'block' : 'none';
|
||||
@@ -307,7 +310,7 @@ document.getElementById('create-form').addEventListener('submit', async (e) => {
|
||||
const config = {};
|
||||
const welcome = fd.get('welcome_message');
|
||||
if (welcome) config.welcome_message = welcome;
|
||||
if (botType === 'support') {
|
||||
if (botType === 'support' || botType === 'llm') {
|
||||
const apiBase = (fd.get('api_base') || '').trim();
|
||||
if (apiBase) config.api_base = apiBase;
|
||||
const apiKey = (fd.get('api_key') || '').trim();
|
||||
|
||||
Reference in New Issue
Block a user