Add web interface control for greeting delay

- Move greeting_delay from system config to user runtime config
- Add GET/POST API endpoints at /api/greeting_delay
- Add delay slider to web interface (0-10 seconds range)
- Implement debounced slider updates (300ms delay)
- Update visual gradient on slider movement
- Display current delay value in seconds
- Allow greeting delay adjustment without editing config files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-24 15:34:58 +07:00
parent 38eff5c2c8
commit 2717edd71e

View File

@@ -105,16 +105,19 @@ class RotaryPhone:
"active_greeting": SYS_CONFIG['system']['active_greeting'],
"extra_button_sound": SYS_CONFIG['system'].get('extra_button_sound', 'button_sound.wav'),
"greetings": [],
"volume": SYS_CONFIG['system']['volume']
"volume": SYS_CONFIG['system']['volume'],
"greeting_delay": SYS_CONFIG['system'].get('greeting_delay_seconds', 0)
}
if os.path.exists(USER_CONFIG_FILE):
try:
with open(USER_CONFIG_FILE, 'r') as f:
config = json.load(f)
# Ensure volume key exists
# Ensure required keys exist
if "volume" not in config:
config["volume"] = SYS_CONFIG['system']['volume']
if "greeting_delay" not in config:
config["greeting_delay"] = SYS_CONFIG['system'].get('greeting_delay_seconds', 0)
return config
except:
pass
@@ -156,6 +159,17 @@ class RotaryPhone:
def get_volume(self):
"""Get current volume setting"""
return self.config.get("volume", 70)
def set_greeting_delay(self, delay):
"""Set greeting delay in seconds (0-10)"""
delay = max(0, min(10, int(delay))) # Clamp between 0-10
self.config["greeting_delay"] = delay
self.save_config()
return delay
def get_greeting_delay(self):
"""Get current greeting delay"""
return self.config.get("greeting_delay", 0)
def generate_default_dialtone(self):
"""Generate a classic dial tone (350Hz + 440Hz) and save as default"""
@@ -349,7 +363,7 @@ class RotaryPhone:
print("\n=== Handset picked up ===")
# Apply greeting delay if configured
greeting_delay = SYS_CONFIG['system'].get('greeting_delay_seconds', 0)
greeting_delay = self.get_greeting_delay()
if greeting_delay > 0:
print(f"Waiting {greeting_delay} seconds before greeting...")
time.sleep(greeting_delay)
@@ -390,6 +404,7 @@ def index():
active_greeting = phone.config.get("active_greeting", "dialtone.wav")
extra_button_sound = phone.config.get("extra_button_sound", "button_sound.wav")
volume = phone.get_volume()
greeting_delay = phone.get_greeting_delay()
return render_template('index.html',
recordings=recordings,
@@ -398,7 +413,8 @@ def index():
extra_button_sound=extra_button_sound,
extra_button_enabled=EXTRA_BUTTON_ENABLED,
status=status,
volume=volume)
volume=volume,
greeting_delay=greeting_delay)
@app.route('/api/status')
def api_status():
@@ -428,6 +444,19 @@ def api_set_volume():
new_volume = phone.set_volume(volume)
return jsonify({"success": True, "volume": new_volume})
@app.route('/api/greeting_delay', methods=['GET'])
def api_get_greeting_delay():
"""Get current greeting delay setting"""
return jsonify({"delay": phone.get_greeting_delay()})
@app.route('/api/greeting_delay', methods=['POST'])
def api_set_greeting_delay():
"""Set greeting delay in seconds"""
data = request.get_json()
delay = data.get('delay', 0)
new_delay = phone.set_greeting_delay(delay)
return jsonify({"success": True, "delay": new_delay})
@app.route('/upload_greeting', methods=['POST'])
def upload_greeting():
"""Upload a new greeting message"""
@@ -1065,10 +1094,13 @@ if __name__ == "__main__":
<button class="btn btn-secondary" onclick="refreshStatus()">🔄 Refresh</button>
</div>
<!-- Volume Control Card -->
<!-- Volume & Delay Control Card -->
<div class="card">
<h2>🔊 Volume Control</h2>
<div style="padding: 20px;">
<h2>🔊 Volume & Delay Control</h2>
<!-- Volume Control -->
<div style="padding: 20px; border-bottom: 1px solid #e5e7eb;">
<h3 style="margin: 0 0 15px 0; font-size: 1.1em; color: #333;">Volume</h3>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-size: 1.5em;">🔇</span>
<input type="range" id="volume-slider" min="0" max="100" value="{{ volume }}"
@@ -1076,8 +1108,23 @@ if __name__ == "__main__":
<span style="font-size: 1.5em;">🔊</span>
<span id="volume-display" style="font-weight: bold; min-width: 50px; text-align: center; font-size: 1.2em;">{{ volume }}%</span>
</div>
<p style="margin-top: 15px; color: #6b7280; font-size: 0.9em; text-align: center;">
Adjust the playback volume for greeting messages
<p style="margin-top: 10px; color: #6b7280; font-size: 0.85em; text-align: center;">
Playback volume for greeting messages
</p>
</div>
<!-- Greeting Delay Control -->
<div style="padding: 20px;">
<h3 style="margin: 0 0 15px 0; font-size: 1.1em; color: #333;">Greeting Delay</h3>
<div style="display: flex; align-items: center; gap: 20px;">
<span style="font-size: 1.5em;">⏱️</span>
<input type="range" id="delay-slider" min="0" max="10" value="{{ greeting_delay }}"
style="flex: 1; height: 8px; border-radius: 5px; outline: none; background: linear-gradient(to right, #667eea 0%, #667eea {{ greeting_delay * 10 }}%, #ddd {{ greeting_delay * 10 }}%, #ddd 100%);">
<span style="font-size: 1.5em;">⏰</span>
<span id="delay-display" style="font-weight: bold; min-width: 50px; text-align: center; font-size: 1.2em;">{{ greeting_delay }}s</span>
</div>
<p style="margin-top: 10px; color: #6b7280; font-size: 0.85em; text-align: center;">
Delay before greeting plays after pickup (0-10 seconds)
</p>
</div>
</div>
@@ -1244,6 +1291,7 @@ if __name__ == "__main__":
<script>
let selectedFiles = null;
let volumeUpdateTimer = null;
let delayUpdateTimer = null;
// Volume control
const volumeSlider = document.getElementById('volume-slider');
@@ -1280,6 +1328,42 @@ if __name__ == "__main__":
.catch(error => console.error('Error updating volume:', error));
}
// Greeting Delay control
const delaySlider = document.getElementById('delay-slider');
const delayDisplay = document.getElementById('delay-display');
delaySlider.addEventListener('input', function() {
const value = this.value;
delayDisplay.textContent = value + 's';
// Update slider background gradient (0-10 range = 0-100%)
const percent = (value / 10) * 100;
this.style.background = `linear-gradient(to right, #667eea 0%, #667eea ${percent}%, #ddd ${percent}%, #ddd 100%)`;
// Debounce API call
clearTimeout(delayUpdateTimer);
delayUpdateTimer = setTimeout(() => {
updateGreetingDelay(value);
}, 300);
});
function updateGreetingDelay(delay) {
fetch('/api/greeting_delay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ delay: parseInt(delay) })
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log('Greeting delay updated to ' + data.delay + 's');
}
})
.catch(error => console.error('Error updating delay:', error));
}
function handleFileSelect(input) {
if (input.files && input.files.length > 0) {
selectedFiles = input.files;