Coverage for src/app/dependencies/dependency_inj.py: 91%

214 statements  

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

1import psycopg2 

2import os 

3from dotenv import load_dotenv 

4from flask import Flask, request, jsonify 

5from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity, get_jwt 

6from flask_bcrypt import Bcrypt 

7from datetime import timedelta 

8 

9from langchain_openai import OpenAIEmbeddings 

10from langchain_community.vectorstores import FAISS 

11from langchain_openai import ChatOpenAI 

12 

13from dependencies.init_vector_store import VECTOR_STORE_PATH, load_vector_store 

14from config.db_config import db_config 

15 

16from controllers.add_file_controller import AddFileController 

17from controllers.chat_controller import ChatController 

18from controllers.delete_template_controller import DeleteTemplateController 

19from controllers.get_conversation_controller import GetConversationController 

20from controllers.get_conversations_controller import GetConversationsController 

21from controllers.get_message_controller import GetMessageController 

22from controllers.get_messages_by_conversation_controller import GetMessagesByConversationController 

23from controllers.get_dashboard_metrics_controller import GetDashboardMetricsController 

24from controllers.get_support_message_controller import GetSupportMessageController 

25from controllers.get_support_messages_controller import GetSupportMessagesController 

26from controllers.mark_done_support_message_contoller import MarkDoneSupportMessagesController 

27from controllers.get_template_controller import GetTemplateController 

28from controllers.get_template_list_controller import GetTemplateListController 

29from controllers.save_conversation_title_controller import SaveConversationTitleController 

30from controllers.delete_conversation_controller import DeleteConversationController 

31from controllers.save_message_controller import SaveMessageController 

32from controllers.update_message_rating_controller import UpdateMessageRatingController 

33from controllers.save_support_message_controller import SaveSupportMessageController 

34from controllers.save_template_controller import SaveTemplateController 

35from controllers.registration_controller import RegistrationController 

36from controllers.authentication_controller import AuthenticationController 

37 

38from services.chat_service import ChatService 

39from services.similarity_search_service import SimilaritySearchService 

40from services.generate_answer_service import GenerateAnswerService 

41from services.add_file_service import AddFileService 

42from services.split_file_service import SplitFileService 

43from services.add_chunks_service import AddChunksService 

44from services.delete_template_service import DeleteTemplateService 

45from services.get_conversation_service import GetConversationService 

46from services.get_conversations_service import GetConversationsService 

47from services.get_message_service import GetMessageService 

48from services.get_messages_by_conversation_service import GetMessagesByConversationService 

49from services.get_dashboard_metrics_services import GetDashboardMetricsService 

50from services.get_support_message_service import GetSupportMessageService 

51from services.get_support_messages_service import GetSupportMessagesService 

52from services.mark_done_support_message_services import MarkDoneSupportMessagesService 

53from services.get_template_list_service import GetTemplateListService 

54from services.get_template_service import GetTemplateService 

55from services.save_conversation_title_service import SaveConversationTitleService 

56from services.delete_conversation_service import DeleteConversationService 

57from services.save_message_service import SaveMessageService 

58from services.update_message_rating_service import UpdateMessageRatingService 

59from services.save_support_message_service import SaveSupportMessageService 

60from services.save_template_service import SaveTemplateService 

61from services.registration_service import RegistrationService 

62from services.validation_service import ValidationService 

63from services.authentication_service import AuthenticationService 

64 

65from adapters.faiss_adapter import FaissAdapter 

66from adapters.langChain_adapter import LangChainAdapter 

67from adapters.conversation_postgres_adapter import ConversationPostgresAdapter 

68from adapters.message_postgres_adapter import MessagePostgresAdapter 

69from adapters.support_message_postgres_adapter import SupportMessagePostgresAdapter 

70from adapters.template_postgres_adapter import TemplatePostgresAdapter 

71from adapters.user_postgres_adapter import UserPostgresAdapter 

72 

73from repositories.faiss_repository import FaissRepository 

74from repositories.langChain_repository import LangChainRepository 

75from repositories.conversation_postgres_repository import ConversationPostgresRepository 

76from repositories.message_postgres_repository import MessagePostgresRepository 

77from repositories.support_message_postgres_repository import SupportMessagePostgresRepository 

78from repositories.template_postgres_repository import TemplatePostgresRepository 

79from repositories.user_postgres_repository import UserPostgresRepository 

80 

81from models.prompt_template_model import PromptTemplateModel 

82 

83load_dotenv() 

84 

85 

86def initialize_postgres(): 

87 """ 

88 """ 

89 try: 

90 

91 conn = psycopg2.connect(**db_config) 

92 with conn.cursor() as cursor: 

93 cursor.execute(""" 

94 CREATE TABLE IF NOT EXISTS Users ( 

95 id SERIAL PRIMARY KEY, 

96 username VARCHAR(256) NOT NULL UNIQUE, 

97 password_hash VARCHAR(512) NOT NULL, 

98 email VARCHAR(256) NOT NULL UNIQUE, 

99 phone CHAR(16), 

100 first_name VARCHAR(256) NOT NULL, 

101 last_name VARCHAR(256) NOT NULL, 

102 is_admin BOOLEAN DEFAULT FALSE 

103 ); 

104 """) 

105 cursor.execute(""" 

106 CREATE TABLE IF NOT EXISTS Conversations ( 

107 id SERIAL PRIMARY KEY, 

108 title VARCHAR(256) NOT NULL 

109 ); 

110 """) 

111 cursor.execute(""" 

112 CREATE TABLE IF NOT EXISTS Messages ( 

113 id SERIAL PRIMARY KEY, 

114 text VARCHAR(1024) NOT NULL, 

115 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, 

116 user_id INTEGER, 

117 conversation_id INTEGER NOT NULL, 

118 rating BOOLEAN, 

119 FOREIGN KEY (user_id) REFERENCES Users(id) ON DELETE CASCADE, 

120 FOREIGN KEY (conversation_id) REFERENCES Conversations(id) ON DELETE CASCADE 

121 ); 

122 """) 

123 cursor.execute(""" 

124 CREATE TABLE IF NOT EXISTS Support ( 

125 id SERIAL PRIMARY KEY, 

126 user_id INTEGER NOT NULL, 

127 description VARCHAR(1024) NOT NULL, 

128 status BOOLEAN DEFAULT FALSE, 

129 subject VARCHAR(256) NOT NULL, 

130 created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, 

131 FOREIGN KEY (user_id) REFERENCES Users(id) ON DELETE CASCADE 

132 ); 

133 """) 

134 cursor.execute(""" 

135 CREATE TABLE IF NOT EXISTS Templates ( 

136 id SERIAL PRIMARY KEY, 

137 question VARCHAR(1024) NOT NULL, 

138 answer VARCHAR(1024) NOT NULL, 

139 author INTEGER NOT NULL, 

140 last_modified TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, 

141 FOREIGN KEY (author) REFERENCES Users(id) ON DELETE CASCADE 

142 ); 

143 """) 

144 conn.commit() 

145 

146 except psycopg2.Error as e: 

147 raise Exception(f"Error connecting to Postgres: {e}") 

148 

149def initialize_langchain() -> LangChainAdapter: 

150 try: 

151 # Read API key from .env 

152 api_key = os.getenv("OPENAI_API_KEY") 

153 if not api_key: 153 ↛ 154line 153 didn't jump to line 154 because the condition on line 153 was never true

154 raise ValueError("OPENAI_API_KEY not found in .env file") 

155 

156 model = ChatOpenAI( 

157 model="gpt-4o-mini", 

158 max_tokens=4000, 

159 temperature=0.7, 

160 request_timeout=15 

161 ) 

162 

163 langchain_repository = LangChainRepository(model) 

164 langchain_adapter = LangChainAdapter(langchain_repository) 

165 

166 return langchain_adapter 

167 

168 except Exception as e: 

169 raise Exception(f"Error initializing LangChain: {e}") 

170 

171 

172def initialize_faiss() -> FaissAdapter: 

173 try: 

174 # Read API key from .env 

175 api_key = os.getenv("OPENAI_API_KEY") 

176 if not api_key: 176 ↛ 177line 176 didn't jump to line 177 because the condition on line 176 was never true

177 raise ValueError("OPENAI_API_KEY not found in .env file") 

178 

179 # OpenAI embedding model 

180 embedding_model = OpenAIEmbeddings(model="text-embedding-3-small", openai_api_key=api_key) 

181 

182 if os.path.exists(VECTOR_STORE_PATH) and os.listdir(VECTOR_STORE_PATH): 182 ↛ 185line 182 didn't jump to line 185 because the condition on line 182 was always true

183 vector_store = load_vector_store(embedding_model) 

184 else: 

185 vector_store = FAISS.from_texts([""], embedding_model) 

186 

187 faiss_repository = FaissRepository(vector_store) 

188 faiss_adapter = FaissAdapter(faiss_repository) 

189 

190 return faiss_adapter 

191 

192 except Exception as e: 

193 raise Exception(f"Error initializing FAISS: {e}") 

194 

195def initialize_prompt_template() -> PromptTemplateModel: 

196 try: 

197 # Define the prompt template for the virtual assistant 

198 template = "Sei un assistente virtuale esperto, progettato per fornire risposte precise, " \ 

199 "esaustive e professionali riguardanti l'azienda Valsana. Rispondi alle domande in italiano con un tono professionale, " \ 

200 "ma accessibile e amichevole, e fai riferimento alle informazioni fornite dall'azienda." 

201 

202 return PromptTemplateModel(template) 

203 except Exception as e: 

204 raise Exception(f"Error initializing prompt template: {e}") 

205 

206 

207def initialize_conversation_postgres() -> ConversationPostgresAdapter: 

208 try: 

209 # Initialize the repository and adapter for conversation-related operations 

210 conversation_postgres_repository = ConversationPostgresRepository(db_config) 

211 

212 return ConversationPostgresAdapter(conversation_postgres_repository) 

213 except Exception as e: 

214 raise Exception(f"Error initializing conversation Postgres adapter: {e}") 

215 

216 

217def initialize_message_postgres() -> MessagePostgresAdapter: 

218 try: 

219 # Initialize the repository and adapter for message-related operations 

220 message_postgres_repository = MessagePostgresRepository(db_config) 

221 

222 return MessagePostgresAdapter(message_postgres_repository) 

223 except Exception as e: 

224 raise Exception(f"Error initializing message Postgres adapter: {e}") 

225 

226 

227def initialize_support_message_postgres() -> SupportMessagePostgresAdapter: 

228 try: 

229 # Initialize the repository and adapter for support message-related operations 

230 support_message_postgres_repository = SupportMessagePostgresRepository(db_config) 

231 

232 return SupportMessagePostgresAdapter(support_message_postgres_repository) 

233 except Exception as e: 

234 raise Exception(f"Error initializing support message Postgres adapter: {e}") 

235 

236 

237def initialize_template_postgres() -> TemplatePostgresAdapter: 

238 try: 

239 # Initialize the repository and adapter for template-related operations 

240 template_postgres_repository = TemplatePostgresRepository(db_config) 

241 

242 return TemplatePostgresAdapter(template_postgres_repository) 

243 except Exception as e: 

244 raise Exception(f"Error initializing template Postgres adapter: {e}") 

245 

246def initialize_user_postgres() -> UserPostgresAdapter: 

247 try: 

248 # Initialize the repository and adapter for user-related operations 

249 user_postgres_repository = UserPostgresRepository(db_config) 

250 

251 return UserPostgresAdapter(user_postgres_repository) 

252 except Exception as e: 

253 raise Exception(f"Error initializing user Postgres adapter: {e}") 

254 

255 

256def dependency_injection(app : Flask) -> dict[str, object]: 

257 """ 

258 Initializes and returns a dictionary of controllers dependencies. 

259 Returns: 

260 - dict[str, object]: A dictionary of controllers dependencies. 

261 """ 

262 try: 

263 

264 # Secure Secret Key 

265 app.config["JWT_SECRET_KEY"] = os.getenv("JWT_SECRET_KEY") 

266 app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=100) # Token expires in 30 min 

267 

268 jwt = JWTManager(app) 

269 bcrypt = Bcrypt(app) 

270 

271 # Initialize Postgres 

272 initialize_postgres() 

273 

274 # Initialize  

275 prompt_template = initialize_prompt_template() 

276 

277 # Adapter 

278 langchain_adapter = initialize_langchain() 

279 faiss_adapter = initialize_faiss() 

280 

281 # Postgres 

282 conversation_postgres_adapter = initialize_conversation_postgres() 

283 message_postgres_adapter = initialize_message_postgres() 

284 support_message_postgres_adapter = initialize_support_message_postgres() 

285 template_postgres_adapter = initialize_template_postgres() 

286 user_postgres_adapter = initialize_user_postgres() 

287 

288 # Services 

289 # Langchain 

290 generate_answer_service = GenerateAnswerService(langchain_adapter, prompt_template) 

291 split_file_service = SplitFileService(langchain_adapter) 

292 

293 # Faiss 

294 similarity_search_service = SimilaritySearchService(faiss_adapter) 

295 add_chunks_service = AddChunksService(faiss_adapter) 

296 

297 # Chat Service 

298 add_file_service = AddFileService(split_file_service, add_chunks_service) 

299 chat_service = ChatService(similarity_search_service, generate_answer_service) 

300 

301 # Postgres 

302 get_conversation_service = GetConversationService(conversation_postgres_adapter) 

303 get_conversations_service = GetConversationsService(conversation_postgres_adapter) 

304 save_conversation_title_service = SaveConversationTitleService(conversation_postgres_adapter) 

305 delete_conversation_service = DeleteConversationService(conversation_postgres_adapter) 

306 

307 get_message_service = GetMessageService(message_postgres_adapter) 

308 get_messages_by_conversation_service = GetMessagesByConversationService(message_postgres_adapter) 

309 save_message_service = SaveMessageService(message_postgres_adapter) 

310 update_message_rating_service = UpdateMessageRatingService(message_postgres_adapter) 

311 get_dashboard_metrics_service = GetDashboardMetricsService(message_postgres_adapter) 

312 

313 get_support_message_service = GetSupportMessageService(support_message_postgres_adapter) 

314 get_support_messages_service = GetSupportMessagesService(support_message_postgres_adapter) 

315 save_support_message_service = SaveSupportMessageService(support_message_postgres_adapter) 

316 mark_done_support_messages_services = MarkDoneSupportMessagesService(support_message_postgres_adapter) 

317 

318 delete_template_service = DeleteTemplateService(template_postgres_adapter) 

319 get_template_service = GetTemplateService(template_postgres_adapter) 

320 get_template_list_service = GetTemplateListService(template_postgres_adapter) 

321 save_template_service = SaveTemplateService(template_postgres_adapter) 

322 

323 validation_service = ValidationService(user_postgres_adapter) 

324 registration_service = RegistrationService(user_postgres_adapter, validation_service, bcrypt) 

325 authentication_service = AuthenticationService(user_postgres_adapter, bcrypt) 

326 

327 

328 # Controllers 

329 add_file_controller = AddFileController(add_file_service) 

330 chat_controller = ChatController(chat_service) 

331 

332 get_conversation_controller = GetConversationController(get_conversation_service) 

333 get_conversations_controller = GetConversationsController(get_conversations_service) 

334 save_conversation_title_controller = SaveConversationTitleController(save_conversation_title_service) 

335 delete_conversation_controller = DeleteConversationController(delete_conversation_service) 

336 

337 get_message_controller = GetMessageController(get_message_service) 

338 get_messages_by_conversation_controller = GetMessagesByConversationController(get_messages_by_conversation_service) 

339 save_message_controller = SaveMessageController(save_message_service) 

340 update_message_rating_controller = UpdateMessageRatingController(update_message_rating_service) 

341 get_dashboard_metrics_controller = GetDashboardMetricsController(get_dashboard_metrics_service) 

342 

343 get_support_message_controller = GetSupportMessageController(get_support_message_service) 

344 get_support_messages_controller = GetSupportMessagesController(get_support_messages_service) 

345 save_support_message_controller = SaveSupportMessageController(save_support_message_service) 

346 mark_done_support_message_controller = MarkDoneSupportMessagesController(mark_done_support_messages_services) 

347 

348 delete_template_controller = DeleteTemplateController(delete_template_service) 

349 get_template_controller = GetTemplateController(get_template_service) 

350 get_template_list_controller = GetTemplateListController(get_template_list_service) 

351 save_template_controller = SaveTemplateController(save_template_service) 

352 

353 registration_controller = RegistrationController(registration_service) 

354 authentication_controller = AuthenticationController(authentication_service) 

355 

356 dependencies = { 

357 "chat_controller": chat_controller, 

358 "add_file_controller": add_file_controller, 

359 "get_conversation_controller": get_conversation_controller, 

360 "get_conversations_controller": get_conversations_controller, 

361 "save_conversation_title_controller": save_conversation_title_controller, 

362 "get_message_controller": get_message_controller, 

363 "get_messages_by_conversation_controller": get_messages_by_conversation_controller, 

364 "save_message_controller": save_message_controller, 

365 "update_message_rating_controller": update_message_rating_controller, 

366 "get_support_message_controller": get_support_message_controller, 

367 "get_support_messages_controller": get_support_messages_controller, 

368 "save_support_message_controller": save_support_message_controller, 

369 "delete_template_controller": delete_template_controller, 

370 "get_template_controller": get_template_controller, 

371 "get_template_list_controller": get_template_list_controller, 

372 "save_template_controller": save_template_controller, 

373 "registration_controller": registration_controller, 

374 "authentication_controller": authentication_controller, 

375 "delete_conversation_controller": delete_conversation_controller, 

376 "mark_done_support_message_controller": mark_done_support_message_controller, 

377 "get_dashboard_metrics_controller": get_dashboard_metrics_controller 

378 } 

379 

380 return dependencies 

381 

382 except Exception as e: 

383 raise Exception(f"Error during dependency injection: {e}") 

384