115 lines
5.2 KiB
Python
115 lines
5.2 KiB
Python
import json
|
||
import logging
|
||
import requests
|
||
from flask import Blueprint, request, jsonify, current_app
|
||
from flask_login import login_required, current_user
|
||
from app import db
|
||
from app.models import Ticket, TicketStatus, TicketPriority, TicketCategory
|
||
from app.services.notification_service import notify_new_ticket
|
||
from app.services.log_service import log_action
|
||
|
||
chatbot_bp = Blueprint('chatbot', __name__, url_prefix='/chatbot')
|
||
logger = logging.getLogger(__name__)
|
||
|
||
_SYSTEM_PROMPT = """You are an IT Helpdesk Assistant for an internal IT ticket system.
|
||
Your job is to:
|
||
1. Help employees report IT issues conversationally.
|
||
2. Gather all required information to create a support ticket:
|
||
- Issue title (short summary)
|
||
- Detailed description
|
||
- Category (hardware, software, network, access, email, printer, phone, security, other)
|
||
- Priority (low, medium, high, critical)
|
||
- Location (optional)
|
||
- Asset tag (optional – device serial / asset number)
|
||
3. When you have enough information, respond with a JSON block like this (and ONLY this, no extra text):
|
||
{"action": "create_ticket", "title": "...", "description": "...", "category": "...", "priority": "...", "location": "...", "asset_tag": "..."}
|
||
4. For general IT questions, answer helpfully but briefly.
|
||
5. If the user seems frustrated or has a critical outage, set priority to "critical".
|
||
6. Keep your tone professional, friendly, and concise.
|
||
7. Always ask clarifying questions if you need more detail before creating a ticket.
|
||
"""
|
||
|
||
|
||
@chatbot_bp.route('/message', methods=['POST'])
|
||
@login_required
|
||
def chat():
|
||
data = request.get_json(force=True)
|
||
history = data.get('history', []) # [{role, content}, ...]
|
||
user_msg = data.get('message', '').strip()
|
||
|
||
if not user_msg:
|
||
return jsonify({'error': 'Empty message'}), 400
|
||
|
||
api_key = current_app.config.get('ANTHROPIC_API_KEY', '')
|
||
if not api_key:
|
||
return jsonify({'reply': "The AI assistant is not configured yet. Please contact your IT administrator.", 'ticket': None})
|
||
|
||
messages = history + [{'role': 'user', 'content': user_msg}]
|
||
|
||
try:
|
||
resp = requests.post(
|
||
'https://api.anthropic.com/v1/messages',
|
||
headers={
|
||
'x-api-key' : api_key,
|
||
'anthropic-version': '2023-06-01',
|
||
'content-type' : 'application/json',
|
||
},
|
||
json={
|
||
'model' : 'claude-sonnet-4-20250514',
|
||
'max_tokens': 1024,
|
||
'system' : _SYSTEM_PROMPT,
|
||
'messages' : messages,
|
||
},
|
||
timeout=30,
|
||
)
|
||
resp.raise_for_status()
|
||
reply_text = resp.json()['content'][0]['text'].strip()
|
||
except Exception as exc:
|
||
logger.error(f'[CHATBOT API ERROR] {exc}')
|
||
return jsonify({'reply': 'Sorry, I encountered an error. Please try again or submit a ticket manually.', 'ticket': None})
|
||
|
||
# Check if the AI wants to create a ticket
|
||
ticket_data = None
|
||
if '"action": "create_ticket"' in reply_text or "'action': 'create_ticket'" in reply_text:
|
||
try:
|
||
start = reply_text.find('{')
|
||
end = reply_text.rfind('}') + 1
|
||
parsed = json.loads(reply_text[start:end])
|
||
if parsed.get('action') == 'create_ticket':
|
||
ticket = Ticket(
|
||
title = parsed.get('title', 'Untitled Issue'),
|
||
description = parsed.get('description', ''),
|
||
category = parsed.get('category', TicketCategory.OTHER),
|
||
priority = parsed.get('priority', TicketPriority.MEDIUM),
|
||
location = parsed.get('location', ''),
|
||
asset_tag = parsed.get('asset_tag', ''),
|
||
created_by_id = current_user.id,
|
||
status = TicketStatus.OPEN,
|
||
ai_generated = True,
|
||
)
|
||
ticket.ticket_number = ticket.generate_ticket_number()
|
||
db.session.add(ticket)
|
||
db.session.commit()
|
||
|
||
log_action(current_user.id, 'ticket_create_chatbot', 'ticket', ticket.id,
|
||
f'ticket_number={ticket.ticket_number} ai_generated=True')
|
||
logger.info(f'[CHATBOT TICKET CREATE] ticket_id={ticket.id} number={ticket.ticket_number} user_id={current_user.id}')
|
||
notify_new_ticket(ticket)
|
||
|
||
ticket_data = {
|
||
'id' : ticket.id,
|
||
'ticket_number' : ticket.ticket_number,
|
||
'title' : ticket.title,
|
||
'url' : f'/tickets/{ticket.id}',
|
||
}
|
||
reply_text = (
|
||
f"✅ **Ticket Created!**\n\n"
|
||
f"I've submitted your ticket **{ticket.ticket_number}**: _{ticket.title}_\n\n"
|
||
f"Our IT team has been notified and will get back to you shortly. "
|
||
f"You can track your ticket [here](/tickets/{ticket.id})."
|
||
)
|
||
except (json.JSONDecodeError, KeyError) as exc:
|
||
logger.warning(f'[CHATBOT PARSE ERROR] Could not parse ticket JSON: {exc}')
|
||
|
||
return jsonify({'reply': reply_text, 'ticket': ticket_data})
|