Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
|
|
| 24 |
|
| 25 |
app = Flask(__name__)
|
| 26 |
|
| 27 |
-
# ---------- CORS and session
|
| 28 |
CORS(app, resources={r"/*": {"origins": "*"}}, supports_credentials=False,
|
| 29 |
allow_headers=["Content-Type", "Authorization"], methods=["GET", "POST", "OPTIONS"])
|
| 30 |
|
|
@@ -56,7 +56,7 @@ if not HF_TOKEN:
|
|
| 56 |
hf_client = None
|
| 57 |
else:
|
| 58 |
hf_client = OpenAI(base_url="https://router.huggingface.co/v1", api_key=HF_TOKEN)
|
| 59 |
-
HF_MODEL = "google/gemma-2-2b-it:featherless-ai"
|
| 60 |
|
| 61 |
def mock_response(message, rag_context, ticket_context):
|
| 62 |
msg_lower = message.lower()
|
|
@@ -72,10 +72,72 @@ def mock_response(message, rag_context, ticket_context):
|
|
| 72 |
return "Hello! I'm TMCBot. How can I help you today?"
|
| 73 |
return "I'm here to help with cables, orders, and technical support. Could you provide more details?"
|
| 74 |
|
| 75 |
-
# ---------- Database and RAG
|
| 76 |
db = DatabaseManager()
|
| 77 |
rag_helper = RAGHelper(use_vector_search=True)
|
| 78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
# ---------- ChatBot class (original, with send_message replaced) ----------
|
| 80 |
class ChatBot:
|
| 81 |
def __init__(self, db_manager, configured_model="mistral:7b"):
|
|
@@ -543,6 +605,14 @@ Summary:"""
|
|
| 543 |
def create_ticket_from_chat(self, user_id, subject, description, category, priority, conversation_id):
|
| 544 |
return self.db_manager.create_support_ticket(user_id, subject, description, category, conversation_id, priority)
|
| 545 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 546 |
# ------------------------------------------------------------------
|
| 547 |
# End of ChatBot class
|
| 548 |
# ------------------------------------------------------------------
|
|
@@ -741,9 +811,8 @@ IMPORTANT: Respond with ONLY the number (1-10). Do not include any explanation,
|
|
| 741 |
return None, None
|
| 742 |
|
| 743 |
def get_ai_security_analysis(prompt):
|
| 744 |
-
#
|
| 745 |
-
#
|
| 746 |
-
# For a production system, you could call a dedicated security model, but here we return 2 (safe).
|
| 747 |
logger.info("Security analysis using rule-based fallback (safe score 2)")
|
| 748 |
return 2
|
| 749 |
|
|
@@ -866,6 +935,7 @@ def admin():
|
|
| 866 |
return redirect(url_for('admin_tickets'))
|
| 867 |
|
| 868 |
@app.route('/admin/tickets')
|
|
|
|
| 869 |
def admin_tickets():
|
| 870 |
return render_template('admin_tickets.html')
|
| 871 |
|
|
@@ -1072,8 +1142,8 @@ def get_conversations():
|
|
| 1072 |
@app.route('/api/health')
|
| 1073 |
def health_check():
|
| 1074 |
try:
|
| 1075 |
-
|
| 1076 |
-
ollama_status =
|
| 1077 |
except:
|
| 1078 |
ollama_status = False
|
| 1079 |
try:
|
|
|
|
| 24 |
|
| 25 |
app = Flask(__name__)
|
| 26 |
|
| 27 |
+
# ---------- CORS and session ----------
|
| 28 |
CORS(app, resources={r"/*": {"origins": "*"}}, supports_credentials=False,
|
| 29 |
allow_headers=["Content-Type", "Authorization"], methods=["GET", "POST", "OPTIONS"])
|
| 30 |
|
|
|
|
| 56 |
hf_client = None
|
| 57 |
else:
|
| 58 |
hf_client = OpenAI(base_url="https://router.huggingface.co/v1", api_key=HF_TOKEN)
|
| 59 |
+
HF_MODEL = "google/gemma-2-2b-it:featherless-ai" # or "google/gemma-2-2b-it"
|
| 60 |
|
| 61 |
def mock_response(message, rag_context, ticket_context):
|
| 62 |
msg_lower = message.lower()
|
|
|
|
| 72 |
return "Hello! I'm TMCBot. How can I help you today?"
|
| 73 |
return "I'm here to help with cables, orders, and technical support. Could you provide more details?"
|
| 74 |
|
| 75 |
+
# ---------- Database and RAG ----------
|
| 76 |
db = DatabaseManager()
|
| 77 |
rag_helper = RAGHelper(use_vector_search=True)
|
| 78 |
|
| 79 |
+
# ---------- Authentication helpers (must be defined before routes) ----------
|
| 80 |
+
def is_authenticated():
|
| 81 |
+
session_id = session.get('session_id')
|
| 82 |
+
user_id = session.get('user_id')
|
| 83 |
+
if not session_id or not user_id:
|
| 84 |
+
return False
|
| 85 |
+
user = db.get_user_by_session(session_id)
|
| 86 |
+
return user and user['id'] == user_id
|
| 87 |
+
|
| 88 |
+
def refresh_session_timeout():
|
| 89 |
+
if 'session_id' in session:
|
| 90 |
+
session.permanent = True
|
| 91 |
+
|
| 92 |
+
def require_auth(f):
|
| 93 |
+
@wraps(f)
|
| 94 |
+
def decorated_function(*args, **kwargs):
|
| 95 |
+
if not is_authenticated():
|
| 96 |
+
return jsonify({'success': False, 'error': 'Authentication required'}), 401
|
| 97 |
+
return f(*args, **kwargs)
|
| 98 |
+
return decorated_function
|
| 99 |
+
|
| 100 |
+
def require_role(required_role):
|
| 101 |
+
def decorator(f):
|
| 102 |
+
@wraps(f)
|
| 103 |
+
def decorated_function(*args, **kwargs):
|
| 104 |
+
user_id = session.get('user_id')
|
| 105 |
+
if not user_id:
|
| 106 |
+
return jsonify({'error': 'Authentication required'}), 401
|
| 107 |
+
user_role = db.get_user_role(user_id)
|
| 108 |
+
allowed_roles = ['admin'] if required_role == 'admin' else ['admin', 'staff', 'user']
|
| 109 |
+
if user_role not in allowed_roles:
|
| 110 |
+
logger.warning(f"Unauthorized role access attempt: user {user_id}, role {user_role}, required {required_role}")
|
| 111 |
+
return jsonify({'error': 'Insufficient privileges'}), 403
|
| 112 |
+
return f(*args, **kwargs)
|
| 113 |
+
return decorated_function
|
| 114 |
+
return decorator
|
| 115 |
+
|
| 116 |
+
def require_resource_ownership(resource_type):
|
| 117 |
+
def decorator(f):
|
| 118 |
+
@wraps(f)
|
| 119 |
+
def decorated_function(*args, **kwargs):
|
| 120 |
+
user_id = session.get('user_id')
|
| 121 |
+
if not user_id:
|
| 122 |
+
return jsonify({'error': 'Authentication required'}), 401
|
| 123 |
+
resource_id = kwargs.get('ticket_id') or kwargs.get('conversation_id')
|
| 124 |
+
if not resource_id:
|
| 125 |
+
data = request.get_json() if request.is_json else {}
|
| 126 |
+
resource_id = data.get('ticket_id') or data.get('conversation_id')
|
| 127 |
+
if not resource_id:
|
| 128 |
+
return jsonify({'error': 'Resource ID required'}), 400
|
| 129 |
+
if resource_type == 'ticket':
|
| 130 |
+
if not db.user_owns_ticket(user_id, resource_id):
|
| 131 |
+
logger.warning(f"Unauthorized ticket access attempt: user {user_id}, ticket {resource_id}")
|
| 132 |
+
return jsonify({'error': 'Access denied'}), 403
|
| 133 |
+
elif resource_type == 'conversation':
|
| 134 |
+
if not db.user_owns_conversation(user_id, resource_id):
|
| 135 |
+
logger.warning(f"Unauthorized conversation access attempt: user {user_id}, conversation {resource_id}")
|
| 136 |
+
return jsonify({'error': 'Access denied'}), 403
|
| 137 |
+
return f(*args, **kwargs)
|
| 138 |
+
return decorated_function
|
| 139 |
+
return decorator
|
| 140 |
+
|
| 141 |
# ---------- ChatBot class (original, with send_message replaced) ----------
|
| 142 |
class ChatBot:
|
| 143 |
def __init__(self, db_manager, configured_model="mistral:7b"):
|
|
|
|
| 605 |
def create_ticket_from_chat(self, user_id, subject, description, category, priority, conversation_id):
|
| 606 |
return self.db_manager.create_support_ticket(user_id, subject, description, category, conversation_id, priority)
|
| 607 |
|
| 608 |
+
def get_available_models(self):
|
| 609 |
+
# For HF version, we don't have models list; return a placeholder
|
| 610 |
+
return [HF_MODEL]
|
| 611 |
+
|
| 612 |
+
def check_ollama_health(self):
|
| 613 |
+
# Not needed for HF version, but kept for compatibility
|
| 614 |
+
return True
|
| 615 |
+
|
| 616 |
# ------------------------------------------------------------------
|
| 617 |
# End of ChatBot class
|
| 618 |
# ------------------------------------------------------------------
|
|
|
|
| 811 |
return None, None
|
| 812 |
|
| 813 |
def get_ai_security_analysis(prompt):
|
| 814 |
+
# For the HF version, we can call the router for security analysis.
|
| 815 |
+
# To avoid recursive calls, we fall back to a simple rule-based score.
|
|
|
|
| 816 |
logger.info("Security analysis using rule-based fallback (safe score 2)")
|
| 817 |
return 2
|
| 818 |
|
|
|
|
| 935 |
return redirect(url_for('admin_tickets'))
|
| 936 |
|
| 937 |
@app.route('/admin/tickets')
|
| 938 |
+
@require_role('admin')
|
| 939 |
def admin_tickets():
|
| 940 |
return render_template('admin_tickets.html')
|
| 941 |
|
|
|
|
| 1142 |
@app.route('/api/health')
|
| 1143 |
def health_check():
|
| 1144 |
try:
|
| 1145 |
+
# For HF version, ollama is not used; return a placeholder
|
| 1146 |
+
ollama_status = True
|
| 1147 |
except:
|
| 1148 |
ollama_status = False
|
| 1149 |
try:
|