feat: reorganize tabs + add Last Prompt CC/Fallback toggle
- Split Status tab: moved DM management to new dedicated 📱 DM Management tab
- Added Last Prompt source toggle (Cheshire Cat / Bot Fallback) with
localStorage persistence, CC as default
- Backend: added LAST_CAT_INTERACTION global, /prompt/cat API endpoint
- Bot tracks Cat interactions (prompt, response, user, mood, timestamp)
- Auto-load data on tab switch (Status loads prompt, DM tab loads users)
This commit is contained in:
@@ -201,6 +201,14 @@ def get_logs():
|
||||
def get_last_prompt():
|
||||
return {"prompt": globals.LAST_FULL_PROMPT or "No prompt has been issued yet."}
|
||||
|
||||
@app.get("/prompt/cat")
|
||||
def get_last_cat_prompt():
|
||||
"""Get the last Cheshire Cat interaction (prompt + response) for Web UI."""
|
||||
interaction = globals.LAST_CAT_INTERACTION
|
||||
if not interaction.get("prompt"):
|
||||
return {"prompt": "No Cheshire Cat interaction has occurred yet.", "response": "", "user": "", "mood": "", "timestamp": ""}
|
||||
return interaction
|
||||
|
||||
@app.get("/mood")
|
||||
def get_current_mood():
|
||||
return {"mood": globals.DM_MOOD, "description": globals.DM_MOOD_DESCRIPTION}
|
||||
|
||||
27
bot/bot.py
27
bot/bot.py
@@ -99,9 +99,12 @@ async def on_ready():
|
||||
intercept_external_loggers()
|
||||
|
||||
# Restore evil mode state from previous session (if any)
|
||||
from utils.evil_mode import restore_evil_mode_on_startup
|
||||
from utils.evil_mode import restore_evil_mode_on_startup, restore_evil_cat_state
|
||||
restore_evil_mode_on_startup()
|
||||
|
||||
# Restore Cat personality/model state (async — needs event loop running)
|
||||
await restore_evil_cat_state()
|
||||
|
||||
# Restore bipolar mode state from previous session (if any)
|
||||
from utils.bipolar_mode import restore_bipolar_mode_on_startup
|
||||
restore_bipolar_mode_on_startup()
|
||||
@@ -549,6 +552,14 @@ async def on_message(message):
|
||||
)
|
||||
if response:
|
||||
logger.info(f"🐱 Cat embed response for {author_name}")
|
||||
import datetime
|
||||
globals.LAST_CAT_INTERACTION = {
|
||||
"prompt": enhanced_prompt,
|
||||
"response": response[:500] if response else "",
|
||||
"user": author_name,
|
||||
"mood": globals.DM_MOOD,
|
||||
"timestamp": datetime.datetime.now().isoformat(),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"🐱 Cat embed error, fallback: {e}")
|
||||
response = None
|
||||
@@ -637,7 +648,19 @@ async def on_message(message):
|
||||
response_type=response_type,
|
||||
)
|
||||
if response:
|
||||
logger.info(f"🐱 Cat response for {author_name} (mood: {current_mood})")
|
||||
effective_mood = current_mood
|
||||
if globals.EVIL_MODE:
|
||||
effective_mood = f"EVIL:{getattr(globals, 'EVIL_DM_MOOD', 'evil_neutral')}"
|
||||
logger.info(f"🐱 Cat response for {author_name} (mood: {effective_mood})")
|
||||
# Track Cat interaction for Web UI Last Prompt view
|
||||
import datetime
|
||||
globals.LAST_CAT_INTERACTION = {
|
||||
"prompt": prompt,
|
||||
"response": response[:500] if response else "",
|
||||
"user": author_name,
|
||||
"mood": effective_mood,
|
||||
"timestamp": datetime.datetime.now().isoformat(),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"🐱 Cat pipeline error, falling back to query_llama: {e}")
|
||||
response = None
|
||||
|
||||
@@ -68,7 +68,7 @@ AVAILABLE_MOODS = [
|
||||
EVIL_MODE = False
|
||||
EVIL_DM_MOOD = "evil_neutral"
|
||||
EVIL_DM_MOOD_DESCRIPTION = "Evil Miku is calculating and cold."
|
||||
EVIL_AVAILABLE_MOODS = ["aggressive", "cunning", "sarcastic", "evil_neutral"]
|
||||
EVIL_AVAILABLE_MOODS = ["aggressive", "cunning", "sarcastic", "evil_neutral", "bored", "manic", "jealous", "melancholic", "playful_cruel", "contemptuous"]
|
||||
# EVIL_MOOD_EMOJIS removed — canonical source is utils/moods.py
|
||||
|
||||
# Bipolar Mode System (both Mikus can argue via webhooks)
|
||||
@@ -83,6 +83,15 @@ BOT_USER = None
|
||||
|
||||
LAST_FULL_PROMPT = ""
|
||||
|
||||
# Cheshire Cat last interaction tracking (for Web UI Last Prompt toggle)
|
||||
LAST_CAT_INTERACTION = {
|
||||
"prompt": "",
|
||||
"response": "",
|
||||
"user": "",
|
||||
"mood": "",
|
||||
"timestamp": "",
|
||||
}
|
||||
|
||||
# Persona Dialogue System (conversations between Miku and Evil Miku)
|
||||
LAST_PERSONA_DIALOGUE_TIME = 0 # Timestamp of last dialogue for cooldown
|
||||
|
||||
|
||||
@@ -434,6 +434,20 @@
|
||||
border-bottom-color: #4CAF50;
|
||||
}
|
||||
|
||||
/* Prompt source toggle buttons */
|
||||
.prompt-source-btn {
|
||||
background: #333;
|
||||
color: #aaa;
|
||||
}
|
||||
.prompt-source-btn.active {
|
||||
background: #4CAF50;
|
||||
color: #fff;
|
||||
}
|
||||
.prompt-source-btn:hover:not(.active) {
|
||||
background: #444;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
@@ -661,6 +675,7 @@
|
||||
<button class="tab-button active" data-tab="tab1" onclick="switchTab('tab1')">Server Management</button>
|
||||
<button class="tab-button" data-tab="tab2" onclick="switchTab('tab2')">Actions</button>
|
||||
<button class="tab-button" data-tab="tab3" onclick="switchTab('tab3')">Status</button>
|
||||
<button class="tab-button" data-tab="tab10" onclick="switchTab('tab10')">📱 DM Management</button>
|
||||
<button class="tab-button" data-tab="tab4" onclick="switchTab('tab4')">⚙️ LLM Settings</button>
|
||||
<button class="tab-button" data-tab="tab5" onclick="switchTab('tab5')">🎨 Image Generation</button>
|
||||
<button class="tab-button" data-tab="tab6" onclick="switchTab('tab6')">📊 Autonomous Stats</button>
|
||||
@@ -1149,13 +1164,35 @@
|
||||
|
||||
<!-- Status Tab Content -->
|
||||
<div id="tab3" class="tab-content">
|
||||
<div class="section">
|
||||
<h3>Status</h3>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h3>Status</h3>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>📱 DM Logs</h3>
|
||||
<h3>Last Prompt</h3>
|
||||
<div style="margin-bottom: 0.75rem; display: flex; align-items: center; gap: 0.75rem;">
|
||||
<label style="font-size: 0.9rem; color: #aaa;">Source:</label>
|
||||
<div style="display: inline-flex; border-radius: 6px; overflow: hidden; border: 1px solid #444;">
|
||||
<button id="prompt-src-cat" class="prompt-source-btn active" onclick="switchPromptSource('cat')"
|
||||
style="padding: 0.4rem 1rem; border: none; cursor: pointer; font-size: 0.85rem; transition: all 0.2s;">
|
||||
🐱 Cheshire Cat
|
||||
</button>
|
||||
<button id="prompt-src-fallback" class="prompt-source-btn" onclick="switchPromptSource('fallback')"
|
||||
style="padding: 0.4rem 1rem; border: none; cursor: pointer; font-size: 0.85rem; transition: all 0.2s;">
|
||||
🤖 Bot Fallback
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="prompt-cat-info" style="margin-bottom: 0.5rem; font-size: 0.85rem; color: #aaa;"></div>
|
||||
<pre id="last-prompt" style="white-space: pre-wrap; word-break: break-word;"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DM Management Tab Content -->
|
||||
<div id="tab10" class="tab-content">
|
||||
<div class="section">
|
||||
<h3>📱 DM Management</h3>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<button onclick="loadDMUsers()">🔄 Refresh DM Users</button>
|
||||
<button onclick="exportAllDMs()">📤 Export All DMs</button>
|
||||
@@ -1179,11 +1216,6 @@
|
||||
<div id="blocked-users-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Last Prompt</h3>
|
||||
<pre id="last-prompt"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LLM Settings Tab Content -->
|
||||
@@ -1842,10 +1874,18 @@ function switchTab(tabId) {
|
||||
console.log('🔄 Refreshing figurine subscribers for Server Management tab');
|
||||
refreshFigurineSubscribers();
|
||||
}
|
||||
if (tabId === 'tab3') {
|
||||
loadStatus();
|
||||
loadLastPrompt();
|
||||
}
|
||||
if (tabId === 'tab9') {
|
||||
console.log('🧠 Refreshing memory stats for Memories tab');
|
||||
refreshMemoryStats();
|
||||
}
|
||||
if (tabId === 'tab10') {
|
||||
console.log('📱 Loading DM users for DM Management tab');
|
||||
loadDMUsers();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -1945,6 +1985,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
initLogsScrollDetection();
|
||||
initChatImagePreview();
|
||||
initModalAccessibility();
|
||||
initPromptSourceToggle();
|
||||
|
||||
// Load initial data
|
||||
loadStatus();
|
||||
@@ -3948,14 +3989,43 @@ async function loadStatus() {
|
||||
}
|
||||
|
||||
async function loadLastPrompt() {
|
||||
const source = localStorage.getItem('miku-prompt-source') || 'cat';
|
||||
const promptEl = document.getElementById('last-prompt');
|
||||
const infoEl = document.getElementById('prompt-cat-info');
|
||||
|
||||
try {
|
||||
const result = await apiCall('/prompt');
|
||||
document.getElementById('last-prompt').textContent = result.prompt;
|
||||
if (source === 'cat') {
|
||||
const result = await apiCall('/prompt/cat');
|
||||
if (result.timestamp) {
|
||||
infoEl.innerHTML = `<strong>User:</strong> ${escapeHtml(result.user || '?')} | <strong>Mood:</strong> ${escapeHtml(result.mood || '?')} | <strong>Time:</strong> ${new Date(result.timestamp).toLocaleString()}`;
|
||||
promptEl.textContent = `[User message → Cat]\n${result.prompt}\n\n[Cat response]\n${result.response}`;
|
||||
} else {
|
||||
infoEl.textContent = '';
|
||||
promptEl.textContent = result.prompt || 'No Cheshire Cat interaction yet.';
|
||||
}
|
||||
} else {
|
||||
infoEl.textContent = '';
|
||||
const result = await apiCall('/prompt');
|
||||
promptEl.textContent = result.prompt;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load last prompt:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function switchPromptSource(source) {
|
||||
localStorage.setItem('miku-prompt-source', source);
|
||||
document.querySelectorAll('.prompt-source-btn').forEach(btn => btn.classList.remove('active'));
|
||||
document.getElementById(`prompt-src-${source}`).classList.add('active');
|
||||
loadLastPrompt();
|
||||
}
|
||||
|
||||
function initPromptSourceToggle() {
|
||||
const saved = localStorage.getItem('miku-prompt-source') || 'cat';
|
||||
document.querySelectorAll('.prompt-source-btn').forEach(btn => btn.classList.remove('active'));
|
||||
document.getElementById(`prompt-src-${saved}`).classList.add('active');
|
||||
}
|
||||
|
||||
// Log auto-scroll state
|
||||
let logsAutoScroll = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user