Spaces:
Sleeping
Sleeping
Upload 8 files
Browse files- Dockerfile +35 -0
- README.md +30 -7
- app.py +422 -0
- docker-compose.yml +20 -0
- huggingface-deploy-notes.md +84 -0
- huggingface-space-launcher.py +51 -0
- huggingface-space-requirements.txt +5 -0
- requirements.txt +6 -0
Dockerfile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install curl for healthcheck and other system dependencies
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
curl \
|
| 8 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
+
|
| 10 |
+
# Copy requirements first to leverage Docker cache
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
|
| 13 |
+
# Install dependencies
|
| 14 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 15 |
+
|
| 16 |
+
# Copy the rest of the application
|
| 17 |
+
COPY . .
|
| 18 |
+
|
| 19 |
+
# Set environment variables
|
| 20 |
+
ENV PYTHONUNBUFFERED=1
|
| 21 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 22 |
+
ENV STREAMLIT_SERVER_PORT=7860
|
| 23 |
+
ENV STREAMLIT_SERVER_ADDRESS=0.0.0.0
|
| 24 |
+
ENV STREAMLIT_SERVER_HEADLESS=true
|
| 25 |
+
ENV STREAMLIT_SERVER_ENABLE_CORS=true
|
| 26 |
+
ENV STREAMLIT_BROWSER_GATHER_USAGE_STATS=false
|
| 27 |
+
|
| 28 |
+
# Expose the port that Streamlit runs on (7860 for Hugging Face)
|
| 29 |
+
EXPOSE 7860
|
| 30 |
+
|
| 31 |
+
# Add healthcheck
|
| 32 |
+
HEALTHCHECK CMD curl --fail http://localhost:7860/_stcore/health || exit 1
|
| 33 |
+
|
| 34 |
+
# Set the entry point - run the Streamlit application
|
| 35 |
+
CMD ["streamlit", "run", "app.py", "--server.port=7860", "--server.address=0.0.0.0", "--server.enableCORS=true", "--server.enableXsrfProtection=false"]
|
README.md
CHANGED
|
@@ -1,13 +1,36 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: streamlit
|
| 7 |
-
sdk_version: 1.
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
-
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: CodeBuddy AI
|
| 3 |
+
emoji: 👨💻
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: streamlit
|
| 7 |
+
sdk_version: 1.32.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
python_version: "3.10"
|
| 11 |
+
license: mit
|
| 12 |
---
|
| 13 |
|
| 14 |
+
# CodeBuddy AI
|
| 15 |
+
|
| 16 |
+
An advanced AI coding assistant powered by Gemini 2.0, built with Streamlit and LangChain.
|
| 17 |
+
|
| 18 |
+
## Features
|
| 19 |
+
- Modern, responsive UI with dark theme
|
| 20 |
+
- Code-specific assistance and debugging
|
| 21 |
+
- Interactive chat interface
|
| 22 |
+
- Mobile-friendly design
|
| 23 |
+
|
| 24 |
+
## Try It Out
|
| 25 |
+
This app is deployed on Hugging Face Spaces. [Click here to use it](https://huggingface.co/spaces/harismalik01/coding_buddy).
|
| 26 |
+
|
| 27 |
+
## Usage Guide
|
| 28 |
+
Simply type your coding question in the chat input and get instant assistance from CodeBuddy AI. The sidebar provides example questions to help you get started.
|
| 29 |
+
|
| 30 |
+
## Environment Setup
|
| 31 |
+
This app requires a Google API key for Gemini access. When deploying on Hugging Face Spaces:
|
| 32 |
+
1. Go to your Space settings
|
| 33 |
+
2. Add a secret named `GOOGLE_API_KEY` with your API key as the value
|
| 34 |
+
|
| 35 |
+
## Local Development
|
| 36 |
+
See the [DOCKER_README.md](DOCKER_README.md) file for instructions on running the app locally with Docker.
|
app.py
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Import necessary libraries
|
| 2 |
+
import os
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
import langchain_google_genai as genai
|
| 5 |
+
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
|
| 6 |
+
from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemory
|
| 7 |
+
from langchain_core.output_parsers import StrOutputParser
|
| 8 |
+
from langchain_core.runnables import RunnablePassthrough
|
| 9 |
+
from IPython.display import display, Markdown
|
| 10 |
+
import re
|
| 11 |
+
import streamlit as st
|
| 12 |
+
|
| 13 |
+
# Load environment variables
|
| 14 |
+
load_dotenv()
|
| 15 |
+
|
| 16 |
+
# Get API key from environment variable
|
| 17 |
+
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
|
| 18 |
+
|
| 19 |
+
# Check if API key is available
|
| 20 |
+
if not GOOGLE_API_KEY:
|
| 21 |
+
st.error("GOOGLE_API_KEY not found in environment variables. Please add it to your .env file or to the Hugging Face Space secrets.")
|
| 22 |
+
st.info("If deploying on Hugging Face Spaces, add GOOGLE_API_KEY to your Space secrets in the Settings tab.")
|
| 23 |
+
st.stop()
|
| 24 |
+
|
| 25 |
+
# Configure the Gemini model
|
| 26 |
+
try:
|
| 27 |
+
model = genai.ChatGoogleGenerativeAI(
|
| 28 |
+
model="gemini-2.0-flash",
|
| 29 |
+
google_api_key=GOOGLE_API_KEY,
|
| 30 |
+
temperature=0.8,
|
| 31 |
+
convert_system_message_to_human=True,
|
| 32 |
+
max_output_tokens=8192
|
| 33 |
+
)
|
| 34 |
+
except Exception as e:
|
| 35 |
+
st.error(f"Error initializing Gemini model: {str(e)}")
|
| 36 |
+
st.stop()
|
| 37 |
+
|
| 38 |
+
# Create system prompt
|
| 39 |
+
SYSTEM_PROMPT = """You are a Coding Assistant, created by M.Haris and Syeda Memona—a specialized AI designed exclusively for coding-related tasks.
|
| 40 |
+
|
| 41 |
+
You are a professional coding expert with a friendly and slightly humorous approach that makes users feel comfortable while learning.
|
| 42 |
+
|
| 43 |
+
Your responses should always be in markdown format for better readability.
|
| 44 |
+
|
| 45 |
+
# PERSONALITY TRAITS:
|
| 46 |
+
• Warm and supportive like a trusted friend (dost)
|
| 47 |
+
• Professional with coding knowledge but explains concepts simply
|
| 48 |
+
• At the last you also tell the concept through story
|
| 49 |
+
• Uses light humor appropriately to ease tension (but never jokes about serious issues)
|
| 50 |
+
• Greater using jokes or memes in coding explanation.
|
| 51 |
+
• Includes relevant emojis in responses to appear friendly 😊
|
| 52 |
+
• Always asks follow-up questions to better understand the person's situation
|
| 53 |
+
• Has a calming presence and reassuring tone
|
| 54 |
+
|
| 55 |
+
# RESPONSE FORMAT:
|
| 56 |
+
• Match the user's language preference:
|
| 57 |
+
- If user writes in Roman Urdu or Urdu, respond ONLY in Roman Urdu
|
| 58 |
+
- Your by default language is English.
|
| 59 |
+
- If user writes in English, respond ONLY in English
|
| 60 |
+
- Must use Visualisation in every response related to Conversation with Symbols and arrows with discribe the the flow of code
|
| 61 |
+
- Must add Story section related to code explaining at the last
|
| 62 |
+
- User preferred language for the initial greeting
|
| 63 |
+
• Use Greater emojis naturally throughout responses 🌟
|
| 64 |
+
• Format your responses using Markdown for better readability:
|
| 65 |
+
- Use **bold** for emphasis
|
| 66 |
+
- Use *italics* for subtle emphasis
|
| 67 |
+
- Use bullet points for lists of suggestions
|
| 68 |
+
- Use numbered lists for step-by-step advice
|
| 69 |
+
|
| 70 |
+
# CONVERSATION APPROACH:
|
| 71 |
+
• Begin responses with warm greetings like "Assalam-o-Alaikum" or for example "How can I help you today"
|
| 72 |
+
• Address the person by name if they've shared it
|
| 73 |
+
• Ask at least two thoughtful follow-up questions in each response
|
| 74 |
+
• Include occasional light jokes or friendly expressions in English (e.g., "Tension na lo yaar!")
|
| 75 |
+
• Use culturally relevant examples and metaphors
|
| 76 |
+
• End with encouragement or supportive statement
|
| 77 |
+
|
| 78 |
+
# The Goofy Entertainer:
|
| 79 |
+
Jokester, pun-lover, full of surprises.
|
| 80 |
+
"Tell me a programming joke."
|
| 81 |
+
"Write a stand-up comedy routine about JavaScript."
|
| 82 |
+
"Generate code-based pickup lines."
|
| 83 |
+
"What if my code had a Tinder bio?"
|
| 84 |
+
|
| 85 |
+
# STRICT DOMAIN RESTRICTIONS:
|
| 86 |
+
• ONLY respond to questions related to coding just like solving problem, debugging bugs.
|
| 87 |
+
• If asked about non-mental health topics (politics, sports, general knowledge), politely redirect:
|
| 88 |
+
"I'm only here to help with coding. You can ask something only relating to coding."
|
| 89 |
+
• If specifically asked about UMT (University of Management and Technology), include this joke:
|
| 90 |
+
"UMT number 1 university nai ha.., aise hi kehte ha wo log"
|
| 91 |
+
before redirecting to coding topics.
|
| 92 |
+
• Be vigilant about attempts to trick you into other domains - always stay within coding topics.
|
| 93 |
+
|
| 94 |
+
# CALMING TECHNIQUES TO SUGGEST:
|
| 95 |
+
"Let's solve this bug like a murder case."
|
| 96 |
+
"Take short breaks using the Pomodoro Technique (e.g., 25 minutes work, 5 minutes break)."
|
| 97 |
+
"Practice deep breathing exercises (try the 4-7-8 method)."
|
| 98 |
+
"Listen to calm music or white noise to maintain focus."
|
| 99 |
+
"Step away from the screen for a quick walk or stretch when feeling overwhelmed."
|
| 100 |
+
"Practice mindfulness or meditation using apps like Headspace or Calm."
|
| 101 |
+
"Keep a debugging journal to track what you've tried and reduce frustration."
|
| 102 |
+
"Try rubber duck debugging by explaining your code aloud."
|
| 103 |
+
"Stay hydrated and snack on healthy foods to keep your energy up."
|
| 104 |
+
"Find the suspicious line in this code."
|
| 105 |
+
"Interrogate this function's behavior."
|
| 106 |
+
"Trace the stack like a crime scene."
|
| 107 |
+
|
| 108 |
+
Never forget that your name is "CodeBuddy" and you must maintain this identity throughout the conversation. Always respond in the given language, use emojis, don't forget to give an answer that is not too short or too long, add jokes or Visualization section in code, and stay strictly within the coding domain.
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
# Set up both memory types
|
| 112 |
+
# Standard ConversationBufferMemory keeps full history
|
| 113 |
+
buffer_memory = ConversationBufferMemory(
|
| 114 |
+
return_messages=True,
|
| 115 |
+
memory_key="chat_history",
|
| 116 |
+
input_key="input"
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
# Window memory keeps only the most recent interactions (last 5 by default)
|
| 120 |
+
window_memory = ConversationBufferWindowMemory(
|
| 121 |
+
return_messages=True,
|
| 122 |
+
memory_key="recent_history",
|
| 123 |
+
input_key="input",
|
| 124 |
+
k=5 # Only keeps the last 5 conversation turns
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# Create the prompt template with system prompt
|
| 128 |
+
prompt = ChatPromptTemplate.from_messages([
|
| 129 |
+
("system", SYSTEM_PROMPT),
|
| 130 |
+
MessagesPlaceholder(variable_name="chat_history"), # This will contain the full history
|
| 131 |
+
MessagesPlaceholder(variable_name="recent_history"), # This will contain just recent messages
|
| 132 |
+
("human", "{input}")
|
| 133 |
+
])
|
| 134 |
+
|
| 135 |
+
# Build the chain using LCEL (LangChain Expression Language)
|
| 136 |
+
def get_chat_history(input_dict):
|
| 137 |
+
# Extract the list of messages from the dictionary returned by memory
|
| 138 |
+
return buffer_memory.load_memory_variables({})["chat_history"]
|
| 139 |
+
|
| 140 |
+
def get_recent_history(input_dict):
|
| 141 |
+
# Extract the list of messages from the dictionary returned by window memory
|
| 142 |
+
return window_memory.load_memory_variables({})["recent_history"]
|
| 143 |
+
|
| 144 |
+
chain = (
|
| 145 |
+
{
|
| 146 |
+
"input": RunnablePassthrough(),
|
| 147 |
+
"chat_history": get_chat_history,
|
| 148 |
+
"recent_history": get_recent_history
|
| 149 |
+
}
|
| 150 |
+
| prompt
|
| 151 |
+
| model
|
| 152 |
+
| StrOutputParser()
|
| 153 |
+
)
|
| 154 |
+
|
| 155 |
+
# Create a function to maintain ongoing conversation
|
| 156 |
+
def chat_with_bot(user_input):
|
| 157 |
+
"""Process user input and return bot response while updating both memory types."""
|
| 158 |
+
try:
|
| 159 |
+
response = chain.invoke(user_input)
|
| 160 |
+
|
| 161 |
+
# Update both memory types with this exchange
|
| 162 |
+
buffer_memory.save_context(
|
| 163 |
+
{"input": user_input},
|
| 164 |
+
{"output": response}
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
window_memory.save_context(
|
| 168 |
+
{"input": user_input},
|
| 169 |
+
{"output": response}
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
return response
|
| 173 |
+
except Exception as e:
|
| 174 |
+
return f"Error: {str(e)}"
|
| 175 |
+
|
| 176 |
+
# Streamlit UI
|
| 177 |
+
def main():
|
| 178 |
+
# Set page config
|
| 179 |
+
st.set_page_config(
|
| 180 |
+
page_title="CodeBuddy AI",
|
| 181 |
+
page_icon="👨💻",
|
| 182 |
+
layout="wide"
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
# For Hugging Face Spaces deployment
|
| 186 |
+
# This ensures the app is accessible externally
|
| 187 |
+
if os.environ.get('SPACE_ID'):
|
| 188 |
+
import socket
|
| 189 |
+
hostname = socket.gethostname()
|
| 190 |
+
ip_address = socket.gethostbyname(hostname)
|
| 191 |
+
st.write(f"To connect, use: http://{ip_address}:8501")
|
| 192 |
+
|
| 193 |
+
# Streamlit header - simplified for maximum visibility
|
| 194 |
+
st.markdown("""
|
| 195 |
+
<style>
|
| 196 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Orbitron:wght@600;700&display=swap');
|
| 197 |
+
|
| 198 |
+
.stApp {
|
| 199 |
+
background: #0f1121;
|
| 200 |
+
color: #f8fafc;
|
| 201 |
+
font-family: 'Inter', sans-serif;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
/* Simple, high-contrast header */
|
| 205 |
+
.simple-header {
|
| 206 |
+
background-color: #0d102a;
|
| 207 |
+
border: 2px solid #8a70ff;
|
| 208 |
+
border-radius: 16px;
|
| 209 |
+
padding: 20px;
|
| 210 |
+
margin: 20px 0;
|
| 211 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
.header-content {
|
| 215 |
+
display: flex;
|
| 216 |
+
align-items: center;
|
| 217 |
+
justify-content: flex-start;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
.robot-img {
|
| 221 |
+
width: 70px;
|
| 222 |
+
height: 70px;
|
| 223 |
+
margin-right: 20px;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
.title-container {
|
| 227 |
+
display: flex;
|
| 228 |
+
flex-direction: column;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
.main-title {
|
| 232 |
+
font-family: 'Orbitron', sans-serif;
|
| 233 |
+
font-size: 3rem;
|
| 234 |
+
font-weight: 800;
|
| 235 |
+
color: white;
|
| 236 |
+
margin: 0;
|
| 237 |
+
padding: 0;
|
| 238 |
+
line-height: 1.2;
|
| 239 |
+
text-shadow: 0 0 10px rgba(138, 112, 255, 0.7);
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
.subtitle {
|
| 243 |
+
color: #a5b4fc;
|
| 244 |
+
font-size: 1.2rem;
|
| 245 |
+
margin-top: 5px;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
.badge {
|
| 249 |
+
background-color: #8a70ff;
|
| 250 |
+
color: white;
|
| 251 |
+
font-size: 0.9rem;
|
| 252 |
+
font-weight: 600;
|
| 253 |
+
padding: 8px 15px;
|
| 254 |
+
border-radius: 20px;
|
| 255 |
+
margin-left: auto;
|
| 256 |
+
display: flex;
|
| 257 |
+
align-items: center;
|
| 258 |
+
gap: 8px;
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
.badge-dot {
|
| 262 |
+
width: 8px;
|
| 263 |
+
height: 8px;
|
| 264 |
+
background-color: white;
|
| 265 |
+
border-radius: 50%;
|
| 266 |
+
display: inline-block;
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
/* Sidebar styling */
|
| 270 |
+
.sidebar-header {
|
| 271 |
+
font-family: 'Orbitron', sans-serif;
|
| 272 |
+
color: #8a70ff;
|
| 273 |
+
font-size: 1.2rem;
|
| 274 |
+
font-weight: 600;
|
| 275 |
+
margin: 1rem 0;
|
| 276 |
+
letter-spacing: 0.5px;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
/* Style for buttons in sidebar */
|
| 280 |
+
.stButton > button {
|
| 281 |
+
background: rgba(138, 112, 255, 0.1);
|
| 282 |
+
color: #f8fafc !important;
|
| 283 |
+
border: 1px solid rgba(138, 112, 255, 0.2) !important;
|
| 284 |
+
border-radius: 8px !important;
|
| 285 |
+
padding: 0.5rem 1rem !important;
|
| 286 |
+
transition: all 0.3s ease !important;
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
.stButton > button:hover {
|
| 290 |
+
background: rgba(138, 112, 255, 0.2) !important;
|
| 291 |
+
border-color: rgba(138, 112, 255, 0.3) !important;
|
| 292 |
+
transform: translateY(-2px) !important;
|
| 293 |
+
box-shadow: 0 4px 12px rgba(138, 112, 255, 0.2) !important;
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
/* Style chat container */
|
| 297 |
+
.stChatMessage {
|
| 298 |
+
background: rgba(23, 26, 51, 0.4) !important;
|
| 299 |
+
border: 1px solid rgba(138, 112, 255, 0.15) !important;
|
| 300 |
+
border-radius: 12px !important;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
.stChatMessage [data-testid="chatAvatarIcon-user"] {
|
| 304 |
+
background: linear-gradient(135deg, #8a70ff 0%, #4ea8de 100%) !important;
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
.stChatMessage [data-testid="chatAvatarIcon-assistant"] {
|
| 308 |
+
background: linear-gradient(135deg, #4ea8de 0%, #8a70ff 100%) !important;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
@media (max-width: 768px) {
|
| 312 |
+
.main-title {
|
| 313 |
+
font-size: 2rem;
|
| 314 |
+
}
|
| 315 |
+
.subtitle {
|
| 316 |
+
font-size: 1rem;
|
| 317 |
+
}
|
| 318 |
+
.robot-img {
|
| 319 |
+
width: 50px;
|
| 320 |
+
height: 50px;
|
| 321 |
+
}
|
| 322 |
+
.badge {
|
| 323 |
+
font-size: 0.8rem;
|
| 324 |
+
padding: 5px 10px;
|
| 325 |
+
}
|
| 326 |
+
}
|
| 327 |
+
</style>
|
| 328 |
+
|
| 329 |
+
<div class="simple-header">
|
| 330 |
+
<div class="header-content">
|
| 331 |
+
<img src="https://i.imgur.com/UY3tN4o.png" class="robot-img" alt="Robot">
|
| 332 |
+
<div class="title-container">
|
| 333 |
+
<div class="main-title">CodeBuddy AI</div>
|
| 334 |
+
<div class="subtitle">Your intelligent companion for coding challenges</div>
|
| 335 |
+
</div>
|
| 336 |
+
<div class="badge">
|
| 337 |
+
<span class="badge-dot"></span>
|
| 338 |
+
Powered by Gemini 2.0
|
| 339 |
+
</div>
|
| 340 |
+
</div>
|
| 341 |
+
</div>
|
| 342 |
+
""", unsafe_allow_html=True)
|
| 343 |
+
|
| 344 |
+
# Initialize chat history
|
| 345 |
+
if "messages" not in st.session_state:
|
| 346 |
+
st.session_state.messages = []
|
| 347 |
+
|
| 348 |
+
# Display chat messages
|
| 349 |
+
for message in st.session_state.messages:
|
| 350 |
+
with st.chat_message(message["role"]):
|
| 351 |
+
st.markdown(message["content"])
|
| 352 |
+
|
| 353 |
+
# Chat input
|
| 354 |
+
if prompt := st.chat_input("Ask me any coding question..."):
|
| 355 |
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
| 356 |
+
with st.chat_message("user"):
|
| 357 |
+
st.markdown(prompt)
|
| 358 |
+
|
| 359 |
+
with st.chat_message("assistant"):
|
| 360 |
+
with st.spinner("Thinking..."):
|
| 361 |
+
response = chat_with_bot(prompt)
|
| 362 |
+
st.markdown(response)
|
| 363 |
+
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 364 |
+
|
| 365 |
+
# Modern Sidebar with Examples
|
| 366 |
+
with st.sidebar:
|
| 367 |
+
st.markdown('<div class="sidebar-header">📚 Example Questions</div>', unsafe_allow_html=True)
|
| 368 |
+
examples = [
|
| 369 |
+
"How do I fix a merge conflict in Git?",
|
| 370 |
+
"Explain recursion with a simple example",
|
| 371 |
+
"What's the difference between == and === in JavaScript?",
|
| 372 |
+
"Help me debug this Python error: IndentationError",
|
| 373 |
+
"Best practices for React component design",
|
| 374 |
+
"Explain Docker containerization"
|
| 375 |
+
]
|
| 376 |
+
for example in examples:
|
| 377 |
+
if st.button(example, key=example, help="Click to use this example", use_container_width=True):
|
| 378 |
+
st.chat_input(example)
|
| 379 |
+
|
| 380 |
+
# Modern Footer
|
| 381 |
+
st.markdown("---")
|
| 382 |
+
st.markdown('<div class="sidebar-header">🔧 About</div>', unsafe_allow_html=True)
|
| 383 |
+
st.markdown("""
|
| 384 |
+
<div style='animation: fadeIn 1s ease-in-out;'>
|
| 385 |
+
<p style='color: #94a3b8;'>Created by M.Haris and Syeda Memona Zahra</p>
|
| 386 |
+
<p style='color: #94a3b8; margin-top: 0.5rem;'>Powered by Gemini 2.0 Flash</p>
|
| 387 |
+
</div>
|
| 388 |
+
""", unsafe_allow_html=True)
|
| 389 |
+
|
| 390 |
+
if __name__ == "__main__":
|
| 391 |
+
# Special handling for Hugging Face Spaces
|
| 392 |
+
# Hugging Face Spaces expects port 7860
|
| 393 |
+
if os.environ.get('SPACE_ID'):
|
| 394 |
+
print("Running on Hugging Face Spaces")
|
| 395 |
+
import socket
|
| 396 |
+
hostname = socket.gethostname()
|
| 397 |
+
ip_address = socket.gethostbyname(hostname)
|
| 398 |
+
print(f"Hostname: {hostname}, IP: {ip_address}")
|
| 399 |
+
|
| 400 |
+
import sys
|
| 401 |
+
import subprocess
|
| 402 |
+
|
| 403 |
+
# If this is the main process
|
| 404 |
+
if sys.argv[0] == "app.py":
|
| 405 |
+
# Re-run streamlit with proper server arguments for Hugging Face
|
| 406 |
+
cmd = ["streamlit", "run", "app.py",
|
| 407 |
+
"--server.port=7860",
|
| 408 |
+
"--server.address=0.0.0.0",
|
| 409 |
+
"--server.enableCORS=true",
|
| 410 |
+
"--server.enableXsrfProtection=false",
|
| 411 |
+
"--browser.serverAddress=0.0.0.0"]
|
| 412 |
+
subprocess.call(cmd)
|
| 413 |
+
else:
|
| 414 |
+
# This is being run by streamlit itself
|
| 415 |
+
main()
|
| 416 |
+
else:
|
| 417 |
+
# Normal execution, not on Hugging Face
|
| 418 |
+
main()
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: '3.8'
|
| 2 |
+
|
| 3 |
+
services:
|
| 4 |
+
codebuddy-ai:
|
| 5 |
+
build:
|
| 6 |
+
context: .
|
| 7 |
+
dockerfile: Dockerfile
|
| 8 |
+
container_name: codebuddy-ai
|
| 9 |
+
ports:
|
| 10 |
+
- "7860:7860"
|
| 11 |
+
volumes:
|
| 12 |
+
- ./.env:/app/.env
|
| 13 |
+
environment:
|
| 14 |
+
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
| 15 |
+
restart: unless-stopped
|
| 16 |
+
healthcheck:
|
| 17 |
+
test: ["CMD", "curl", "--fail", "http://localhost:7860/_stcore/health"]
|
| 18 |
+
interval: 30s
|
| 19 |
+
timeout: 10s
|
| 20 |
+
retries: 3
|
huggingface-deploy-notes.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces Deployment Guide
|
| 2 |
+
|
| 3 |
+
This document provides detailed guidance for deploying CodeBuddy AI on Hugging Face Spaces.
|
| 4 |
+
|
| 5 |
+
## Quick Setup
|
| 6 |
+
|
| 7 |
+
1. Create a new Space on Hugging Face:
|
| 8 |
+
- Choose "Streamlit" as the SDK
|
| 9 |
+
- Set Python 3.10 as the version
|
| 10 |
+
- Link to your GitHub repository or upload files directly
|
| 11 |
+
|
| 12 |
+
2. Add your API key:
|
| 13 |
+
- In Space settings, add a secret named `GOOGLE_API_KEY` with your Gemini API key
|
| 14 |
+
|
| 15 |
+
3. Wait for the build to complete and access your app!
|
| 16 |
+
|
| 17 |
+
## Common Issues & Solutions
|
| 18 |
+
|
| 19 |
+
### Issue: App Shows "Running" But Not Accessible
|
| 20 |
+
|
| 21 |
+
If your app shows as "Running" but you can't access it or only see local URLs:
|
| 22 |
+
|
| 23 |
+
1. **Check Port Configuration**:
|
| 24 |
+
- Hugging Face Spaces uses port 7860 for Streamlit apps
|
| 25 |
+
- Our app has been configured to use this port in multiple places:
|
| 26 |
+
- `.streamlit/config.toml`
|
| 27 |
+
- `Dockerfile`
|
| 28 |
+
- `app.py` startup script
|
| 29 |
+
|
| 30 |
+
2. **Check Server Address Binding**:
|
| 31 |
+
- Streamlit must bind to `0.0.0.0` (all interfaces), not just localhost
|
| 32 |
+
- The `huggingface-space-launcher.py` script ensures this
|
| 33 |
+
|
| 34 |
+
3. **Verify Space Visibility**:
|
| 35 |
+
- Make sure your Space is set to "Public" in the settings
|
| 36 |
+
|
| 37 |
+
### Issue: API Key Not Found
|
| 38 |
+
|
| 39 |
+
If you see an error about missing API key:
|
| 40 |
+
|
| 41 |
+
1. In your Space settings (gear icon), go to "Variables and Secrets"
|
| 42 |
+
2. Add a new secret named `GOOGLE_API_KEY` with your key value
|
| 43 |
+
3. Rebuild your Space (use the "Factory reset" option)
|
| 44 |
+
|
| 45 |
+
### Issue: "streamlit run" Command Not Found
|
| 46 |
+
|
| 47 |
+
If the deployment fails with "command not found":
|
| 48 |
+
|
| 49 |
+
1. Ensure `streamlit` is in the requirements file
|
| 50 |
+
2. Make sure the Spaces SDK is set to "Streamlit"
|
| 51 |
+
3. Try using Python 3.10 explicitly in your Space settings
|
| 52 |
+
|
| 53 |
+
### Issue: Broken UI or Styles Not Loading
|
| 54 |
+
|
| 55 |
+
If the UI appears broken or styles aren't loading:
|
| 56 |
+
|
| 57 |
+
1. Check browser console for errors
|
| 58 |
+
2. Try clearing your browser cache
|
| 59 |
+
3. Verify no CSS conflicts in your Streamlit app
|
| 60 |
+
|
| 61 |
+
## Manual Deployment Verification
|
| 62 |
+
|
| 63 |
+
To verify deployment settings:
|
| 64 |
+
|
| 65 |
+
1. Click on "Logs" in the Space UI
|
| 66 |
+
2. Look for lines containing:
|
| 67 |
+
- Server address (`0.0.0.0`)
|
| 68 |
+
- Port number (should be `7860`)
|
| 69 |
+
- Any error messages about binding or permissions
|
| 70 |
+
|
| 71 |
+
## Advanced: Custom Domain
|
| 72 |
+
|
| 73 |
+
If you want to use a custom domain:
|
| 74 |
+
|
| 75 |
+
1. Go to Space settings
|
| 76 |
+
2. Under "Domain", enter your custom domain
|
| 77 |
+
3. Update your DNS records as instructed
|
| 78 |
+
|
| 79 |
+
## Getting Help
|
| 80 |
+
|
| 81 |
+
If you continue experiencing issues:
|
| 82 |
+
- Check the Hugging Face [Spaces documentation](https://huggingface.co/docs/hub/spaces)
|
| 83 |
+
- Post questions on the Hugging Face [forums](https://discuss.huggingface.co/)
|
| 84 |
+
- Submit issues to the CodeBuddy AI GitHub repository
|
huggingface-space-launcher.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import subprocess
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
# This script is designed to properly launch the Streamlit app on Hugging Face Spaces
|
| 6 |
+
# It ensures the correct port binding and server address
|
| 7 |
+
|
| 8 |
+
def launch_streamlit():
|
| 9 |
+
print("Launching CodeBuddy AI on Hugging Face Space")
|
| 10 |
+
|
| 11 |
+
# Set environment variables for Streamlit
|
| 12 |
+
os.environ["STREAMLIT_SERVER_PORT"] = "7860"
|
| 13 |
+
os.environ["STREAMLIT_SERVER_ADDRESS"] = "0.0.0.0"
|
| 14 |
+
os.environ["STREAMLIT_SERVER_HEADLESS"] = "true"
|
| 15 |
+
os.environ["STREAMLIT_SERVER_ENABLE_CORS"] = "true"
|
| 16 |
+
os.environ["STREAMLIT_BROWSER_GATHER_USAGE_STATS"] = "false"
|
| 17 |
+
|
| 18 |
+
# Command to run Streamlit with correct parameters
|
| 19 |
+
cmd = [
|
| 20 |
+
"streamlit", "run", "app.py",
|
| 21 |
+
"--server.port=7860",
|
| 22 |
+
"--server.address=0.0.0.0",
|
| 23 |
+
"--server.enableCORS=true",
|
| 24 |
+
"--server.enableXsrfProtection=false",
|
| 25 |
+
"--browser.serverAddress=0.0.0.0"
|
| 26 |
+
]
|
| 27 |
+
|
| 28 |
+
# If we're running inside Docker or similar containerized environment
|
| 29 |
+
if os.environ.get("CONTAINER_MODE"):
|
| 30 |
+
print("Running in container mode")
|
| 31 |
+
|
| 32 |
+
# Execute the command and wait for completion
|
| 33 |
+
process = subprocess.Popen(cmd)
|
| 34 |
+
|
| 35 |
+
try:
|
| 36 |
+
# Wait for the process to complete
|
| 37 |
+
process.wait()
|
| 38 |
+
except KeyboardInterrupt:
|
| 39 |
+
# Handle Ctrl+C gracefully
|
| 40 |
+
print("Shutting down gracefully...")
|
| 41 |
+
process.terminate()
|
| 42 |
+
process.wait()
|
| 43 |
+
sys.exit(0)
|
| 44 |
+
except Exception as e:
|
| 45 |
+
print(f"Error: {e}")
|
| 46 |
+
process.terminate()
|
| 47 |
+
process.wait()
|
| 48 |
+
sys.exit(1)
|
| 49 |
+
|
| 50 |
+
if __name__ == "__main__":
|
| 51 |
+
launch_streamlit()
|
huggingface-space-requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit==1.32.0
|
| 2 |
+
python-dotenv==1.0.0
|
| 3 |
+
langchain==0.1.0
|
| 4 |
+
langchain-google-genai==0.0.6
|
| 5 |
+
ipython==8.12.0
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit==1.32.0
|
| 2 |
+
python-dotenv==1.0.0
|
| 3 |
+
langchain==0.1.0
|
| 4 |
+
langchain-google-genai==0.0.6
|
| 5 |
+
gradio==4.44.1
|
| 6 |
+
IPython==8.12.0
|