USER-GNEXUSES commited on
Commit
18b6d8a
·
verified ·
1 Parent(s): e7597b4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +339 -1
app.py CHANGED
@@ -831,4 +831,342 @@ class RequirementsAnalysisModule:
831
  for i, req in enumerate(requirements):
832
  related = []
833
 
834
- for j
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
  for i, req in enumerate(requirements):
832
  related = []
833
 
834
+ for j, similarity in enumerate(similarity_matrix[i]):
835
+ if i != j and similarity > 0.3: # Threshold for relationship
836
+ related.append({
837
+ "id": requirements[j]["id"],
838
+ "similarity": float(similarity),
839
+ "relationship_type": self._determine_relationship_type(req, requirements[j])
840
+ })
841
+
842
+ # Sort by similarity
843
+ related.sort(key=lambda x: x["similarity"], reverse=True)
844
+
845
+ # Add to requirement
846
+ req["related_requirements"] = related[:5] # Top 5 related requirements
847
+
848
+ def _determine_relationship_type(self, req1: Dict, req2: Dict) -> str:
849
+ """
850
+ Determine the type of relationship between two requirements.
851
+
852
+ Args:
853
+ req1: First requirement
854
+ req2: Second requirement
855
+
856
+ Returns:
857
+ Relationship type string
858
+ """
859
+ # Check for system relationships
860
+ systems1 = set(req1["extracted"]["systems"])
861
+ systems2 = set(req2["extracted"]["systems"])
862
+
863
+ if systems1.intersection(systems2):
864
+ return "same_system"
865
+
866
+ # Check for business domain relationships
867
+ domains1 = [d[0] for d in req1["extracted"]["business_domain"]]
868
+ domains2 = [d[0] for d in req2["extracted"]["business_domain"]]
869
+
870
+ if set(domains1).intersection(set(domains2)):
871
+ return "same_domain"
872
+
873
+ # Check for action relationships
874
+ actions1 = set(req1["extracted"]["actions"])
875
+ actions2 = set(req2["extracted"]["actions"])
876
+
877
+ if actions1.intersection(actions2):
878
+ return "similar_action"
879
+
880
+ # Default relationship type
881
+ return "related"
882
+
883
+ def map_requirements_to_processes(self, requirements: List[Dict], process_models: List[Dict]) -> Dict:
884
+ """
885
+ Map requirements to process models based on content matching.
886
+
887
+ Args:
888
+ requirements: List of analyzed requirements
889
+ process_models: List of process model dictionaries
890
+
891
+ Returns:
892
+ Dictionary mapping process IDs to requirement IDs
893
+ """
894
+ process_to_reqs = {}
895
+ req_to_process = {}
896
+
897
+ for process in process_models:
898
+ process_id = process.get("id", "unknown")
899
+ process_text = process.get("description", "") + " " + process.get("name", "")
900
+ process_doc = self.nlp(process_text)
901
+
902
+ # Find matching requirements
903
+ matching_reqs = []
904
+
905
+ for req in requirements:
906
+ req_text = req["text"]
907
+ req_doc = self.nlp(req_text)
908
+
909
+ # Calculate similarity
910
+ similarity = process_doc.similarity(req_doc)
911
+
912
+ if similarity > 0.6: # Threshold for matching
913
+ matching_reqs.append({
914
+ "req_id": req["id"],
915
+ "similarity": float(similarity)
916
+ })
917
+ req_to_process[req["id"]] = process_id
918
+
919
+ # Sort by similarity
920
+ matching_reqs.sort(key=lambda x: x["similarity"], reverse=True)
921
+ process_to_reqs[process_id] = matching_reqs
922
+
923
+ return {
924
+ "process_to_requirements": process_to_reqs,
925
+ "requirement_to_process": req_to_process
926
+ }
927
+
928
+ def evaluate_automation_potential(self, requirement: Dict) -> Dict:
929
+ """
930
+ Evaluate the automation potential of a requirement.
931
+
932
+ Args:
933
+ requirement: Analyzed requirement
934
+
935
+ Returns:
936
+ Automation potential assessment
937
+ """
938
+ # Basic score starts at 5 out of 10
939
+ score = 5
940
+
941
+ # Complexity factor (high complexity decreases score)
942
+ complexity = requirement["extracted"]["complexity"]
943
+ if complexity == "high":
944
+ score -= 2
945
+ elif complexity == "low":
946
+ score += 2
947
+
948
+ # Action factor (certain actions are more automatable)
949
+ automatable_actions = ["extract", "transfer", "copy", "move", "calculate",
950
+ "update", "generate", "validate", "verify", "send",
951
+ "notify", "schedule", "retrieve", "check"]
952
+
953
+ for action in requirement["extracted"]["actions"]:
954
+ if action in automatable_actions:
955
+ score += 0.5
956
+
957
+ # System factor (presence of systems increases score)
958
+ if requirement["extracted"]["systems"]:
959
+ score += len(requirement["extracted"]["systems"]) * 0.5
960
+
961
+ # Data elements factor (more data elements suggests more structure)
962
+ data_elements = requirement["extracted"]["data_elements"]
963
+ if data_elements:
964
+ score += min(len(data_elements) * 0.3, 2) # Cap at +2
965
+
966
+ # Cap score between 1-10
967
+ score = max(1, min(10, score))
968
+
969
+ # Determine category
970
+ category = "high" if score >= 7.5 else "medium" if score >= 5 else "low"
971
+
972
+ # Identify automation technology
973
+ tech = self._recommend_automation_technology(requirement, score)
974
+
975
+ return {
976
+ "automation_score": round(score, 1),
977
+ "automation_category": category,
978
+ "recommended_technology": tech,
979
+ "rationale": self._generate_automation_rationale(requirement, score, category)
980
+ }
981
+
982
+ def _recommend_automation_technology(self, requirement: Dict, score: float) -> str:
983
+ """
984
+ Recommend suitable automation technology.
985
+
986
+ Args:
987
+ requirement: Analyzed requirement
988
+ score: Automation score
989
+
990
+ Returns:
991
+ Recommended technology
992
+ """
993
+ complexity = requirement["extracted"]["complexity"]
994
+ actions = requirement["extracted"]["actions"]
995
+
996
+ # Decision tree for technology recommendation
997
+ if score >= 8:
998
+ if any(a in actions for a in ["extract", "scrape", "read"]):
999
+ return "RPA with OCR/Document Understanding"
1000
+ else:
1001
+ return "Traditional RPA"
1002
+ elif score >= 5:
1003
+ if complexity == "high":
1004
+ return "RPA with Human-in-the-Loop"
1005
+ elif any(a in actions for a in ["decide", "evaluate", "assess"]):
1006
+ return "RPA with Decision Automation"
1007
+ else:
1008
+ return "Traditional RPA"
1009
+ else:
1010
+ if any(a in actions for a in ["review", "approve"]):
1011
+ return "Workflow Automation"
1012
+ else:
1013
+ return "Partial Automation with Human Tasks"
1014
+
1015
+ def _generate_automation_rationale(self, requirement: Dict, score: float, category: str) -> str:
1016
+ """
1017
+ Generate explanation for automation assessment.
1018
+
1019
+ Args:
1020
+ requirement: Analyzed requirement
1021
+ score: Automation score
1022
+ category: Automation category
1023
+
1024
+ Returns:
1025
+ Rationale text
1026
+ """
1027
+ complexity = requirement["extracted"]["complexity"]
1028
+
1029
+ if category == "high":
1030
+ return (f"This requirement has {complexity} complexity but shows strong automation "
1031
+ f"potential due to clear structure and defined data elements. "
1032
+ f"Score of {score}/10 indicates this is a prime automation candidate.")
1033
+ elif category == "medium":
1034
+ return (f"This {complexity} complexity requirement has moderate automation potential. "
1035
+ f"Score of {score}/10 suggests partial automation with some human oversight.")
1036
+ else:
1037
+ return (f"The {complexity} complexity and ambiguous nature of this requirement "
1038
+ f"limits automation potential. Score of {score}/10 indicates this may "
1039
+ f"require significant human involvement or process redesign.")
1040
+
1041
+ def assess_requirements_automation_potential(self, requirements: List[Dict]) -> List[Dict]:
1042
+ """
1043
+ Assess automation potential for a batch of requirements.
1044
+
1045
+ Args:
1046
+ requirements: List of analyzed requirements
1047
+
1048
+ Returns:
1049
+ Requirements with automation assessment added
1050
+ """
1051
+ for req in requirements:
1052
+ req["automation_potential"] = self.evaluate_automation_potential(req)
1053
+
1054
+ return requirements
1055
+
1056
+ def generate_requirements_report(self, requirements: List[Dict]) -> Dict:
1057
+ """
1058
+ Generate a summary report of requirements analysis.
1059
+
1060
+ Args:
1061
+ requirements: List of analyzed requirements
1062
+
1063
+ Returns:
1064
+ Report dictionary
1065
+ """
1066
+ # Count by complexity
1067
+ complexity_counts = {"high": 0, "medium": 0, "low": 0}
1068
+ for req in requirements:
1069
+ complexity = req["extracted"]["complexity"]
1070
+ complexity_counts[complexity] += 1
1071
+
1072
+ # Count by automation potential
1073
+ if all("automation_potential" in req for req in requirements):
1074
+ automation_counts = {"high": 0, "medium": 0, "low": 0}
1075
+ for req in requirements:
1076
+ category = req["automation_potential"]["automation_category"]
1077
+ automation_counts[category] += 1
1078
+ else:
1079
+ automation_counts = None
1080
+
1081
+ # Find common systems
1082
+ all_systems = []
1083
+ for req in requirements:
1084
+ all_systems.extend(req["extracted"]["systems"])
1085
+
1086
+ system_counts = {}
1087
+ for system in all_systems:
1088
+ if system in system_counts:
1089
+ system_counts[system] += 1
1090
+ else:
1091
+ system_counts[system] = 1
1092
+
1093
+ # Sort systems by frequency
1094
+ top_systems = sorted(system_counts.items(), key=lambda x: x[1], reverse=True)[:5]
1095
+
1096
+ # Generate report
1097
+ report = {
1098
+ "total_requirements": len(requirements),
1099
+ "complexity_distribution": complexity_counts,
1100
+ "automation_potential": automation_counts,
1101
+ "top_systems": top_systems,
1102
+ "recommendations": self._generate_overall_recommendations(requirements)
1103
+ }
1104
+
1105
+ return report
1106
+
1107
+ def _generate_overall_recommendations(self, requirements: List[Dict]) -> List[str]:
1108
+ """
1109
+ Generate overall recommendations based on requirements analysis.
1110
+
1111
+ Args:
1112
+ requirements: List of analyzed requirements
1113
+
1114
+ Returns:
1115
+ List of recommendation strings
1116
+ """
1117
+ recommendations = []
1118
+
1119
+ # Check if automation assessment is available
1120
+ automation_available = all("automation_potential" in req for req in requirements)
1121
+
1122
+ if automation_available:
1123
+ # Count high automation potential requirements
1124
+ high_potential = [r for r in requirements
1125
+ if r["automation_potential"]["automation_category"] == "high"]
1126
+
1127
+ if len(high_potential) >= len(requirements) * 0.7:
1128
+ recommendations.append(
1129
+ "High automation potential across most requirements. "
1130
+ "Consider an end-to-end automation solution."
1131
+ )
1132
+ elif len(high_potential) >= len(requirements) * 0.3:
1133
+ recommendations.append(
1134
+ "Significant automation potential in a subset of requirements. "
1135
+ "Consider a phased automation approach starting with high-potential areas."
1136
+ )
1137
+ else:
1138
+ recommendations.append(
1139
+ "Limited automation potential in current requirements. "
1140
+ "Consider process redesign to increase automation potential."
1141
+ )
1142
+
1143
+ # Recommend technologies
1144
+ tech_counts = {}
1145
+ for req in requirements:
1146
+ tech = req["automation_potential"]["recommended_technology"]
1147
+ tech_counts[tech] = tech_counts.get(tech, 0) + 1
1148
+
1149
+ top_tech = max(tech_counts.items(), key=lambda x: x[1])[0]
1150
+ recommendations.append(f"Primary recommended technology: {top_tech}")
1151
+
1152
+ # Requirements quality recommendations
1153
+ completeness_issues = False
1154
+ for req in requirements:
1155
+ if (not req["extracted"]["actions"] or
1156
+ not req["extracted"]["systems"] or
1157
+ not req["extracted"]["data_elements"]):
1158
+ completeness_issues = True
1159
+ break
1160
+
1161
+ if completeness_issues:
1162
+ recommendations.append(
1163
+ "Some requirements lack necessary details. "
1164
+ "Consider refining requirements to specify actions, systems, and data elements."
1165
+ )
1166
+
1167
+ return recommendations
1168
+
1169
+ Version 2 of 2
1170
+
1171
+
1172
+