Gradii commited on
Commit
4fc93b8
Β·
1 Parent(s): 550177e
QUICKSTART.md ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quick Reference Guide
2
+
3
+ ## πŸš€ Starting the Backend
4
+
5
+ ### First Time Setup (Windows)
6
+ ```powershell
7
+ cd backend
8
+ python setup.py
9
+ venv\Scripts\activate
10
+ python main.py
11
+ ```
12
+
13
+ ### First Time Setup (macOS/Linux)
14
+ ```bash
15
+ cd backend
16
+ python setup.py
17
+ source venv/bin/activate
18
+ python main.py
19
+ ```
20
+
21
+ ### Subsequent Times
22
+ ```bash
23
+ cd backend
24
+ run.bat # Windows
25
+ # OR
26
+ ./run.sh # macOS/Linux
27
+ ```
28
+
29
+ ## πŸ“‘ API Quick Test
30
+
31
+ ### Health Check
32
+ ```bash
33
+ curl http://localhost:8000/
34
+ ```
35
+
36
+ ### Analyze a File
37
+ ```bash
38
+ curl -X POST http://localhost:8000/analyze \
39
+ -H "Content-Type: application/json" \
40
+ -d '{"file_url": "https://example.com/video.mp4"}'
41
+ ```
42
+
43
+ ### Documentation
44
+ - **Swagger UI**: http://localhost:8000/docs
45
+ - **ReDoc**: http://localhost:8000/redoc
46
+
47
+ ## πŸ”§ Configuration
48
+
49
+ Edit `backend/.env`:
50
+ ```env
51
+ HOST=127.0.0.1
52
+ PORT=8000
53
+ DEFAULT_DETECTOR_MODEL=mock
54
+ LOG_LEVEL=INFO
55
+ DOWNLOAD_TIMEOUT=30
56
+ MAX_FILE_SIZE=104857600
57
+ ```
58
+
59
+ ## πŸ“¦ Project Structure
60
+
61
+ ```
62
+ backend/
63
+ β”œβ”€β”€ app/
64
+ β”‚ β”œβ”€β”€ api/ # Routes
65
+ β”‚ β”œβ”€β”€ services/ # Business logic (download, ML models, queuing)
66
+ β”‚ β”œβ”€β”€ models/ # Data schemas
67
+ β”‚ β”œβ”€β”€ core/ # Configuration
68
+ β”‚ └── utils/ # Exceptions
69
+ β”œβ”€β”€ main.py # Entry point
70
+ β”œβ”€β”€ README.md # Full API docs
71
+ └── DEVELOPMENT.md # Adding models, Redis, etc.
72
+ ```
73
+
74
+ ## βž• Adding a New ML Model
75
+
76
+ 1. Copy `DETECTOR_TEMPLATE.py`
77
+ 2. Implement the `detect()` method
78
+ 3. Register in `app/services/detector/__init__.py`
79
+ 4. Update `.env` if setting as default
80
+
81
+ See `DEVELOPMENT.md` for detailed steps.
82
+
83
+ ## πŸ”— Integrating with Discord Bot
84
+
85
+ Use `DISCORD_BOT_EXAMPLE.py` as a template:
86
+
87
+ ```python
88
+ from discord_bot_example import setup
89
+
90
+ # In your bot startup:
91
+ await setup(bot)
92
+
93
+ # Then use in your bot:
94
+ # !deepfake_check https://example.com/video.mp4
95
+ # !backend_status
96
+ ```
97
+
98
+ ## πŸ› Common Issues
99
+
100
+ | Problem | Solution |
101
+ |---------|----------|
102
+ | `ModuleNotFoundError` | Activate venv first |
103
+ | Port 8000 in use | Change port: `PORT=8001 python main.py` |
104
+ | Import errors | `pip install -r requirements.txt` |
105
+ | Download timeout | Increase: `DOWNLOAD_TIMEOUT=60 python main.py` |
106
+
107
+ ## πŸ“Š Supported File Types
108
+
109
+ Any file type via URL:
110
+ - Videos: `.mp4`, `.webm`, `.avi`, etc.
111
+ - Images: `.jpg`, `.png`, `.gif`, etc.
112
+ - Any file up to 100 MB (configurable)
113
+
114
+ ## πŸ”„ Async Support
115
+
116
+ Backend is fully async:
117
+ - Non-blocking file downloads
118
+ - Concurrent requests supported
119
+ - Scalable to Redis task queuing
120
+
121
+ ## πŸ“ Logging Levels
122
+
123
+ ```bash
124
+ # Normal operation
125
+ LOG_LEVEL=INFO python main.py
126
+
127
+ # Verbose debugging
128
+ LOG_LEVEL=DEBUG python main.py
129
+
130
+ # Warnings and errors only
131
+ LOG_LEVEL=WARNING python main.py
132
+ ```
133
+
134
+ ## πŸš€ Production Deployment
135
+
136
+ For production, use Gunicorn with Uvicorn:
137
+
138
+ ```bash
139
+ pip install gunicorn
140
+ gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
141
+ ```
142
+
143
+ ## πŸ“ž Response Format
144
+
145
+ **Success:**
146
+ ```json
147
+ {
148
+ "is_deepfake": true,
149
+ "confidence": 0.95,
150
+ "analysis_time": 1.5,
151
+ "model_used": "mock"
152
+ }
153
+ ```
154
+
155
+ **Error:**
156
+ ```json
157
+ {
158
+ "error": "Invalid URL format",
159
+ "status_code": 400,
160
+ "details": null
161
+ }
162
+ ```
163
+
164
+ ## πŸ” Default Security Settings
165
+
166
+ - Max file size: 100 MB
167
+ - Download timeout: 30 seconds
168
+ - URL validation: Enabled
169
+ - Error details: Minimal (no leakage)
170
+
171
+ Increase security for production:
172
+ - Add API keys/authentication
173
+ - Implement rate limiting
174
+ - Use HTTPS
175
+ - Add CORS restrictions
176
+
177
+ ## 🎯 Next Steps
178
+
179
+ 1. βœ… Backend running?
180
+ 2. ⏳ Test with sample URLs
181
+ 3. ⏳ Create Discord bot using example
182
+ 4. ⏳ Add your ML models
183
+ 5. ⏳ Deploy to production
184
+
185
+ ---
186
+
187
+ For complete documentation, see `README.md` and `DEVELOPMENT.md` in the backend folder.
README.md CHANGED
@@ -1 +0,0 @@
1
- # DiscordBot
 
 
backend/.env.example ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deepfake Detection Service - Environment Variables
2
+
3
+ # Application Settings
4
+ APP_NAME=Deepfake Detection Service
5
+ APP_VERSION=1.0.0
6
+ DEBUG=True
7
+
8
+ # Server Configuration
9
+ HOST=127.0.0.1
10
+ PORT=8000
11
+
12
+ # File Handling
13
+ DOWNLOAD_TIMEOUT=30
14
+ MAX_FILE_SIZE=104857600
15
+
16
+ # ML Model Configuration
17
+ DEFAULT_DETECTOR_MODEL=mock
18
+ # Supported models: mock, deepseek, openai, etc.
19
+
20
+ # Redis Configuration (for future queuing)
21
+ REDIS_ENABLED=False
22
+ REDIS_URL=redis://localhost:6379
23
+ REDIS_QUEUE_NAME=deepfake_analysis
24
+
25
+ # Logging
26
+ LOG_LEVEL=INFO
27
+ LOG_FILE=
backend/.gitignore ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environments
24
+ venv/
25
+ ENV/
26
+ env/
27
+ .venv
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+ .DS_Store
36
+
37
+ # Environment variables
38
+ .env
39
+ .env.local
40
+ .env.*.local
41
+
42
+ # Logs
43
+ logs/
44
+ *.log
45
+ *.log.*
46
+
47
+ # Redis
48
+ dump.rdb
49
+
50
+ # Testing
51
+ .pytest_cache/
52
+ .coverage
53
+ htmlcov/
54
+
55
+ # Temporary files
56
+ *.tmp
57
+ *.temp
backend/DETECTOR_TEMPLATE.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Template for creating new detector models.
3
+
4
+ Copy this file and implement the detect() method with your custom ML logic.
5
+ Then register it in app/services/detector/__init__.py
6
+
7
+ Example:
8
+ # Copy this file as app/services/detector/mydetector.py
9
+ # Modify the class and model_name
10
+ # Add to get_detector() in __init__.py
11
+ """
12
+
13
+ import logging
14
+ import time
15
+ from typing import Dict, Any
16
+
17
+ from app.services.detector.base import BaseDetector
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class MyDetector(BaseDetector):
23
+ """
24
+ Template detector implementation.
25
+
26
+ Replace 'MyDetector' with your detector name.
27
+ """
28
+
29
+ def __init__(self):
30
+ """Initialize the detector."""
31
+ # Change 'mydetector' to your model name
32
+ super().__init__("mydetector")
33
+
34
+ async def detect(self, file_bytes: bytes) -> Dict[str, Any]:
35
+ """
36
+ Detect if file is a deepfake.
37
+
38
+ Args:
39
+ file_bytes: The file contents as bytes
40
+
41
+ Returns:
42
+ Dictionary with:
43
+ - is_deepfake: Boolean
44
+ - confidence: Float between 0.0 and 1.0
45
+ - analysis_time: Float in seconds
46
+ """
47
+ logger.info(f"Starting detection with {self.model_name}...")
48
+
49
+ start_time = time.time()
50
+
51
+ # ========================================
52
+ # TODO: Implement your ML model logic here
53
+ # ========================================
54
+ # Example:
55
+ # 1. Preprocess file_bytes if needed
56
+ # 2. Load your ML model
57
+ # 3. Run inference
58
+ # 4. Post-process results
59
+
60
+ # For now, return placeholder results
61
+ is_deepfake = True
62
+ confidence = 0.85
63
+
64
+ analysis_time = time.time() - start_time
65
+
66
+ result = {
67
+ "is_deepfake": is_deepfake,
68
+ "confidence": round(confidence, 3),
69
+ "analysis_time": round(analysis_time, 3),
70
+ }
71
+
72
+ logger.info(f"Detection completed. Result: {result}")
73
+ return result
74
+
75
+
76
+ # =====================================================
77
+ # REGISTRATION INSTRUCTIONS:
78
+ # =====================================================
79
+ #
80
+ # 1. Save this file as: app/services/detector/mydetector.py
81
+ #
82
+ # 2. Update app/services/detector/__init__.py:
83
+ #
84
+ # from app.services.detector.mydetector import MyDetector
85
+ #
86
+ # def get_detector(model_name: str = "mock") -> BaseDetector:
87
+ # detectors = {
88
+ # "mock": MockDetector,
89
+ # "mydetector": MyDetector, # ADD THIS LINE
90
+ # }
91
+ # # ... rest of function
92
+ #
93
+ # 3. Update .env.example:
94
+ #
95
+ # DEFAULT_DETECTOR_MODEL=mydetector
96
+ #
97
+ # 4. Test your detector:
98
+ #
99
+ # POST /analyze
100
+ # {
101
+ # "file_url": "https://example.com/video.mp4",
102
+ # "model": "mydetector"
103
+ # }
104
+ #
105
+ # =====================================================
backend/DEVELOPMENT.md ADDED
@@ -0,0 +1,351 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Development Guide for Deepfake Detection Backend
2
+
3
+ ## Project Overview
4
+
5
+ This is a production-ready FastAPI backend for deepfake detection with a modular, extensible architecture. It's designed to support multiple ML models and easy integration with task queues like Redis.
6
+
7
+ ## Architecture Overview
8
+
9
+ ```
10
+ FastAPI Application (app/__init__.py)
11
+ β”œβ”€β”€ API Routes (app/api/routes.py)
12
+ β”‚ β”œβ”€β”€ GET / (Health check)
13
+ β”‚ └── POST /analyze (Main endpoint)
14
+ β”œβ”€β”€ Services Layer (app/services/)
15
+ β”‚ β”œβ”€β”€ download.py (File downloading)
16
+ β”‚ β”œβ”€β”€ queue.py (Redis-ready task queue)
17
+ β”‚ └── detector/ (ML model implementations)
18
+ β”‚ β”œβ”€β”€ base.py (Abstract interface)
19
+ β”‚ β”œβ”€β”€ mock.py (Test implementation)
20
+ β”‚ └── [custom_detector].py (Add your models here)
21
+ β”œβ”€β”€ Models/Schemas (app/models/schemas.py)
22
+ └── Core Configuration (app/core/)
23
+ β”œβ”€β”€ config.py (Settings)
24
+ └── logging_config.py (Logging setup)
25
+ ```
26
+
27
+ ## Adding a New ML Model
28
+
29
+ ### Step 1: Create Your Detector Class
30
+
31
+ Create a new file in `app/services/detector/` (e.g., `deepseek.py`):
32
+
33
+ ```python
34
+ import logging
35
+ import time
36
+ from typing import Dict, Any
37
+ from app.services.detector.base import BaseDetector
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+ class DeepseekDetector(BaseDetector):
42
+ def __init__(self):
43
+ super().__init__("deepseek")
44
+ # Initialize your model here
45
+ # self.model = load_deepseek_model()
46
+
47
+ async def detect(self, file_bytes: bytes) -> Dict[str, Any]:
48
+ logger.info("Starting Deepseek detection...")
49
+ start_time = time.time()
50
+
51
+ # Your detection logic
52
+ is_deepfake = False # Your ML logic
53
+ confidence = 0.95
54
+
55
+ analysis_time = time.time() - start_time
56
+
57
+ return {
58
+ "is_deepfake": is_deepfake,
59
+ "confidence": round(confidence, 3),
60
+ "analysis_time": round(analysis_time, 3),
61
+ }
62
+ ```
63
+
64
+ ### Step 2: Register the Detector
65
+
66
+ Update `app/services/detector/__init__.py`:
67
+
68
+ ```python
69
+ from app.services.detector.deepseek import DeepseekDetector
70
+
71
+ def get_detector(model_name: str = "mock") -> BaseDetector:
72
+ detectors = {
73
+ "mock": MockDetector,
74
+ "deepseek": DeepseekDetector, # Add this
75
+ }
76
+ # ... rest of code
77
+ ```
78
+
79
+ ### Step 3: Update Configuration
80
+
81
+ Add to `.env`:
82
+ ```
83
+ DEFAULT_DETECTOR_MODEL=deepseek
84
+ ```
85
+
86
+ ### Step 4: Test Your Model
87
+
88
+ ```bash
89
+ curl -X POST http://localhost:8000/analyze \
90
+ -H "Content-Type: application/json" \
91
+ -d '{"file_url": "https://example.com/video.mp4", "model": "deepseek"}'
92
+ ```
93
+
94
+ ## Adding Redis Task Queuing
95
+
96
+ ### Step 1: Install Redis
97
+
98
+ ```bash
99
+ pip install redis aioredis
100
+ ```
101
+
102
+ ### Step 2: Update requirements.txt
103
+
104
+ Add to `requirements.txt`:
105
+ ```
106
+ redis==5.0.0
107
+ aioredis==2.0.1
108
+ ```
109
+
110
+ ### Step 3: Enable Redis
111
+
112
+ In `.env`:
113
+ ```
114
+ REDIS_ENABLED=True
115
+ REDIS_URL=redis://localhost:6379
116
+ ```
117
+
118
+ ### Step 4: Implement Queue Service
119
+
120
+ Update `app/services/queue.py` to implement async Redis operations:
121
+
122
+ ```python
123
+ import aioredis
124
+ import json
125
+
126
+ class QueueService:
127
+ async def _initialize_redis(self):
128
+ self.redis_client = await aioredis.create_redis_pool(
129
+ self.settings.REDIS_URL
130
+ )
131
+
132
+ async def enqueue_analysis(self, file_url: str, model: str, task_id: str):
133
+ task_data = {
134
+ "task_id": task_id,
135
+ "file_url": file_url,
136
+ "model": model,
137
+ }
138
+ await self.redis_client.lpush(
139
+ self.settings.REDIS_QUEUE_NAME,
140
+ json.dumps(task_data)
141
+ )
142
+
143
+ async def get_task_result(self, task_id: str):
144
+ result = await self.redis_client.get(f"result:{task_id}")
145
+ return json.loads(result) if result else None
146
+ ```
147
+
148
+ ### Step 5: Create Worker
149
+
150
+ Create `worker.py` in the backend directory:
151
+
152
+ ```python
153
+ import asyncio
154
+ import json
155
+ import aioredis
156
+ from app.services.detector import get_detector
157
+ from app.services.download import download_file
158
+
159
+ async def worker():
160
+ redis = await aioredis.create_redis_pool("redis://localhost:6379")
161
+
162
+ while True:
163
+ task_json = await redis.rpop("deepfake_analysis")
164
+ if not task_json:
165
+ await asyncio.sleep(1)
166
+ continue
167
+
168
+ task = json.loads(task_json)
169
+ try:
170
+ file_bytes = await download_file(task["file_url"])
171
+ detector = get_detector(task["model"])
172
+ result = await detector.detect(file_bytes)
173
+
174
+ await redis.set(
175
+ f"result:{task['task_id']}",
176
+ json.dumps(result)
177
+ )
178
+ except Exception as e:
179
+ logger.error(f"Task failed: {e}")
180
+
181
+ await asyncio.sleep(0.1)
182
+
183
+ if __name__ == "__main__":
184
+ asyncio.run(worker())
185
+ ```
186
+
187
+ ## Configuration Options
188
+
189
+ See `.env.example` for all available settings:
190
+
191
+ - `HOST`, `PORT` - Server address
192
+ - `DOWNLOAD_TIMEOUT` - File download timeout in seconds
193
+ - `MAX_FILE_SIZE` - Maximum file size in bytes
194
+ - `DEFAULT_DETECTOR_MODEL` - Default ML model to use
195
+ - `REDIS_ENABLED` - Enable Redis queuing
196
+ - `LOG_LEVEL` - Logging verbosity (DEBUG, INFO, WARNING, ERROR)
197
+
198
+ ## API Response Format
199
+
200
+ All responses follow a consistent format:
201
+
202
+ **Success (200):**
203
+ ```json
204
+ {
205
+ "is_deepfake": boolean,
206
+ "confidence": float,
207
+ "analysis_time": float,
208
+ "model_used": "model_name"
209
+ }
210
+ ```
211
+
212
+ **Error (4xx/5xx):**
213
+ ```json
214
+ {
215
+ "error": "Error message",
216
+ "status_code": 400,
217
+ "details": "Optional additional details"
218
+ }
219
+ ```
220
+
221
+ ## Error Handling
222
+
223
+ The service handles:
224
+ - **400 Bad Request**: Invalid URL, file too large, unsupported model
225
+ - **408 Request Timeout**: Download timeout
226
+ - **500 Internal Server Error**: Detector failure or unexpected error
227
+
228
+ Custom exceptions in `app/utils/exceptions.py` provide specific error types for proper handling.
229
+
230
+ ## Logging
231
+
232
+ All operations are logged with timestamps and levels:
233
+
234
+ ```python
235
+ logger.info("User action") # Normal operations
236
+ logger.warning("Something odd") # Unexpected but handled
237
+ logger.error("Failed action") # Error occurred
238
+ logger.debug("Detailed info") # Debug information (if enabled)
239
+ ```
240
+
241
+ Enable debug logging:
242
+ ```
243
+ LOG_LEVEL=DEBUG python main.py
244
+ ```
245
+
246
+ ## Testing
247
+
248
+ ### Unit Test Example
249
+
250
+ ```python
251
+ # tests/test_detector.py
252
+ import pytest
253
+ from app.services.detector import get_detector
254
+
255
+ @pytest.mark.asyncio
256
+ async def test_mock_detector():
257
+ detector = get_detector("mock")
258
+ result = await detector.detect(b"test_data")
259
+
260
+ assert "is_deepfake" in result
261
+ assert 0.0 <= result["confidence"] <= 1.0
262
+ assert result["analysis_time"] > 0
263
+ ```
264
+
265
+ ### Integration Test Example
266
+
267
+ ```python
268
+ # tests/test_api.py
269
+ from fastapi.testclient import TestClient
270
+ from app import create_app
271
+
272
+ client = TestClient(create_app())
273
+
274
+ def test_health():
275
+ response = client.get("/")
276
+ assert response.status_code == 200
277
+ assert response.json()["status"] == "ok"
278
+
279
+ @pytest.mark.asyncio
280
+ async def test_analyze():
281
+ response = await client.post(
282
+ "/analyze",
283
+ json={"file_url": "https://example.com/file.mp4"}
284
+ )
285
+ assert response.status_code == 200
286
+ ```
287
+
288
+ ## Performance Considerations
289
+
290
+ 1. **Async Operations**: All I/O is non-blocking using async/await
291
+ 2. **Connection Pooling**: httpx uses connection pooling for downloads
292
+ 3. **Memory Management**: Files are kept in memory (configure MAX_FILE_SIZE)
293
+ 4. **Timeouts**: All operations have configurable timeouts
294
+ 5. **Logging Overhead**: Disable debug logging in production
295
+
296
+ ## Security Considerations
297
+
298
+ - Validate all URLs with Pydantic's HttpUrl validator
299
+ - Limit file size to prevent DoS attacks
300
+ - Add rate limiting for production use (FastAPI-limiter)
301
+ - Sanitize error messages to avoid information leakage
302
+ - Use HTTPS in production
303
+ - Add API authentication/authorization
304
+
305
+ ## Deployment
306
+
307
+ For production deployment:
308
+
309
+ 1. Use a production ASGI server (Gunicorn + Uvicorn)
310
+ 2. Set `DEBUG=False` in `.env`
311
+ 3. Configure logging to file
312
+ 4. Enable Redis for scalability
313
+ 5. Use environment secrets management
314
+ 6. Add reverse proxy (nginx/Apache)
315
+ 7. Enable CORS if needed
316
+ 8. Add health checks for monitoring
317
+
318
+ ## Common Issues and Solutions
319
+
320
+ **Issue**: Port 8000 already in use
321
+ ```bash
322
+ PORT=8001 python main.py
323
+ ```
324
+
325
+ **Issue**: Module import errors
326
+ ```bash
327
+ # Make sure you're in backend directory and venv is activated
328
+ cd backend
329
+ source venv/bin/activate # or venv\Scripts\activate on Windows
330
+ ```
331
+
332
+ **Issue**: File download fails
333
+ - Check URL is accessible
334
+ - Increase DOWNLOAD_TIMEOUT
335
+ - Check MAX_FILE_SIZE limit
336
+
337
+ **Issue**: Detector not found
338
+ - Check model name spelling
339
+ - Verify registration in `get_detector()`
340
+ - List available models: `GET /`
341
+
342
+ ## Additional Resources
343
+
344
+ - [FastAPI Documentation](https://fastapi.tiangolo.com/)
345
+ - [Pydantic Validation](https://docs.pydantic.dev/)
346
+ - [Uvicorn Configuration](https://www.uvicorn.org/)
347
+ - [Python asyncio](https://docs.python.org/3/library/asyncio.html)
348
+
349
+ ---
350
+
351
+ For more help, refer to README.md or the inline code documentation.
backend/DISCORD_BOT_EXAMPLE.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Example: Integrating the Deepfake Detection Backend with Discord Bot
3
+
4
+ This example shows how to call the backend API from a Discord bot.
5
+ """
6
+
7
+ import discord
8
+ from discord.ext import commands
9
+ import httpx
10
+ import asyncio
11
+ from typing import Optional
12
+
13
+ # Backend configuration
14
+ BACKEND_URL = "http://127.0.0.1:8000"
15
+ BACKEND_TIMEOUT = 60 # seconds
16
+
17
+
18
+ class DeepfakeDetector(commands.Cog):
19
+ """Discord bot cog for deepfake detection."""
20
+
21
+ def __init__(self, bot: commands.Bot):
22
+ self.bot = bot
23
+ self.backend_url = BACKEND_URL
24
+ self.http_client = None
25
+
26
+ @commands.Cog.listener()
27
+ async def on_ready(self):
28
+ """Initialize HTTP client when bot is ready."""
29
+ if self.http_client is None:
30
+ self.http_client = httpx.AsyncClient(timeout=BACKEND_TIMEOUT)
31
+ print(f"Deepfake detector loaded - Backend: {self.backend_url}")
32
+
33
+ async def analyze_url(self, file_url: str, model: str = "mock") -> Optional[dict]:
34
+ """
35
+ Send a file URL to the backend for deepfake analysis.
36
+
37
+ Args:
38
+ file_url: URL of the file to analyze
39
+ model: Model to use for detection
40
+
41
+ Returns:
42
+ Analysis result or None if failed
43
+ """
44
+ try:
45
+ if self.http_client is None:
46
+ self.http_client = httpx.AsyncClient(timeout=BACKEND_TIMEOUT)
47
+
48
+ response = await self.http_client.post(
49
+ f"{self.backend_url}/analyze",
50
+ json={"file_url": file_url, "model": model},
51
+ )
52
+
53
+ if response.status_code == 200:
54
+ return response.json()
55
+ else:
56
+ print(f"Backend error: {response.status_code} - {response.text}")
57
+ return None
58
+ except Exception as e:
59
+ print(f"Failed to analyze: {e}")
60
+ return None
61
+
62
+ @commands.command(name="deepfake_check")
63
+ async def deepfake_check(self, ctx: commands.Context, url: str):
64
+ """
65
+ Check if a file at the given URL is a deepfake.
66
+
67
+ Usage:
68
+ !deepfake_check https://example.com/video.mp4
69
+ """
70
+ # Validate URL format
71
+ if not url.startswith(("http://", "https://")):
72
+ await ctx.send("❌ Invalid URL. Please provide a valid HTTP(S) URL.")
73
+ return
74
+
75
+ # Show loading message
76
+ async with ctx.typing():
77
+ # Check if backend is running
78
+ try:
79
+ health_response = await self.http_client.get(f"{self.backend_url}/")
80
+ if health_response.status_code != 200:
81
+ await ctx.send("❌ Backend service is not responding. Please try again later.")
82
+ return
83
+ except Exception as e:
84
+ await ctx.send(f"❌ Cannot connect to backend service: {e}")
85
+ return
86
+
87
+ # Analyze the file
88
+ await ctx.send(f"πŸ” Analyzing file from: {url}\nThis may take a moment...")
89
+
90
+ result = await self.analyze_url(url)
91
+
92
+ if result is None:
93
+ await ctx.send("❌ Analysis failed. Please check the URL and try again.")
94
+ return
95
+
96
+ # Format and display results
97
+ is_deepfake = result["is_deepfake"]
98
+ confidence = result["confidence"]
99
+ analysis_time = result["analysis_time"]
100
+ model_used = result.get("model_used", "unknown")
101
+
102
+ # Create embed for nice formatting
103
+ embed = discord.Embed(
104
+ title="πŸ”¬ Deepfake Detection Result",
105
+ color=discord.Color.red() if is_deepfake else discord.Color.green(),
106
+ )
107
+
108
+ embed.add_field(
109
+ name="Detection Result",
110
+ value="⚠️ **DEEPFAKE DETECTED**" if is_deepfake else "βœ… **AUTHENTIC**",
111
+ inline=False,
112
+ )
113
+
114
+ embed.add_field(
115
+ name="Confidence",
116
+ value=f"{confidence:.1%}",
117
+ inline=True,
118
+ )
119
+
120
+ embed.add_field(
121
+ name="Analysis Time",
122
+ value=f"{analysis_time:.2f}s",
123
+ inline=True,
124
+ )
125
+
126
+ embed.add_field(
127
+ name="Model Used",
128
+ value=model_used,
129
+ inline=True,
130
+ )
131
+
132
+ embed.set_footer(text="Analysis performed by Deepfake Detection Service")
133
+
134
+ await ctx.send(embed=embed)
135
+
136
+ @commands.command(name="backend_status")
137
+ async def backend_status(self, ctx: commands.Context):
138
+ """Check the status of the deepfake detection backend."""
139
+ try:
140
+ async with ctx.typing():
141
+ response = await self.http_client.get(f"{self.backend_url}/")
142
+
143
+ if response.status_code == 200:
144
+ data = response.json()
145
+ embed = discord.Embed(
146
+ title="🟒 Backend Status",
147
+ color=discord.Color.green(),
148
+ )
149
+ embed.add_field(
150
+ name="Service",
151
+ value=data["service"],
152
+ inline=True,
153
+ )
154
+ embed.add_field(
155
+ name="Version",
156
+ value=data["version"],
157
+ inline=True,
158
+ )
159
+ embed.add_field(
160
+ name="Available Models",
161
+ value=", ".join(data["available_models"]),
162
+ inline=False,
163
+ )
164
+ await ctx.send(embed=embed)
165
+ else:
166
+ await ctx.send("❌ Backend is not responding properly.")
167
+ except Exception as e:
168
+ await ctx.send(f"❌ Cannot connect to backend: {e}")
169
+
170
+ async def cog_unload(self):
171
+ """Cleanup when cog is unloaded."""
172
+ if self.http_client:
173
+ await self.http_client.aclose()
174
+
175
+
176
+ # Setup function to add this cog to your bot
177
+ async def setup(bot: commands.Bot):
178
+ """Add the deepfake detector cog to the bot."""
179
+ await bot.add_cog(DeepfakeDetector(bot))
180
+
181
+
182
+ # ============================================================================
183
+ # EXAMPLE BOT IMPLEMENTATION
184
+ # ============================================================================
185
+
186
+ # If you want to use this as a standalone bot, here's how:
187
+
188
+ # bot = commands.Bot(command_prefix="!", intents=discord.Intents.default())
189
+
190
+ # @bot.event
191
+ # async def on_ready():
192
+ # print(f"Bot logged in as {bot.user}")
193
+
194
+ # async def main():
195
+ # async with bot:
196
+ # await setup(bot)
197
+ # await bot.start("YOUR_BOT_TOKEN")
198
+
199
+ # if __name__ == "__main__":
200
+ # asyncio.run(main())
201
+
202
+ # ============================================================================
203
+ # USAGE IN YOUR BOT
204
+ # ============================================================================
205
+
206
+ # 1. Save this file as: discord_bot_example.py or similar
207
+ #
208
+ # 2. In your main bot file, add:
209
+ #
210
+ # from discord_bot_example import setup
211
+ #
212
+ # async def main():
213
+ # async with bot:
214
+ # await setup(bot) # Load the deepfake detector cog
215
+ # await bot.start(TOKEN)
216
+ #
217
+ # 3. Start the backend server:
218
+ # cd backend
219
+ # python main.py
220
+ #
221
+ # 4. Run your Discord bot
222
+ #
223
+ # 5. In Discord, use the commands:
224
+ # !deepfake_check https://example.com/video.mp4
225
+ # !backend_status
226
+
227
+ # ============================================================================
228
+ # COMMAND EXAMPLES
229
+ # ============================================================================
230
+
231
+ # !deepfake_check https://example.com/suspicious_video.mp4
232
+ # Analyzes the video at the given URL for deepfake content
233
+ #
234
+ # !backend_status
235
+ # Shows the current status and available models of the backend
236
+
237
+ # ============================================================================
238
+ # API RESPONSE HANDLING
239
+ # ============================================================================
240
+
241
+ # The backend returns responses like:
242
+ # {
243
+ # "is_deepfake": true,
244
+ # "confidence": 0.847,
245
+ # "analysis_time": 1.234,
246
+ # "model_used": "mock"
247
+ # }
248
+ #
249
+ # Error responses:
250
+ # {
251
+ # "error": "Invalid URL format",
252
+ # "status_code": 400,
253
+ # "details": null
254
+ # }
255
+
256
+ # ============================================================================
257
+ # CUSTOMIZATION OPTIONS
258
+ # ============================================================================
259
+
260
+ # 1. Change model selection:
261
+ # await detector.analyze_url(url, model="deepseek")
262
+ #
263
+ # 2. Add custom formatting:
264
+ # - Modify the embed creation in deepfake_check()
265
+ # - Add database logging of results
266
+ # - Notify admins of detected deepfakes
267
+ #
268
+ # 3. Add rate limiting:
269
+ # - Use discord.ext.commands.cooldown decorator
270
+ # - Implement per-user/channel limits
271
+ #
272
+ # 4. Add file upload support:
273
+ # - Check message attachments
274
+ # - Upload to temporary storage
275
+ # - Generate URL for backend analysis
276
+
277
+ print("Discord Bot Deepfake Detector Example - Ready to integrate!")
backend/README.md ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deepfake Detection Service Backend
2
+
3
+ A scalable FastAPI backend for deepfake detection with support for multiple ML models and future Redis integration for task queuing.
4
+
5
+ ## πŸ“ Project Structure
6
+
7
+ ```
8
+ backend/
9
+ β”œβ”€β”€ app/
10
+ β”‚ β”œβ”€β”€ core/ # Core configuration and setup
11
+ β”‚ β”‚ β”œβ”€β”€ config.py # Settings management
12
+ β”‚ β”‚ └── logging_config.py # Logging setup
13
+ β”‚ β”œβ”€β”€ models/ # Data models
14
+ β”‚ β”‚ └── schemas.py # Pydantic request/response models
15
+ β”‚ β”œβ”€β”€ services/ # Business logic layer
16
+ β”‚ β”‚ β”œβ”€β”€ download.py # File download service
17
+ β”‚ β”‚ β”œβ”€β”€ queue.py # Task queue service (Redis-ready)
18
+ β”‚ β”‚ └── detector/ # ML detector models
19
+ β”‚ β”‚ β”œβ”€β”€ base.py # Abstract base detector class
20
+ β”‚ β”‚ └── mock.py # Mock detector implementation
21
+ β”‚ β”œβ”€β”€ api/ # API endpoints
22
+ β”‚ β”‚ └── routes.py # Route handlers
23
+ β”‚ └── utils/ # Utilities
24
+ β”‚ └── exceptions.py # Custom exceptions
25
+ β”œβ”€β”€ main.py # Application entry point
26
+ β”œβ”€β”€ requirements.txt # Python dependencies
27
+ β”œβ”€β”€ .env.example # Example environment variables
28
+ └── README.md # This file
29
+ ```
30
+
31
+ ## πŸš€ Quick Start
32
+
33
+ ### Prerequisites
34
+ - Python 3.8+
35
+ - pip or conda
36
+
37
+ ### Installation
38
+
39
+ 1. **Navigate to the backend directory:**
40
+ ```bash
41
+ cd backend
42
+ ```
43
+
44
+ 2. **Create a virtual environment (recommended):**
45
+ ```bash
46
+ # Using venv
47
+ python -m venv venv
48
+
49
+ # Activate virtual environment
50
+ # On Windows:
51
+ venv\Scripts\activate
52
+ # On macOS/Linux:
53
+ source venv/bin/activate
54
+ ```
55
+
56
+ 3. **Install dependencies:**
57
+ ```bash
58
+ pip install -r requirements.txt
59
+ ```
60
+
61
+ 4. **Run the server:**
62
+ ```bash
63
+ python main.py
64
+ ```
65
+
66
+ The server will start on `http://127.0.0.1:8000`
67
+
68
+ ## πŸ“– API Documentation
69
+
70
+ Once the server is running, interactive API documentation is available at:
71
+ - Swagger UI: `http://127.0.0.1:8000/docs`
72
+ - ReDoc: `http://127.0.0.1:8000/redoc`
73
+
74
+ ## πŸ”Œ API Endpoints
75
+
76
+ ### Health Check
77
+ ```bash
78
+ GET /
79
+ ```
80
+
81
+ Returns service status and available models.
82
+
83
+ **Response:**
84
+ ```json
85
+ {
86
+ "status": "ok",
87
+ "service": "Deepfake Detection Service",
88
+ "version": "1.0.0",
89
+ "available_models": ["mock"]
90
+ }
91
+ ```
92
+
93
+ ### Analyze File
94
+ ```bash
95
+ POST /analyze
96
+ Content-Type: application/json
97
+
98
+ {
99
+ "file_url": "https://example.com/video.mp4",
100
+ "model": "mock"
101
+ }
102
+ ```
103
+
104
+ **Request Parameters:**
105
+ - `file_url` (required): URL of the file to analyze
106
+ - `model` (optional): Detector model to use. Defaults to configured model
107
+
108
+ **Response (200 OK):**
109
+ ```json
110
+ {
111
+ "is_deepfake": true,
112
+ "confidence": 0.847,
113
+ "analysis_time": 1.234,
114
+ "model_used": "mock"
115
+ }
116
+ ```
117
+
118
+ **Error Responses:**
119
+ - `400 Bad Request`: Invalid URL, file too large, or unsupported model
120
+ - `408 Request Timeout`: File download timed out
121
+ - `500 Internal Server Error`: Server error during analysis
122
+
123
+ ## βš™οΈ Configuration
124
+
125
+ Configuration is managed through environment variables. Create a `.env` file in the `backend/` directory:
126
+
127
+ ```bash
128
+ cp .env.example .env
129
+ ```
130
+
131
+ Edit `.env` with your settings:
132
+
133
+ ```env
134
+ # Server
135
+ HOST=127.0.0.1
136
+ PORT=8000
137
+
138
+ # File handling
139
+ DOWNLOAD_TIMEOUT=30
140
+ MAX_FILE_SIZE=104857600 # 100 MB
141
+
142
+ # ML Model
143
+ DEFAULT_DETECTOR_MODEL=mock
144
+
145
+ # Redis (for future use)
146
+ REDIS_ENABLED=False
147
+ REDIS_URL=redis://localhost:6379
148
+
149
+ # Logging
150
+ LOG_LEVEL=INFO
151
+ LOG_FILE=
152
+ ```
153
+
154
+ ## 🎯 Adding New ML Models
155
+
156
+ The architecture supports easy addition of new detector models:
157
+
158
+ 1. **Create a new detector class** in `app/services/detector/`:
159
+
160
+ ```python
161
+ # app/services/detector/deepseek.py
162
+ from app.services.detector.base import BaseDetector
163
+
164
+ class DeepseekDetector(BaseDetector):
165
+ def __init__(self):
166
+ super().__init__("deepseek")
167
+
168
+ async def detect(self, file_bytes: bytes) -> dict:
169
+ # Your ML model implementation
170
+ return {
171
+ "is_deepfake": False,
172
+ "confidence": 0.95,
173
+ "analysis_time": 2.5
174
+ }
175
+ ```
176
+
177
+ 2. **Register the detector** in `app/services/detector/__init__.py`:
178
+
179
+ ```python
180
+ def get_detector(model_name: str = "mock") -> BaseDetector:
181
+ detectors = {
182
+ "mock": MockDetector,
183
+ "deepseek": DeepseekDetector, # Add this
184
+ # ... more models
185
+ }
186
+ # ... rest of code
187
+ ```
188
+
189
+ 3. **Update `.env.example`** to document the new model
190
+
191
+ ## 🚦 Future Redis Integration
192
+
193
+ The queue service is designed to support Redis task queuing without major refactoring:
194
+
195
+ 1. Set `REDIS_ENABLED=True` in `.env`
196
+ 2. Set correct `REDIS_URL`
197
+ 3. The queue service will automatically use Redis for task management
198
+
199
+ Redis support will enable:
200
+ - Asynchronous task processing
201
+ - Task result caching
202
+ - Improved scalability for high-volume requests
203
+
204
+ ## πŸ“ Logging
205
+
206
+ Logs are configured in `app/core/logging_config.py`. By default:
207
+ - Level: INFO
208
+ - Output: Console
209
+ - Rotation: Automatic (if LOG_FILE is set)
210
+
211
+ Configure logging level via environment:
212
+ ```bash
213
+ LOG_LEVEL=DEBUG # For verbose logging
214
+ ```
215
+
216
+ ## πŸ§ͺ Testing the API
217
+
218
+ ### Using curl:
219
+ ```bash
220
+ curl -X POST http://localhost:8000/analyze \
221
+ -H "Content-Type: application/json" \
222
+ -d '{"file_url": "https://example.com/video.mp4"}'
223
+ ```
224
+
225
+ ### Using Python requests:
226
+ ```python
227
+ import requests
228
+
229
+ response = requests.post(
230
+ "http://localhost:8000/analyze",
231
+ json={"file_url": "https://example.com/video.mp4"}
232
+ )
233
+ print(response.json())
234
+ ```
235
+
236
+ ### Using httpx (async):
237
+ ```python
238
+ import httpx
239
+ import asyncio
240
+
241
+ async def test():
242
+ async with httpx.AsyncClient() as client:
243
+ response = await client.post(
244
+ "http://localhost:8000/analyze",
245
+ json={"file_url": "https://example.com/video.mp4"}
246
+ )
247
+ print(response.json())
248
+
249
+ asyncio.run(test())
250
+ ```
251
+
252
+ ## πŸ”’ Error Handling
253
+
254
+ The API provides comprehensive error handling:
255
+
256
+ ```python
257
+ # Invalid URL
258
+ {
259
+ "error": "Invalid URL format",
260
+ "status_code": 400,
261
+ "details": null
262
+ }
263
+
264
+ # File too large
265
+ {
266
+ "error": "File size exceeds maximum allowed size of 104857600 bytes",
267
+ "status_code": 400,
268
+ "details": null
269
+ }
270
+
271
+ # Download timeout
272
+ {
273
+ "error": "File download timed out",
274
+ "status_code": 408,
275
+ "details": null
276
+ }
277
+
278
+ # Unsupported model
279
+ {
280
+ "error": "Detector model 'invalid' is not supported. Available models: mock",
281
+ "status_code": 400,
282
+ "details": null
283
+ }
284
+ ```
285
+
286
+ ## πŸ”§ Troubleshooting
287
+
288
+ **Port already in use:**
289
+ ```bash
290
+ # Change port via environment variable
291
+ PORT=8001 python main.py
292
+ ```
293
+
294
+ **Import errors:**
295
+ ```bash
296
+ # Ensure you're in the backend directory and have activated venv
297
+ cd backend
298
+ source venv/bin/activate # or venv\Scripts\activate on Windows
299
+ pip install -r requirements.txt
300
+ ```
301
+
302
+ **Timeout issues:**
303
+ ```bash
304
+ # Increase timeout for slow downloads
305
+ DOWNLOAD_TIMEOUT=60 python main.py
306
+ ```
307
+
308
+ ## πŸ“¦ Dependencies
309
+
310
+ - **FastAPI**: Modern async web framework
311
+ - **Uvicorn**: ASGI server
312
+ - **Pydantic**: Data validation and settings
313
+ - **httpx**: Async HTTP client for file downloads
314
+
315
+ See `requirements.txt` for exact versions.
316
+
317
+ ## πŸ“„ License
318
+
319
+ This project is part of the DiscordBot backend service.
320
+
321
+ ## 🀝 Contributing
322
+
323
+ To add new features or models:
324
+
325
+ 1. Follow the existing code structure
326
+ 2. Implement abstract base classes for new functionality
327
+ 3. Add comprehensive logging
328
+ 4. Update documentation and examples
329
+
330
+ ## πŸ“§ Support
331
+
332
+ For issues or questions, please refer to the project documentation or contact the development team.
backend/app/__init__.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Deepfake Detection Service Application"""
2
+
3
+ from fastapi import FastAPI
4
+ from app.api.routes import router as api_router
5
+ from app.core.logging_config import setup_logging
6
+ from app.core.config import Settings
7
+
8
+ __version__ = Settings.APP_VERSION or "1.0.0"
9
+
10
+
11
+ def create_app() -> FastAPI:
12
+ """Create and configure the FastAPI application."""
13
+ setup_logging()
14
+
15
+ app = FastAPI(
16
+ title="Deepfake Detection Service",
17
+ description="Backend service for deepfake detection with support for multiple ML models",
18
+ version=__version__,
19
+ )
20
+
21
+ # Include API routes
22
+ app.include_router(api_router)
23
+
24
+ @app.on_event("startup")
25
+ async def startup_event():
26
+ import logging
27
+ logger = logging.getLogger(__name__)
28
+ logger.info("Deepfake Detection Service is starting up...")
29
+
30
+ @app.on_event("shutdown")
31
+ async def shutdown_event():
32
+ import logging
33
+ logger = logging.getLogger(__name__)
34
+ logger.info("Deepfake Detection Service is shutting down...")
35
+
36
+ return app
backend/app/api/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """API routes and endpoints."""
backend/app/api/routes.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """API route handlers."""
2
+
3
+ import logging
4
+ from fastapi import APIRouter, HTTPException
5
+
6
+ from app.models.schemas import (
7
+ AnalysisRequest,
8
+ AnalysisResponse,
9
+ ErrorResponse,
10
+ HealthResponse,
11
+ )
12
+ from app.services.download import download_file
13
+ from app.services.detector import get_detector
14
+ from app.core.config import get_settings
15
+ from app.utils.exceptions import DeepfakeDetectionError
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ router = APIRouter()
20
+
21
+
22
+ @router.get(
23
+ "/",
24
+ response_model=HealthResponse,
25
+ tags=["Health"],
26
+ summary="Health check endpoint",
27
+ )
28
+ async def health_check() -> HealthResponse:
29
+ """
30
+ Health check endpoint to verify service is running.
31
+
32
+ Returns:
33
+ Service status and version information
34
+ """
35
+ settings = get_settings()
36
+ logger.info("Health check endpoint accessed")
37
+
38
+ available_models = ["mock"] # Add more as you implement them
39
+
40
+ return HealthResponse(
41
+ status="ok",
42
+ service="Deepfake Detection Service",
43
+ version=settings.APP_VERSION,
44
+ available_models=available_models,
45
+ )
46
+
47
+
48
+ @router.post(
49
+ "/analyze",
50
+ response_model=AnalysisResponse,
51
+ responses={
52
+ 400: {"model": ErrorResponse, "description": "Bad request"},
53
+ 408: {"model": ErrorResponse, "description": "Request timeout"},
54
+ 500: {"model": ErrorResponse, "description": "Internal server error"},
55
+ },
56
+ tags=["Analysis"],
57
+ summary="Analyze file for deepfake detection",
58
+ )
59
+ async def analyze(request: AnalysisRequest) -> AnalysisResponse:
60
+ """
61
+ Analyze a file for deepfake detection.
62
+
63
+ Args:
64
+ request: AnalysisRequest containing file_url and optional model selection
65
+
66
+ Returns:
67
+ AnalysisResponse with detection results
68
+
69
+ Raises:
70
+ HTTPException: For various error conditions during processing
71
+ """
72
+ settings = get_settings()
73
+ detector_model = request.model or settings.DEFAULT_DETECTOR_MODEL
74
+
75
+ logger.info(
76
+ f"Received analysis request for URL: {request.file_url} "
77
+ f"using model: {detector_model}"
78
+ )
79
+
80
+ try:
81
+ try:
82
+ detector = get_detector(detector_model)
83
+ except ValueError as e:
84
+ logger.error(f"Invalid detector model: {str(e)}")
85
+ raise HTTPException(
86
+ status_code=400,
87
+ detail=str(e),
88
+ )
89
+
90
+ file_bytes = await download_file(str(request.file_url))
91
+
92
+ if not file_bytes:
93
+ logger.error("File download returned empty bytes")
94
+ raise HTTPException(
95
+ status_code=500,
96
+ detail="Failed to download and process file",
97
+ )
98
+
99
+ analysis_result = await detector.detect(file_bytes)
100
+
101
+ logger.info(
102
+ f"Analysis request completed successfully. "
103
+ f"File URL: {request.file_url}, Model: {detector_model}, "
104
+ f"Result: {analysis_result}"
105
+ )
106
+
107
+ return AnalysisResponse(
108
+ is_deepfake=analysis_result["is_deepfake"],
109
+ confidence=analysis_result["confidence"],
110
+ analysis_time=analysis_result["analysis_time"],
111
+ model_used=detector_model,
112
+ )
113
+
114
+ except HTTPException:
115
+ raise
116
+ except DeepfakeDetectionError as e:
117
+ logger.error(f"Detection error: {e.message}")
118
+ raise HTTPException(
119
+ status_code=e.status_code,
120
+ detail=e.message,
121
+ )
122
+ except Exception as e:
123
+ logger.error(f"Unexpected error during analysis: {str(e)}", exc_info=True)
124
+ raise HTTPException(
125
+ status_code=500,
126
+ detail="An unexpected error occurred during analysis. Please try again later.",
127
+ )
backend/app/core/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Core application configuration and setup."""
backend/app/core/config.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Optional
3
+ from functools import lru_cache
4
+
5
+
6
+ class Settings:
7
+ """Application settings with environment variable support."""
8
+
9
+ # Application
10
+ APP_NAME: str = "Deepfake Detection Service"
11
+ APP_VERSION: str = "1.0.0"
12
+ DEBUG: bool = os.getenv("DEBUG", "True").lower() == "true"
13
+
14
+ # Server
15
+ HOST: str = os.getenv("HOST", "127.0.0.1")
16
+ PORT: int = int(os.getenv("PORT", "8000"))
17
+
18
+ # File handling
19
+ DOWNLOAD_TIMEOUT: int = int(os.getenv("DOWNLOAD_TIMEOUT", "30"))
20
+ MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", str(100 * 1024 * 1024))) # 100 MB
21
+
22
+ # ML Model configuration
23
+ DEFAULT_DETECTOR_MODEL: str = os.getenv("DEFAULT_DETECTOR_MODEL", "mock")
24
+ # Supported models: "mock", "deepseek", "openai", etc. (easy to add more)
25
+
26
+ # Redis configuration (for future queuing)
27
+ REDIS_ENABLED: bool = os.getenv("REDIS_ENABLED", "False").lower() == "true"
28
+ REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379")
29
+ REDIS_QUEUE_NAME: str = os.getenv("REDIS_QUEUE_NAME", "deepfake_analysis")
30
+
31
+ # Logging
32
+ LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
33
+ LOG_FILE: Optional[str] = os.getenv("LOG_FILE", None)
34
+
35
+
36
+ @lru_cache()
37
+ def get_settings() -> Settings:
38
+ """Get cached application settings."""
39
+ return Settings()
backend/app/core/logging_config.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import logging.handlers
3
+ from app.core.config import get_settings
4
+
5
+
6
+ def setup_logging():
7
+ """Configure logging for the application."""
8
+ settings = get_settings()
9
+
10
+ # Create logger
11
+ logger = logging.getLogger()
12
+ logger.setLevel(getattr(logging, settings.LOG_LEVEL))
13
+
14
+ # Remove existing handlers
15
+ logger.handlers.clear()
16
+
17
+ # Console handler
18
+ console_handler = logging.StreamHandler()
19
+ console_handler.setLevel(getattr(logging, settings.LOG_LEVEL))
20
+ formatter = logging.Formatter(
21
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
22
+ )
23
+ console_handler.setFormatter(formatter)
24
+ logger.addHandler(console_handler)
25
+
26
+ # File handler (if specified)
27
+ if settings.LOG_FILE:
28
+ file_handler = logging.handlers.RotatingFileHandler(
29
+ settings.LOG_FILE,
30
+ maxBytes=10485760, # 10 MB
31
+ backupCount=5,
32
+ )
33
+ file_handler.setLevel(getattr(logging, settings.LOG_LEVEL))
34
+ file_handler.setFormatter(formatter)
35
+ logger.addHandler(file_handler)
backend/app/models/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Data models and schemas."""
backend/app/models/schemas.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, HttpUrl, Field
2
+ from typing import Optional
3
+
4
+
5
+ class AnalysisRequest(BaseModel):
6
+ """Request model for deepfake analysis."""
7
+
8
+ file_url: HttpUrl = Field(
9
+ ..., description="URL of the file to analyze for deepfake detection"
10
+ )
11
+ model: Optional[str] = Field(
12
+ None, description="Detector model to use (e.g., 'mock', 'deepseek', 'openai')"
13
+ )
14
+
15
+ class Config:
16
+ json_schema_extra = {
17
+ "example": {
18
+ "file_url": "https://example.com/video.mp4",
19
+ "model": "mock"
20
+ }
21
+ }
22
+
23
+
24
+ class AnalysisResponse(BaseModel):
25
+ """Response model for deepfake analysis results."""
26
+
27
+ is_deepfake: bool = Field(
28
+ ..., description="Whether the file is detected as a deepfake"
29
+ )
30
+ confidence: float = Field(
31
+ ..., ge=0.0, le=1.0, description="Confidence score between 0.0 and 1.0"
32
+ )
33
+ analysis_time: float = Field(
34
+ ..., description="Time taken for analysis in seconds"
35
+ )
36
+ model_used: str = Field(
37
+ ..., description="The detector model that was used"
38
+ )
39
+
40
+ class Config:
41
+ json_schema_extra = {
42
+ "example": {
43
+ "is_deepfake": True,
44
+ "confidence": 0.847,
45
+ "analysis_time": 1.234,
46
+ "model_used": "mock"
47
+ }
48
+ }
49
+
50
+
51
+ class ErrorResponse(BaseModel):
52
+ """Response model for errors."""
53
+
54
+ error: str = Field(..., description="Error message")
55
+ status_code: int = Field(..., description="HTTP status code")
56
+ details: Optional[str] = Field(
57
+ None, description="Additional error details"
58
+ )
59
+
60
+ class Config:
61
+ json_schema_extra = {
62
+ "example": {
63
+ "error": "Invalid URL format",
64
+ "status_code": 400,
65
+ "details": "The provided file_url is not a valid URL"
66
+ }
67
+ }
68
+
69
+
70
+ class HealthResponse(BaseModel):
71
+ """Response model for health check."""
72
+
73
+ status: str = Field(..., description="Service status")
74
+ service: str = Field(..., description="Service name")
75
+ version: str = Field(..., description="Service version")
76
+ available_models: list = Field(..., description="Available detector models")
backend/app/services/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Service layer for business logic."""
backend/app/services/detector/__init__.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Detector models for deepfake detection."""
2
+
3
+ from app.services.detector.base import BaseDetector
4
+ from app.services.detector.mock import MockDetector
5
+
6
+ __all__ = ["BaseDetector", "MockDetector", "get_detector"]
7
+
8
+
9
+ def get_detector(model_name: str = "mock") -> BaseDetector:
10
+ """
11
+ Factory function to get detector instance by model name.
12
+
13
+ Args:
14
+ model_name: Name of the detector model
15
+
16
+ Returns:
17
+ Instance of the requested detector
18
+
19
+ Raises:
20
+ ValueError: If model is not supported
21
+ """
22
+ detectors = {
23
+ "mock": MockDetector,
24
+ # Future models:
25
+ # "deepseek": DeepseekDetector,
26
+ # "openai": OpenAIDetector,
27
+ # "huggingface": HuggingFaceDetector,
28
+ }
29
+
30
+ if model_name not in detectors:
31
+ available = ", ".join(detectors.keys())
32
+ raise ValueError(
33
+ f"Detector model '{model_name}' is not supported. "
34
+ f"Available models: {available}"
35
+ )
36
+
37
+ return detectors[model_name]()
backend/app/services/detector/base.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Base detector class defining the interface for all detectors."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Dict, Any
5
+
6
+
7
+ class BaseDetector(ABC):
8
+ """
9
+ Abstract base class for deepfake detectors.
10
+
11
+ All detector implementations should inherit from this class and implement
12
+ the detect() method.
13
+ """
14
+
15
+ def __init__(self, model_name: str):
16
+ """
17
+ Initialize the detector.
18
+
19
+ Args:
20
+ model_name: Name of the detector model
21
+ """
22
+ self.model_name = model_name
23
+
24
+ @abstractmethod
25
+ async def detect(self, file_bytes: bytes) -> Dict[str, Any]:
26
+ """
27
+ Detect if file is a deepfake.
28
+
29
+ Args:
30
+ file_bytes: The file contents as bytes
31
+
32
+ Returns:
33
+ Dictionary containing:
34
+ - is_deepfake: Boolean indicating if file is a deepfake
35
+ - confidence: Float between 0.0 and 1.0
36
+ - analysis_time: Float representing processing time
37
+ """
38
+ pass
backend/app/services/detector/mock.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Mock detector implementation for testing and development."""
2
+
3
+ import asyncio
4
+ import logging
5
+ import time
6
+ from typing import Dict, Any
7
+
8
+ from app.services.detector.base import BaseDetector
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class MockDetector(BaseDetector):
14
+ """
15
+ Mock detector for testing and development.
16
+
17
+ Simulates deepfake detection without requiring actual ML models.
18
+ """
19
+
20
+ def __init__(self):
21
+ """Initialize the mock detector."""
22
+ super().__init__("mock")
23
+
24
+ async def detect(self, file_bytes: bytes) -> Dict[str, Any]:
25
+ """
26
+ Simulate deepfake detection with a random result.
27
+
28
+ Args:
29
+ file_bytes: The file contents as bytes
30
+
31
+ Returns:
32
+ Dictionary with is_deepfake, confidence, and analysis_time
33
+ """
34
+ logger.info("Starting mock deepfake analysis...")
35
+
36
+ start_time = time.time()
37
+
38
+ # Simulate processing delay (1 to 2 seconds)
39
+ delay = 1.0 + (hash(file_bytes) % 100) / 100.0
40
+ await asyncio.sleep(delay)
41
+
42
+ analysis_time = time.time() - start_time
43
+
44
+ # Simulate ML model output (deterministic based on file content hash)
45
+ file_hash = hash(file_bytes) % 100
46
+ is_deepfake = file_hash > 50 # ~50% chance
47
+ confidence = (file_hash % 100) / 100.0
48
+
49
+ result = {
50
+ "is_deepfake": is_deepfake,
51
+ "confidence": round(confidence, 3),
52
+ "analysis_time": round(analysis_time, 3),
53
+ }
54
+
55
+ logger.info(f"Mock analysis completed. Result: {result}")
56
+ return result
backend/app/services/download.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import httpx
3
+
4
+ from app.core.config import get_settings
5
+ from app.utils.exceptions import (
6
+ FileDownloadError,
7
+ InvalidURLError,
8
+ DownloadTimeoutError,
9
+ FileSizeError,
10
+ )
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ async def download_file(file_url: str) -> bytes:
16
+ """
17
+ Asynchronously download a file from the given URL.
18
+
19
+ Args:
20
+ file_url: The URL of the file to download
21
+
22
+ Returns:
23
+ The file contents as bytes
24
+
25
+ Raises:
26
+ InvalidURLError: If the URL is invalid
27
+ DownloadTimeoutError: If download times out
28
+ FileSizeError: If file size exceeds limit
29
+ FileDownloadError: If download fails for other reasons
30
+ """
31
+ settings = get_settings()
32
+ logger.info(f"Starting file download from: {file_url}")
33
+
34
+ try:
35
+ async with httpx.AsyncClient(timeout=settings.DOWNLOAD_TIMEOUT) as client:
36
+ response = await client.get(file_url, follow_redirects=True)
37
+
38
+ # Check for HTTP errors
39
+ if response.status_code != 200:
40
+ logger.error(
41
+ f"Failed to download file. Status code: {response.status_code}"
42
+ )
43
+ raise FileDownloadError(
44
+ f"Failed to download file. Server returned status code {response.status_code}",
45
+ status_code=response.status_code,
46
+ )
47
+
48
+ # Check content length header
49
+ content_length = response.headers.get("content-length")
50
+ if content_length and int(content_length) > settings.MAX_FILE_SIZE:
51
+ logger.error(
52
+ f"File size exceeds maximum allowed size: {content_length} bytes"
53
+ )
54
+ raise FileSizeError(
55
+ f"File size exceeds maximum allowed size of {settings.MAX_FILE_SIZE} bytes"
56
+ )
57
+
58
+ file_bytes = response.content
59
+
60
+ # Check actual content size
61
+ if len(file_bytes) > settings.MAX_FILE_SIZE:
62
+ logger.error(
63
+ f"Downloaded file exceeds maximum size: {len(file_bytes)} bytes"
64
+ )
65
+ raise FileSizeError(
66
+ f"File size exceeds maximum allowed size of {settings.MAX_FILE_SIZE} bytes"
67
+ )
68
+
69
+ logger.info(
70
+ f"File download completed successfully. Size: {len(file_bytes)} bytes"
71
+ )
72
+ return file_bytes
73
+
74
+ except httpx.InvalidURL as e:
75
+ logger.error(f"Invalid URL provided: {file_url} - {str(e)}")
76
+ raise InvalidURLError("Invalid URL format")
77
+ except httpx.TimeoutException as e:
78
+ logger.error(f"Download timeout for URL: {file_url}")
79
+ raise DownloadTimeoutError("File download timed out. Please try again with a faster source.")
80
+ except (FileSizeError, InvalidURLError, DownloadTimeoutError):
81
+ # Re-raise custom exceptions
82
+ raise
83
+ except httpx.RequestError as e:
84
+ logger.error(f"Failed to download file from {file_url}: {str(e)}")
85
+ raise FileDownloadError(
86
+ "Failed to download file from the provided URL. Please check the URL and try again."
87
+ )
88
+ except Exception as e:
89
+ logger.error(f"Unexpected error during file download: {str(e)}")
90
+ raise FileDownloadError(
91
+ "An unexpected error occurred during file download."
92
+ )
backend/app/services/queue.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import Optional, Any, Dict
3
+ import json
4
+
5
+ from app.core.config import get_settings
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class QueueService:
11
+ """
12
+ Queue service for managing asynchronous analysis tasks.
13
+
14
+ Currently uses in-memory queue, can be extended to use Redis.
15
+ """
16
+
17
+ def __init__(self):
18
+ """Initialize the queue service."""
19
+ self.settings = get_settings()
20
+ self.redis_client = None
21
+
22
+ if self.settings.REDIS_ENABLED:
23
+ self._initialize_redis()
24
+
25
+ def _initialize_redis(self):
26
+ """Initialize Redis connection (future implementation)."""
27
+ # This will be implemented when Redis support is added
28
+ logger.info(
29
+ f"Redis queue service initialized: {self.settings.REDIS_URL}"
30
+ )
31
+
32
+ async def enqueue_analysis(
33
+ self,
34
+ file_url: str,
35
+ model: str,
36
+ task_id: str,
37
+ ) -> bool:
38
+ """
39
+ Enqueue an analysis task.
40
+
41
+ Args:
42
+ file_url: URL of the file to analyze
43
+ model: Detector model to use
44
+ task_id: Unique task identifier
45
+
46
+ Returns:
47
+ True if successful, False otherwise
48
+ """
49
+ task_data = {
50
+ "task_id": task_id,
51
+ "file_url": file_url,
52
+ "model": model,
53
+ }
54
+
55
+ logger.info(f"Enqueuing analysis task: {task_id}")
56
+
57
+ if self.settings.REDIS_ENABLED:
58
+ # Future: Push to Redis queue
59
+ # await self.redis_client.lpush(
60
+ # self.settings.REDIS_QUEUE_NAME,
61
+ # json.dumps(task_data)
62
+ # )
63
+ pass
64
+
65
+ return True
66
+
67
+ async def get_task_result(self, task_id: str) -> Optional[Dict[str, Any]]:
68
+ """
69
+ Get analysis result for a task.
70
+
71
+ Args:
72
+ task_id: Task identifier
73
+
74
+ Returns:
75
+ Analysis result or None if not found
76
+ """
77
+ logger.info(f"Retrieving result for task: {task_id}")
78
+
79
+ if self.settings.REDIS_ENABLED:
80
+ # Future: Get from Redis
81
+ # result = await self.redis_client.get(f"result:{task_id}")
82
+ # return json.loads(result) if result else None
83
+ pass
84
+
85
+ return None
86
+
87
+
88
+ # Singleton instance
89
+ _queue_service: Optional[QueueService] = None
90
+
91
+
92
+ def get_queue_service() -> QueueService:
93
+ """Get or create the queue service singleton."""
94
+ global _queue_service
95
+ if _queue_service is None:
96
+ _queue_service = QueueService()
97
+ return _queue_service
backend/app/utils/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """Utility functions and exception classes."""
backend/app/utils/exceptions.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Custom exception classes."""
2
+
3
+
4
+ class DeepfakeDetectionError(Exception):
5
+ """Base exception for deepfake detection service."""
6
+
7
+ def __init__(self, message: str, status_code: int = 500):
8
+ self.message = message
9
+ self.status_code = status_code
10
+ super().__init__(self.message)
11
+
12
+
13
+ class FileDownloadError(DeepfakeDetectionError):
14
+ """Exception raised when file download fails."""
15
+
16
+ def __init__(self, message: str, status_code: int = 400):
17
+ super().__init__(message, status_code)
18
+
19
+
20
+ class InvalidURLError(DeepfakeDetectionError):
21
+ """Exception raised when URL is invalid."""
22
+
23
+ def __init__(self, message: str = "Invalid URL format"):
24
+ super().__init__(message, 400)
25
+
26
+
27
+ class DownloadTimeoutError(DeepfakeDetectionError):
28
+ """Exception raised when file download times out."""
29
+
30
+ def __init__(self, message: str = "File download timed out"):
31
+ super().__init__(message, 408)
32
+
33
+
34
+ class FileSizeError(DeepfakeDetectionError):
35
+ """Exception raised when file size exceeds limit."""
36
+
37
+ def __init__(self, message: str = "File size exceeds maximum allowed size"):
38
+ super().__init__(message, 400)
39
+
40
+
41
+ class DetectorError(DeepfakeDetectionError):
42
+ """Exception raised when detector model fails."""
43
+
44
+ def __init__(self, message: str = "Deepfake detection failed"):
45
+ super().__init__(message, 500)
46
+
47
+
48
+ class UnsupportedModelError(DeepfakeDetectionError):
49
+ """Exception raised when requested model is not supported."""
50
+
51
+ def __init__(self, model_name: str):
52
+ message = f"Detector model '{model_name}' is not supported"
53
+ super().__init__(message, 400)
backend/main.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Deepfake Detection Service - Backend Entry Point
3
+
4
+ This is the main entry point for the FastAPI application.
5
+ Run this file directly to start the server on localhost:8000
6
+ """
7
+
8
+ import logging
9
+ from app import create_app
10
+ from app.core.config import get_settings
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def main():
16
+ """Initialize and run the FastAPI application."""
17
+ settings = get_settings()
18
+ app = create_app()
19
+
20
+ import uvicorn
21
+
22
+ logger.info(
23
+ f"Starting {settings.APP_NAME} on {settings.HOST}:{settings.PORT}"
24
+ )
25
+
26
+ uvicorn.run(
27
+ app,
28
+ host=settings.HOST,
29
+ port=settings.PORT,
30
+ log_level=settings.LOG_LEVEL.lower(),
31
+ )
32
+
33
+
34
+ if __name__ == "__main__":
35
+ main()
backend/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi==0.115.0
2
+ uvicorn[standard]==0.30.0
3
+ httpx==0.27.0
4
+ pydantic==2.8.2
5
+ pydantic-settings==2.3.1
6
+ python-multipart==0.0.6
backend/run.bat ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ @echo off
2
+ REM Deepfake Detection Service - Windows Run Script
3
+
4
+ echo Starting Deepfake Detection Service Backend...
5
+ python main.py
6
+ pause
backend/setup.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Setup script for the Deepfake Detection Service backend.
4
+
5
+ Run: python setup.py
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import subprocess
11
+
12
+
13
+ def run_command(command, description):
14
+ """Run a command and handle errors."""
15
+ print(f"\n{'='*60}")
16
+ print(f"πŸ“ {description}")
17
+ print(f"{'='*60}")
18
+ try:
19
+ result = subprocess.run(command, shell=True, check=True)
20
+ return result.returncode == 0
21
+ except subprocess.CalledProcessError as e:
22
+ print(f"❌ Error: {description} failed")
23
+ return False
24
+
25
+
26
+ def main():
27
+ """Setup the development environment."""
28
+ print("\n" + "="*60)
29
+ print("πŸš€ Deepfake Detection Service - Backend Setup")
30
+ print("="*60)
31
+
32
+ # Check Python version
33
+ if sys.version_info < (3, 8):
34
+ print("❌ Python 3.8 or higher is required")
35
+ sys.exit(1)
36
+
37
+ print(f"βœ… Python version: {sys.version}")
38
+
39
+ # Determine OS for venv activation
40
+ is_windows = sys.platform == "win32"
41
+ venv_path = "venv"
42
+
43
+ # Create virtual environment
44
+ if not run_command(
45
+ f"{sys.executable} -m venv {venv_path}",
46
+ "Creating virtual environment"
47
+ ):
48
+ sys.exit(1)
49
+
50
+ # Activate venv and install dependencies
51
+ if is_windows:
52
+ activate_cmd = f"{venv_path}\\Scripts\\activate && pip install -r requirements.txt"
53
+ else:
54
+ activate_cmd = f"source {venv_path}/bin/activate && pip install -r requirements.txt"
55
+
56
+ if not run_command(activate_cmd, "Installing dependencies"):
57
+ sys.exit(1)
58
+
59
+ # Create .env file if it doesn't exist
60
+ if not os.path.exists(".env"):
61
+ run_command("copy .env.example .env" if is_windows else "cp .env.example .env",
62
+ "Creating .env file from template")
63
+
64
+ print("\n" + "="*60)
65
+ print("βœ… Setup completed successfully!")
66
+ print("="*60)
67
+ print("\nπŸ“ Next steps:")
68
+ print(f" 1. Activate virtual environment:")
69
+ if is_windows:
70
+ print(f" {venv_path}\\Scripts\\activate")
71
+ else:
72
+ print(f" source {venv_path}/bin/activate")
73
+ print(f"\n 2. Start the server:")
74
+ print(f" python main.py")
75
+ print(f"\n 3. Visit http://127.0.0.1:8000/docs for interactive API docs")
76
+ print(f"\n 4. Check .env file for configuration options")
77
+ print("\n" + "="*60)
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()