Naz786 commited on
Commit
23e009d
·
verified ·
1 Parent(s): d689e85

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +334 -0
app.py ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import difflib
2
+ import streamlit as st
3
+ from groq import Groq
4
+ import os
5
+
6
+ # --- Custom CSS for Professional Look ---
7
+ st.markdown("""
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');
10
+ html, body, [class*="css"] {
11
+ font-family: 'Inter', sans-serif;
12
+ background-color: #f7f9fb;
13
+ }
14
+ .stApp {
15
+ background-color: #f7f9fb;
16
+ }
17
+ .stSidebar {
18
+ background-color: #22304a !important;
19
+ }
20
+ .stButton>button {
21
+ background-color: #22304a;
22
+ color: #fff;
23
+ border-radius: 6px;
24
+ border: none;
25
+ font-weight: 600;
26
+ padding: 0.5rem 1.5rem;
27
+ margin-top: 0.5rem;
28
+ margin-bottom: 0.5rem;
29
+ transition: background 0.2s;
30
+ }
31
+ .stButton>button:hover {
32
+ background-color: #1a2333;
33
+ color: #fff;
34
+ }
35
+ .stTextInput>div>div>input, .stTextArea>div>textarea {
36
+ background: #fff;
37
+ border: 1px solid #d1d5db;
38
+ border-radius: 6px;
39
+ color: #22304a;
40
+ font-size: 1rem;
41
+ }
42
+ .stDownloadButton>button {
43
+ background-color: #22304a;
44
+ color: #fff;
45
+ border-radius: 6px;
46
+ border: none;
47
+ font-weight: 600;
48
+ padding: 0.5rem 1.5rem;
49
+ margin-top: 0.5rem;
50
+ margin-bottom: 0.5rem;
51
+ transition: background 0.2s;
52
+ }
53
+ .stDownloadButton>button:hover {
54
+ background-color: #1a2333;
55
+ color: #fff;
56
+ }
57
+ .stExpanderHeader {
58
+ font-weight: 600;
59
+ color: #22304a;
60
+ font-size: 1.1rem;
61
+ }
62
+ .stMarkdown {
63
+ color: #22304a;
64
+ }
65
+ .stAlert {
66
+ border-radius: 6px;
67
+ }
68
+ </style>
69
+ """, unsafe_allow_html=True)
70
+
71
+ # --- Groq API Setup ---
72
+ GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
73
+ if not GROQ_API_KEY:
74
+ st.error("GROQ_API_KEY environment variable not set. Please set it in your Hugging Face Space secrets.")
75
+ st.stop()
76
+ client = Groq(api_key=GROQ_API_KEY)
77
+
78
+ def groq_api_call(prompt):
79
+ chat_completion = client.chat.completions.create(
80
+ messages=[{"role": "user", "content": prompt}],
81
+ model="llama3-70b-8192",
82
+ )
83
+ return chat_completion.choices[0].message.content
84
+
85
+ def get_diff_html(original, modified):
86
+ original_lines = original.splitlines()
87
+ modified_lines = modified.splitlines()
88
+ differ = difflib.HtmlDiff(tabsize=4, wrapcolumn=80)
89
+ return differ.make_table(original_lines, modified_lines, "Original", "Modified", context=True, numlines=2)
90
+
91
+ def code_complexity(code):
92
+ lines = code.count('\n') + 1
93
+ functions = code.count('def ')
94
+ classes = code.count('class ')
95
+ comments = code.count('#')
96
+ return f"Lines: {lines}, Functions: {functions}, Classes: {classes}, Comments: {comments}"
97
+
98
+ def detect_code_type(code, programming_language):
99
+ backend_keywords = [
100
+ 'flask', 'django', 'express', 'fastapi', 'spring', 'controller', 'api', 'server', 'database', 'sql', 'mongoose'
101
+ ]
102
+ frontend_keywords = [
103
+ 'react', 'vue', 'angular', 'component', 'html', 'css', 'document.getelementbyid', 'window.', 'render', 'jsx',
104
+ '<html', '<body', '<script', '<div', 'getelementbyid', 'queryselector', 'addeventlistener', 'innerhtml'
105
+ ]
106
+ data_science_keywords = [
107
+ 'pandas', 'numpy', 'sklearn', 'matplotlib', 'seaborn', 'plt', 'train_test_split', 'randomforestclassifier', 'classification_report'
108
+ ]
109
+ code_lower = code.lower()
110
+ if any(word in code_lower for word in data_science_keywords):
111
+ return 'data_science'
112
+ if any(word in code_lower for word in frontend_keywords):
113
+ return 'frontend'
114
+ if programming_language.lower() in ['python', 'java', 'c#']:
115
+ if any(word in code_lower for word in backend_keywords):
116
+ return 'backend'
117
+ if programming_language.lower() in ['javascript', 'typescript', 'java', 'c#']:
118
+ if any(word in code_lower for word in frontend_keywords):
119
+ return 'frontend'
120
+ if programming_language.lower() in ['python', 'java', 'c#']:
121
+ return 'backend'
122
+ if programming_language.lower() in ['javascript', 'typescript']:
123
+ return 'frontend'
124
+ return 'unknown'
125
+
126
+ def code_matches_language(code: str, language: str) -> bool:
127
+ code = code.strip().lower()
128
+ if language.lower() == "python":
129
+ return "def " in code or "import " in code or ".py" in code
130
+ if language.lower() == "c++":
131
+ return "#include" in code or "int main" in code or ".cpp" in code or "std::" in code
132
+ if language.lower() == "java":
133
+ return "public class" in code or "public static void main" in code or ".java" in code
134
+ if language.lower() == "c#":
135
+ return "using system" in code or "namespace" in code or ".cs" in code
136
+ if language.lower() == "javascript":
137
+ return "function " in code or "const " in code or "let " in code or "var " in code or ".js" in code
138
+ if language.lower() == "typescript":
139
+ return "function " in code or "const " in code or "let " in code or "var " in code or ": string" in code or ".ts" in code
140
+ if language.lower() == "html":
141
+ return "<html" in code or "<!doctype html" in code
142
+ return True # fallback
143
+
144
+ def agentic_workflow(code, skill_level, programming_language, explanation_language, user_role):
145
+ timeline = []
146
+ suggestions = []
147
+
148
+ explain_prompt = (
149
+ f"Explain the following {programming_language} code line by line or function by function "
150
+ f"for a {skill_level.lower()} {user_role} in {explanation_language}:\n{code}"
151
+ )
152
+ explanation = groq_api_call(explain_prompt)
153
+ timeline.append({
154
+ "step": "Explain",
155
+ "description": "Step-by-step explanation of your code.",
156
+ "output": explanation,
157
+ "code": code
158
+ })
159
+ suggestions.append("Refactor your code for better readability and performance.")
160
+
161
+ refactor_prompt = (
162
+ f"Refactor the following {programming_language} code for better readability, performance, and structure. "
163
+ f"Explain what changes you made and why, for a {skill_level.lower()} {user_role} in {explanation_language}:\n{code}"
164
+ )
165
+ refactor_response = groq_api_call(refactor_prompt)
166
+ if "```" in refactor_response:
167
+ parts = refactor_response.split("```")
168
+ refactor_explanation = parts[0].strip()
169
+ refactored_code = ""
170
+ for i in range(1, len(parts)):
171
+ if parts[i].strip().startswith(programming_language.lower()):
172
+ refactored_code = parts[i].strip().split('\n', 1)[1] if '\n' in parts[i] else ""
173
+ break
174
+ elif i == 1:
175
+ refactored_code = parts[i].strip().split('\n', 1)[1] if '\n' in parts[i] else ""
176
+ if not refactored_code:
177
+ refactored_code = refactor_response.strip()
178
+ else:
179
+ refactor_explanation = "Refactored code below."
180
+ refactored_code = refactor_response.strip()
181
+ timeline.append({
182
+ "step": "Refactor",
183
+ "description": refactor_explanation,
184
+ "output": refactored_code,
185
+ "code": refactored_code
186
+ })
187
+ suggestions.append("Review the refactored code for best practices and improvements.")
188
+
189
+ review_prompt = (
190
+ f"Provide a code review for the following {programming_language} code. "
191
+ f"Include feedback on best practices, code smells, optimization, and security issues, for a {skill_level.lower()} {user_role} in {explanation_language}:\n{refactored_code}"
192
+ )
193
+ review_feedback = groq_api_call(review_prompt)
194
+ timeline.append({
195
+ "step": "Review",
196
+ "description": "AI code review and feedback.",
197
+ "output": review_feedback,
198
+ "code": refactored_code
199
+ })
200
+ suggestions.append("Generate unit tests for your code.")
201
+
202
+ test_prompt = (
203
+ f"Write unit tests for the following {programming_language} code. "
204
+ f"Use pytest style and cover all functions. For a {skill_level.lower()} {user_role} in {explanation_language}:\n{refactored_code}"
205
+ )
206
+ test_code = groq_api_call(test_prompt)
207
+ timeline.append({
208
+ "step": "Test Generation",
209
+ "description": "AI-generated unit tests for your code.",
210
+ "output": test_code,
211
+ "code": test_code
212
+ })
213
+ suggestions.append("Run the generated tests in your local environment.")
214
+
215
+ return timeline, suggestions
216
+
217
+ st.set_page_config(page_title="AI Code Assistant", layout="wide")
218
+ st.markdown(
219
+ "<h2 style='text-align: center; color: #22304a; font-weight: 600; margin-bottom: 0.5em;'>AI Code Assistant</h2>",
220
+ unsafe_allow_html=True
221
+ )
222
+
223
+ with st.sidebar:
224
+ st.title("Settings")
225
+ programming_language = st.selectbox(
226
+ "Programming Language",
227
+ ["Python", "C++", "Java", "C#", "JavaScript", "TypeScript", "HTML"]
228
+ )
229
+ explanation_language = st.selectbox(
230
+ "Explanation Language",
231
+ ["English", "Urdu", "Chinese", "Spanish"]
232
+ )
233
+ skill_level = st.selectbox("Skill Level", ["Beginner", "Intermediate", "Expert"])
234
+ user_role = st.selectbox(
235
+ "Choose Role",
236
+ ["Data Scientist", "Backend Developer", "Frontend Developer", "Student"]
237
+ )
238
+ st.markdown("---")
239
+ st.markdown("<span style='color:#fff;'>Powered by <b>BLACKBOX.AI</b></span>", unsafe_allow_html=True)
240
+
241
+ if "code" not in st.session_state:
242
+ st.session_state.code = ""
243
+ if "timeline" not in st.session_state:
244
+ st.session_state.timeline = []
245
+ if "suggestions" not in st.session_state:
246
+ st.session_state.suggestions = []
247
+
248
+ col1, col2 = st.columns([2, 3], gap="large")
249
+
250
+ with col1:
251
+ st.subheader(f"{programming_language} Code")
252
+ uploaded_file = st.file_uploader(f"Upload .{programming_language.lower()} file", type=[programming_language.lower()])
253
+ code_input = st.text_area(
254
+ "Paste or edit your code here:",
255
+ height=300,
256
+ value=st.session_state.code,
257
+ key="main_code_input"
258
+ )
259
+ if uploaded_file is not None:
260
+ code = uploaded_file.read().decode("utf-8")
261
+ st.session_state.code = code
262
+ st.success("File uploaded successfully.")
263
+ elif code_input:
264
+ st.session_state.code = code_input
265
+
266
+ st.markdown(f"<b>Complexity:</b> {code_complexity(st.session_state.code)}", unsafe_allow_html=True)
267
+
268
+ st.markdown("---")
269
+ st.markdown("#### Agent Suggestions")
270
+ for suggestion in st.session_state.suggestions[-3:]:
271
+ st.markdown(f"- {suggestion}")
272
+
273
+ st.markdown("---")
274
+ st.markdown("#### Download Full Report")
275
+ if st.session_state.timeline:
276
+ report = ""
277
+ for step in st.session_state.timeline:
278
+ report += f"## {step['step']}\n{step['description']}\n\n{step['output']}\n\n"
279
+ st.download_button("Download Report", report, file_name="ai_code_assistant_report.txt")
280
+
281
+ with col2:
282
+ st.subheader("Agentic Workflow")
283
+ if st.button("Run Full AI Agent Workflow"):
284
+ if not st.session_state.code.strip():
285
+ st.warning("Please enter or upload code first.")
286
+ else:
287
+ # Language check
288
+ if not code_matches_language(st.session_state.code, programming_language):
289
+ st.error(f"It looks like you provided code in a different language. Please provide {programming_language} code.")
290
+ else:
291
+ code_type = detect_code_type(st.session_state.code, programming_language)
292
+ # Role/code type enforcement
293
+ if code_type == "data_science" and user_role != "Data Scientist":
294
+ st.error("It looks like you provided data science code. Please select 'Data Scientist' as your role.")
295
+ elif code_type == "frontend" and user_role != "Frontend Developer":
296
+ st.error("It looks like you provided frontend code. Please select 'Frontend Developer' as your role.")
297
+ elif code_type == "backend" and user_role != "Backend Developer":
298
+ st.error("It looks like you provided backend code. Please select 'Backend Developer' as your role.")
299
+ elif code_type == "unknown":
300
+ st.warning("Could not determine the code type. Please make sure your code is complete and clear.")
301
+ else:
302
+ with st.spinner("AI Agent is working through all steps..."):
303
+ timeline, suggestions = agentic_workflow(
304
+ st.session_state.code,
305
+ skill_level,
306
+ programming_language,
307
+ explanation_language,
308
+ user_role
309
+ )
310
+ st.session_state.timeline = timeline
311
+ st.session_state.suggestions = suggestions
312
+ st.success("Agentic workflow complete. See timeline below.")
313
+
314
+ if st.session_state.timeline:
315
+ for i, step in enumerate(st.session_state.timeline):
316
+ with st.expander(f"Step {i+1}: {step['step']}"):
317
+ st.markdown(f"<b>{step['description']}</b>", unsafe_allow_html=True)
318
+ if step['step'] in ["Refactor", "Test Generation"]:
319
+ if i > 0:
320
+ prev_code = st.session_state.timeline[i-1]['code']
321
+ diff_html = get_diff_html(prev_code, step['code'])
322
+ st.markdown("**Side-by-Side Diff:**")
323
+ st.components.v1.html(diff_html, height=400, scrolling=True)
324
+ if step['step'] in ["Refactor", "Test Generation"]:
325
+ st.markdown("**Code Output:**")
326
+ st.code(step['output'], language=programming_language.lower())
327
+ else:
328
+ st.markdown("**Output:**")
329
+ st.write(step['output'])
330
+ else:
331
+ st.info("Run the agentic workflow to see step-by-step results, explanations, and code evolution.")
332
+
333
+ st.markdown("---")
334
+ st.markdown('<div style="text-align: center; color: #22304a; font-size: 1rem; margin-top: 2em;">Powered by <b>BLACKBOX.AI</b></div>', unsafe_allow_html=True)