Aug 7 - Update: knowledge base MT19
This commit is contained in:
@@ -69,6 +69,11 @@ class SupportKnowledge(db.Model):
|
||||
title = db.Column(db.String(200), nullable=False)
|
||||
body = db.Column(db.Text, nullable=False)
|
||||
active = db.Column(db.Boolean, default=True, nullable=False)
|
||||
# MT-19 — admin-controlled ordering. Entries are injected into the support
|
||||
# chat's system prompt in this order, so a low sort_order is how an admin
|
||||
# promotes the guidance the assistant should reach for first. Ties break on
|
||||
# id, keeping the order stable.
|
||||
sort_order = db.Column(db.Integer, nullable=False, default=0)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=now_eastern, nullable=False)
|
||||
updated_at = db.Column(db.DateTime, default=now_eastern, nullable=False)
|
||||
|
||||
+28
-2
@@ -91,7 +91,9 @@ FAQS = [
|
||||
def _system_prompt_with_kb():
|
||||
"""Return the Groq system prompt, appending active knowledge base entries."""
|
||||
try:
|
||||
entries = SupportKnowledge.query.filter_by(active=True).order_by(SupportKnowledge.id).all()
|
||||
entries = (SupportKnowledge.query.filter_by(active=True)
|
||||
.order_by(SupportKnowledge.sort_order.asc(),
|
||||
SupportKnowledge.id.asc()).all())
|
||||
except Exception:
|
||||
return _SYSTEM_PROMPT
|
||||
if not entries:
|
||||
@@ -516,10 +518,31 @@ def admin_conversation_detail(session_id):
|
||||
@login_required
|
||||
@supervisor_required
|
||||
def admin_knowledge():
|
||||
entries = SupportKnowledge.query.order_by(SupportKnowledge.created_at.desc()).all()
|
||||
# Same order the chat prompt uses, so the admin list shows the real
|
||||
# priority rather than a different one.
|
||||
entries = (SupportKnowledge.query
|
||||
.order_by(SupportKnowledge.sort_order.asc(),
|
||||
SupportKnowledge.id.asc()).all())
|
||||
return render_template('support/admin_knowledge.html', entries=entries)
|
||||
|
||||
|
||||
def _parse_sort_order(raw, fallback=0):
|
||||
"""Coerce a submitted sort_order to a sane int.
|
||||
|
||||
The column is NOT NULL, so a blank or non-numeric field must not reach the
|
||||
DB. Clamped to 0..9999 to match the range ST validates, and falls back to
|
||||
the existing value on edit so a blank field means "leave it alone" rather
|
||||
than silently resetting the entry to the top.
|
||||
"""
|
||||
raw = (raw or '').strip()
|
||||
if not raw:
|
||||
return fallback
|
||||
try:
|
||||
return max(0, min(9999, int(raw)))
|
||||
except (TypeError, ValueError):
|
||||
return fallback
|
||||
|
||||
|
||||
@bp.route('/admin/knowledge/add', methods=['POST'])
|
||||
@login_required
|
||||
@supervisor_required
|
||||
@@ -534,6 +557,7 @@ def admin_knowledge_add():
|
||||
title = title,
|
||||
body = body,
|
||||
active = True,
|
||||
sort_order = _parse_sort_order(request.form.get('sort_order')),
|
||||
created_by = current_user.id,
|
||||
created_at = now_eastern(),
|
||||
updated_at = now_eastern(),
|
||||
@@ -561,6 +585,8 @@ def admin_knowledge_edit(entry_id):
|
||||
return redirect(url_for('support.admin_knowledge_edit', entry_id=entry_id))
|
||||
entry.title = title
|
||||
entry.body = body
|
||||
entry.sort_order = _parse_sort_order(request.form.get('sort_order'),
|
||||
entry.sort_order)
|
||||
entry.updated_at = now_eastern()
|
||||
db.session.commit()
|
||||
log_action(ACTION_UPDATE, 'SupportKnowledge', entry.id, title[:60], 'edited')
|
||||
|
||||
@@ -34,6 +34,12 @@
|
||||
placeholder="Add facts, FAQs, or instructions the AI should know about this customer's account…"></textarea>
|
||||
<div class="form-text">Keep entries focused and factual. Combined active entries are capped at 6,000 characters.</div>
|
||||
</div>
|
||||
<div class="mb-3" style="max-width:200px;">
|
||||
<label class="form-label fw-semibold">Sort Order</label>
|
||||
<input type="number" name="sort_order" class="form-control"
|
||||
min="0" max="9999" step="1" value="0">
|
||||
<div class="form-text">Lower numbers are sent to the assistant first. Leave at 0 unless an entry should take priority.</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-plus me-1"></i>Add Entry
|
||||
</button>
|
||||
@@ -54,6 +60,7 @@
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div class="flex-grow-1 me-3">
|
||||
<div class="d-flex align-items-center gap-2 mb-1">
|
||||
<span class="badge bg-light text-dark border" title="Sort order">#{{ entry.sort_order }}</span>
|
||||
<span class="fw-semibold">{{ entry.title }}</span>
|
||||
{% if entry.active %}
|
||||
<span class="badge bg-success">Active</span>
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
<textarea name="body" class="form-control" rows="8" required>{{ entry.body }}</textarea>
|
||||
<div class="form-text">Combined active entries are capped at 6,000 characters in the AI prompt.</div>
|
||||
</div>
|
||||
<div class="mb-3" style="max-width:200px;">
|
||||
<label class="form-label fw-semibold">Sort Order</label>
|
||||
<input type="number" name="sort_order" class="form-control"
|
||||
min="0" max="9999" step="1" value="{{ entry.sort_order }}">
|
||||
<div class="form-text">Lower numbers are sent to the assistant first. Leave at 0 unless an entry should take priority.</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg me-1"></i>Save Changes
|
||||
|
||||
Reference in New Issue
Block a user