CoolFace
Apppublic

deepmindfx/surveillance.chat

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
backend.py426 linesDownload Raw Back to root
1from flask import Flask
2from flask_sqlalchemy import SQLAlchemy
3from flask_cors import CORS
4import os
5from flask import request, jsonify
6from flask_bcrypt import Bcrypt
7from flask_login import LoginManager, login_user, logout_user, login_required, current_user, UserMixin
8from werkzeug.utils import secure_filename
9from flask import send_from_directory
10from datetime import timedelta
11
12app = Flask(__name__)
13CORS(app)
14
15# Configurations
16app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///cctv_chat.db'
17app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
18app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev_secret_key')
19app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=24)  # Session timeout
20
21db = SQLAlchemy(app)
22
23bcrypt = Bcrypt(app)
24login_manager = LoginManager(app)
25
26# Update User model to inherit from UserMixin
27class User(UserMixin, db.Model):
28    id = db.Column(db.Integer, primary_key=True)
29    email = db.Column(db.String(120), unique=True, nullable=False)
30    password_hash = db.Column(db.String(128), nullable=False)
31    username = db.Column(db.String(64), unique=True, nullable=False)
32    created_at = db.Column(db.DateTime, server_default=db.func.now())
33    last_login = db.Column(db.DateTime)
34    is_active = db.Column(db.Boolean, default=True)
35    videos = db.relationship('Video', backref='user', lazy=True)
36    chats = db.relationship('ChatHistory', backref='user', lazy=True)
37
38    def get_id(self):
39        return str(self.id)
40
41@login_manager.user_loader
42def load_user(user_id):
43    return User.query.get(int(user_id))
44
45# User registration endpoint
46@app.route('/api/register', methods=['POST'])
47def register():
48    data = request.json
49    email = data.get('email')
50    username = data.get('username')
51    password = data.get('password')
52    if not email or not username or not password:
53        return jsonify({'error': 'Missing required fields'}), 400
54    if User.query.filter((User.email == email) | (User.username == username)).first():
55        return jsonify({'error': 'User already exists'}), 409
56    password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
57    user = User(email=email, username=username, password_hash=password_hash)
58    db.session.add(user)
59    db.session.commit()
60    return jsonify({'message': 'User registered successfully'}), 201
61
62# User login endpoint
63@app.route('/api/login', methods=['POST'])
64def login():
65    data = request.json
66    email = data.get('email')
67    password = data.get('password')
68    user = User.query.filter_by(email=email).first()
69    if user and bcrypt.check_password_hash(user.password_hash, password):
70        login_user(user)
71        response = jsonify({'message': 'Login successful', 'user_id': user.id, 'username': user.username})
72        return response, 200
73    return jsonify({'error': 'Invalid credentials'}), 401
74
75# Logout endpoint
76@app.route('/api/logout', methods=['POST'])
77@login_required
78def logout():
79    logout_user()
80    return jsonify({'message': 'Logged out successfully'}), 200
81
82# Video model
83class Video(db.Model):
84    id = db.Column(db.Integer, primary_key=True)
85    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
86    video_name = db.Column(db.String(256))
87    video_type = db.Column(db.String(32)) # upload/camera/url
88    file_path_or_url = db.Column(db.String(512))
89    upload_date = db.Column(db.DateTime, server_default=db.func.now())
90    file_size = db.Column(db.Integer)
91    duration = db.Column(db.Integer)
92    thumbnail_path = db.Column(db.String(512))
93    is_processed = db.Column(db.Boolean, default=False)
94    is_favorite = db.Column(db.Boolean, default=False)
95    chats = db.relationship('ChatHistory', backref='video', lazy=True)
96
97# Chat history model
98class ChatHistory(db.Model):
99    id = db.Column(db.Integer, primary_key=True)
100    video_id = db.Column(db.Integer, db.ForeignKey('video.id'), nullable=False)
101    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
102    question = db.Column(db.Text, nullable=False)
103    answer = db.Column(db.Text)
104    timestamp = db.Column(db.DateTime, server_default=db.func.now())
105    model_used = db.Column(db.String(64))
106
107UPLOAD_FOLDER = os.path.join(os.getcwd(), 'upload')
108ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv'}
109app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
110os.makedirs(UPLOAD_FOLDER, exist_ok=True)
111
112def allowed_file(filename):
113    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
114
115# Video upload endpoint (file)
116@app.route('/api/upload_video', methods=['POST'])
117@login_required
118def upload_video():
119    if 'file' not in request.files:
120        return jsonify({'error': 'No file part'}), 400
121    file = request.files['file']
122    if file.filename == '':
123        return jsonify({'error': 'No selected file'}), 400
124    if file and allowed_file(file.filename):
125        filename = secure_filename(file.filename)
126        filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
127        file.save(filepath)
128        video = Video(
129            user_id=current_user.id,
130            video_name=filename,
131            video_type='upload',
132            file_path_or_url=filepath,
133            file_size=os.path.getsize(filepath),
134            is_processed=False
135        )
136        db.session.add(video)
137        db.session.commit()
138        return jsonify({'message': 'Video uploaded successfully', 'video_id': video.id}), 201
139    return jsonify({'error': 'Invalid file type'}), 400
140
141# Video upload endpoint (URL or camera)
142@app.route('/api/add_video', methods=['POST'])
143@login_required
144def add_video():
145    data = request.json
146    video_name = data.get('video_name')
147    video_type = data.get('video_type')  # 'url' or 'camera'
148    file_path_or_url = data.get('file_path_or_url')
149    if not video_name or not video_type or not file_path_or_url:
150        return jsonify({'error': 'Missing required fields'}), 400
151    video = Video(
152        user_id=current_user.id,
153        video_name=video_name,
154        video_type=video_type,
155        file_path_or_url=file_path_or_url,
156        is_processed=False
157    )
158    db.session.add(video)
159    db.session.commit()
160    return jsonify({'message': 'Video added successfully', 'video_id': video.id}), 201
161
162# Get all videos for current user with search and filter
163@app.route('/api/videos', methods=['GET'])
164@login_required
165def get_videos():
166    videos = Video.query.filter_by(user_id=current_user.id)
167    
168    # Search by video name
169    search = request.args.get('search', '').strip()
170    if search:
171        videos = videos.filter(Video.video_name.ilike(f'%{search}%'))
172    
173    # Filter by video type
174    video_type = request.args.get('type', '').strip()
175    if video_type:
176        videos = videos.filter_by(video_type=video_type)
177    
178    # Filter by favorite status
179    favorite = request.args.get('favorite', '').strip()
180    if favorite.lower() == 'true':
181        videos = videos.filter_by(is_favorite=True)
182    elif favorite.lower() == 'false':
183        videos = videos.filter_by(is_favorite=False)
184    
185    # Sort by favorite status and upload date
186    videos = videos.order_by(Video.is_favorite.desc(), Video.upload_date.desc())
187    
188    # Pagination
189    page = request.args.get('page', 1, type=int)
190    per_page = request.args.get('per_page', 10, type=int)
191    per_page = min(per_page, 50)  # Limit max items per page
192    
193    pagination = videos.paginate(page=page, per_page=per_page, error_out=False)
194    
195    video_list = []
196    for video in pagination.items:
197        video_data = {
198            'id': video.id,
199            'video_name': video.video_name,
200            'video_type': video.video_type,
201            'file_path_or_url': video.file_path_or_url,
202            'upload_date': video.upload_date.strftime('%Y-%m-%d %H:%M:%S'),
203            'file_size': video.file_size,
204            'duration': video.duration,
205            'thumbnail_path': video.thumbnail_path,
206            'is_processed': video.is_processed,
207            'is_favorite': video.is_favorite
208        }
209        video_list.append(video_data)
210    
211    return jsonify({
212        'videos': video_list,
213        'pagination': {
214            'page': page,
215            'per_page': per_page,
216            'total': pagination.total,
217            'pages': pagination.pages,
218            'has_next': pagination.has_next,
219            'has_prev': pagination.has_prev
220        }
221    })
222
223# Serve uploaded video files
224@app.route('/api/video_file/<filename>')
225def get_video_file(filename):
226    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
227
228# Save a chat/question for a video
229@app.route('/api/chat', methods=['POST'])
230@login_required
231def save_chat():
232    data = request.json
233    video_id = data.get('video_id')
234    question = data.get('question')
235    answer = data.get('answer')
236    model_used = data.get('model_used')
237    if not video_id or not question or not answer:
238        return jsonify({'error': 'Missing required fields'}), 400
239    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
240    if not video:
241        return jsonify({'error': 'Video not found or not owned by user'}), 404
242    chat = ChatHistory(
243        video_id=video_id,
244        user_id=current_user.id,
245        question=question,
246        answer=answer,
247        model_used=model_used
248    )
249    db.session.add(chat)
250    db.session.commit()
251    return jsonify({'message': 'Chat saved successfully', 'chat_id': chat.id}), 201
252
253# Get chat history for a video
254@app.route('/api/chat_history/<int:video_id>', methods=['GET'])
255@login_required
256def get_chat_history(video_id):
257    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
258    if not video:
259        return jsonify({'error': 'Video not found or not owned by user'}), 404
260    chats = ChatHistory.query.filter_by(video_id=video_id, user_id=current_user.id).order_by(ChatHistory.timestamp.asc()).all()
261    chat_list = [
262        {
263            'id': c.id,
264            'question': c.question,
265            'answer': c.answer,
266            'timestamp': c.timestamp,
267            'model_used': c.model_used
268        } for c in chats
269    ]
270    return jsonify({'chats': chat_list}), 200
271
272# Delete a specific chat Q&A pair
273@app.route('/api/chat/<int:chat_id>', methods=['DELETE'])
274@login_required
275def delete_chat(chat_id):
276    chat = ChatHistory.query.filter_by(id=chat_id, user_id=current_user.id).first()
277    if not chat:
278        return jsonify({'error': 'Chat not found or not owned by user'}), 404
279    db.session.delete(chat)
280    db.session.commit()
281    return jsonify({'message': 'Chat deleted successfully'}), 200
282
283# Delete a video
284@app.route('/api/video/<int:video_id>', methods=['DELETE'])
285@login_required
286def delete_video(video_id):
287    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
288    if not video:
289        return jsonify({'error': 'Video not found or not owned by user'}), 404
290    db.session.delete(video)
291    db.session.commit()
292    return jsonify({'message': 'Video deleted successfully'}), 200
293
294# Rename a video
295@app.route('/api/video/<int:video_id>/rename', methods=['POST'])
296@login_required
297def rename_video(video_id):
298    data = request.json
299    new_name = data.get('new_name')  # Changed from 'video_name' to 'new_name'
300    if not new_name:
301        return jsonify({'error': 'New video name is required'}), 400
302    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
303    if not video:
304        return jsonify({'error': 'Video not found or not owned by user'}), 404
305    video.video_name = new_name
306    db.session.commit()
307    return jsonify({'message': 'Video name updated successfully'}), 200
308
309# Toggle favorite status for a video
310@app.route('/api/video/<int:video_id>/favorite', methods=['POST'])
311@login_required
312def toggle_favorite(video_id):
313    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
314    if not video:
315        return jsonify({'error': 'Video not found or not owned by user'}), 404
316    video.is_favorite = not video.is_favorite
317    db.session.commit()
318    return jsonify({'message': 'Favorite status updated', 'is_favorite': video.is_favorite}), 200
319
320# Get current user profile
321@app.route('/api/profile', methods=['GET'])
322@login_required
323def get_profile():
324    user = current_user
325    return jsonify({
326        'id': user.id,
327        'email': user.email,
328        'username': user.username,
329        'created_at': user.created_at,
330        'last_login': user.last_login,
331        'is_active': user.is_active
332    }), 200
333
334# Update current user profile (username only for now)
335@app.route('/api/profile', methods=['POST'])
336@login_required
337def update_profile():
338    data = request.get_json()
339    username = data.get('username')
340    
341    if not username:
342        return jsonify({'error': 'Username is required'}), 400
343    
344    # Check if username is already taken by another user
345    existing_user = User.query.filter_by(username=username).first()
346    if existing_user and existing_user.id != current_user.id:
347        return jsonify({'error': 'Username already taken'}), 400
348    
349    current_user.username = username
350    db.session.commit()
351    return jsonify({'message': 'Profile updated successfully'}), 200
352
353# Change password endpoint
354@app.route('/api/profile/password', methods=['POST'])
355@login_required
356def change_password():
357    data = request.get_json()
358    current_password = data.get('current_password')
359    new_password = data.get('new_password')
360    
361    if not current_password or not new_password:
362        return jsonify({'error': 'Current and new password are required'}), 400
363    
364    # Verify current password
365    if not bcrypt.check_password_hash(current_user.password_hash, current_password):
366        return jsonify({'error': 'Current password is incorrect'}), 400
367    
368    # Hash new password
369    new_password_hash = bcrypt.generate_password_hash(new_password).decode('utf-8')
370    current_user.password_hash = new_password_hash
371    db.session.commit()
372    
373    return jsonify({'message': 'Password changed successfully'}), 200
374
375# Analyze video endpoint
376@app.route('/api/analyze_video', methods=['POST'])
377@login_required
378def analyze_video():
379    data = request.json
380    video_id = data.get('video_id')
381    question = data.get('question')
382    
383    if not video_id or not question:
384        return jsonify({'error': 'Video ID and question are required'}), 400
385    
386    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
387    if not video:
388        return jsonify({'error': 'Video not found or not owned by user'}), 404
389    
390    # For now, return a placeholder response
391    # In a real implementation, this would call the AI model
392    answer = f"Analysis of video {video.video_name}: {question} - This is a placeholder response. The actual AI analysis would be implemented here."
393    
394    return jsonify({'answer': answer}), 200
395
396# Add chat endpoint
397@app.route('/api/add_chat', methods=['POST'])
398@login_required
399def add_chat():
400    data = request.json
401    video_id = data.get('video_id')
402    question = data.get('question')
403    answer = data.get('answer')
404    
405    if not video_id or not question or not answer:
406        return jsonify({'error': 'Video ID, question, and answer are required'}), 400
407    
408    video = Video.query.filter_by(id=video_id, user_id=current_user.id).first()
409    if not video:
410        return jsonify({'error': 'Video not found or not owned by user'}), 404
411    
412    chat = ChatHistory(
413        video_id=video_id,
414        user_id=current_user.id,
415        question=question,
416        answer=answer
417    )
418    db.session.add(chat)
419    db.session.commit()
420    
421    return jsonify({'message': 'Chat saved successfully', 'chat_id': chat.id}), 200
422
423if __name__ == '__main__':
424    with app.app_context():
425        db.create_all()
426    app.run(debug=True)