File size: 13,248 Bytes
13b0d84
 
 
 
 
 
 
 
b9f50c4
 
 
13b0d84
 
 
 
b9f50c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13b0d84
 
 
 
 
 
 
 
b9f50c4
 
 
13b0d84
 
 
b9f50c4
13b0d84
b9f50c4
 
 
 
 
 
13b0d84
 
 
b9f50c4
13b0d84
 
 
b9f50c4
 
 
 
13b0d84
 
 
b9f50c4
13b0d84
 
b9f50c4
13b0d84
b9f50c4
 
13b0d84
b9f50c4
 
13b0d84
b9f50c4
 
 
13b0d84
b9f50c4
 
13b0d84
b9f50c4
13b0d84
 
 
 
 
 
 
 
b9f50c4
13b0d84
 
 
 
b9f50c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13b0d84
 
 
 
b9f50c4
13b0d84
b9f50c4
 
 
 
 
 
 
c87b45b
b9f50c4
 
 
 
 
c87b45b
b9f50c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c71a2a6
b9f50c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c87b45b
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
import streamlit as st
import requests
from fpdf import FPDF
import os
import time
from datetime import datetime
import groq

# API keys (replace with your keys or use environment variables)
mistral_api_key = os.getenv("MISTRAL_API_KEY", "gz6lDXokxgR6cLY72oomALWcm7vhjRzQ")
groq_api_key = os.getenv("GROQ_API_KEY", "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")

# Initialize Groq client
groq_client = groq.Client(api_key=groq_api_key)

# Custom CSS for professional styling
st.markdown("""
    <style>
        .main {
            background-color: #f8f9fa;
        }
        .stTextArea textarea {
            border: 2px solid #4a4e69;
            border-radius: 10px;
            padding: 15px !important;
        }
        .stButton button {
            background-color: #4a4e69;
            color: white;
            border: none;
            padding: 12px 30px;
            border-radius: 8px;
            font-size: 16px;
            font-weight: bold;
            transition: all 0.3s ease;
            width: 100%;
        }
        .stButton button:hover {
            background-color: #3a3e59;
            transform: scale(1.02);
        }
        .report-title {
            color: #4a4e69;
            font-size: 2.5em;
            text-align: center;
            padding: 20px;
            border-bottom: 3px solid #4a4e69;
            margin-bottom: 30px;
        }
        .requirement-card {
            background: white;
            border-radius: 15px;
            padding: 25px;
            margin: 15px 0;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            border-left: 5px solid #4a4e69;
        }
        .sidebar .sidebar-content {
            background-color: #4a4e69;
            color: white;
        }
        .metric-box {
            background: white;
            padding: 15px;
            border-radius: 10px;
            margin: 10px 0;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        }
        .stSpinner > div {
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
""", unsafe_allow_html=True)

# Function to call Mistral API
def call_mistral_api(prompt):
    url = "https://api.mistral.ai/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {mistral_api_key}",
        "Content-Type": "application/json"
    }
    payload = {
        "model": "mistral-medium",
        "messages": [
            {"role": "user", "content": prompt}
        ]
    }
    try:
        response = requests.post(url, headers=headers, json=payload)
        response.raise_for_status()  # Raise an error for bad status codes
        return response.json()['choices'][0]['message']['content']
    except requests.exceptions.HTTPError as err:
        if response.status_code == 429:  # Rate limit exceeded
            st.warning("Rate limit exceeded. Please wait a few seconds and try again.")
            time.sleep(5)  # Wait for 5 seconds before retrying
            return call_mistral_api(prompt)  # Retry the request
        return f"HTTP Error: {err}"
    except Exception as err:
        return f"Error: {err}"

# Function to call Groq API
def call_groq_api(prompt):
    try:
        response = groq_client.chat.completions.create(
            model="llama-3.3-70b-versatile",  # Correct model name
            messages=[
                {"role": "user", "content": prompt}
            ]
        )
        return response.choices[0].message.content
    except Exception as err:
        st.error(f"Error: {err}")
        return f"Error: {err}"

# Function to analyze a single requirement using both models
def analyze_requirement(requirement):
    # Use Mistral for classification and domain identification
    type_prompt = f"Classify the following requirement as Functional or Non-Functional in one word:\n\n{requirement}\n\nType:"
    req_type = call_mistral_api(type_prompt).strip()

    domain_prompt = f"Classify the domain for the following requirement in one word (e.g., E-commerce, Education, etc.):\n\n{requirement}\n\nDomain:"
    domain = call_mistral_api(domain_prompt).strip()

    # Use Groq for defect analysis and rewriting
    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:"""
    defects = call_groq_api(defects_prompt).strip()

    rewritten_prompt = f"""Rewrite the following requirement in 1-2 sentences to address the defects:\n\n{requirement}\n\nRewritten:"""
    rewritten = call_groq_api(rewritten_prompt).strip()

    return {
        "Requirement": requirement,
        "Type": req_type,
        "Domain": domain,
        "Defects": defects,
        "Rewritten": rewritten
    }

# Function to generate a PDF report
def generate_pdf_report(results):
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("Arial", size=12)

    # Add watermark
    pdf.set_font("Arial", 'B', 50)
    pdf.set_text_color(230, 230, 230)  # Light gray color for watermark
    pdf.rotate(45)  # Rotate the text for watermark effect
    pdf.text(60, 150, "AI Powered Requirement Analysis")
    pdf.rotate(0)  # Reset rotation

    # Add title and date/time
    pdf.set_font("Arial", 'B', 16)
    pdf.set_text_color(0, 0, 0)  # Black color for title
    pdf.cell(200, 10, txt="AI Powered Requirement Analysis and Defect Detection", ln=True, align='C')
    pdf.set_font("Arial", size=12)
    pdf.cell(200, 10, txt=f"Report Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", ln=True, align='C')
    pdf.ln(10)  # Add some space

    # Add requirements analysis
    pdf.set_font("Arial", size=12)
    for i, result in enumerate(results, start=1):
        if pdf.get_y() > 250:  # If the content is near the bottom of the page
            pdf.add_page()  # Add a new page
            pdf.set_font("Arial", 'B', 16)
            pdf.cell(200, 10, txt="AI Powered Requirement Analysis and Defect Detection", ln=True, align='C')
            pdf.set_font("Arial", size=12)
            pdf.cell(200, 10, txt=f"Report Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", ln=True, align='C')
            pdf.ln(10)  # Add some space

        # Add requirement details
        pdf.set_font("Arial", 'B', 14)
        pdf.multi_cell(200, 10, txt=f"Requirement R{i}: {result['Requirement']}", align='L')
        pdf.set_font("Arial", size=12)
        pdf.multi_cell(200, 10, txt=f"Type: {result['Type']}", align='L')
        pdf.multi_cell(200, 10, txt=f"Domain: {result['Domain']}", align='L')
        pdf.multi_cell(200, 10, txt=f"Defects: {result['Defects']}", align='L')
        pdf.multi_cell(200, 10, txt=f"Rewritten: {result['Rewritten']}", align='L')
        pdf.multi_cell(200, 10, txt="-" * 50, align='L')
        pdf.ln(5)  # Add some space between requirements

    pdf_output = "requirements_report.pdf"
    pdf.output(pdf_output)
    return pdf_output

# Streamlit app with enhanced UI
def main():
    # Sidebar with team info
    with st.sidebar:
        st.markdown("<h1 style='color: white; text-align: center;'>Team Details</h1>", unsafe_allow_html=True)
        st.markdown("""
            <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px; margin: 15px 0;'>
                <h3 style='color: white; margin-bottom: 10px;'>πŸ‘©πŸ’» Team Members</h3>
                <p style='color: white;'>Sadia<br>Areeba<br>Rabbia<br>Tesmia</p>
            </div>
        """, unsafe_allow_html=True)
        st.markdown("""
            <div style='background: rgba(255,255,255,0.1); padding: 15px; border-radius: 10px;'>
                <h3 style='color: white; margin-bottom: 10px;'>πŸ€– AI Models</h3>
                <p style='color: white;'>Mistral (Classification)<br>Groq (Defect Analysis)</p>
            </div>
        """, unsafe_allow_html=True)

    # Main content area
    col1, col2, col3 = st.columns([1,6,1])
    with col2:
        st.markdown("<h1 class='report-title'>AI Requirement Analyzer</h1>", unsafe_allow_html=True)
        
        # Input section
        with st.container():
            st.markdown("### πŸ“ Enter Requirements")
            input_text = st.text_area(
                "Enter your requirements (one per line or separated by periods):",
                height=200,
                label_visibility="collapsed"
            )
            
        # Analysis button
        if st.button("πŸ” Analyze Requirements", key="analyze_btn"):
            if not input_text.strip():
                st.warning("⚠️ Please enter requirements before analyzing")
            else:
                with st.spinner("πŸ”Ž Analyzing requirements..."):
                    requirements = [req.strip() for req in input_text.replace("\n", ".").split(".") if req.strip()]
                    results = []
                    progress_bar = st.progress(0)
                    for i, req in enumerate(requirements):
                        results.append(analyze_requirement(req.strip()))
                        progress_bar.progress((i+1)/len(requirements))
                    
                    # Display results
                    st.success("βœ… Analysis Complete!")
                    st.markdown("---")
                    st.markdown("## πŸ“Š Analysis Results")
                    
                    # Summary metrics
                    col1, col2, col3 = st.columns(3)
                    with col1:
                        st.markdown(f"""
                            <div class='metric-box'>
                                <h3>πŸ“„ Total Requirements</h3>
                                <h2>{len(results)}</h2>
                            </div>
                        """, unsafe_allow_html=True)
                    with col2:
                        types = [res['Type'] for res in results]
                        st.markdown(f"""
                            <div class='metric-box'>
                                <h3>πŸ“Š Functional/Non-Functional</h3>
                                <h2>{types.count('Functional')}/{types.count('Non-Functional')}</h2>
                            </div>
                        """, unsafe_allow_html=True)
                    with col3:
                        domains = len(set([res['Domain'] for res in results]))
                        st.markdown(f"""
                            <div class='metric-box'>
                                <h3>🌍 Unique Domains</h3>
                                <h2>{domains}</h2>
                            </div>
                        """, unsafe_allow_html=True)
                    
                    # Detailed results
                    st.markdown("---")
                    for i, result in enumerate(results, start=1):
                        with st.container():
                            st.markdown(f"""
                                <div class='requirement-card'>
                                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
                                        <h3>πŸ”– Requirement R{i}</h3>
                                        <span style="font-size: 0.9em; color: #666;">{result['Domain']} Domain</span>
                                    </div>
                                    <p style="color: #444; margin-bottom: 15px;">{result['Requirement']}</p>
                                    <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px;">
                                        <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
                                            <h4>πŸ“Œ Type</h4>
                                            <p>{result['Type']}</p>
                                        </div>
                                        <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
                                            <h4>⚠️ Defects</h4>
                                            <p>{result['Defects']}</p>
                                        </div>
                                        <div style="background: #f8f9fa; padding: 10px; border-radius: 8px;">
                                            <h4>✏️ Improved Version</h4>
                                            <p>{result['Rewritten']}</p>
                                        </div>
                                    </div>
                                </div>
                            """, unsafe_allow_html=True)
                    
                    # PDF Download
                    st.markdown("---")
                    st.markdown("## πŸ“€ Export Results")
                    pdf_report = generate_pdf_report(results)
                    with open(pdf_report, "rb") as f:
                        st.download_button(
                            label="πŸ“₯ Download Full Report (PDF)",
                            data=f,
                            file_name="requirements_report.pdf",
                            mime="application/pdf",
                            help="Download comprehensive PDF report with all analysis details"
                        )

if __name__ == "__main__":
    main()