Aryan Jain commited on
Commit
63dfa98
·
1 Parent(s): b2f266f

categorize the strengths

Browse files
alembic/versions/a3bbab758ddb_categorize_the_analysis.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """categorize the analysis
2
+
3
+ Revision ID: a3bbab758ddb
4
+ Revises: 7fae52a30825
5
+ Create Date: 2025-06-04 14:01:24.366580
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision: str = "a3bbab758ddb"
17
+ down_revision: Union[str, None] = "7fae52a30825"
18
+ branch_labels: Union[str, Sequence[str], None] = None
19
+ depends_on: Union[str, Sequence[str], None] = None
20
+
21
+
22
+ def upgrade() -> None:
23
+ """Upgrade schema."""
24
+ strength_category_enum = sa.Enum(
25
+ "TECHNICAL", "MANAGEMENT", "PAST_PERFORMANCE", "PRICE", name="strengthcategory"
26
+ )
27
+ strength_category_enum.create(op.get_bind())
28
+ op.add_column(
29
+ "proposal_strengths",
30
+ sa.Column(
31
+ "category",
32
+ strength_category_enum,
33
+ nullable=False,
34
+ server_default="TECHNICAL",
35
+ ),
36
+ )
37
+ weakness_category_enum = sa.Enum(
38
+ "TECHNICAL", "MANAGEMENT", "PAST_PERFORMANCE", "PRICE", name="weaknesscategory"
39
+ )
40
+ weakness_category_enum.create(op.get_bind())
41
+ op.add_column(
42
+ "proposal_weaknesses",
43
+ sa.Column(
44
+ "category",
45
+ weakness_category_enum,
46
+ nullable=False,
47
+ server_default="TECHNICAL",
48
+ ),
49
+ )
50
+ rejection_category_enum = sa.Enum(
51
+ "TECHNICAL", "MANAGEMENT", "PAST_PERFORMANCE", "PRICE", name="rejectioncategory"
52
+ )
53
+ rejection_category_enum.create(op.get_bind())
54
+ op.add_column(
55
+ "proposal_rejection_reasons",
56
+ sa.Column(
57
+ "category",
58
+ rejection_category_enum,
59
+ nullable=False,
60
+ server_default="TECHNICAL",
61
+ ),
62
+ )
63
+ improvement_category_enum = sa.Enum(
64
+ "TECHNICAL",
65
+ "MANAGEMENT",
66
+ "PAST_PERFORMANCE",
67
+ "PRICE",
68
+ name="improvementcategory",
69
+ )
70
+ improvement_category_enum.create(op.get_bind())
71
+ op.add_column(
72
+ "proposal_improvements",
73
+ sa.Column(
74
+ "category",
75
+ improvement_category_enum,
76
+ nullable=False,
77
+ server_default="TECHNICAL",
78
+ ),
79
+ )
80
+
81
+
82
+ def downgrade() -> None:
83
+ """Downgrade schema."""
84
+ sa.Enum(name="strengthcategory").drop(op.get_bind(), checkfirst=True)
85
+ op.drop_column("proposal_strengths", "category")
86
+ sa.Enum(name="weaknesscategory").drop(op.get_bind(), checkfirst=True)
87
+ op.drop_column("proposal_weaknesses", "category")
88
+ sa.Enum(name="rejectioncategory").drop(op.get_bind(), checkfirst=True)
89
+ op.drop_column("proposal_rejection_reasons", "category")
90
+ sa.Enum(name="improvementcategory").drop(op.get_bind(), checkfirst=True)
91
+ op.drop_column("proposal_improvements", "category")
src/controllers/_proposal_ai_analysis_controller.py CHANGED
@@ -8,7 +8,7 @@ from src.config import logger
8
 
9
  from src.services import ProposalAIAnalysisService
10
 
11
- from src.models import QueryType, CreateOrUpdateType
12
 
13
 
14
  class ProposalAIAnalysis(BaseModel):
@@ -23,6 +23,7 @@ class ProposalStrength(BaseModel):
23
  id: UUID
24
  proposal_id: UUID
25
  strength_point: str
 
26
  created_at: datetime
27
  updated_at: datetime
28
 
@@ -31,6 +32,7 @@ class ProposalWeakness(BaseModel):
31
  id: UUID
32
  proposal_id: UUID
33
  weakness_point: str
 
34
  created_at: datetime
35
  updated_at: datetime
36
 
@@ -39,6 +41,7 @@ class ProposalRejectionReason(BaseModel):
39
  id: UUID
40
  proposal_id: UUID
41
  reason: str
 
42
  created_at: datetime
43
  updated_at: datetime
44
 
@@ -47,6 +50,7 @@ class ProposalImprovement(BaseModel):
47
  id: UUID
48
  proposal_id: UUID
49
  improvement_point: str
 
50
  created_at: datetime
51
  updated_at: datetime
52
 
@@ -95,13 +99,18 @@ class ProposalImprovementResponse(BaseModel):
95
  status: str
96
  data: Optional[List[ProposalImprovement]]
97
 
 
 
 
 
 
98
 
99
  class ProposalCompleteAnalysis(BaseModel):
100
  ai_score: float
101
- strengths: List[str]
102
- weaknesses: List[str]
103
- rejection_reasons: List[str]
104
- improvements: List[str]
105
 
106
 
107
  class ProposalCompleteAnalysisResponse(BaseModel):
@@ -116,41 +125,49 @@ class DeleteResponse(BaseModel):
116
  class ProposalStrengthRequest(BaseModel):
117
  proposal_id: UUID
118
  strength_point: str
 
119
 
120
 
121
  class UpdateProposalStrengthRequest(BaseModel):
122
  proposal_id: Optional[UUID] = None
123
  strength_point: Optional[str] = None
 
124
 
125
 
126
  class ProposalWeaknessRequest(BaseModel):
127
  proposal_id: UUID
128
  weakness_point: str
 
129
 
130
 
131
  class UpdateProposalWeaknessRequest(BaseModel):
132
  proposal_id: Optional[UUID] = None
133
  weakness_point: Optional[str] = None
 
134
 
135
 
136
  class ProposalRejectionReasonRequest(BaseModel):
137
  proposal_id: UUID
138
  reason: str
 
139
 
140
 
141
  class UpdateProposalRejectionReasonRequest(BaseModel):
142
  proposal_id: Optional[UUID] = None
143
  reason: Optional[str] = None
 
144
 
145
 
146
  class ProposalImprovementRequest(BaseModel):
147
  proposal_id: UUID
148
  improvement_point: str
 
149
 
150
 
151
  class UpdateProposalImprovementRequest(BaseModel):
152
  proposal_id: Optional[UUID] = None
153
  improvement_point: Optional[str] = None
 
154
 
155
 
156
  class CreateAiAnalysisRequest(BaseModel):
@@ -169,34 +186,40 @@ class UpdateAIAnalysisRequestByProposalId(BaseModel):
169
 
170
  class CreateAllProposalStrengthsRequest(BaseModel):
171
  strength_point: List[str]
 
172
 
 
 
173
 
174
  class CreateAllProposalWeaknessRequest(BaseModel):
175
  weakness_point: List[str]
 
176
 
177
 
178
  class CreateAllProposalRejectionReasonsRequest(BaseModel):
179
  reason: List[str]
 
180
 
181
 
182
  class CreateAllProposalImprovementsRequest(BaseModel):
183
  improvement_point: List[str]
 
184
 
185
 
186
  class CreateAllProposalAnalysisRequest(BaseModel):
187
  ai_score: float
188
- strengths: Optional[List[str]] = None
189
- weaknesses: Optional[List[str]] = None
190
- rejection_reasons: Optional[List[str]] = None
191
- improvements: Optional[List[str]] = None
192
 
193
 
194
  class UpdateAllProposalAnalysisRequest(BaseModel):
195
  ai_score: Optional[float] = None
196
- strengths: Optional[List[str]] = None
197
- weaknesses: Optional[List[str]] = None
198
- rejection_reasons: Optional[List[str]] = None
199
- improvements: Optional[List[str]] = None
200
 
201
 
202
  class ProposalAIController:
@@ -204,419 +227,454 @@ class ProposalAIController:
204
  self.__service = ProposalAIAnalysisService
205
  self.router = APIRouter()
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  self.router.add_api_route(
208
- "/proposal-strengths",
209
- self.get_proposal_strengths,
210
- methods=["GET"],
211
- tags=["Proposal Strengths"],
212
- response_model=ProposalStrengthResponse,
213
- )
214
- self.router.add_api_route(
215
- "/proposal-strengths/{id}",
216
- self.get_proposal_strengths_by_id,
217
- methods=["GET"],
218
- tags=["Proposal Strengths by ID"],
219
- response_model=ProposalStrengthResponse,
220
- )
221
- self.router.add_api_route(
222
- "/proposals/{proposal_id}/proposal-strengths",
223
  self.get_proposal_strengths_by_proposal_id,
224
  methods=["GET"],
225
  tags=["Proposal Strengths by Proposal ID"],
226
  response_model=ProposalAllStrengthsResponse,
227
  )
228
  self.router.add_api_route(
229
- "/proposals/{proposal_id}/proposal-strengths/{id}",
230
- self.get_proposal_strengths_by_proposal_and_id,
231
  methods=["GET"],
232
- tags=["Proposal Strengths by Proposal and ID"],
233
- response_model=ProposalStrengthResponse,
234
- )
235
- self.router.add_api_route(
236
- "/proposal-strengths",
237
- self.create_proposal_strengths,
238
- methods=["POST"],
239
- tags=["Proposal Strengths"],
240
- response_model=ProposalStrengthResponse,
241
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  self.router.add_api_route(
243
- "/proposals/{proposal_id}/proposal-strengths",
244
  self.create_all_proposal_strengths,
245
  methods=["POST"],
246
  tags=["Proposal Strengths by Proposal ID"],
247
  response_model=ProposalAllStrengthsResponse,
248
  )
 
 
 
 
 
 
 
249
  self.router.add_api_route(
250
- "/proposal-strengths/{id}",
251
- self.update_proposal_strengths,
252
- methods=["PUT"],
253
- tags=["Proposal Strengths by ID"],
254
- response_model=ProposalStrengthResponse,
255
- )
256
- self.router.add_api_route(
257
- "/proposals/{proposal_id}/proposal-strengths",
258
  self.update_all_proposal_strengths,
259
  methods=["PUT"],
260
- tags=["Proposal Strengths by Proposal ID"],
261
  response_model=ProposalAllStrengthsResponse,
262
  )
 
 
 
 
 
 
 
263
  self.router.add_api_route(
264
- "/proposal-strengths/{id}",
265
- self.delete_proposal_strength,
266
- methods=["DELETE"],
267
- tags=["Proposal Strengths by ID"],
268
- response_model=DeleteResponse,
269
- )
270
- self.router.add_api_route(
271
- "/proposals/{proposal_id}/proposal-strengths",
272
  self.delete_all_proposal_strengths,
273
  methods=["DELETE"],
274
  tags=["Proposal Strengths by Proposal ID"],
275
  response_model=DeleteResponse,
276
  )
277
  self.router.add_api_route(
278
- "/proposals/{proposal_id}/proposal-strengths/{id}",
279
- self.delete_proposal_strengths_by_proposal_and_id,
280
  methods=["DELETE"],
281
- tags=["Proposal Strengths by Proposal and ID"],
282
  response_model=DeleteResponse,
283
  )
284
-
285
- self.router.add_api_route(
286
- "/proposal-weakness",
287
- self.get_proposal_weakness,
288
- methods=["GET"],
289
- tags=["Proposal Weakness"],
290
- response_model=ProposalWeaknessResponse,
291
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  self.router.add_api_route(
293
- "/proposal-weakness/{id}",
294
- self.get_proposal_weakness_by_id,
295
- methods=["GET"],
296
- tags=["Proposal Weakness by ID"],
297
- response_model=ProposalWeaknessResponse,
298
- )
299
- self.router.add_api_route(
300
- "/proposals/{proposal_id}/proposal-weakness",
301
  self.get_proposal_weakness_by_proposal_id,
302
  methods=["GET"],
303
  tags=["Proposal Weakness by Proposal ID"],
304
  response_model=ProposalAllWeaknessesResponse,
305
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  self.router.add_api_route(
307
- "/proposals/{proposal_id}/proposal-weakness/{id}",
308
- self.get_proposal_weakness_by_proposal_and_id,
309
- methods=["GET"],
310
- tags=["Proposal Weakness by Proposal and ID"],
311
- response_model=ProposalWeaknessResponse,
312
- )
313
- self.router.add_api_route(
314
- "/proposal-weakness",
315
- self.create_proposal_weakness,
316
- methods=["POST"],
317
- tags=["Proposal Weakness"],
318
- response_model=ProposalWeaknessResponse,
319
- )
320
- self.router.add_api_route(
321
- "/proposals/{proposal_id}/proposal-weakness",
322
  self.create_all_proposal_weakness,
323
  methods=["POST"],
324
  tags=["Proposal Weakness by Proposal ID"],
325
  response_model=ProposalAllWeaknessesResponse,
326
  )
 
 
 
 
 
 
 
327
  self.router.add_api_route(
328
- "/proposal-weakness/{id}",
329
- self.update_proposal_weakness,
330
- methods=["PUT"],
331
- tags=["Proposal Weakness by ID"],
332
- response_model=ProposalWeaknessResponse,
333
- )
334
- self.router.add_api_route(
335
- "/proposals/{proposal_id}/proposal-weakness",
336
  self.update_all_proposal_weakness,
337
  methods=["PUT"],
338
  tags=["Proposal Weakness by Proposal ID"],
339
  response_model=ProposalAllWeaknessesResponse,
340
  )
 
 
 
 
 
 
 
341
  self.router.add_api_route(
342
- "/proposal-weakness/{id}",
343
- self.delete_proposal_weakness,
344
- methods=["DELETE"],
345
- tags=["Proposal Weakness by ID"],
346
- response_model=DeleteResponse,
347
- )
348
- self.router.add_api_route(
349
- "/proposals/{proposal_id}/proposal-weakness",
350
  self.delete_all_proposal_weakness,
351
  methods=["DELETE"],
352
  tags=["Proposal Weakness by Proposal ID"],
353
  response_model=DeleteResponse,
354
  )
355
  self.router.add_api_route(
356
- "/proposals/{proposal_id}/proposal-weakness/{id}",
357
- self.delete_proposal_weakness_by_proposal_and_id,
358
  methods=["DELETE"],
359
- tags=["Proposal Weakness by Proposal and ID"],
360
  response_model=DeleteResponse,
361
  )
362
-
363
- self.router.add_api_route(
364
- "/proposal-rejections",
365
- self.get_proposal_rejections,
366
- methods=["GET"],
367
- tags=["Proposal Rejections"],
368
- response_model=ProposalRejectionReasonResponse,
369
- )
370
- self.router.add_api_route(
371
- "/proposal-rejections/{id}",
372
- self.get_proposal_rejections_by_id,
373
- methods=["GET"],
374
- tags=["Proposal Rejections by ID"],
375
- response_model=ProposalRejectionReasonResponse,
376
- )
 
 
 
 
 
 
 
377
  self.router.add_api_route(
378
- "/proposals/{proposal_id}/proposal-rejections",
379
  self.get_proposal_rejections_by_proposal_id,
380
  methods=["GET"],
381
  tags=["Proposal Rejections by Proposal ID"],
382
  response_model=ProposalAllRejectionReasonsResponse,
383
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  self.router.add_api_route(
385
- "/proposals/{proposal_id}/proposal-rejections/{id}",
386
- self.get_proposal_rejections_by_proposal_and_id,
387
- methods=["GET"],
388
- tags=["Proposal Rejections by Proposal and ID"],
389
- response_model=ProposalRejectionReasonResponse,
390
- )
391
- self.router.add_api_route(
392
- "/proposal-rejections",
393
- self.create_proposal_rejections,
394
- methods=["POST"],
395
- tags=["Proposal Rejections"],
396
- response_model=ProposalRejectionReasonResponse,
397
- )
398
- self.router.add_api_route(
399
- "/proposals/{proposal_id}/proposal-rejections",
400
  self.create_all_proposal_rejections,
401
  methods=["POST"],
402
  tags=["Proposal Rejections by Proposal ID"],
403
  response_model=ProposalAllRejectionReasonsResponse,
404
  )
 
 
 
 
 
 
 
405
  self.router.add_api_route(
406
- "/proposal-rejections/{id}",
407
- self.update_proposal_rejections,
408
- methods=["PUT"],
409
- tags=["Proposal Rejections by ID"],
410
- response_model=ProposalRejectionReasonResponse,
411
- )
412
- self.router.add_api_route(
413
- "/proposals/{proposal_id}/proposal-rejections",
414
  self.update_all_proposal_rejections,
415
  methods=["PUT"],
416
  tags=["Proposal Rejections by Proposal ID"],
417
  response_model=ProposalAllRejectionReasonsResponse,
418
  )
 
 
 
 
 
 
 
419
  self.router.add_api_route(
420
- "/proposal-rejections/{id}",
421
- self.delete_proposal_rejections,
422
- methods=["DELETE"],
423
- tags=["Proposal Rejections by ID"],
424
- response_model=DeleteResponse,
425
- )
426
- self.router.add_api_route(
427
- "/proposals/{proposal_id}/proposal-rejections",
428
  self.delete_all_proposal_rejections,
429
  methods=["DELETE"],
430
  tags=["Proposal Rejections by Proposal ID"],
431
  response_model=DeleteResponse,
432
  )
433
  self.router.add_api_route(
434
- "/proposals/{proposal_id}/proposal-rejections/{id}",
435
- self.delete_proposal_rejections_by_proposal_and_id,
436
  methods=["DELETE"],
437
- tags=["Proposal Rejections by Proposal and ID"],
438
  response_model=DeleteResponse,
439
  )
440
-
441
- self.router.add_api_route(
442
- "/proposal-improvements",
443
- self.get_proposal_improvements,
444
- methods=["GET"],
445
- tags=["Proposal Improvements"],
446
- response_model=ProposalImprovementResponse,
447
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  self.router.add_api_route(
449
- "/proposal-improvements/{id}",
450
- self.get_proposal_improvements_by_id,
451
- methods=["GET"],
452
- tags=["Proposal Improvements by ID"],
453
- response_model=ProposalImprovementResponse,
454
- )
455
- self.router.add_api_route(
456
- "/proposals/{proposal_id}/proposal-improvements",
457
  self.get_proposal_improvements_by_proposal_id,
458
  methods=["GET"],
459
  tags=["Proposal Improvements by Proposal ID"],
460
  response_model=ProposalAllImprovementsResponse,
461
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  self.router.add_api_route(
463
- "/proposals/{proposal_id}/proposal-improvements/{id}",
464
- self.get_proposal_improvements_by_proposal_and_id,
465
- methods=["GET"],
466
- tags=["Proposal Improvements by Proposal and ID"],
467
- response_model=ProposalImprovementResponse,
468
- )
469
- self.router.add_api_route(
470
- "/proposal-improvements",
471
- self.create_proposal_improvements,
472
- methods=["POST"],
473
- tags=["Proposal Improvements"],
474
- response_model=ProposalImprovementResponse,
475
- )
476
- self.router.add_api_route(
477
- "/proposals/{proposal_id}/proposal-improvements",
478
  self.create_all_proposal_improvements,
479
  methods=["POST"],
480
  tags=["Proposal Improvements by Proposal ID"],
481
  response_model=ProposalAllImprovementsResponse,
482
  )
 
 
 
 
 
 
 
483
  self.router.add_api_route(
484
- "/proposal-improvements/{id}",
485
- self.update_proposal_improvements,
486
- methods=["PUT"],
487
- tags=["Proposal Improvements by ID"],
488
- response_model=ProposalImprovementResponse,
489
- )
490
- self.router.add_api_route(
491
- "/proposals/{proposal_id}/proposal-improvements",
492
  self.update_all_proposal_improvements,
493
  methods=["PUT"],
494
  tags=["Proposal Improvements by Proposal ID"],
495
  response_model=ProposalAllImprovementsResponse,
496
  )
 
 
 
 
 
 
 
497
  self.router.add_api_route(
498
- "/proposal-improvements/{id}",
499
- self.delete_proposal_improvements,
500
- methods=["DELETE"],
501
- tags=["Proposal Improvements by ID"],
502
- response_model=DeleteResponse,
503
- )
504
- self.router.add_api_route(
505
- "/proposals/{proposal_id}/proposal-improvements",
506
  self.delete_all_proposal_improvements,
507
  methods=["DELETE"],
508
  tags=["Proposal Improvements by Proposal ID"],
509
  response_model=DeleteResponse,
510
  )
511
  self.router.add_api_route(
512
- "/proposals/{proposal_id}/proposal-improvements/{id}",
513
- self.delete_proposal_improvements_by_proposal_and_id,
514
  methods=["DELETE"],
515
- tags=["Proposal Improvements by Proposal and ID"],
516
  response_model=DeleteResponse,
517
  )
518
-
519
- self.router.add_api_route(
520
- "/proposal-ai-score",
521
- self.get_proposal_ai_score,
522
- methods=["GET"],
523
- tags=["Proposal AI Score"],
524
- response_model=ProposalAIAnalysisResponse,
525
- )
526
- self.router.add_api_route(
527
- "/proposal-ai-score/{id}",
528
- self.get_proposal_ai_score_by_id,
529
- methods=["GET"],
530
- tags=["Proposal AI Score by ID"],
531
- response_model=ProposalAIAnalysisResponse,
532
- )
 
 
 
 
 
 
 
533
  self.router.add_api_route(
534
- "/proposals/{proposal_id}/proposal-ai-score",
535
  self.get_proposal_ai_score_by_proposal_id,
536
  methods=["GET"],
537
  tags=["Proposal AI Score by Proposal ID"],
538
  response_model=ProposalAIAnalysisResponse,
539
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
  self.router.add_api_route(
541
- "/proposals/{proposal_id}/proposal-ai-score/{id}",
542
- self.get_proposal_ai_score_by_proposal_and_id,
543
- methods=["GET"],
544
- tags=["Proposal AI Score by Proposal and ID"],
545
- response_model=ProposalAIAnalysisResponse,
546
- )
547
- self.router.add_api_route(
548
- "/proposal-ai-score",
549
- self.create_proposal_ai_score,
550
- methods=["POST"],
551
- tags=["Proposal AI Score"],
552
- response_model=ProposalAIAnalysisResponse,
553
- )
554
- self.router.add_api_route(
555
- "/proposals/{proposal_id}/proposal-ai-score",
556
  self.create_proposal_ai_score_by_proposal_id,
557
  methods=["POST"],
558
  tags=["Proposal AI Score by Proposal ID"],
559
  response_model=ProposalAIAnalysisResponse,
560
  )
 
 
 
 
 
 
 
561
  self.router.add_api_route(
562
- "/proposal-ai-score/{id}",
563
- self.update_proposal_ai_score,
564
- methods=["PUT"],
565
- tags=["Proposal AI Score by ID"],
566
- response_model=ProposalAIAnalysisResponse,
567
- )
568
- self.router.add_api_route(
569
- "/proposals/{proposal_id}/proposal-ai-score",
570
  self.update_proposal_ai_score_by_proposal_id,
571
  methods=["PUT"],
572
  tags=["Proposal AI Score by Proposal ID"],
573
  response_model=ProposalAIAnalysisResponse,
574
  )
 
 
 
 
 
 
 
575
  self.router.add_api_route(
576
- "/proposal-ai-score/{id}",
577
- self.delete_proposal_ai_score,
578
- methods=["DELETE"],
579
- tags=["Proposal AI Score by ID"],
580
- response_model=DeleteResponse,
581
- )
582
- self.router.add_api_route(
583
- "/proposals/{proposal_id}/proposal-ai-score",
584
  self.delete_proposal_ai_score_by_proposal_id,
585
  methods=["DELETE"],
586
  tags=["Proposal AI Score by Proposal ID"],
587
  response_model=DeleteResponse,
588
  )
589
- self.router.add_api_route(
590
- "/proposals/{proposal_id}/proposal-ai-score/{id}",
591
- self.delete_proposal_ai_score_by_proposal_and_id,
592
- methods=["DELETE"],
593
- tags=["Proposal AI Score by Proposal and ID"],
594
- response_model=DeleteResponse,
595
- )
596
 
597
  self.router.add_api_route(
598
- "/proposals/{proposal_id}/proposal-analysis",
599
  self.get_all_proposal_analysis,
600
  methods=["GET"],
601
  tags=["Proposal Complete Analysis"],
602
  response_model=ProposalCompleteAnalysisResponse,
603
  )
604
  self.router.add_api_route(
605
- "/proposals/{proposal_id}/proposal-analysis",
606
  self.create_proposal_analysis,
607
  methods=["POST"],
608
  tags=["Proposal Complete Analysis"],
609
  response_model=ProposalCompleteAnalysisResponse,
610
  )
611
  self.router.add_api_route(
612
- "/proposals/{proposal_id}/proposal-analysis",
613
  self.update_proposal_analysis,
614
  methods=["PUT"],
615
  tags=["Proposal Complete Analysis"],
616
  response_model=ProposalCompleteAnalysisResponse,
617
  )
618
  self.router.add_api_route(
619
- "/proposals/{proposal_id}/proposal-analysis",
620
  self.delete_proposal_analysis,
621
  methods=["DELETE"],
622
  tags=["Proposal Complete Analysis"],
@@ -655,7 +713,7 @@ class ProposalAIController:
655
  status_code=500, detail="Failed to retrieve strength."
656
  )
657
 
658
- async def get_proposal_strengths_by_proposal_id(self, proposal_id: UUID = Path(...)):
659
  async with self.__service() as service:
660
  try:
661
  strength = await service.get_all_data(
@@ -670,7 +728,22 @@ class ProposalAIController:
670
  status_code=500, detail="Failed to retrieve strength."
671
  )
672
 
673
- async def get_proposal_strengths_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  async with self.__service() as service:
675
  try:
676
  strength = await service.get_all_data(
@@ -703,7 +776,7 @@ class ProposalAIController:
703
  )
704
 
705
  async def create_all_proposal_strengths(
706
- self, strengths: CreateAllProposalStrengthsRequest, proposal_id: UUID = Path(...)
707
  ):
708
  async with self.__service() as service:
709
  try:
@@ -743,12 +816,13 @@ class ProposalAIController:
743
  )
744
 
745
  async def update_all_proposal_strengths(
746
- self, strengths: CreateAllProposalStrengthsRequest, proposal_id: UUID = Path(...)
747
  ):
748
  async with self.__service() as service:
749
  try:
750
  strengths_request = strengths.model_dump(mode="json", exclude_unset=True)
751
  strengths_request["proposal_id"] = proposal_id
 
752
  updated = await service.update_data(
753
  query_type=QueryType.STRENGTHS,
754
  create_or_update_type=CreateOrUpdateType.ALL,
@@ -778,7 +852,7 @@ class ProposalAIController:
778
  status_code=500, detail="Failed to delete strength."
779
  )
780
 
781
- async def delete_all_proposal_strengths(self, proposal_id: UUID = Path(...)):
782
  async with self.__service() as service:
783
  try:
784
  result = await service.delete_data(
@@ -791,7 +865,20 @@ class ProposalAIController:
791
  status_code=500, detail="Failed to delete strengths."
792
  )
793
 
794
- async def delete_proposal_strengths_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
795
  async with self.__service() as service:
796
  try:
797
  result = await service.delete_data(
@@ -836,11 +923,11 @@ class ProposalAIController:
836
  status_code=500, detail="Failed to retrieve weakness."
837
  )
838
 
839
- async def get_proposal_weakness_by_proposal_id(self, proposal_id: UUID = Path(...)):
840
  async with self.__service() as service:
841
  try:
842
  weakness = await service.get_all_data(
843
- query_type=QueryType.WEAKNESSES, proposal_id=proposal_id
844
  )
845
  return ProposalAllWeaknessesResponse(
846
  status="success", data=[w["weakness_point"] for w in weakness]
@@ -851,7 +938,7 @@ class ProposalAIController:
851
  status_code=500, detail="Failed to retrieve weakness."
852
  )
853
 
854
- async def get_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
855
  async with self.__service() as service:
856
  try:
857
  weakness = await service.get_all_data(
@@ -960,7 +1047,7 @@ class ProposalAIController:
960
  )
961
 
962
  async def delete_all_proposal_weakness(
963
- self, proposal_id: UUID = Path(...)
964
  ):
965
  async with self.__service() as service:
966
  try:
@@ -974,7 +1061,20 @@ class ProposalAIController:
974
  status_code=500, detail="Failed to delete weaknesses."
975
  )
976
 
977
- async def delete_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
978
  async with self.__service() as service:
979
  try:
980
  result = await service.delete_data(
@@ -1020,11 +1120,11 @@ class ProposalAIController:
1020
  status_code=500, detail="Failed to retrieve rejection reason."
1021
  )
1022
 
1023
- async def get_proposal_rejections_by_proposal_id(self, proposal_id: UUID = Path(...)):
1024
  async with self.__service() as service:
1025
  try:
1026
  rejection_reason = await service.get_all_data(
1027
- query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id
1028
  )
1029
  return ProposalAllRejectionReasonsResponse(
1030
  status="success", data=[r["reason"] for r in rejection_reason]
@@ -1035,7 +1135,7 @@ class ProposalAIController:
1035
  status_code=500, detail="Failed to retrieve rejection reason."
1036
  )
1037
 
1038
- async def get_proposal_rejections_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
1039
  async with self.__service() as service:
1040
  try:
1041
  rejection_reason = await service.get_all_data(
@@ -1071,7 +1171,7 @@ class ProposalAIController:
1071
  )
1072
 
1073
  async def create_all_proposal_rejections(
1074
- self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...)
1075
  ):
1076
  async with self.__service() as service:
1077
  try:
@@ -1115,7 +1215,7 @@ class ProposalAIController:
1115
  )
1116
 
1117
  async def update_all_proposal_rejections(
1118
- self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...)
1119
  ):
1120
  async with self.__service() as service:
1121
  try:
@@ -1153,7 +1253,7 @@ class ProposalAIController:
1153
  )
1154
 
1155
  async def delete_all_proposal_rejections(
1156
- self, proposal_id: UUID = Path(...)
1157
  ):
1158
  async with self.__service() as service:
1159
  try:
@@ -1168,6 +1268,23 @@ class ProposalAIController:
1168
  status_code=500, detail="Failed to delete rejection reasons."
1169
  )
1170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1171
  async def delete_proposal_rejections_by_proposal_and_id(
1172
  self, proposal_id: UUID = Path(...), id: UUID = Path(...)
1173
  ):
@@ -1223,13 +1340,14 @@ class ProposalAIController:
1223
  )
1224
 
1225
  async def get_proposal_improvements_by_proposal_id(
1226
- self, proposal_id: UUID = Path(...)
1227
  ):
1228
  async with self.__service() as service:
1229
  try:
1230
  improvements = await service.get_all_data(
1231
  query_type=QueryType.IMPROVEMENTS,
1232
- proposal_id=proposal_id
 
1233
  )
1234
  return ProposalAllImprovementsResponse(
1235
  status="success",
@@ -1281,7 +1399,7 @@ class ProposalAIController:
1281
  )
1282
 
1283
  async def create_all_proposal_improvements(
1284
- self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...)
1285
  ):
1286
  async with self.__service() as service:
1287
  try:
@@ -1323,7 +1441,7 @@ class ProposalAIController:
1323
  )
1324
 
1325
  async def update_all_proposal_improvements(
1326
- self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...)
1327
  ):
1328
  async with self.__service() as service:
1329
  try:
@@ -1359,7 +1477,7 @@ class ProposalAIController:
1359
  )
1360
 
1361
  async def delete_all_proposal_improvements(
1362
- self, proposal_id: UUID = Path(...)
1363
  ):
1364
  async with self.__service() as service:
1365
  try:
@@ -1373,6 +1491,21 @@ class ProposalAIController:
1373
  status_code=500, detail="Failed to delete improvements."
1374
  )
1375
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1376
  async def delete_proposal_improvements_by_proposal_and_id(
1377
  self, id: UUID = Path(...), proposal_id: UUID = Path(...)
1378
  ):
@@ -1423,7 +1556,7 @@ class ProposalAIController:
1423
  )
1424
 
1425
  async def get_proposal_ai_score_by_proposal_id(
1426
- self, proposal_id: UUID = Path(...)
1427
  ):
1428
  async with self.__service() as service:
1429
  try:
@@ -1473,7 +1606,7 @@ class ProposalAIController:
1473
  status_code=500, detail="Failed to create AI score."
1474
  )
1475
 
1476
- async def create_proposal_ai_score_by_proposal_id(self, score: CreateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...)):
1477
  async with self.__service() as service:
1478
  try:
1479
  data = score.model_dump(mode="json", exclude_unset=True)
@@ -1512,7 +1645,7 @@ class ProposalAIController:
1512
  status_code=500, detail="Failed to update AI score."
1513
  )
1514
 
1515
- async def update_proposal_ai_score_by_proposal_id(self, score: UpdateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...)):
1516
  async with self.__service() as service:
1517
  try:
1518
  data = score.model_dump(mode="json", exclude_unset=True)
@@ -1547,7 +1680,7 @@ class ProposalAIController:
1547
  )
1548
 
1549
  async def delete_proposal_ai_score_by_proposal_id(
1550
- self, proposal_id: UUID = Path(...)
1551
  ):
1552
  async with self.__service() as service:
1553
  try:
@@ -1576,7 +1709,7 @@ class ProposalAIController:
1576
  status_code=500, detail="Failed to delete AI score."
1577
  )
1578
 
1579
- async def get_all_proposal_analysis(self, proposal_id: UUID = Path(...)):
1580
  async with self.__service() as service:
1581
  try:
1582
  analysis = await service.get_all_data(
@@ -1593,7 +1726,7 @@ class ProposalAIController:
1593
  )
1594
 
1595
  async def create_proposal_analysis(
1596
- self, analysis: CreateAllProposalAnalysisRequest, proposal_id: UUID = Path(...)
1597
  ):
1598
  async with self.__service() as service:
1599
  try:
@@ -1615,7 +1748,7 @@ class ProposalAIController:
1615
  )
1616
 
1617
  async def update_proposal_analysis(
1618
- self, analysis: UpdateAllProposalAnalysisRequest, proposal_id: UUID = Path(...)
1619
  ):
1620
  async with self.__service() as service:
1621
  try:
@@ -1636,7 +1769,7 @@ class ProposalAIController:
1636
  status_code=500, detail="Failed to update analysis."
1637
  )
1638
 
1639
- async def delete_proposal_analysis(self, proposal_id: UUID = Path(...)):
1640
  async with self.__service() as service:
1641
  try:
1642
  result = await service.delete_data(
 
8
 
9
  from src.services import ProposalAIAnalysisService
10
 
11
+ from src.models import QueryType, CreateOrUpdateType, Category
12
 
13
 
14
  class ProposalAIAnalysis(BaseModel):
 
23
  id: UUID
24
  proposal_id: UUID
25
  strength_point: str
26
+ category: Category
27
  created_at: datetime
28
  updated_at: datetime
29
 
 
32
  id: UUID
33
  proposal_id: UUID
34
  weakness_point: str
35
+ category: Category
36
  created_at: datetime
37
  updated_at: datetime
38
 
 
41
  id: UUID
42
  proposal_id: UUID
43
  reason: str
44
+ category: Category
45
  created_at: datetime
46
  updated_at: datetime
47
 
 
50
  id: UUID
51
  proposal_id: UUID
52
  improvement_point: str
53
+ category: Category
54
  created_at: datetime
55
  updated_at: datetime
56
 
 
99
  status: str
100
  data: Optional[List[ProposalImprovement]]
101
 
102
+ class Analysis(BaseModel):
103
+ strengths: Optional[List[str]] = None
104
+ weaknesses: Optional[List[str]] = None
105
+ rejection_reasons: Optional[List[str]] = None
106
+ improvements: Optional[List[str]] = None
107
 
108
  class ProposalCompleteAnalysis(BaseModel):
109
  ai_score: float
110
+ technical: Optional[Analysis] = None
111
+ management: Optional[Analysis] = None
112
+ past_performance: Optional[Analysis] = None
113
+ price: Optional[Analysis] = None
114
 
115
 
116
  class ProposalCompleteAnalysisResponse(BaseModel):
 
125
  class ProposalStrengthRequest(BaseModel):
126
  proposal_id: UUID
127
  strength_point: str
128
+ category: Category
129
 
130
 
131
  class UpdateProposalStrengthRequest(BaseModel):
132
  proposal_id: Optional[UUID] = None
133
  strength_point: Optional[str] = None
134
+ category: Optional[Category] = None
135
 
136
 
137
  class ProposalWeaknessRequest(BaseModel):
138
  proposal_id: UUID
139
  weakness_point: str
140
+ category: Category
141
 
142
 
143
  class UpdateProposalWeaknessRequest(BaseModel):
144
  proposal_id: Optional[UUID] = None
145
  weakness_point: Optional[str] = None
146
+ category: Optional[Category] = None
147
 
148
 
149
  class ProposalRejectionReasonRequest(BaseModel):
150
  proposal_id: UUID
151
  reason: str
152
+ category: Category
153
 
154
 
155
  class UpdateProposalRejectionReasonRequest(BaseModel):
156
  proposal_id: Optional[UUID] = None
157
  reason: Optional[str] = None
158
+ category: Optional[Category] = None
159
 
160
 
161
  class ProposalImprovementRequest(BaseModel):
162
  proposal_id: UUID
163
  improvement_point: str
164
+ category: Category
165
 
166
 
167
  class UpdateProposalImprovementRequest(BaseModel):
168
  proposal_id: Optional[UUID] = None
169
  improvement_point: Optional[str] = None
170
+ category: Optional[Category] = None
171
 
172
 
173
  class CreateAiAnalysisRequest(BaseModel):
 
186
 
187
  class CreateAllProposalStrengthsRequest(BaseModel):
188
  strength_point: List[str]
189
+ category: Category
190
 
191
+ class UpdateAllProposalStrengthsRequest(BaseModel):
192
+ strength_point: Optional[List[str]] = None
193
 
194
  class CreateAllProposalWeaknessRequest(BaseModel):
195
  weakness_point: List[str]
196
+ category: Category
197
 
198
 
199
  class CreateAllProposalRejectionReasonsRequest(BaseModel):
200
  reason: List[str]
201
+ category: Category
202
 
203
 
204
  class CreateAllProposalImprovementsRequest(BaseModel):
205
  improvement_point: List[str]
206
+ category: Category
207
 
208
 
209
  class CreateAllProposalAnalysisRequest(BaseModel):
210
  ai_score: float
211
+ technical: Optional[Analysis] = None
212
+ management: Optional[Analysis] = None
213
+ past_performance: Optional[Analysis] = None
214
+ price: Optional[Analysis] = None
215
 
216
 
217
  class UpdateAllProposalAnalysisRequest(BaseModel):
218
  ai_score: Optional[float] = None
219
+ technical: Optional[Analysis] = None
220
+ management: Optional[Analysis] = None
221
+ past_performance: Optional[Analysis] = None
222
+ price: Optional[Analysis] = None
223
 
224
 
225
  class ProposalAIController:
 
227
  self.__service = ProposalAIAnalysisService
228
  self.router = APIRouter()
229
 
230
+ # self.router.add_api_route(
231
+ # "/proposal-strengths",
232
+ # self.get_proposal_strengths,
233
+ # methods=["GET"],
234
+ # tags=["Proposal Strengths"],
235
+ # response_model=ProposalStrengthResponse,
236
+ # )
237
+ # self.router.add_api_route(
238
+ # "/proposal-strengths/{id}",
239
+ # self.get_proposal_strengths_by_id,
240
+ # methods=["GET"],
241
+ # tags=["Proposal Strengths by ID"],
242
+ # response_model=ProposalStrengthResponse,
243
+ # )
244
  self.router.add_api_route(
245
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  self.get_proposal_strengths_by_proposal_id,
247
  methods=["GET"],
248
  tags=["Proposal Strengths by Proposal ID"],
249
  response_model=ProposalAllStrengthsResponse,
250
  )
251
  self.router.add_api_route(
252
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths/{category}",
253
+ self.get_proposal_strengths_by_proposal_and_category,
254
  methods=["GET"],
255
+ tags=["Proposal Strengths by Proposal and Category"],
256
+ response_model=ProposalAllStrengthsResponse,
 
 
 
 
 
 
 
257
  )
258
+ # self.router.add_api_route(
259
+ # "/rfps/{rfp_id}/proposals/{proposal_id}/strengths/{id}",
260
+ # self.get_proposal_strengths_by_proposal_and_id,
261
+ # methods=["GET"],
262
+ # tags=["Proposal Strengths by Proposal and ID"],
263
+ # response_model=ProposalStrengthResponse,
264
+ # )
265
+ # self.router.add_api_route(
266
+ # "/proposal-strengths",
267
+ # self.create_proposal_strengths,
268
+ # methods=["POST"],
269
+ # tags=["Proposal Strengths"],
270
+ # response_model=ProposalStrengthResponse,
271
+ # )
272
  self.router.add_api_route(
273
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths",
274
  self.create_all_proposal_strengths,
275
  methods=["POST"],
276
  tags=["Proposal Strengths by Proposal ID"],
277
  response_model=ProposalAllStrengthsResponse,
278
  )
279
+ # self.router.add_api_route(
280
+ # "/proposal-strengths/{id}",
281
+ # self.update_proposal_strengths,
282
+ # methods=["PUT"],
283
+ # tags=["Proposal Strengths by ID"],
284
+ # response_model=ProposalStrengthResponse,
285
+ # )
286
  self.router.add_api_route(
287
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths/{category}",
 
 
 
 
 
 
 
288
  self.update_all_proposal_strengths,
289
  methods=["PUT"],
290
+ tags=["Proposal Strengths by Proposal and Category"],
291
  response_model=ProposalAllStrengthsResponse,
292
  )
293
+ # self.router.add_api_route(
294
+ # "/proposal-strengths/{id}",
295
+ # self.delete_proposal_strength,
296
+ # methods=["DELETE"],
297
+ # tags=["Proposal Strengths by ID"],
298
+ # response_model=DeleteResponse,
299
+ # )
300
  self.router.add_api_route(
301
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths",
 
 
 
 
 
 
 
302
  self.delete_all_proposal_strengths,
303
  methods=["DELETE"],
304
  tags=["Proposal Strengths by Proposal ID"],
305
  response_model=DeleteResponse,
306
  )
307
  self.router.add_api_route(
308
+ "/rfps/{rfp_id}/proposals/{proposal_id}/strengths/{category}",
309
+ self.delete_proposal_strengths_by_proposal_and_category,
310
  methods=["DELETE"],
311
+ tags=["Proposal Strengths by Proposal and Category"],
312
  response_model=DeleteResponse,
313
  )
314
+ # self.router.add_api_route(
315
+ # "rfps/{rfp_id}/proposals/{proposal_id}/strengths/{id}",
316
+ # self.delete_proposal_strengths_by_proposal_and_id,
317
+ # methods=["DELETE"],
318
+ # tags=["Proposal Strengths by Proposal and ID"],
319
+ # response_model=DeleteResponse,
320
+ # )
321
+
322
+ # self.router.add_api_route(
323
+ # "/proposal-weakness",
324
+ # self.get_proposal_weakness,
325
+ # methods=["GET"],
326
+ # tags=["Proposal Weakness"],
327
+ # response_model=ProposalWeaknessResponse,
328
+ # )
329
+ # self.router.add_api_route(
330
+ # "/proposal-weakness/{id}",
331
+ # self.get_proposal_weakness_by_id,
332
+ # methods=["GET"],
333
+ # tags=["Proposal Weakness by ID"],
334
+ # response_model=ProposalWeaknessResponse,
335
+ # )
336
  self.router.add_api_route(
337
+ "/rfps/{rfp_id}/proposals/{proposal_id}/weakness",
 
 
 
 
 
 
 
338
  self.get_proposal_weakness_by_proposal_id,
339
  methods=["GET"],
340
  tags=["Proposal Weakness by Proposal ID"],
341
  response_model=ProposalAllWeaknessesResponse,
342
  )
343
+ # self.router.add_api_route(
344
+ # "/rfps/{rfp_id}/proposals/{proposal_id}/weakness/{id}",
345
+ # self.get_proposal_weakness_by_proposal_and_id,
346
+ # methods=["GET"],
347
+ # tags=["Proposal Weakness by Proposal and ID"],
348
+ # response_model=ProposalWeaknessResponse,
349
+ # )
350
+ # self.router.add_api_route(
351
+ # "/proposal-weakness",
352
+ # self.create_proposal_weakness,
353
+ # methods=["POST"],
354
+ # tags=["Proposal Weakness"],
355
+ # response_model=ProposalWeaknessResponse,
356
+ # )
357
  self.router.add_api_route(
358
+ "/rfps/{rfp_id}/proposals/{proposal_id}/weakness",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  self.create_all_proposal_weakness,
360
  methods=["POST"],
361
  tags=["Proposal Weakness by Proposal ID"],
362
  response_model=ProposalAllWeaknessesResponse,
363
  )
364
+ # self.router.add_api_route(
365
+ # "/proposal-weakness/{id}",
366
+ # self.update_proposal_weakness,
367
+ # methods=["PUT"],
368
+ # tags=["Proposal Weakness by ID"],
369
+ # response_model=ProposalWeaknessResponse,
370
+ # )
371
  self.router.add_api_route(
372
+ "/rfps/{rfp_id}/proposals/{proposal_id}/weakness",
 
 
 
 
 
 
 
373
  self.update_all_proposal_weakness,
374
  methods=["PUT"],
375
  tags=["Proposal Weakness by Proposal ID"],
376
  response_model=ProposalAllWeaknessesResponse,
377
  )
378
+ # self.router.add_api_route(
379
+ # "/proposal-weakness/{id}",
380
+ # self.delete_proposal_weakness,
381
+ # methods=["DELETE"],
382
+ # tags=["Proposal Weakness by ID"],
383
+ # response_model=DeleteResponse,
384
+ # )
385
  self.router.add_api_route(
386
+ "/rfps/{rfp_id}/proposals/{proposal_id}/weakness",
 
 
 
 
 
 
 
387
  self.delete_all_proposal_weakness,
388
  methods=["DELETE"],
389
  tags=["Proposal Weakness by Proposal ID"],
390
  response_model=DeleteResponse,
391
  )
392
  self.router.add_api_route(
393
+ "/rfps/{rfp_id}/proposals/{proposal_id}/weakness/{category}",
394
+ self.delete_proposal_weakness_by_proposal_and_category,
395
  methods=["DELETE"],
396
+ tags=["Proposal Weakness by Proposal and Category"],
397
  response_model=DeleteResponse,
398
  )
399
+ # self.router.add_api_route(
400
+ # "/rfps/{rfp_id}/proposals/{proposal_id}/weakness/{id}",
401
+ # self.delete_proposal_weakness_by_proposal_and_id,
402
+ # methods=["DELETE"],
403
+ # tags=["Proposal Weakness by Proposal and ID"],
404
+ # response_model=DeleteResponse,
405
+ # )
406
+
407
+ # self.router.add_api_route(
408
+ # "/proposal-rejections",
409
+ # self.get_proposal_rejections,
410
+ # methods=["GET"],
411
+ # tags=["Proposal Rejections"],
412
+ # response_model=ProposalRejectionReasonResponse,
413
+ # )
414
+ # self.router.add_api_route(
415
+ # "/proposal-rejections/{id}",
416
+ # self.get_proposal_rejections_by_id,
417
+ # methods=["GET"],
418
+ # tags=["Proposal Rejections by ID"],
419
+ # response_model=ProposalRejectionReasonResponse,
420
+ # )
421
  self.router.add_api_route(
422
+ "/rfps/{rfp_id}/proposals/{proposal_id}/rejections",
423
  self.get_proposal_rejections_by_proposal_id,
424
  methods=["GET"],
425
  tags=["Proposal Rejections by Proposal ID"],
426
  response_model=ProposalAllRejectionReasonsResponse,
427
  )
428
+ # self.router.add_api_route(
429
+ # "/rfps/{rfp_id}/proposals/{proposal_id}/rejections/{id}",
430
+ # self.get_proposal_rejections_by_proposal_and_id,
431
+ # methods=["GET"],
432
+ # tags=["Proposal Rejections by Proposal and ID"],
433
+ # response_model=ProposalRejectionReasonResponse,
434
+ # )
435
+ # self.router.add_api_route(
436
+ # "/proposal-rejections",
437
+ # self.create_proposal_rejections,
438
+ # methods=["POST"],
439
+ # tags=["Proposal Rejections"],
440
+ # response_model=ProposalRejectionReasonResponse,
441
+ # )
442
  self.router.add_api_route(
443
+ "/rfps/{rfp_id}/proposals/{proposal_id}/rejections",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  self.create_all_proposal_rejections,
445
  methods=["POST"],
446
  tags=["Proposal Rejections by Proposal ID"],
447
  response_model=ProposalAllRejectionReasonsResponse,
448
  )
449
+ # self.router.add_api_route(
450
+ # "/proposal-rejections/{id}",
451
+ # self.update_proposal_rejections,
452
+ # methods=["PUT"],
453
+ # tags=["Proposal Rejections by ID"],
454
+ # response_model=ProposalRejectionReasonResponse,
455
+ # )
456
  self.router.add_api_route(
457
+ "/rfps/{rfp_id}/proposals/{proposal_id}/rejections",
 
 
 
 
 
 
 
458
  self.update_all_proposal_rejections,
459
  methods=["PUT"],
460
  tags=["Proposal Rejections by Proposal ID"],
461
  response_model=ProposalAllRejectionReasonsResponse,
462
  )
463
+ # self.router.add_api_route(
464
+ # "/proposal-rejections/{id}",
465
+ # self.delete_proposal_rejections,
466
+ # methods=["DELETE"],
467
+ # tags=["Proposal Rejections by ID"],
468
+ # response_model=DeleteResponse,
469
+ # )
470
  self.router.add_api_route(
471
+ "/rfps/{rfp_id}/proposals/{proposal_id}/rejections",
 
 
 
 
 
 
 
472
  self.delete_all_proposal_rejections,
473
  methods=["DELETE"],
474
  tags=["Proposal Rejections by Proposal ID"],
475
  response_model=DeleteResponse,
476
  )
477
  self.router.add_api_route(
478
+ "/rfps/{rfp_id}/proposals/{proposal_id}/rejections/{category}",
479
+ self.delete_proposal_rejections_by_proposal_and_category,
480
  methods=["DELETE"],
481
+ tags=["Proposal Rejections by Proposal and Category"],
482
  response_model=DeleteResponse,
483
  )
484
+ # self.router.add_api_route(
485
+ # "/rfps/{rfp_id}/proposals/{proposal_id}/proposal-rejections/{id}",
486
+ # self.delete_proposal_rejections_by_proposal_and_id,
487
+ # methods=["DELETE"],
488
+ # tags=["Proposal Rejections by Proposal and ID"],
489
+ # response_model=DeleteResponse,
490
+ # )
491
+
492
+ # self.router.add_api_route(
493
+ # "/proposal-improvements",
494
+ # self.get_proposal_improvements,
495
+ # methods=["GET"],
496
+ # tags=["Proposal Improvements"],
497
+ # response_model=ProposalImprovementResponse,
498
+ # )
499
+ # self.router.add_api_route(
500
+ # "/proposal-improvements/{id}",
501
+ # self.get_proposal_improvements_by_id,
502
+ # methods=["GET"],
503
+ # tags=["Proposal Improvements by ID"],
504
+ # response_model=ProposalImprovementResponse,
505
+ # )
506
  self.router.add_api_route(
507
+ "/rfps/{rfp_id}/proposals/{proposal_id}/improvements",
 
 
 
 
 
 
 
508
  self.get_proposal_improvements_by_proposal_id,
509
  methods=["GET"],
510
  tags=["Proposal Improvements by Proposal ID"],
511
  response_model=ProposalAllImprovementsResponse,
512
  )
513
+ # self.router.add_api_route(
514
+ # "/proposals/{proposal_id}/proposal-improvements/{id}",
515
+ # self.get_proposal_improvements_by_proposal_and_id,
516
+ # methods=["GET"],
517
+ # tags=["Proposal Improvements by Proposal and ID"],
518
+ # response_model=ProposalImprovementResponse,
519
+ # )
520
+ # self.router.add_api_route(
521
+ # "/proposal-improvements",
522
+ # self.create_proposal_improvements,
523
+ # methods=["POST"],
524
+ # tags=["Proposal Improvements"],
525
+ # response_model=ProposalImprovementResponse,
526
+ # )
527
  self.router.add_api_route(
528
+ "/rfps/{rfp_id}/proposals/{proposal_id}/improvements",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  self.create_all_proposal_improvements,
530
  methods=["POST"],
531
  tags=["Proposal Improvements by Proposal ID"],
532
  response_model=ProposalAllImprovementsResponse,
533
  )
534
+ # self.router.add_api_route(
535
+ # "/proposal-improvements/{id}",
536
+ # self.update_proposal_improvements,
537
+ # methods=["PUT"],
538
+ # tags=["Proposal Improvements by ID"],
539
+ # response_model=ProposalImprovementResponse,
540
+ # )
541
  self.router.add_api_route(
542
+ "/rfps/{rfp_id}/proposals/{proposal_id}/improvements",
 
 
 
 
 
 
 
543
  self.update_all_proposal_improvements,
544
  methods=["PUT"],
545
  tags=["Proposal Improvements by Proposal ID"],
546
  response_model=ProposalAllImprovementsResponse,
547
  )
548
+ # self.router.add_api_route(
549
+ # "/proposal-improvements/{id}",
550
+ # self.delete_proposal_improvements,
551
+ # methods=["DELETE"],
552
+ # tags=["Proposal Improvements by ID"],
553
+ # response_model=DeleteResponse,
554
+ # )
555
  self.router.add_api_route(
556
+ "/rfps/{rfp_id}/proposals/{proposal_id}/improvements",
 
 
 
 
 
 
 
557
  self.delete_all_proposal_improvements,
558
  methods=["DELETE"],
559
  tags=["Proposal Improvements by Proposal ID"],
560
  response_model=DeleteResponse,
561
  )
562
  self.router.add_api_route(
563
+ "/rfps/{rfp_id}/proposals/{proposal_id}/improvements/{category}",
564
+ self.delete_proposal_improvements_by_proposal_and_category,
565
  methods=["DELETE"],
566
+ tags=["Proposal Improvements by Proposal and Category"],
567
  response_model=DeleteResponse,
568
  )
569
+ # self.router.add_api_route(
570
+ # "/proposals/{proposal_id}/proposal-improvements/{id}",
571
+ # self.delete_proposal_improvements_by_proposal_and_id,
572
+ # methods=["DELETE"],
573
+ # tags=["Proposal Improvements by Proposal and ID"],
574
+ # response_model=DeleteResponse,
575
+ # )
576
+
577
+ # self.router.add_api_route(
578
+ # "/proposal-ai-score",
579
+ # self.get_proposal_ai_score,
580
+ # methods=["GET"],
581
+ # tags=["Proposal AI Score"],
582
+ # response_model=ProposalAIAnalysisResponse,
583
+ # )
584
+ # self.router.add_api_route(
585
+ # "/proposal-ai-score/{id}",
586
+ # self.get_proposal_ai_score_by_id,
587
+ # methods=["GET"],
588
+ # tags=["Proposal AI Score by ID"],
589
+ # response_model=ProposalAIAnalysisResponse,
590
+ # )
591
  self.router.add_api_route(
592
+ "/rfps/{rfp_id}/proposals/{proposal_id}/ai-score",
593
  self.get_proposal_ai_score_by_proposal_id,
594
  methods=["GET"],
595
  tags=["Proposal AI Score by Proposal ID"],
596
  response_model=ProposalAIAnalysisResponse,
597
  )
598
+ # self.router.add_api_route(
599
+ # "/proposals/{proposal_id}/proposal-ai-score/{id}",
600
+ # self.get_proposal_ai_score_by_proposal_and_id,
601
+ # methods=["GET"],
602
+ # tags=["Proposal AI Score by Proposal and ID"],
603
+ # response_model=ProposalAIAnalysisResponse,
604
+ # )
605
+ # self.router.add_api_route(
606
+ # "/proposal-ai-score",
607
+ # self.create_proposal_ai_score,
608
+ # methods=["POST"],
609
+ # tags=["Proposal AI Score"],
610
+ # response_model=ProposalAIAnalysisResponse,
611
+ # )
612
  self.router.add_api_route(
613
+ "/rfps/{rfp_id}/proposals/{proposal_id}/ai-score",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
  self.create_proposal_ai_score_by_proposal_id,
615
  methods=["POST"],
616
  tags=["Proposal AI Score by Proposal ID"],
617
  response_model=ProposalAIAnalysisResponse,
618
  )
619
+ # self.router.add_api_route(
620
+ # "/proposal-ai-score/{id}",
621
+ # self.update_proposal_ai_score,
622
+ # methods=["PUT"],
623
+ # tags=["Proposal AI Score by ID"],
624
+ # response_model=ProposalAIAnalysisResponse,
625
+ # )
626
  self.router.add_api_route(
627
+ "/rfps/{rfp_id}/proposals/{proposal_id}/ai-score",
 
 
 
 
 
 
 
628
  self.update_proposal_ai_score_by_proposal_id,
629
  methods=["PUT"],
630
  tags=["Proposal AI Score by Proposal ID"],
631
  response_model=ProposalAIAnalysisResponse,
632
  )
633
+ # self.router.add_api_route(
634
+ # "/proposal-ai-score/{id}",
635
+ # self.delete_proposal_ai_score,
636
+ # methods=["DELETE"],
637
+ # tags=["Proposal AI Score by ID"],
638
+ # response_model=DeleteResponse,
639
+ # )
640
  self.router.add_api_route(
641
+ "/rfps/{rfp_id}/proposals/{proposal_id}/ai-score",
 
 
 
 
 
 
 
642
  self.delete_proposal_ai_score_by_proposal_id,
643
  methods=["DELETE"],
644
  tags=["Proposal AI Score by Proposal ID"],
645
  response_model=DeleteResponse,
646
  )
647
+ # self.router.add_api_route(
648
+ # "/proposals/{proposal_id}/proposal-ai-score/{id}",
649
+ # self.delete_proposal_ai_score_by_proposal_and_id,
650
+ # methods=["DELETE"],
651
+ # tags=["Proposal AI Score by Proposal and ID"],
652
+ # response_model=DeleteResponse,
653
+ # )
654
 
655
  self.router.add_api_route(
656
+ "/rfps/{rfp_id}/proposals/{proposal_id}/analysis",
657
  self.get_all_proposal_analysis,
658
  methods=["GET"],
659
  tags=["Proposal Complete Analysis"],
660
  response_model=ProposalCompleteAnalysisResponse,
661
  )
662
  self.router.add_api_route(
663
+ "/rfps/{rfp_id}/proposals/{proposal_id}/analysis",
664
  self.create_proposal_analysis,
665
  methods=["POST"],
666
  tags=["Proposal Complete Analysis"],
667
  response_model=ProposalCompleteAnalysisResponse,
668
  )
669
  self.router.add_api_route(
670
+ "/rfps/{rfp_id}/proposals/{proposal_id}/analysis",
671
  self.update_proposal_analysis,
672
  methods=["PUT"],
673
  tags=["Proposal Complete Analysis"],
674
  response_model=ProposalCompleteAnalysisResponse,
675
  )
676
  self.router.add_api_route(
677
+ "/rfps/{rfp_id}/proposals/{proposal_id}/analysis",
678
  self.delete_proposal_analysis,
679
  methods=["DELETE"],
680
  tags=["Proposal Complete Analysis"],
 
713
  status_code=500, detail="Failed to retrieve strength."
714
  )
715
 
716
+ async def get_proposal_strengths_by_proposal_id(self, rfp_id: UUID = Path(...), proposal_id: UUID = Path(...)):
717
  async with self.__service() as service:
718
  try:
719
  strength = await service.get_all_data(
 
728
  status_code=500, detail="Failed to retrieve strength."
729
  )
730
 
731
+ async def get_proposal_strengths_by_proposal_and_category(self, rfp_id: UUID = Path(...), proposal_id: UUID = Path(...), category: Category = Path(...)):
732
+ async with self.__service() as service:
733
+ try:
734
+ strength = await service.get_all_data(
735
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id, category=category
736
+ )
737
+ return ProposalAllStrengthsResponse(
738
+ status="success", data=[s["strength_point"] for s in strength]
739
+ )
740
+ except Exception as e:
741
+ logger.exception(e)
742
+ raise HTTPException(
743
+ status_code=500, detail="Failed to retrieve strength."
744
+ )
745
+
746
+ async def get_proposal_strengths_by_proposal_and_id(self, rfp_id: UUID = Path(...), proposal_id: UUID = Path(...), id: UUID = Path(...)):
747
  async with self.__service() as service:
748
  try:
749
  strength = await service.get_all_data(
 
776
  )
777
 
778
  async def create_all_proposal_strengths(
779
+ self, strengths: CreateAllProposalStrengthsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
780
  ):
781
  async with self.__service() as service:
782
  try:
 
816
  )
817
 
818
  async def update_all_proposal_strengths(
819
+ self, strengths: UpdateAllProposalStrengthsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...), category: Category = Path(...)
820
  ):
821
  async with self.__service() as service:
822
  try:
823
  strengths_request = strengths.model_dump(mode="json", exclude_unset=True)
824
  strengths_request["proposal_id"] = proposal_id
825
+ strengths_request["category"] = category
826
  updated = await service.update_data(
827
  query_type=QueryType.STRENGTHS,
828
  create_or_update_type=CreateOrUpdateType.ALL,
 
852
  status_code=500, detail="Failed to delete strength."
853
  )
854
 
855
+ async def delete_all_proposal_strengths(self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)):
856
  async with self.__service() as service:
857
  try:
858
  result = await service.delete_data(
 
865
  status_code=500, detail="Failed to delete strengths."
866
  )
867
 
868
+ async def delete_proposal_strengths_by_proposal_and_category(self, proposal_id: UUID = Path(...), category: Category = Path(...), rfp_id: UUID = Path(...)):
869
+ async with self.__service() as service:
870
+ try:
871
+ result = await service.delete_data(
872
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id, category=category
873
+ )
874
+ return DeleteResponse(status="success")
875
+ except Exception as e:
876
+ logger.exception(e)
877
+ raise HTTPException(
878
+ status_code=500, detail="Failed to delete strength."
879
+ )
880
+
881
+ async def delete_proposal_strengths_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...), rfp_id: UUID = Path(...)):
882
  async with self.__service() as service:
883
  try:
884
  result = await service.delete_data(
 
923
  status_code=500, detail="Failed to retrieve weakness."
924
  )
925
 
926
+ async def get_proposal_weakness_by_proposal_id(self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...), category: Category = Query(None)):
927
  async with self.__service() as service:
928
  try:
929
  weakness = await service.get_all_data(
930
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id, category=category
931
  )
932
  return ProposalAllWeaknessesResponse(
933
  status="success", data=[w["weakness_point"] for w in weakness]
 
938
  status_code=500, detail="Failed to retrieve weakness."
939
  )
940
 
941
+ async def get_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...), rfp_id: UUID = Path(...)):
942
  async with self.__service() as service:
943
  try:
944
  weakness = await service.get_all_data(
 
1047
  )
1048
 
1049
  async def delete_all_proposal_weakness(
1050
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1051
  ):
1052
  async with self.__service() as service:
1053
  try:
 
1061
  status_code=500, detail="Failed to delete weaknesses."
1062
  )
1063
 
1064
+ async def delete_proposal_weakness_by_proposal_and_category(self, proposal_id: UUID = Path(...), category: Category = Path(...), rfp_id: UUID = Path(...)):
1065
+ async with self.__service() as service:
1066
+ try:
1067
+ result = await service.delete_data(
1068
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id, category=category
1069
+ )
1070
+ return DeleteResponse(status="success")
1071
+ except Exception as e:
1072
+ logger.exception(e)
1073
+ raise HTTPException(
1074
+ status_code=500, detail="Failed to delete weakness."
1075
+ )
1076
+
1077
+ async def delete_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...), rfp_id: UUID = Path(...)):
1078
  async with self.__service() as service:
1079
  try:
1080
  result = await service.delete_data(
 
1120
  status_code=500, detail="Failed to retrieve rejection reason."
1121
  )
1122
 
1123
+ async def get_proposal_rejections_by_proposal_id(self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...), category: Category = Query(None)):
1124
  async with self.__service() as service:
1125
  try:
1126
  rejection_reason = await service.get_all_data(
1127
+ query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id, category=category
1128
  )
1129
  return ProposalAllRejectionReasonsResponse(
1130
  status="success", data=[r["reason"] for r in rejection_reason]
 
1135
  status_code=500, detail="Failed to retrieve rejection reason."
1136
  )
1137
 
1138
+ async def get_proposal_rejections_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...), rfp_id: UUID = Path(...)):
1139
  async with self.__service() as service:
1140
  try:
1141
  rejection_reason = await service.get_all_data(
 
1171
  )
1172
 
1173
  async def create_all_proposal_rejections(
1174
+ self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1175
  ):
1176
  async with self.__service() as service:
1177
  try:
 
1215
  )
1216
 
1217
  async def update_all_proposal_rejections(
1218
+ self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1219
  ):
1220
  async with self.__service() as service:
1221
  try:
 
1253
  )
1254
 
1255
  async def delete_all_proposal_rejections(
1256
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1257
  ):
1258
  async with self.__service() as service:
1259
  try:
 
1268
  status_code=500, detail="Failed to delete rejection reasons."
1269
  )
1270
 
1271
+ async def delete_proposal_rejections_by_proposal_and_category(
1272
+ self, proposal_id: UUID = Path(...), category: str = Path(...), rfp_id: UUID = Path(...)
1273
+ ):
1274
+ async with self.__service() as service:
1275
+ try:
1276
+ result = await service.delete_data(
1277
+ query_type=QueryType.REJECTION_REASONS,
1278
+ category=category,
1279
+ proposal_id=proposal_id
1280
+ )
1281
+ return DeleteResponse(status="success")
1282
+ except Exception as e:
1283
+ logger.exception(e)
1284
+ raise HTTPException(
1285
+ status_code=500, detail="Failed to delete rejection reason."
1286
+ )
1287
+
1288
  async def delete_proposal_rejections_by_proposal_and_id(
1289
  self, proposal_id: UUID = Path(...), id: UUID = Path(...)
1290
  ):
 
1340
  )
1341
 
1342
  async def get_proposal_improvements_by_proposal_id(
1343
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...), category: Category = Query(None)
1344
  ):
1345
  async with self.__service() as service:
1346
  try:
1347
  improvements = await service.get_all_data(
1348
  query_type=QueryType.IMPROVEMENTS,
1349
+ proposal_id=proposal_id,
1350
+ category=category
1351
  )
1352
  return ProposalAllImprovementsResponse(
1353
  status="success",
 
1399
  )
1400
 
1401
  async def create_all_proposal_improvements(
1402
+ self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1403
  ):
1404
  async with self.__service() as service:
1405
  try:
 
1441
  )
1442
 
1443
  async def update_all_proposal_improvements(
1444
+ self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1445
  ):
1446
  async with self.__service() as service:
1447
  try:
 
1477
  )
1478
 
1479
  async def delete_all_proposal_improvements(
1480
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1481
  ):
1482
  async with self.__service() as service:
1483
  try:
 
1491
  status_code=500, detail="Failed to delete improvements."
1492
  )
1493
 
1494
+ async def delete_proposal_improvements_by_proposal_and_category(
1495
+ self, category: str = Path(...), proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1496
+ ):
1497
+ async with self.__service() as service:
1498
+ try:
1499
+ result = await service.delete_data(
1500
+ query_type=QueryType.IMPROVEMENTS, category=category, proposal_id=proposal_id
1501
+ )
1502
+ return DeleteResponse(status="success")
1503
+ except Exception as e:
1504
+ logger.exception(e)
1505
+ raise HTTPException(
1506
+ status_code=500, detail="Failed to delete improvement."
1507
+ )
1508
+
1509
  async def delete_proposal_improvements_by_proposal_and_id(
1510
  self, id: UUID = Path(...), proposal_id: UUID = Path(...)
1511
  ):
 
1556
  )
1557
 
1558
  async def get_proposal_ai_score_by_proposal_id(
1559
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1560
  ):
1561
  async with self.__service() as service:
1562
  try:
 
1606
  status_code=500, detail="Failed to create AI score."
1607
  )
1608
 
1609
+ async def create_proposal_ai_score_by_proposal_id(self, score: CreateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)):
1610
  async with self.__service() as service:
1611
  try:
1612
  data = score.model_dump(mode="json", exclude_unset=True)
 
1645
  status_code=500, detail="Failed to update AI score."
1646
  )
1647
 
1648
+ async def update_proposal_ai_score_by_proposal_id(self, score: UpdateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)):
1649
  async with self.__service() as service:
1650
  try:
1651
  data = score.model_dump(mode="json", exclude_unset=True)
 
1680
  )
1681
 
1682
  async def delete_proposal_ai_score_by_proposal_id(
1683
+ self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1684
  ):
1685
  async with self.__service() as service:
1686
  try:
 
1709
  status_code=500, detail="Failed to delete AI score."
1710
  )
1711
 
1712
+ async def get_all_proposal_analysis(self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)):
1713
  async with self.__service() as service:
1714
  try:
1715
  analysis = await service.get_all_data(
 
1726
  )
1727
 
1728
  async def create_proposal_analysis(
1729
+ self, analysis: CreateAllProposalAnalysisRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1730
  ):
1731
  async with self.__service() as service:
1732
  try:
 
1748
  )
1749
 
1750
  async def update_proposal_analysis(
1751
+ self, analysis: UpdateAllProposalAnalysisRequest, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)
1752
  ):
1753
  async with self.__service() as service:
1754
  try:
 
1769
  status_code=500, detail="Failed to update analysis."
1770
  )
1771
 
1772
+ async def delete_proposal_analysis(self, proposal_id: UUID = Path(...), rfp_id: UUID = Path(...)):
1773
  async with self.__service() as service:
1774
  try:
1775
  result = await service.delete_data(
src/models/__init__.py CHANGED
@@ -7,6 +7,7 @@ from ._proposal_ai_analysis import (
7
  ProposalWeakness,
8
  ProposalImprovement,
9
  ProposalRejectionReason,
 
10
  )
11
  from ._proposal_detailed_analysis import ProposalDetailAnalysis, OperationCriteria
12
  from ._proposal_query_models import QueryType, CreateOrUpdateType
@@ -33,6 +34,7 @@ __all__ = [
33
  "EvaluationCriteria",
34
  "EvaluationCriteriaType",
35
  "RFPStatus",
 
36
  ]
37
  __version__ = "0.1.0"
38
  __author__ = "Aryan Jain"
 
7
  ProposalWeakness,
8
  ProposalImprovement,
9
  ProposalRejectionReason,
10
+ Category
11
  )
12
  from ._proposal_detailed_analysis import ProposalDetailAnalysis, OperationCriteria
13
  from ._proposal_query_models import QueryType, CreateOrUpdateType
 
34
  "EvaluationCriteria",
35
  "EvaluationCriteriaType",
36
  "RFPStatus",
37
+ "Category",
38
  ]
39
  __version__ = "0.1.0"
40
  __author__ = "Aryan Jain"
src/models/_proposal_ai_analysis.py CHANGED
@@ -13,6 +13,11 @@ from sqlalchemy import (
13
  from sqlalchemy.dialects.postgresql import UUID
14
  from ._base import Base
15
 
 
 
 
 
 
16
 
17
  class ProposalAIAnalysis(Base):
18
  __tablename__ = "proposal_ai_analyses"
@@ -40,6 +45,7 @@ class ProposalStrength(Base):
40
  nullable=False,
41
  )
42
  strength_point = Column(String, nullable=False)
 
43
  created_at = Column(DateTime, nullable=False, default=func.now())
44
  updated_at = Column(
45
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
@@ -56,6 +62,7 @@ class ProposalRejectionReason(Base):
56
  nullable=False,
57
  )
58
  reason = Column(String, nullable=False)
 
59
  created_at = Column(DateTime, nullable=False, default=func.now())
60
  updated_at = Column(
61
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
@@ -72,6 +79,7 @@ class ProposalWeakness(Base):
72
  nullable=False,
73
  )
74
  weakness_point = Column(String, nullable=False)
 
75
  created_at = Column(DateTime, nullable=False, default=func.now())
76
  updated_at = Column(
77
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
@@ -88,6 +96,7 @@ class ProposalImprovement(Base):
88
  nullable=False,
89
  )
90
  improvement_point = Column(String, nullable=False)
 
91
  created_at = Column(DateTime, nullable=False, default=func.now())
92
  updated_at = Column(
93
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
 
13
  from sqlalchemy.dialects.postgresql import UUID
14
  from ._base import Base
15
 
16
+ class Category(PyEnum):
17
+ TECHNICAL = "TECHNICAL"
18
+ MANAGEMENT = "MANAGEMENT"
19
+ PAST_PERFORMANCE = "PAST_PERFORMANCE"
20
+ PRICE = "PRICE"
21
 
22
  class ProposalAIAnalysis(Base):
23
  __tablename__ = "proposal_ai_analyses"
 
45
  nullable=False,
46
  )
47
  strength_point = Column(String, nullable=False)
48
+ category = Column(Enum(Category, name="strengthcategory"), nullable=False)
49
  created_at = Column(DateTime, nullable=False, default=func.now())
50
  updated_at = Column(
51
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
 
62
  nullable=False,
63
  )
64
  reason = Column(String, nullable=False)
65
+ category = Column(Enum(Category, name="rejectioncategory"), nullable=False)
66
  created_at = Column(DateTime, nullable=False, default=func.now())
67
  updated_at = Column(
68
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
 
79
  nullable=False,
80
  )
81
  weakness_point = Column(String, nullable=False)
82
+ category = Column(Enum(Category, name="weaknesscategory"), nullable=False)
83
  created_at = Column(DateTime, nullable=False, default=func.now())
84
  updated_at = Column(
85
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
 
96
  nullable=False,
97
  )
98
  improvement_point = Column(String, nullable=False)
99
+ category = Column(Enum(Category, name="improvementcategory"), nullable=False)
100
  created_at = Column(DateTime, nullable=False, default=func.now())
101
  updated_at = Column(
102
  DateTime, nullable=False, default=func.now(), onupdate=func.now()
src/services/_proposal_ai_analysis_service.py CHANGED
@@ -2,7 +2,7 @@ from enum import Enum as PyEnum
2
 
3
  from src.utils import ProposalAIAnalysisClient
4
 
5
- from src.models import QueryType, CreateOrUpdateType
6
 
7
 
8
  class ProposalAIAnalysisService:
@@ -20,13 +20,14 @@ class ProposalAIAnalysisService:
20
  query_type: QueryType = QueryType.ALL,
21
  id: str = None,
22
  proposal_id: str = None,
 
23
  ):
24
  async with self.proposal_ai_analysis_client() as client:
25
  if query_type == QueryType.ALL:
26
  return await client.get_complete_analysis(proposal_id=proposal_id)
27
  else:
28
  return await client.get_all_data(
29
- query_type=query_type, id=id, proposal_id=proposal_id
30
  )
31
 
32
  async def create_data(
@@ -66,11 +67,12 @@ class ProposalAIAnalysisService:
66
  query_type: QueryType = QueryType.ALL,
67
  id: str = None,
68
  proposal_id: str = None,
 
69
  ):
70
  async with self.proposal_ai_analysis_client() as client:
71
  if query_type == QueryType.ALL:
72
  return await client.delete_complete_analysis(proposal_id=proposal_id)
73
  else:
74
  return await client.delete_data(
75
- query_type=query_type, id=id, proposal_id=proposal_id
76
  )
 
2
 
3
  from src.utils import ProposalAIAnalysisClient
4
 
5
+ from src.models import QueryType, CreateOrUpdateType, Category
6
 
7
 
8
  class ProposalAIAnalysisService:
 
20
  query_type: QueryType = QueryType.ALL,
21
  id: str = None,
22
  proposal_id: str = None,
23
+ category: Category = None,
24
  ):
25
  async with self.proposal_ai_analysis_client() as client:
26
  if query_type == QueryType.ALL:
27
  return await client.get_complete_analysis(proposal_id=proposal_id)
28
  else:
29
  return await client.get_all_data(
30
+ query_type=query_type, id=id, proposal_id=proposal_id, category=category
31
  )
32
 
33
  async def create_data(
 
67
  query_type: QueryType = QueryType.ALL,
68
  id: str = None,
69
  proposal_id: str = None,
70
+ category: Category = None,
71
  ):
72
  async with self.proposal_ai_analysis_client() as client:
73
  if query_type == QueryType.ALL:
74
  return await client.delete_complete_analysis(proposal_id=proposal_id)
75
  else:
76
  return await client.delete_data(
77
+ query_type=query_type, id=id, proposal_id=proposal_id, category=category
78
  )
src/utils/_proposal_ai_analysis_client.py CHANGED
@@ -4,7 +4,7 @@ import uuid
4
  from sqlalchemy import select
5
  from src.repositories import BaseRepository
6
 
7
- from src.models import QueryType, CreateOrUpdateType, ProposalAIAnalysis, ProposalStrength, ProposalWeakness, ProposalRejectionReason, ProposalImprovement
8
 
9
  class ProposalAIAnalysisClient:
10
  def __init__(self):
@@ -23,13 +23,15 @@ class ProposalAIAnalysisClient:
23
  async def __aexit__(self, exc_type, exc_value, traceback):
24
  pass
25
 
26
- async def get_all_data(self, query_type: QueryType = QueryType.ALL, id: str = None, proposal_id: str = None):
27
  async with self.repository(model=self.tables_mapping[query_type.name]).get_session() as session:
28
  query = select(self.tables_mapping[query_type.name])
29
  if id:
30
  query = query.where(self.tables_mapping[query_type.name].id == id)
31
  if proposal_id:
32
  query = query.where(self.tables_mapping[query_type.name].proposal_id == proposal_id)
 
 
33
  result = await session.execute(query)
34
  all_result = result.scalars().all()
35
  final_result_dict = [{k: v for k, v in r.__dict__.items() if not k.startswith("_")} for r in all_result]
@@ -50,11 +52,11 @@ class ProposalAIAnalysisClient:
50
  return await self.get_all_data(query_type=query_type, id=result.id)
51
  else:
52
  for d in data:
53
- if d != "proposal_id":
54
  for point in data[d]:
55
- entry_data = {"proposal_id": data["proposal_id"], d: point}
56
  await self.create_entry(query_type=query_type, data=entry_data)
57
- return await self.get_all_data(query_type=query_type, proposal_id=data["proposal_id"])
58
 
59
  async def update_data(self, query_type: QueryType = QueryType.ALL, create_or_update_type: CreateOrUpdateType = CreateOrUpdateType.ALL, data: dict = None):
60
  if query_type == QueryType.AI_SCORE:
@@ -88,16 +90,18 @@ class ProposalAIAnalysisClient:
88
  await session.refresh(r)
89
  return await self.get_all_data(query_type=query_type, id=data["id"])
90
  else:
91
- await self.delete_data(query_type=query_type, proposal_id=data["proposal_id"])
92
  return await self.create_data(query_type=query_type, create_or_update_type=create_or_update_type, data=data)
93
 
94
- async def delete_data(self, query_type: QueryType = QueryType.ALL, id: str = None, proposal_id: str = None):
95
  async with self.repository(model=self.tables_mapping[query_type.name]).get_session() as session:
96
  query = select(self.tables_mapping[query_type.name])
97
  if id:
98
  query = query.where(self.tables_mapping[query_type.name].id == id)
99
  if proposal_id:
100
  query = query.where(self.tables_mapping[query_type.name].proposal_id == proposal_id)
 
 
101
  result = await session.execute(query)
102
  all_result = result.scalars().all()
103
  for r in all_result:
@@ -108,34 +112,72 @@ class ProposalAIAnalysisClient:
108
  async def get_complete_analysis(self, proposal_id: str = None):
109
  analysis = {
110
  "ai_score": 0,
111
- "strengths": [],
112
- "weaknesses": [],
113
- "rejection_reasons": [],
114
- "improvements": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
  result = await self.get_all_data(query_type=QueryType.AI_SCORE, proposal_id=proposal_id)
117
  analysis["ai_score"] = result[0]["ai_score"]
118
- strengths = await self.get_all_data(query_type=QueryType.STRENGTHS, proposal_id=proposal_id)
119
- analysis["strengths"] = [s["strength_point"] for s in strengths]
120
- weakness = await self.get_all_data(query_type=QueryType.WEAKNESSES, proposal_id=proposal_id)
121
- analysis["weaknesses"] = [w["weakness_point"] for w in weakness]
122
- rejection_reason = await self.get_all_data(query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id)
123
- analysis["rejection_reasons"] = [r["reason"] for r in rejection_reason]
124
- improvements = await self.get_all_data(query_type=QueryType.IMPROVEMENTS, proposal_id=proposal_id)
125
- analysis["improvements"] = [i["improvement_point"] for i in improvements]
 
 
 
 
 
 
 
 
 
126
  return analysis
127
 
128
  async def create_complete_analysis(self, data: dict = None):
129
  if "ai_score" in data:
130
  await self.create_data(query_type=QueryType.AI_SCORE, create_or_update_type=CreateOrUpdateType.ID, data={"proposal_id": data["proposal_id"], "ai_score": data["ai_score"]})
131
- if "strengths" in data:
132
- await self.create_data(query_type=QueryType.STRENGTHS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "strength_point": data["strengths"]})
133
- if "weaknesses" in data:
134
- await self.create_data(query_type=QueryType.WEAKNESSES, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "weakness_point": data["weaknesses"]})
135
- if "rejection_reasons" in data:
136
- await self.create_data(query_type=QueryType.REJECTION_REASONS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "reason": data["rejection_reasons"]})
137
- if "improvements" in data:
138
- await self.create_data(query_type=QueryType.IMPROVEMENTS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "improvement_point": data["improvements"]})
 
 
 
 
 
 
 
 
 
139
  return await self.get_complete_analysis(proposal_id=data["proposal_id"])
140
 
141
  async def delete_complete_analysis(self, proposal_id: str = None):
@@ -150,14 +192,25 @@ class ProposalAIAnalysisClient:
150
  old_data = await self.get_complete_analysis(proposal_id=data["proposal_id"])
151
  if "ai_score" in data:
152
  old_data["ai_score"] = data["ai_score"]
153
- if "strengths" in data:
154
- old_data["strengths"] = data["strengths"]
155
- if "weaknesses" in data:
156
- old_data["weaknesses"] = data["weaknesses"]
157
- if "rejection_reasons" in data:
158
- old_data["rejection_reasons"] = data["rejection_reasons"]
159
- if "improvements" in data:
160
- old_data["improvements"] = data["improvements"]
 
 
 
 
 
 
 
 
 
 
 
161
  await self.delete_complete_analysis(proposal_id=data["proposal_id"])
162
  old_data["proposal_id"] = data["proposal_id"]
163
  return await self.create_complete_analysis(data=old_data)
 
4
  from sqlalchemy import select
5
  from src.repositories import BaseRepository
6
 
7
+ from src.models import QueryType, CreateOrUpdateType, ProposalAIAnalysis, ProposalStrength, ProposalWeakness, ProposalRejectionReason, ProposalImprovement, Category
8
 
9
  class ProposalAIAnalysisClient:
10
  def __init__(self):
 
23
  async def __aexit__(self, exc_type, exc_value, traceback):
24
  pass
25
 
26
+ async def get_all_data(self, query_type: QueryType = QueryType.ALL, id: str = None, proposal_id: str = None, category: Category = None):
27
  async with self.repository(model=self.tables_mapping[query_type.name]).get_session() as session:
28
  query = select(self.tables_mapping[query_type.name])
29
  if id:
30
  query = query.where(self.tables_mapping[query_type.name].id == id)
31
  if proposal_id:
32
  query = query.where(self.tables_mapping[query_type.name].proposal_id == proposal_id)
33
+ if category:
34
+ query = query.where(self.tables_mapping[query_type.name].category == category)
35
  result = await session.execute(query)
36
  all_result = result.scalars().all()
37
  final_result_dict = [{k: v for k, v in r.__dict__.items() if not k.startswith("_")} for r in all_result]
 
52
  return await self.get_all_data(query_type=query_type, id=result.id)
53
  else:
54
  for d in data:
55
+ if d != "proposal_id" and d != "category":
56
  for point in data[d]:
57
+ entry_data = {"proposal_id": data["proposal_id"], "category": data["category"], d: point}
58
  await self.create_entry(query_type=query_type, data=entry_data)
59
+ return await self.get_all_data(query_type=query_type, proposal_id=data["proposal_id"], category=data["category"])
60
 
61
  async def update_data(self, query_type: QueryType = QueryType.ALL, create_or_update_type: CreateOrUpdateType = CreateOrUpdateType.ALL, data: dict = None):
62
  if query_type == QueryType.AI_SCORE:
 
90
  await session.refresh(r)
91
  return await self.get_all_data(query_type=query_type, id=data["id"])
92
  else:
93
+ await self.delete_data(query_type=query_type, proposal_id=data["proposal_id"], category=data["category"])
94
  return await self.create_data(query_type=query_type, create_or_update_type=create_or_update_type, data=data)
95
 
96
+ async def delete_data(self, query_type: QueryType = QueryType.ALL, id: str = None, proposal_id: str = None, category: Category = None):
97
  async with self.repository(model=self.tables_mapping[query_type.name]).get_session() as session:
98
  query = select(self.tables_mapping[query_type.name])
99
  if id:
100
  query = query.where(self.tables_mapping[query_type.name].id == id)
101
  if proposal_id:
102
  query = query.where(self.tables_mapping[query_type.name].proposal_id == proposal_id)
103
+ if category:
104
+ query = query.where(self.tables_mapping[query_type.name].category == category)
105
  result = await session.execute(query)
106
  all_result = result.scalars().all()
107
  for r in all_result:
 
112
  async def get_complete_analysis(self, proposal_id: str = None):
113
  analysis = {
114
  "ai_score": 0,
115
+ "technical": {
116
+ "strengths": [],
117
+ "weaknesses": [],
118
+ "rejection_reasons": [],
119
+ "improvements": []
120
+ },
121
+ "management": {
122
+ "strengths": [],
123
+ "weaknesses": [],
124
+ "rejection_reasons": [],
125
+ "improvements": []
126
+ },
127
+ "past_performance": {
128
+ "strengths": [],
129
+ "weaknesses": [],
130
+ "rejection_reasons": [],
131
+ "improvements": []
132
+ },
133
+ "price": {
134
+ "strengths": [],
135
+ "weaknesses": [],
136
+ "rejection_reasons": [],
137
+ "improvements": []
138
+ }
139
  }
140
  result = await self.get_all_data(query_type=QueryType.AI_SCORE, proposal_id=proposal_id)
141
  analysis["ai_score"] = result[0]["ai_score"]
142
+ for category in Category:
143
+ strengths = await self.get_all_data(query_type=QueryType.STRENGTHS, proposal_id=proposal_id, category=category)
144
+ analysis[category.value.lower()]["strengths"] = [s["strength_point"] for s in strengths] if strengths else []
145
+ weaknesses = await self.get_all_data(query_type=QueryType.WEAKNESSES, proposal_id=proposal_id, category=category)
146
+ analysis[category.value.lower()]["weaknesses"] = [w["weakness_point"] for w in weaknesses] if weaknesses else []
147
+ rejection_reason = await self.get_all_data(query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id, category=category)
148
+ analysis[category.value.lower()]["rejection_reasons"] = [r["reason"] for r in rejection_reason] if rejection_reason else []
149
+ improvements = await self.get_all_data(query_type=QueryType.IMPROVEMENTS, proposal_id=proposal_id, category=category)
150
+ analysis[category.value.lower()]["improvements"] = [i["improvement_point"] for i in improvements] if improvements else []
151
+ # strengths = await self.get_all_data(query_type=QueryType.STRENGTHS, proposal_id=proposal_id)
152
+ # analysis["strengths"] = [s["strength_point"] for s in strengths]
153
+ # weakness = await self.get_all_data(query_type=QueryType.WEAKNESSES, proposal_id=proposal_id)
154
+ # analysis["weaknesses"] = [w["weakness_point"] for w in weakness]
155
+ # rejection_reason = await self.get_all_data(query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id)
156
+ # analysis["rejection_reasons"] = [r["reason"] for r in rejection_reason]
157
+ # improvements = await self.get_all_data(query_type=QueryType.IMPROVEMENTS, proposal_id=proposal_id)
158
+ # analysis["improvements"] = [i["improvement_point"] for i in improvements]
159
  return analysis
160
 
161
  async def create_complete_analysis(self, data: dict = None):
162
  if "ai_score" in data:
163
  await self.create_data(query_type=QueryType.AI_SCORE, create_or_update_type=CreateOrUpdateType.ID, data={"proposal_id": data["proposal_id"], "ai_score": data["ai_score"]})
164
+ for category in Category:
165
+ if "strengths" in data[category.value.lower()]:
166
+ await self.create_data(query_type=QueryType.STRENGTHS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "category": category, "strength_point": data[category.value.lower()]["strengths"]})
167
+ if "weaknesses" in data[category.value.lower()]:
168
+ await self.create_data(query_type=QueryType.WEAKNESSES, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "category": category, "weakness_point": data[category.value.lower()]["weaknesses"]})
169
+ if "rejection_reasons" in data[category.value.lower()]:
170
+ await self.create_data(query_type=QueryType.REJECTION_REASONS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "category": category, "reason": data[category.value.lower()]["rejection_reasons"]})
171
+ if "improvements" in data[category.value.lower()]:
172
+ await self.create_data(query_type=QueryType.IMPROVEMENTS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "category": category, "improvement_point": data[category.value.lower()]["improvements"]})
173
+ # if "strengths" in data:
174
+ # await self.create_data(query_type=QueryType.STRENGTHS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "strength_point": data["strengths"]})
175
+ # if "weaknesses" in data:
176
+ # await self.create_data(query_type=QueryType.WEAKNESSES, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "weakness_point": data["weaknesses"]})
177
+ # if "rejection_reasons" in data:
178
+ # await self.create_data(query_type=QueryType.REJECTION_REASONS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "reason": data["rejection_reasons"]})
179
+ # if "improvements" in data:
180
+ # await self.create_data(query_type=QueryType.IMPROVEMENTS, create_or_update_type=CreateOrUpdateType.ALL, data={"proposal_id": data["proposal_id"], "improvement_point": data["improvements"]})
181
  return await self.get_complete_analysis(proposal_id=data["proposal_id"])
182
 
183
  async def delete_complete_analysis(self, proposal_id: str = None):
 
192
  old_data = await self.get_complete_analysis(proposal_id=data["proposal_id"])
193
  if "ai_score" in data:
194
  old_data["ai_score"] = data["ai_score"]
195
+ for category in Category:
196
+ if category.value.lower() not in data:
197
+ continue
198
+ if "strengths" in data[category.value.lower()]:
199
+ old_data[category.value.lower()]["strengths"] = data[category.value.lower()]["strengths"]
200
+ if "weaknesses" in data[category.value.lower()]:
201
+ old_data[category.value.lower()]["weaknesses"] = data[category.value.lower()]["weaknesses"]
202
+ if "rejection_reasons" in data[category.value.lower()]:
203
+ old_data[category.value.lower()]["rejection_reasons"] = data[category.value.lower()]["rejection_reasons"]
204
+ if "improvements" in data[category.value.lower()]:
205
+ old_data[category.value.lower()]["improvements"] = data[category.value.lower()]["improvements"]
206
+ # if "strengths" in data:
207
+ # old_data["strengths"] = data["strengths"]
208
+ # if "weaknesses" in data:
209
+ # old_data["weaknesses"] = data["weaknesses"]
210
+ # if "rejection_reasons" in data:
211
+ # old_data["rejection_reasons"] = data["rejection_reasons"]
212
+ # if "improvements" in data:
213
+ # old_data["improvements"] = data["improvements"]
214
  await self.delete_complete_analysis(proposal_id=data["proposal_id"])
215
  old_data["proposal_id"] = data["proposal_id"]
216
  return await self.create_complete_analysis(data=old_data)