iisadia commited on
Commit
b9f50c4
Β·
verified Β·
1 Parent(s): 79b7148

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +243 -145
app.py CHANGED
@@ -6,13 +6,75 @@ import time
6
  from datetime import datetime
7
  import groq
8
 
9
- # API keys (replace with your actual keys)
10
- mistral_api_key = os.getenv("MISTRAL_API_KEY", "your_mistral_key_here")
11
- groq_api_key = os.getenv("GROQ_API_KEY", "your_groq_key_here")
12
 
13
  # Initialize Groq client
14
  groq_client = groq.Client(api_key=groq_api_key)
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def call_mistral_api(prompt):
17
  url = "https://api.mistral.ai/v1/chat/completions"
18
  headers = {
@@ -21,38 +83,53 @@ def call_mistral_api(prompt):
21
  }
22
  payload = {
23
  "model": "mistral-medium",
24
- "messages": [{"role": "user", "content": prompt}]
 
 
25
  }
26
  try:
27
  response = requests.post(url, headers=headers, json=payload)
28
- response.raise_for_status()
29
  return response.json()['choices'][0]['message']['content']
 
 
 
 
 
 
30
  except Exception as err:
31
  return f"Error: {err}"
32
 
 
33
  def call_groq_api(prompt):
34
  try:
35
  response = groq_client.chat.completions.create(
36
- model="llama-3.3-70b-versatile",
37
- messages=[{"role": "user", "content": prompt}]
 
 
38
  )
39
  return response.choices[0].message.content
40
  except Exception as err:
 
41
  return f"Error: {err}"
42
 
 
43
  def analyze_requirement(requirement):
44
- type_prompt = f"Classify as Functional or Non-Functional in one word:\n{requirement}\nType:"
 
45
  req_type = call_mistral_api(type_prompt).strip()
46
-
47
- domain_prompt = f"Classify domain in one word:\n{requirement}\nDomain:"
48
  domain = call_mistral_api(domain_prompt).strip()
49
-
50
- defects_prompt = f"List major defects (1-2 words each):\n{requirement}\nDefects:"
 
51
  defects = call_groq_api(defects_prompt).strip()
52
-
53
- rewritten_prompt = f"Rewrite to address defects:\n{requirement}\nRewritten:"
54
  rewritten = call_groq_api(rewritten_prompt).strip()
55
-
56
  return {
57
  "Requirement": requirement,
58
  "Type": req_type,
@@ -61,148 +138,169 @@ def analyze_requirement(requirement):
61
  "Rewritten": rewritten
62
  }
63
 
 
64
  def generate_pdf_report(results):
65
  pdf = FPDF()
66
  pdf.add_page()
67
  pdf.set_font("Arial", size=12)
68
-
69
- # PDF content (same as previous)
70
- # ... [Keep the existing PDF generation code] ...
71
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  pdf_output = "requirements_report.pdf"
73
  pdf.output(pdf_output)
74
  return pdf_output
75
 
 
76
  def main():
77
- st.markdown("""
78
- <style>
79
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
80
- * { font-family: 'Poppins', sans-serif; }
81
- .main-container { max-width: 800px; margin: 0 auto; padding: 2rem; }
82
- .gradient-header {
83
- background: linear-gradient(45deg, #4F46E5, #1E40AF);
84
- color: white;
85
- padding: 2rem;
86
- border-radius: 15px;
87
- margin-bottom: 2rem;
88
- }
89
- .team-card {
90
- background: #f8f9fa;
91
- padding: 1.5rem;
92
- border-radius: 15px;
93
- margin: 1rem 0;
94
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
95
- }
96
- .result-card {
97
- background: white;
98
- padding: 1.5rem;
99
- border-radius: 15px;
100
- margin: 1rem 0;
101
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
102
- }
103
- .badge {
104
- padding: 0.5rem 1rem;
105
- border-radius: 20px;
106
- font-size: 0.9rem;
107
- margin-right: 0.5rem;
108
- display: inline-block;
109
- }
110
- .type-badge { background: #4F46E510; color: #4F46E5; }
111
- .domain-badge { background: #10B98110; color: #10B981; }
112
- .defect-badge { background: #EF444410; color: #EF4444; }
113
- .animate-hover { transition: transform 0.2s; }
114
- .animate-hover:hover { transform: translateY(-2px); }
115
- .styled-textarea {
116
- border: 2px solid #e0e0e0 !important;
117
- border-radius: 10px !important;
118
- padding: 1rem !important;
119
- }
120
- </style>
121
- """, unsafe_allow_html=True)
122
-
123
- st.markdown("""
124
- <div class="main-container">
125
- <div class="gradient-header">
126
- <h1 style="margin: 0; font-weight: 600;">🧠 AI Requirement Analyzer</h1>
127
- <p style="margin: 0.5rem 0 0; opacity: 0.9;">Smart Analysis & Quality Enhancement System</p>
128
  </div>
129
-
130
- <div class="team-card">
131
- <h3 style="margin: 0 0 1rem;">πŸ‘₯ Team Members</h3>
132
- <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem;">
133
- <div style="background: #4F46E510; padding: 0.5rem; border-radius: 10px;">
134
- <p style="margin: 0; color: #4F46E5;">Sadia</p>
135
- </div>
136
- <div style="background: #10B98110; padding: 0.5rem; border-radius: 10px;">
137
- <p style="margin: 0; color: #10B981;">Areeba</p>
138
- </div>
139
- <div style="background: #EF444410; padding: 0.5rem; border-radius: 10px;">
140
- <p style="margin: 0; color: #EF4444;">Rabbia</p>
141
- </div>
142
- <div style="background: #3B82F610; padding: 0.5rem; border-radius: 10px;">
143
- <p style="margin: 0; color: #3B82F6;">Tesmia</p>
144
- </div>
145
- </div>
146
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
- <div style="margin: 2rem 0;">
149
- <h2>πŸ“₯ Input Requirements</h2>
150
- <p style="opacity: 0.8;">Enter multiple requirements separated by new lines or periods</p>
151
- """, unsafe_allow_html=True)
152
-
153
- input_text = st.text_area("", height=200, key="input_area",
154
- help="Example:\n1. The system must handle 1000 users\n2. User interface should be responsive")
155
-
156
- if st.button("πŸš€ Start Analysis", key="analyze_btn", use_container_width=True):
157
- if not input_text.strip():
158
- st.warning("⚠️ Please enter requirements to analyze")
159
- else:
160
- requirements = [req.strip() for req in input_text.replace("\n", ".").split(".") if req.strip()]
161
- results = []
162
- progress_bar = st.progress(0)
163
-
164
- with st.spinner("πŸ” Analyzing requirements..."):
165
- for i, req in enumerate(requirements):
166
- results.append(analyze_requirement(req))
167
- progress_bar.progress((i+1)/len(requirements))
168
- time.sleep(0.1)
169
-
170
- st.success("βœ… Analysis completed!")
171
- st.markdown("---")
172
-
173
- for i, result in enumerate(results, 1):
174
- st.markdown(f"""
175
- <div class="result-card animate-hover">
176
- <h3 style="margin: 0 0 1rem;">πŸ”– Requirement R{i}</h3>
177
- <p style="font-size: 1.1rem; margin-bottom: 1.5rem;">{result['Requirement']}</p>
178
-
179
- <div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
180
- <span class="badge type-badge">πŸ“ {result['Type']}</span>
181
- <span class="badge domain-badge">🌍 {result['Domain']}</span>
182
- <span class="badge defect-badge">⚠️ {result['Defects']}</span>
183
- </div>
184
-
185
- <div style="background: #f8f9fa; padding: 1rem; border-radius: 10px;">
186
- <p style="margin: 0; color: #3B82F6;">✏️ Optimized Version:</p>
187
- <p style="margin: 0.5rem 0 0; font-weight: 500;">{result['Rewritten']}</p>
188
- </div>
189
- </div>
190
- """, unsafe_allow_html=True)
191
-
192
- st.markdown("---")
193
- st.markdown("### πŸ“„ Generate Report")
194
- pdf_report = generate_pdf_report(results)
195
- with open(pdf_report, "rb") as f:
196
- st.download_button(
197
- label="πŸ“₯ Download PDF Report",
198
- data=f,
199
- file_name="requirements_analysis.pdf",
200
- mime="application/pdf",
201
- use_container_width=True,
202
- key="download_btn"
203
- )
204
-
205
- st.markdown("</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
  if __name__ == "__main__":
208
  main()
 
6
  from datetime import datetime
7
  import groq
8
 
9
+ # API keys (replace with your keys or use environment variables)
10
+ mistral_api_key = os.getenv("MISTRAL_API_KEY", "gz6lDXokxgR6cLY72oomALWcm7vhjRzQ")
11
+ groq_api_key = os.getenv("GROQ_API_KEY", "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")
12
 
13
  # Initialize Groq client
14
  groq_client = groq.Client(api_key=groq_api_key)
15
 
16
+ # Custom CSS for professional styling
17
+ st.markdown("""
18
+ <style>
19
+ .main {
20
+ background-color: #f8f9fa;
21
+ }
22
+ .stTextArea textarea {
23
+ border: 2px solid #4a4e69;
24
+ border-radius: 10px;
25
+ padding: 15px !important;
26
+ }
27
+ .stButton button {
28
+ background-color: #4a4e69;
29
+ color: white;
30
+ border: none;
31
+ padding: 12px 30px;
32
+ border-radius: 8px;
33
+ font-size: 16px;
34
+ font-weight: bold;
35
+ transition: all 0.3s ease;
36
+ width: 100%;
37
+ }
38
+ .stButton button:hover {
39
+ background-color: #3a3e59;
40
+ transform: scale(1.02);
41
+ }
42
+ .report-title {
43
+ color: #4a4e69;
44
+ font-size: 2.5em;
45
+ text-align: center;
46
+ padding: 20px;
47
+ border-bottom: 3px solid #4a4e69;
48
+ margin-bottom: 30px;
49
+ }
50
+ .requirement-card {
51
+ background: white;
52
+ border-radius: 15px;
53
+ padding: 25px;
54
+ margin: 15px 0;
55
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
56
+ border-left: 5px solid #4a4e69;
57
+ }
58
+ .sidebar .sidebar-content {
59
+ background-color: #4a4e69;
60
+ color: white;
61
+ }
62
+ .metric-box {
63
+ background: white;
64
+ padding: 15px;
65
+ border-radius: 10px;
66
+ margin: 10px 0;
67
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
68
+ }
69
+ .stSpinner > div {
70
+ display: flex;
71
+ justify-content: center;
72
+ align-items: center;
73
+ }
74
+ </style>
75
+ """, unsafe_allow_html=True)
76
+
77
+ # Function to call Mistral API
78
  def call_mistral_api(prompt):
79
  url = "https://api.mistral.ai/v1/chat/completions"
80
  headers = {
 
83
  }
84
  payload = {
85
  "model": "mistral-medium",
86
+ "messages": [
87
+ {"role": "user", "content": prompt}
88
+ ]
89
  }
90
  try:
91
  response = requests.post(url, headers=headers, json=payload)
92
+ response.raise_for_status() # Raise an error for bad status codes
93
  return response.json()['choices'][0]['message']['content']
94
+ except requests.exceptions.HTTPError as err:
95
+ if response.status_code == 429: # Rate limit exceeded
96
+ st.warning("Rate limit exceeded. Please wait a few seconds and try again.")
97
+ time.sleep(5) # Wait for 5 seconds before retrying
98
+ return call_mistral_api(prompt) # Retry the request
99
+ return f"HTTP Error: {err}"
100
  except Exception as err:
101
  return f"Error: {err}"
102
 
103
+ # Function to call Groq API
104
  def call_groq_api(prompt):
105
  try:
106
  response = groq_client.chat.completions.create(
107
+ model="llama-3.3-70b-versatile", # Correct model name
108
+ messages=[
109
+ {"role": "user", "content": prompt}
110
+ ]
111
  )
112
  return response.choices[0].message.content
113
  except Exception as err:
114
+ st.error(f"Error: {err}")
115
  return f"Error: {err}"
116
 
117
+ # Function to analyze a single requirement using both models
118
  def analyze_requirement(requirement):
119
+ # Use Mistral for classification and domain identification
120
+ type_prompt = f"Classify the following requirement as Functional or Non-Functional in one word:\n\n{requirement}\n\nType:"
121
  req_type = call_mistral_api(type_prompt).strip()
122
+
123
+ domain_prompt = f"Classify the domain for the following requirement in one word (e.g., E-commerce, Education, etc.):\n\n{requirement}\n\nDomain:"
124
  domain = call_mistral_api(domain_prompt).strip()
125
+
126
+ # Use Groq for defect analysis and rewriting
127
+ defects_prompt = f"""List ONLY the major defects in the following requirement (e.g., Ambiguity, Incompleteness, etc.) in 1-2 words each:\n\n{requirement}\n\nDefects:"""
128
  defects = call_groq_api(defects_prompt).strip()
129
+
130
+ rewritten_prompt = f"""Rewrite the following requirement in 1-2 sentences to address the defects:\n\n{requirement}\n\nRewritten:"""
131
  rewritten = call_groq_api(rewritten_prompt).strip()
132
+
133
  return {
134
  "Requirement": requirement,
135
  "Type": req_type,
 
138
  "Rewritten": rewritten
139
  }
140
 
141
+ # Function to generate a PDF report
142
  def generate_pdf_report(results):
143
  pdf = FPDF()
144
  pdf.add_page()
145
  pdf.set_font("Arial", size=12)
146
+
147
+ # Add watermark
148
+ pdf.set_font("Arial", 'B', 50)
149
+ pdf.set_text_color(230, 230, 230) # Light gray color for watermark
150
+ pdf.rotate(45) # Rotate the text for watermark effect
151
+ pdf.text(60, 150, "AI Powered Requirement Analysis")
152
+ pdf.rotate(0) # Reset rotation
153
+
154
+ # Add title and date/time
155
+ pdf.set_font("Arial", 'B', 16)
156
+ pdf.set_text_color(0, 0, 0) # Black color for title
157
+ pdf.cell(200, 10, txt="AI Powered Requirement Analysis and Defect Detection", ln=True, align='C')
158
+ pdf.set_font("Arial", size=12)
159
+ pdf.cell(200, 10, txt=f"Report Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", ln=True, align='C')
160
+ pdf.ln(10) # Add some space
161
+
162
+ # Add requirements analysis
163
+ pdf.set_font("Arial", size=12)
164
+ for i, result in enumerate(results, start=1):
165
+ if pdf.get_y() > 250: # If the content is near the bottom of the page
166
+ pdf.add_page() # Add a new page
167
+ pdf.set_font("Arial", 'B', 16)
168
+ pdf.cell(200, 10, txt="AI Powered Requirement Analysis and Defect Detection", ln=True, align='C')
169
+ pdf.set_font("Arial", size=12)
170
+ pdf.cell(200, 10, txt=f"Report Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", ln=True, align='C')
171
+ pdf.ln(10) # Add some space
172
+
173
+ # Add requirement details
174
+ pdf.set_font("Arial", 'B', 14)
175
+ pdf.multi_cell(200, 10, txt=f"Requirement R{i}: {result['Requirement']}", align='L')
176
+ pdf.set_font("Arial", size=12)
177
+ pdf.multi_cell(200, 10, txt=f"Type: {result['Type']}", align='L')
178
+ pdf.multi_cell(200, 10, txt=f"Domain: {result['Domain']}", align='L')
179
+ pdf.multi_cell(200, 10, txt=f"Defects: {result['Defects']}", align='L')
180
+ pdf.multi_cell(200, 10, txt=f"Rewritten: {result['Rewritten']}", align='L')
181
+ pdf.multi_cell(200, 10, txt="-" * 50, align='L')
182
+ pdf.ln(5) # Add some space between requirements
183
+
184
  pdf_output = "requirements_report.pdf"
185
  pdf.output(pdf_output)
186
  return pdf_output
187
 
188
+ # Streamlit app with enhanced UI
189
  def main():
190
+ # Sidebar with team info
191
+ with st.sidebar:
192
+ st.markdown("<h1 style='color: white; text-align: center;'>Team Details</h1>", unsafe_allow_html=True)
193
+ st.markdown("""
194
+ <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px; margin: 15px 0;'>
195
+ <h3 style='color: white; margin-bottom: 10px;'>πŸ‘©πŸ’» Team Members</h3>
196
+ <p style='color: white;'>Sadia<br>Areeba<br>Rabbia<br>Tesmia</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  </div>
198
+ """, unsafe_allow_html=True)
199
+ st.markdown("""
200
+ <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;'>
201
+ <h3 style='color: white; margin-bottom: 10px;'>πŸ€– AI Models</h3>
202
+ <p style='color: white;'>Mistral (Classification)<br>Groq (Defect Analysis)</p>
 
 
 
 
 
 
 
 
 
 
 
 
203
  </div>
204
+ """, unsafe_allow_html=True)
205
+
206
+ # Main content area
207
+ col1, col2, col3 = st.columns([1,6,1])
208
+ with col2:
209
+ st.markdown("<h1 class='report-title'>AI Requirement Analyzer</h1>", unsafe_allow_html=True)
210
+
211
+ # Input section
212
+ with st.container():
213
+ st.markdown("### πŸ“ Enter Requirements")
214
+ input_text = st.text_area(
215
+ "Enter your requirements (one per line or separated by periods):",
216
+ height=200,
217
+ label_visibility="collapsed"
218
+ )
219
 
220
+ # Analysis button
221
+ if st.button("πŸ” Analyze Requirements", key="analyze_btn"):
222
+ if not input_text.strip():
223
+ st.warning("⚠️ Please enter requirements before analyzing")
224
+ else:
225
+ with st.spinner("πŸ”Ž Analyzing requirements..."):
226
+ requirements = [req.strip() for req in input_text.replace("\n", ".").split(".") if req.strip()]
227
+ results = []
228
+ progress_bar = st.progress(0)
229
+ for i, req in enumerate(requirements):
230
+ results.append(analyze_requirement(req.strip()))
231
+ progress_bar.progress((i+1)/len(requirements))
232
+
233
+ # Display results
234
+ st.success("βœ… Analysis Complete!")
235
+ st.markdown("---")
236
+ st.markdown("## πŸ“Š Analysis Results")
237
+
238
+ # Summary metrics
239
+ col1, col2, col3 = st.columns(3)
240
+ with col1:
241
+ st.markdown(f"""
242
+ <div class='metric-box'>
243
+ <h3>πŸ“„ Total Requirements</h3>
244
+ <h2>{len(results)}</h2>
245
+ </div>
246
+ """, unsafe_allow_html=True)
247
+ with col2:
248
+ types = [res['Type'] for res in results]
249
+ st.markdown(f"""
250
+ <div class='metric-box'>
251
+ <h3>πŸ“Š Functional/Non-Functional</h3>
252
+ <h2>{types.count('Functional')}/{types.count('Non-Functional')}</h2>
253
+ </div>
254
+ """, unsafe_allow_html=True)
255
+ with col3:
256
+ domains = len(set([res['Domain'] for res in results]))
257
+ st.markdown(f"""
258
+ <div class='metric-box'>
259
+ <h3>🌍 Unique Domains</h3>
260
+ <h2>{domains}</h2>
261
+ </div>
262
+ """, unsafe_allow_html=True)
263
+
264
+ # Detailed results
265
+ st.markdown("---")
266
+ for i, result in enumerate(results, start=1):
267
+ with st.container():
268
+ st.markdown(f"""
269
+ <div class='requirement-card'>
270
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
271
+ <h3>πŸ”– Requirement R{i}</h3>
272
+ <span style="font-size: 0.9em; color: #666;">{result['Domain']} Domain</span>
273
+ </div>
274
+ <p style="color: #444; margin-bottom: 15px;">{result['Requirement']}</p>
275
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px;">
276
+ <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
277
+ <h4>πŸ“Œ Type</h4>
278
+ <p>{result['Type']}</p>
279
+ </div>
280
+ <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
281
+ <h4>⚠️ Defects</h4>
282
+ <p>{result['Defects']}</p>
283
+ </div>
284
+ <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
285
+ <h4>✏️ Improved Version</h4>
286
+ <p>{result['Rewritten']}</p>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ """, unsafe_allow_html=True)
291
+
292
+ # PDF Download
293
+ st.markdown("---")
294
+ st.markdown("## πŸ“€ Export Results")
295
+ pdf_report = generate_pdf_report(results)
296
+ with open(pdf_report, "rb") as f:
297
+ st.download_button(
298
+ label="πŸ“₯ Download Full Report (PDF)",
299
+ data=f,
300
+ file_name="requirements_report.pdf",
301
+ mime="application/pdf",
302
+ help="Download comprehensive PDF report with all analysis details"
303
+ )
304
 
305
  if __name__ == "__main__":
306
  main()