Spaces:
Sleeping
Sleeping
| import difflib | |
| import streamlit as st | |
| from groq import Groq | |
| import os | |
| # --- Set page config FIRST! --- | |
| st.set_page_config(page_title="AI Code Assistant", layout="wide") | |
| # --- Custom CSS for Professional Look --- | |
| st.markdown(""" | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap'); | |
| html, body, [class*="css"] { | |
| font-family: 'Inter', sans-serif; | |
| background-color: #f7f9fb; | |
| } | |
| .stApp { | |
| background-color: #f7f9fb; | |
| } | |
| .stSidebar { | |
| background-color: #22304a !important; | |
| } | |
| .stButton>button { | |
| background-color: #22304a; | |
| color: #fff; | |
| border-radius: 6px; | |
| border: none; | |
| font-weight: 600; | |
| padding: 0.5rem 1.5rem; | |
| margin-top: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| transition: background 0.2s; | |
| } | |
| .stButton>button:hover { | |
| background-color: #1a2333; | |
| color: #fff; | |
| } | |
| .stTextInput>div>div>input, .stTextArea>div>textarea { | |
| background: #fff; | |
| border: 1px solid #d1d5db; | |
| border-radius: 6px; | |
| color: #22304a; | |
| font-size: 1rem; | |
| } | |
| .stDownloadButton>button { | |
| background-color: #22304a; | |
| color: #fff; | |
| border-radius: 6px; | |
| border: none; | |
| font-weight: 600; | |
| padding: 0.5rem 1.5rem; | |
| margin-top: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| transition: background 0.2s; | |
| } | |
| .stDownloadButton>button:hover { | |
| background-color: #1a2333; | |
| color: #fff; | |
| } | |
| .stExpanderHeader { | |
| font-weight: 600; | |
| color: #22304a; | |
| font-size: 1.1rem; | |
| } | |
| .stMarkdown { | |
| color: #22304a; | |
| } | |
| .stAlert { | |
| border-radius: 6px; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- Groq API Setup --- | |
| GROQ_API_KEY = os.environ.get("GROQ_API_KEY") | |
| if not GROQ_API_KEY: | |
| st.error("GROQ_API_KEY environment variable not set. Please set it in your Hugging Face Space secrets.") | |
| st.stop() | |
| client = Groq(api_key=GROQ_API_KEY) | |
| # --- Blackbox AI Agent Setup --- | |
| BLACKBOX_API_KEY = os.environ.get("BLACKBOX_API_KEY") | |
| if not BLACKBOX_API_KEY: | |
| st.error("BLACKBOX_API_KEY environment variable not set. Please set it in your Hugging Face Space secrets.") | |
| st.stop() | |
| # Chat history management | |
| if "chat_history" not in st.session_state: | |
| st.session_state.chat_history = [] | |
| def groq_api_call(prompt): | |
| chat_completion = client.chat.completions.create( | |
| messages=[{"role": "user", "content": prompt}], | |
| model="llama3-70b-8192", | |
| ) | |
| return chat_completion.choices[0].message.content | |
| def blackbox_ai_call(messages): | |
| # This is a placeholder for actual Blackbox AI API call using BLACKBOX_API_KEY | |
| # For demonstration, we simulate a response by echoing last user message | |
| last_user_message = messages[-1]["content"] if messages else "" | |
| response = f"Blackbox AI response to: {last_user_message}" | |
| return response | |
| def get_diff_html(original, modified): | |
| original_lines = original.splitlines() | |
| modified_lines = modified.splitlines() | |
| differ = difflib.HtmlDiff(tabsize=4, wrapcolumn=80) | |
| return differ.make_table(original_lines, modified_lines, "Original", "Modified", context=True, numlines=2) | |
| def code_complexity(code): | |
| lines = code.count('\n') + 1 | |
| functions = code.count('def ') | |
| classes = code.count('class ') | |
| comments = code.count('#') | |
| return f"Lines: {lines}, Functions: {functions}, Classes: {classes}, Comments: {comments}" | |
| def detect_code_type(code, programming_language): | |
| backend_keywords = [ | |
| 'flask', 'django', 'express', 'fastapi', 'spring', 'controller', 'api', 'server', 'database', 'sql', 'mongoose' | |
| ] | |
| frontend_keywords = [ | |
| 'react', 'vue', 'angular', 'component', 'html', 'css', 'document.getelementbyid', 'window.', 'render', 'jsx', | |
| '<html', '<body', '<script', '<div', 'getelementbyid', 'queryselector', 'addeventlistener', 'innerhtml' | |
| ] | |
| data_science_keywords = [ | |
| 'pandas', 'numpy', 'sklearn', 'matplotlib', 'seaborn', 'plt', 'train_test_split', 'randomforestclassifier', 'classification_report' | |
| ] | |
| code_lower = code.lower() | |
| if any(word in code_lower for word in data_science_keywords): | |
| return 'data_science' | |
| if any(word in code_lower for word in frontend_keywords): | |
| return 'frontend' | |
| if programming_language.lower() in ['python', 'java', 'c#']: | |
| if any(word in code_lower for word in backend_keywords): | |
| return 'backend' | |
| if programming_language.lower() in ['javascript', 'typescript', 'java', 'c#']: | |
| if any(word in code_lower for word in frontend_keywords): | |
| return 'frontend' | |
| if programming_language.lower() in ['python', 'java', 'c#']: | |
| return 'backend' | |
| if programming_language.lower() in ['javascript', 'typescript']: | |
| return 'frontend' | |
| return 'unknown' | |
| def code_matches_language(code: str, language: str) -> bool: | |
| code = code.strip().lower() | |
| if language.lower() == "python": | |
| return "def " in code or "import " in code or ".py" in code | |
| if language.lower() == "c++": | |
| return "#include" in code or "int main" in code or ".cpp" in code or "std::" in code | |
| if language.lower() == "java": | |
| return "public class" in code or "public static void main" in code or ".java" in code | |
| if language.lower() == "c#": | |
| return "using system" in code or "namespace" in code or ".cs" in code | |
| if language.lower() == "javascript": | |
| return "function " in code or "const " in code or "let " in code or "var " in code or ".js" in code | |
| if language.lower() == "typescript": | |
| return "function " in code or "const " in code or "let " in code or "var " in code or ": string" in code or ".ts" in code | |
| if language.lower() == "html": | |
| return "<html" in code or "<!doctype html" in code | |
| return True # fallback | |
| def agentic_workflow(code, skill_level, programming_language, explanation_language, user_role): | |
| timeline = [] | |
| suggestions = [] | |
| explain_prompt = ( | |
| f"Explain the following {programming_language} code line by line or function by function " | |
| f"for a {skill_level.lower()} {user_role} in {explanation_language}:\n{code}" | |
| ) | |
| explanation = groq_api_call(explain_prompt) | |
| timeline.append({ | |
| "step": "Explain", | |
| "description": "Step-by-step explanation of your code.", | |
| "output": explanation, | |
| "code": code | |
| }) | |
| suggestions.append("Refactor your code for better readability and performance.") | |
| refactor_prompt = ( | |
| f"Refactor the following {programming_language} code for better readability, performance, and structure. " | |
| f"Explain what changes you made and why, for a {skill_level.lower()} {user_role} in {explanation_language}:\n{code}" | |
| ) | |
| refactor_response = groq_api_call(refactor_prompt) | |
| if "```" in refactor_response: | |
| parts = refactor_response.split("```") | |
| refactor_explanation = parts[0].strip() | |
| refactored_code = "" | |
| for i in range(1, len(parts)): | |
| if parts[i].strip().startswith(programming_language.lower()): | |
| refactored_code = parts[i].strip().split('\n', 1)[1] if '\n' in parts[i] else "" | |
| break | |
| elif i == 1: | |
| refactored_code = parts[i].strip().split('\n', 1)[1] if '\n' in parts[i] else "" | |
| if not refactored_code: | |
| refactored_code = refactor_response.strip() | |
| else: | |
| refactor_explanation = "Refactored code below." | |
| refactored_code = refactor_response.strip() | |
| timeline.append({ | |
| "step": "Refactor", | |
| "description": refactor_explanation, | |
| "output": refactored_code, | |
| "code": refactored_code | |
| }) | |
| suggestions.append("Review the refactored code for best practices and improvements.") | |
| review_prompt = ( | |
| f"Provide a code review for the following {programming_language} code. " | |
| 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}" | |
| ) | |
| review_feedback = groq_api_call(review_prompt) | |
| timeline.append({ | |
| "step": "Review", | |
| "description": "AI code review and feedback.", | |
| "output": review_feedback, | |
| "code": refactored_code | |
| }) | |
| suggestions.append("Generate unit tests for your code.") | |
| test_prompt = ( | |
| f"Write unit tests for the following {programming_language} code. " | |
| f"Use pytest style and cover all functions. For a {skill_level.lower()} {user_role} in {explanation_language}:\n{refactored_code}" | |
| ) | |
| test_code = groq_api_call(test_prompt) | |
| timeline.append({ | |
| "step": "Test Generation", | |
| "description": "AI-generated unit tests for your code.", | |
| "output": test_code, | |
| "code": test_code | |
| }) | |
| suggestions.append("Run the generated tests in your local environment.") | |
| return timeline, suggestions | |
| st.markdown( | |
| "<h2 style='text-align: center; color: #22304a; font-weight: 600; margin-bottom: 0.5em;'>AI Code Assistant</h2>", | |
| unsafe_allow_html=True | |
| ) | |
| with st.sidebar: | |
| st.title("Settings") | |
| programming_language = st.selectbox( | |
| "Programming Language", | |
| ["Python", "C++", "Java", "C#", "JavaScript", "TypeScript", "HTML"] | |
| ) | |
| explanation_language = st.selectbox( | |
| "Explanation Language", | |
| ["English", "Urdu", "Chinese", "Spanish"] | |
| ) | |
| skill_level = st.selectbox("Skill Level", ["Beginner", "Intermediate", "Expert"]) | |
| user_role = st.selectbox( | |
| "Choose Role", | |
| ["Data Scientist", "Backend Developer", "Frontend Developer", "Student"] | |
| ) | |
| st.markdown("---") | |
| st.markdown("<span style='color:#fff;'>Powered by <b>BLACKBOX.AI</b></span>", unsafe_allow_html=True) | |
| if "code" not in st.session_state: | |
| st.session_state.code = "" | |
| if "timeline" not in st.session_state: | |
| st.session_state.timeline = [] | |
| if "suggestions" not in st.session_state: | |
| st.session_state.suggestions = [] | |
| if "chat_history" not in st.session_state: | |
| st.session_state.chat_history = [] | |
| col1, col2 = st.columns([2, 3], gap="large") | |
| with col1: | |
| st.subheader(f"{programming_language} Code") | |
| uploaded_file = st.file_uploader(f"Upload .{programming_language.lower()} file", type=[programming_language.lower()]) | |
| code_input = st.text_area( | |
| "Paste or edit your code here:", | |
| height=300, | |
| value=st.session_state.code, | |
| key="main_code_input" | |
| ) | |
| if uploaded_file is not None: | |
| code = uploaded_file.read().decode("utf-8") | |
| st.session_state.code = code | |
| st.success("File uploaded successfully.") | |
| elif code_input: | |
| st.session_state.code = code_input | |
| st.markdown(f"<b>Complexity:</b> {code_complexity(st.session_state.code)}", unsafe_allow_html=True) | |
| st.markdown("---") | |
| st.markdown("#### Agent Suggestions") | |
| for suggestion in st.session_state.suggestions[-3:]: | |
| st.markdown(f"- {suggestion}") | |
| st.markdown("---") | |
| st.markdown("#### Download Full Report") | |
| if st.session_state.timeline: | |
| report = "" | |
| for step in st.session_state.timeline: | |
| report += f"## {step['step']}\n{step['description']}\n\n{step['output']}\n\n" | |
| st.download_button("Download Report", report, file_name="ai_code_assistant_report.txt") | |
| with col2: | |
| st.subheader("Agentic Workflow") | |
| if st.button("Run Full AI Agent Workflow"): | |
| if not st.session_state.code.strip(): | |
| st.warning("Please enter or upload code first.") | |
| else: | |
| # Language check | |
| if not code_matches_language(st.session_state.code, programming_language): | |
| st.error(f"It looks like you provided code in a different language. Please provide {programming_language} code.") | |
| else: | |
| code_type = detect_code_type(st.session_state.code, programming_language) | |
| # Role/code type enforcement | |
| if code_type == "data_science" and user_role != "Data Scientist": | |
| st.error("It looks like you provided data science code. Please select 'Data Scientist' as your role.") | |
| elif code_type == "frontend" and user_role != "Frontend Developer": | |
| st.error("It looks like you provided frontend code. Please select 'Frontend Developer' as your role.") | |
| elif code_type == "backend" and user_role != "Backend Developer": | |
| st.error("It looks like you provided backend code. Please select 'Backend Developer' as your role.") | |
| elif code_type == "unknown": | |
| st.warning("Could not determine the code type. Please make sure your code is complete and clear.") | |
| else: | |
| with st.spinner("AI Agent is working through all steps..."): | |
| timeline, suggestions = agentic_workflow( | |
| st.session_state.code, | |
| skill_level, | |
| programming_language, | |
| explanation_language, | |
| user_role | |
| ) | |
| st.session_state.timeline = timeline | |
| st.session_state.suggestions = suggestions | |
| st.success("Agentic workflow complete. See timeline below.") | |
| # Chatbox with history using Blackbox AI agent | |
| st.subheader("Chat with Blackbox AI Agent") | |
| user_input = st.text_input("Enter your message:", key="chat_input") | |
| if user_input: | |
| st.session_state.chat_history.append({"role": "user", "content": user_input}) | |
| response = blackbox_ai_call(st.session_state.chat_history) | |
| st.session_state.chat_history.append({"role": "assistant", "content": response}) | |
| for chat in st.session_state.chat_history: | |
| if chat["role"] == "user": | |
| st.markdown(f"**You:** {chat['content']}") | |
| else: | |
| st.markdown(f"**Blackbox AI:** {chat['content']}") | |
| st.markdown("---") | |
| 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) | |