Coverage for src/app/main.py: 48%

296 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-04-03 00:42 +0200

1from flask import Flask, request, jsonify 

2from flask_cors import CORS 

3from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity, get_jwt 

4from flask import Flask, request, jsonify 

5 

6import os 

7import fitz 

8import pytz 

9from datetime import datetime 

10 

11from utils.midleware_admin import admin_required 

12 

13from dependencies.encoding import detect_encoding 

14from dependencies.dependency_inj import dependency_injection 

15 

16from dto.answer_dto import AnswerDTO 

17from dto.question_dto import QuestionDTO 

18from dto.file_dto import FileDTO 

19from dto.conversation_dto import ConversationDTO 

20from dto.message_dto import MessageDTO 

21from dto.support_message_dto import SupportMessageDTO 

22from dto.template_dto import TemplateDTO 

23from dto.user_dto import UserDTO 

24 

25 

26italy_tz = pytz.timezone('Europe/Rome') 

27 

28BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 

29UPLOAD_FOLDER = os.path.join(BASE_DIR, "uploads") 

30os.makedirs(UPLOAD_FOLDER, exist_ok=True) 

31 

32app = Flask(__name__) 

33CORS(app) # Enable CORS for all routes 

34 

35# Initialize dependencies 

36dependencies = dependency_injection(app) 

37 

38chat_controller = dependencies["chat_controller"] 

39add_file_controller = dependencies["add_file_controller"] 

40 

41get_conversation_controller = dependencies["get_conversation_controller"] 

42get_conversations_controller = dependencies["get_conversations_controller"] 

43save_conversation_title_controller = dependencies["save_conversation_title_controller"] 

44delete_conversation_controller = dependencies["delete_conversation_controller"] 

45 

46get_message_controller = dependencies["get_message_controller"] 

47get_messages_by_conversation_controller = dependencies["get_messages_by_conversation_controller"] 

48save_message_controller = dependencies["save_message_controller"] 

49 

50get_support_message_controller = dependencies["get_support_message_controller"] 

51get_support_messages_controller = dependencies["get_support_messages_controller"] 

52save_support_message_controller = dependencies["save_support_message_controller"] 

53mark_done_support_message_controller = dependencies["mark_done_support_message_controller"] 

54update_message_rating_controller = dependencies["update_message_rating_controller"] 

55get_dashboard_metrics_controller = dependencies["get_dashboard_metrics_controller"] 

56 

57delete_template_controller = dependencies["delete_template_controller"] 

58get_template_controller = dependencies["get_template_controller"] 

59get_template_list_controller = dependencies["get_template_list_controller"] 

60save_template_controller = dependencies["save_template_controller"] 

61 

62registration_controller = dependencies["registration_controller"] 

63authentication_controller = dependencies["authentication_controller"] 

64 

65# ---- Authentication Routes ---- 

66 

67@app.route("/register", methods=["POST"]) 

68def register(): 

69 """ 

70 curl -X POST http://127.0.0.1:5001/register \ 

71 -H "Content-Type: application/json" \ 

72 -d '{"username": "john", "password": "secret", "email": "john@example.com", "phone": "1234567890", "first_name": "John", "last_name": "Doe"}' 

73 """ 

74 try: 

75 data = request.json 

76 

77 username = data.get("username") 

78 password = data.get("password") 

79 email = data.get("email") 

80 phone = data.get("phone", "") 

81 first_name = data.get("first_name", "") 

82 last_name = data.get("last_name", "") 

83 

84 user_dto = UserDTO( 

85 username=username, 

86 password=password, 

87 email=email, 

88 phone=phone, 

89 first_name=first_name, 

90 last_name=last_name, 

91 is_admin=False 

92 ) 

93 

94 registration_controller.register(user_dto) 

95 

96 return jsonify({"message": "User registered successfully"}), 200 

97 

98 except Exception as e: 

99 return jsonify({"error": str(e)}), 500 

100 

101@app.route("/login", methods=["POST"]) 

102def login(): 

103 """ 

104 curl -X POST http://127.0.0.1:5001/login \ 

105 -H "Content-Type: application/json" \ 

106 -d '{"username": "johnny", "password": "secret"}' 

107 """ 

108 try: 

109 data = request.json 

110 username = data.get("username") 

111 password = data.get("password") 

112 

113 user_dto = UserDTO( 

114 username=username, 

115 password=password 

116 ) 

117 

118 user_result = authentication_controller.login(user_dto) 

119 

120 access_token = create_access_token(identity=str(user_result.get_id()), additional_claims={"is_admin": user_result.get_is_admin()}) 

121 

122 return jsonify({ 

123 "access_token": access_token, 

124 "user": { 

125 "username": user_result.get_username(), 

126 "email": user_result.get_email(), 

127 "phone": user_result.get_phone(), 

128 "first_name": user_result.get_first_name(), 

129 "last_name": user_result.get_last_name() 

130 } 

131 }), 200 

132 

133 except Exception as e: 

134 return jsonify({"error": str(e)}), 500 

135 

136@app.route("/is_admin", methods=["GET"]) 

137@jwt_required() 

138def is_admin(): 

139 """ 

140 Endpoint to check if the user associated with the provided token is an admin. 

141 curl -X GET http://127.0.0.1:5001/is_admin \ 

142 -H "Authorization: Bearer <your_token>" 

143 """ 

144 try: 

145 claims = get_jwt() 

146 is_admin = claims.get("is_admin", False) 

147 return jsonify({"is_admin": is_admin}), 200 

148 except Exception as e: 

149 return jsonify({"error": str(e)}), 500 

150 

151# ---- Conversation Routes ---- 

152@app.route("/conversation/get/<int:conversation_id>", methods=["GET"]) 

153@jwt_required() 

154def get_conversation(conversation_id): 

155 """ 

156 # To test this endpoint with curl: 

157 curl -X GET http://127.0.0.1:5001/conversation/get/<conversation_id> \ 

158 -H "Authorization: Bearer <your_token>" 

159  

160 """ 

161 conversation = ConversationDTO( 

162 id=conversation_id 

163 ) 

164 

165 try: 

166 conversation_result = get_conversation_controller.get_conversation(conversation) 

167 except Exception as e: 

168 return jsonify({"error": str(e)}), 500 

169 

170 return jsonify({ 

171 "id": conversation_result.get_id(), 

172 "title": conversation_result.get_title() 

173 }), 200 

174 

175 

176@app.route("/conversation/get_all", methods=["GET"]) 

177@jwt_required() 

178def get_conversations(): 

179 """ 

180 # To test this endpoint with curl: 

181 curl -X GET http://127.0.0.1:5001/conversation/get_all \ 

182 -H "Authorization: Bearer <your_token>" 

183 """ 

184 try: 

185 user_id = int(get_jwt_identity()) 

186 

187 conversation = ConversationDTO( 

188 user_id=user_id 

189 ) 

190 

191 conversations = get_conversations_controller.get_conversations(conversation) 

192 except Exception as e: 

193 return jsonify({"error": str(e)}), 500 

194 

195 return jsonify([{ 

196 "id": conversation.get_id(), 

197 "title": conversation.get_title(), 

198 "user_id": conversation.get_user_id() 

199 } for conversation in conversations]), 200 

200 

201 

202@app.route("/conversation/save_title", methods=["POST"]) 

203@jwt_required() 

204def save_conversation_title(): 

205 try: 

206 data = request.get_json() 

207 # print("Received data:", data) # Debugging log 

208 user = int(get_jwt_identity()) 

209 # print("User ID:", user) # Debugging log 

210 

211 conversation = ConversationDTO( 

212 title=data.get("title"), 

213 user_id=user 

214 ) 

215 saved_id = save_conversation_title_controller.save_conversation_title(conversation) 

216 except Exception as e: 

217 # print("Error:", str(e)) # Debugging log 

218 return jsonify({"error": str(e)}), 500 

219 

220 return jsonify({"message": f"Conversation title saved with id: {saved_id}"}), 200 

221 

222 

223@app.route("/conversation/delete/<int:conversation_id>", methods=["DELETE"]) 

224@jwt_required() 

225def delete_conversation(conversation_id): 

226 """ 

227 Endpoint to delete a conversation by its ID. 

228 curl -X DELETE http://127.0.0.1:5001/conversation/delete/<conversation_id> \ 

229 -H "Authorization: Bearer <your_token>" 

230 

231 API Call: 

232 - Method: DELETE 

233 - URL: /conversation/delete/<conversation_id> 

234 - Requires JWT Authorization. 

235 

236 Possible Responses: 

237 - 200 OK: {"message": "Conversation deleted successfully"} 

238 - 500 Internal Server Error: {"error": "<error message>"} (if an internal error occurs) 

239 

240 Functionality: 

241 - Validates the conversation ID. 

242 - Calls the controller to delete the conversation. 

243 - Returns a success message or an error in case of issues. 

244 """ 

245 try: 

246 user_id = int(get_jwt_identity()) # Get the user ID from the JWT token 

247 

248 # Create a DTO for the conversation 

249 conversation = ConversationDTO( 

250 id=conversation_id, 

251 user_id=user_id 

252 ) 

253 

254 # Call the controller to delete the conversation 

255 delete_conversation_controller.delete_conversation(conversation) 

256 

257 return jsonify({"message": "Conversation deleted successfully"}), 200 

258 except Exception as e: 

259 return jsonify({"error": str(e)}), 500 

260 

261# ---- Message Routes ---- 

262@app.route("/message/get/<int:message_id>", methods=["GET"]) 

263@jwt_required() 

264def get_message(message_id): 

265 """ 

266 # To test this endpoint with curl: 

267 curl -X GET http://127.0.0.1:5001/message/get/<message_id> \ 

268 -H "Authorization: Bearer <your_token>" 

269 """ 

270 

271 message = MessageDTO( 

272 id=message_id 

273 ) 

274 

275 try: 

276 message_result = get_message_controller.get_message(message) 

277 except Exception as e: 

278 return jsonify({"error": str(e)}), 500 

279 

280 return jsonify({ 

281 "id": message_result.get_id(), 

282 "text": message_result.get_text(), 

283 "is_bot": message_result.get_is_bot(), 

284 "conversation_id": message_result.get_conversation_id(), 

285 "rating": message_result.get_rating(), 

286 "created_at": message_result.get_created_at() 

287 }), 200 

288 

289 

290@app.route("/message/get_by_conversation/<int:conversation_id>", methods=["GET"]) 

291@jwt_required() 

292def get_messages_by_conversation(conversation_id): 

293 """ 

294 # To test this endpoint with curl: 

295 curl -X GET http://127.0.0.1:5001/message/get_by_conversation/<conversation_id> \ 

296 -H "Authorization: Bearer <your_token>" 

297 """ 

298 

299 message = MessageDTO( 

300 conversation_id=conversation_id 

301 ) 

302 

303 try: 

304 messages_result = get_messages_by_conversation_controller.get_messages_by_conversation(message) 

305 

306 except Exception as e: 

307 return jsonify({"error": str(e)}), 500 

308 

309 return jsonify([{ 

310 "id": message.get_id(), 

311 "text": message.get_text(), 

312 "is_bot": message.get_is_bot(), 

313 "conversation_id": message.get_conversation_id(), 

314 "rating": message.get_rating(), 

315 "created_at": message.get_created_at() 

316 } for message in messages_result]), 200 

317 

318 

319@app.route("/message/save", methods=["POST"]) 

320@jwt_required() 

321def save_message(): 

322 """ 

323 # To test this endpoint with curl: 

324 curl -X POST http://127.0.0.1:5001/message/save \ 

325 -H "Content-Type: application/json" \ 

326 -d '{"text": "Message text", "conversation_id": 2, "rating": true, "is_bot": false}' \ 

327 -H "Authorization: Bearer <your_token>"  

328 """ 

329 data = request.get_json() 

330 

331 # Create DTO 

332 message = MessageDTO( 

333 text=data.get("text"), 

334 conversation_id=data.get("conversation_id"), 

335 rating=data.get("rating"), 

336 is_bot=data.get("is_bot"), 

337 created_at=datetime.now(italy_tz) 

338 ) 

339 

340 try: 

341 saved_id = save_message_controller.save_message(message) 

342 except Exception as e: 

343 return jsonify({"error": str(e)}), 500 

344 

345 return jsonify({"message": f"Message saved with id: {saved_id}"}), 200 

346 

347@app.route("/message/update_rating", methods=["POST"]) 

348@jwt_required() 

349def update_message_rating(): 

350 data = request.get_json() 

351 

352 message = MessageDTO( 

353 id=data.get("id"), 

354 rating=data.get("rating") 

355 ) 

356 

357 try: 

358 result = update_message_rating_controller.update_message_rating(message) 

359 except Exception as e: 

360 return jsonify({"error": str(e)}), 500 

361 

362 return jsonify({"message": f"Message rating updated with id: {message.get_id()}"}), 200 

363 

364@app.route("/dashboard/metrics", methods=["GET"]) 

365@admin_required 

366def get_dashboard_metrics(): 

367 """ 

368 Endpoint to calculate and return dashboard metrics. 

369 curl -X GET http://127.0.0.1:5001/dashboard/metrics \ 

370 -H "Authorization: Bearer <your_token>" 

371 """ 

372 try: 

373 

374 metrics_dto = get_dashboard_metrics_controller.get_dashboard_metrics() 

375 

376 return jsonify({ 

377 "total_likes": metrics_dto.get_total_likes(), 

378 "total_dislikes": metrics_dto.get_total_dislikes(), 

379 "total_messages": metrics_dto.get_total_messages(), 

380 "positive_rating": metrics_dto.get_positive_rating() 

381 }), 200 

382 

383 except Exception as e: 

384 return jsonify({"error": str(e)}), 500 

385 

386 

387# ---- Support Message Routes ---- 

388@app.route("/support_message/get/<int:support_message_id>", methods=["GET"]) 

389@admin_required 

390def get_support_message(support_message_id): 

391 """ 

392 # To test this endpoint with curl: 

393 curl -X GET http://127.0.0.1:5001/support_message/get/<support_message_id> \ 

394 -H "Authorization: Bearer <your_token>" 

395 """ 

396 

397 support_message_dto = SupportMessageDTO( 

398 id=support_message_id 

399 ) 

400 

401 try: 

402 support_message = get_support_message_controller.get_support_message(support_message_dto) 

403 except Exception as e: 

404 return jsonify({"error": str(e)}), 500 

405 

406 return jsonify({ 

407 "id": support_message.get_id(), 

408 "user_id": support_message.get_user_id(), 

409 "description": support_message.get_description(), 

410 "status": support_message.get_status(), 

411 "subject": support_message.get_subject(), 

412 "created_at": support_message.get_created_at() 

413 }), 200 

414 

415 

416@app.route("/support_message/get_all", methods=["GET"]) 

417@admin_required 

418def get_support_messages(): 

419 """ 

420 # To test this endpoint with curl: 

421 curl -X GET http://127.0.0.1:5001/support_message/get_all \ 

422 -H "Authorization: Bearer <your_token>" 

423 """ 

424 try: 

425 support_messages = get_support_messages_controller.get_support_messages() 

426 except Exception as e: 

427 return jsonify({"error": str(e)}), 500 

428 

429 return jsonify([{ 

430 "id": message.get_id(), 

431 "user_id": message.get_user_id(), 

432 "user_email": message.get_user_email(), 

433 "description": message.get_description(), 

434 "status": message.get_status(), 

435 "subject": message.get_subject(), 

436 "created_at": message.get_created_at() 

437 } for message in support_messages]), 200 

438 

439 

440@app.route("/support_message/save", methods=["POST"]) 

441@jwt_required() 

442def save_support_message(): 

443 """ 

444 # To test this endpoint with curl: 

445 curl -X POST http://127.0.0.1:5001/support_message/save \ 

446 -H "Content-Type: application/json" \ 

447 -d '{"description": "Support message description", "status": "true", "subject": "Support subject"}' \ 

448 -H "Authorization: Bearer <your_token>" 

449 """ 

450 data = request.get_json() 

451 user_id = int(get_jwt_identity()) 

452 

453 # Create DTO 

454 support_message = SupportMessageDTO( 

455 user_id=user_id, 

456 description=data.get("description"), 

457 status=False, 

458 subject=data.get("subject"), 

459 created_at=datetime.now(italy_tz) 

460 ) 

461 

462 try: 

463 saved_id = save_support_message_controller.save_support_message(support_message) 

464 except Exception as e: 

465 return jsonify({"error": str(e)}), 500 

466 

467 return jsonify({"message": f"Support message saved with id: {saved_id}"}), 200 

468 

469 

470@app.route("/support_message/mark_done/<int:support_message_id>", methods=["POST"]) 

471@admin_required 

472def mark_support_message_done(support_message_id): 

473 """ 

474 Endpoint to mark a support message as done. 

475 curl -X POST http://127.0.0.1:5001/support_message/mark_done/<support_message_id> \ 

476 -H "Authorization: Bearer <your_token>" 

477 """ 

478 try: 

479 # Create DTO with the support message ID and status set to True 

480 support_message_dto = SupportMessageDTO( 

481 id=support_message_id, 

482 status=True 

483 ) 

484 # Call the controller to update the status 

485 result = mark_done_support_message_controller.mark_done_support_messages(support_message_dto) 

486 if result: 

487 return jsonify({"message": f"Support message with id {result} marked as done"}), 200 

488 else: 

489 return jsonify({"error": f"Failed to mark support message with id {result} as done"}), 500 

490 except Exception as e: 

491 return jsonify({"error": str(e)}), 500 

492 

493# ---- Template Routes ---- 

494@app.route("/template/delete/<int:template_id>", methods=["DELETE"]) 

495@admin_required 

496def delete_template(template_id): 

497 """ 

498 # To test this endpoint with curl: 

499 curl -X DELETE http://127.0.0.1:5001/template/delete/<template_id> \ 

500 -H "Authorization: Bearer <your_token>" 

501 """ 

502 template_dto = TemplateDTO( 

503 id=template_id 

504 ) 

505 

506 try: 

507 result = delete_template_controller.delete_template(template_dto) 

508 except Exception as e: 

509 return jsonify({"error": str(e)}), 500 

510 

511 if result: 

512 return jsonify({"message": f"Template with id {template_id} deleted successfully"}), 200 

513 else: 

514 return jsonify({"error": f"Failed to delete template with id {template_id}"}), 500 

515 

516 

517@app.route("/template/get/<int:template_id>", methods=["GET"]) 

518@jwt_required() 

519def get_template(template_id): 

520 """ 

521 # To test this endpoint with curl: 

522 curl -X GET http://127.0.0.1:5001/template/get/<template_id> \ 

523 -H "Authorization: Bearer <your_token>" 

524 """ 

525 

526 template_dto = TemplateDTO( 

527 id=template_id 

528 ) 

529 

530 try: 

531 template = get_template_controller.get_template(template_dto) 

532 except Exception as e: 

533 return jsonify({"error": str(e)}), 500 

534 

535 return jsonify({ 

536 "id": template.get_id(), 

537 "question": template.get_question(), 

538 "answer": template.get_answer(), 

539 "author_id": template.get_author_id(), 

540 "last_modified": template.get_last_modified() 

541 }), 200 

542 

543 

544@app.route("/template/get_list", methods=["GET"]) 

545@jwt_required() 

546def get_template_list(): 

547 """ 

548 # To test this endpoint with curl: 

549 curl -X GET http://127.0.0.1:5001/template/get_list \ 

550 -H "Authorization: Bearer <your_token>" 

551 """ 

552 try: 

553 templates = get_template_list_controller.get_template_list() 

554 except Exception as e: 

555 return jsonify({"error": str(e)}), 500 

556 

557 return jsonify([{ 

558 "id": template.get_id(), 

559 "question": template.get_question(), 

560 "answer": template.get_answer(), 

561 "author_id": template.get_author_id(), 

562 "last_modified": template.get_last_modified() 

563 } for template in templates]), 200 

564 

565 

566@app.route("/template/save", methods=["POST"]) 

567@admin_required 

568def save_template(): 

569 """ 

570 # To test this endpoint with curl: 

571 curl -X POST http://127.0.0.1:5001/template/save \ 

572 -H "Content-Type: application/json" \ 

573 -d '{"question": "Sample question", "answer": "Sample answer"}' \ 

574 -H "Authorization: Bearer <your_token>" 

575 """ 

576 data = request.get_json() 

577 user_id = int(get_jwt_identity()) 

578 

579 # Create DTO 

580 template = TemplateDTO( 

581 question=data.get("question"), 

582 answer=data.get("answer"), 

583 author_id=user_id, 

584 last_modified=datetime.now(italy_tz) 

585 ) 

586 

587 try: 

588 saved_id = save_template_controller.save_template(template) 

589 except Exception as e: 

590 return jsonify({"error": str(e)}), 500 

591 

592 return jsonify({"message": f"Template saved with id: {saved_id}"}), 200 

593 

594 

595@app.route("/api/add_file", methods=["POST"]) 

596@admin_required 

597def add_file(): 

598 """Endpoint to upload a PDF or TXT file. 

599 curl -X POST http://127.0.0.1:5001/api/add_file \ 

600 -H "Authorization: Bearer <your_token>" \ 

601 -F "file=@/path/to/your/file.pdf" 

602 

603 API Call: 

604 - Method: POST 

605 - URL: /api/add_file 

606 - Request Body (multipart/form-data): 

607 - "file": the file to upload (must be PDF or TXT) 

608 

609 Possible Responses: 

610 - 200 OK: {"message": "File successfully uploaded"} 

611 - 400 Bad Request: {"error": "No file part"} (if no file is provided) 

612 - 400 Bad Request: {"error": "No selected file"} (if the file is not selected) 

613 - 400 Bad Request: {"error": "Unsupported file type"} (if the file is not a PDF or TXT) 

614 - 400 Bad Request: {"error": "File encoding not supported. Please use UTF-8."} (if a TXT file has unsupported encoding) 

615 - 400 Bad Request: {"error": "Error reading PDF: <details>"} (if there is an issue reading the PDF) 

616  

617 Functionality: 

618 - Checks if a file was uploaded correctly. 

619 - Validates the file extension (.pdf or .txt). 

620 - Saves the file in UPLOAD_FOLDER. (optional) 

621 - Reads the file content and passes it to the controller via a DTO. 

622 """ 

623 

624 if 'file' not in request.files: 

625 return jsonify({"error": "No file part"}), 400 

626 

627 file = request.files['file'] 

628 if file.filename == '': 

629 return jsonify({"error": "No selected file"}), 400 

630 

631 # verify file type 

632 if not (file.filename.endswith('.pdf') or file.filename.endswith('.txt')): 

633 return jsonify({"error": "Unsupported file type"}), 400 

634 

635 # save file  

636 file_path = os.path.join(UPLOAD_FOLDER, file.filename) 

637 file.save(file_path) 

638 

639 # Read file content 

640 if file.filename.endswith('.txt'): 

641 file_encoding = detect_encoding(file_path) 

642 try: 

643 with open(file_path, 'r', encoding=file_encoding) as f: 

644 file_content = f.read() 

645 except UnicodeDecodeError: 

646 return jsonify({"error": "File encoding not supported. Please use UTF-8."}), 400 

647 

648 elif file.filename.endswith('.pdf'): 

649 try: 

650 doc = fitz.open(file_path) 

651 file_content = "\n".join([page.get_text() for page in doc]) 

652 except Exception as e: 

653 return jsonify({"error": f"Error reading PDF: {str(e)}"}), 400 

654 

655 # DTO and controller 

656 file_dto = FileDTO(file.filename, file_content) 

657 add_file_controller.load_file(file_dto) 

658 

659 return jsonify({"message": "File successfully uploaded"}), 200 

660 

661 

662@app.route("/api/chat_interact", methods=["POST"]) 

663@jwt_required() 

664def chat(): 

665 """Chat endpoint to receive a question and return an answer. 

666 curl -X POST http://localhost:5001/api/chat_interact \ 

667 -H "Content-Type: application/json" \ 

668 -d "{\"question\": \"parlami dell'olio che hai?\"}" \ 

669 -H "Authorization: Bearer <your_token>" 

670  

671 API Call: 

672 - Method: POST 

673 - URL: /api/chat_interact 

674 - Request Body (JSON): 

675 { 

676 "question": "Question text" 

677 } 

678 

679 Possible Responses: 

680 - 200 OK: {"answer": "Generated assistant response"} 

681 - 400 Bad Request: {"error": "Invalid input"} (if required fields are missing) 

682 - 500 Internal Server Error: {"error": "<error message>"} (if an internal error occurs) 

683 

684 Functionality: 

685 - Validates that the request JSON contains "user" and "question" fields. 

686 - Creates a DTO with the user input. 

687 - Calls the controller to generate a response. 

688 - Returns the generated answer or an error in case of issues. 

689  

690 """ 

691 data = request.get_json() 

692 user_id = int(get_jwt_identity()) 

693 

694 # Validate input 

695 if "question" not in data: 

696 return jsonify({"error": "Invalid input"}), 400 

697 

698 question = data["question"] 

699 

700 # Create DTO and get response 

701 user_input = QuestionDTO(user_id, question) 

702 answer = chat_controller.get_answer(user_input) 

703 

704 try: 

705 return jsonify({"answer": answer.get_answer()}), 200 

706 except Exception as e: 

707 return jsonify({"error": str(e)}), 500 

708 

709@app.errorhandler(400) 

710def bad_request(error): 

711 response = jsonify({"error": "Invalid input"}) 

712 response.status_code = 400 

713 return response 

714 

715 

716if __name__ == "__main__": 716 ↛ 717line 716 didn't jump to line 717 because the condition on line 716 was never true

717 app.run(host="0.0.0.0", port=5001, debug=True)