VirtualArchAI / app.py
rajat1343's picture
Update app.py
f468e41 verified
import gradio as gr
import cv2
import numpy as np
import pytesseract
import groq
import os
import tempfile
from gtts import gTTS # Google Text-to-Speech
from PIL import Image
from dotenv import load_dotenv
# Initialize Groq Client
load_dotenv() # Load environment variables from .env file
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
groq_client = groq.Client(api_key=GROQ_API_KEY)
# Set Tesseract OCR path (Update if needed)
if not os.path.exists("/usr/bin/tesseract"):
os.system("apt-get update && apt-get install -y tesseract-ocr")
# Now set the correct Tesseract path
pytesseract.pytesseract.tesseract_cmd = "/usr/bin/tesseract"
# Global storage for chat history & last floorplan analysis
chat_history = []
last_floorplan_context = {"features": "No floorplan uploaded yet.", "text": "No text detected."}
latest_audio_file = None # Stores the latest AI voice response
### πŸ“Œ **Floorplan Feature Detection**
def detect_floorplan_features(image):
"""Detect walls, rooms, and extract text using OpenCV & OCR."""
# Convert PIL Image to OpenCV format
image_cv = np.array(image.convert("RGB"))
gray = cv2.cvtColor(image_cv, cv2.COLOR_RGB2GRAY)
# Apply edge detection
edges = cv2.Canny(gray, 50, 150)
# Detect walls using Hough Transform
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=120, minLineLength=80, maxLineGap=10)
wall_count = len(lines) if lines is not None else 0 # Ensure it is always defined
# Detect rooms using contours
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
room_count = sum(1 for c in contours if cv2.contourArea(c) > 1000) # Ensure it is always defined
# Extract text labels using OCR
extracted_text = pytesseract.image_to_string(gray, config='--psm 6').strip()
detected_features = f"Walls: {wall_count}, Rooms: {room_count}"
return detected_features, extracted_text, edges, wall_count, room_count
### πŸ— **Analyze Floorplan (AI Processing)**
def analyze_floorplan(image):
"""Analyze the floorplan, update chat history, and generate AI response."""
global last_floorplan_context, chat_history, latest_audio_file
# Call feature detection function
detected_features, extracted_text, edges, wall_count, room_count = detect_floorplan_features(image)
# Convert edges to a PIL Image
edges_pil = Image.fromarray(cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB))
# Store context for chat
last_floorplan_context = {
"features": detected_features,
"text": extracted_text if extracted_text else "No text detected"
}
# AI Architectural Analysis Prompt (Improved)
prompt = f"""
πŸ“ **Architectural Floorplan Analysis**
**Detected Structural Features**
- **Rooms Identified:** {room_count}
- **Walls Detected:** {wall_count} (Load-bearing & Partition)
- **Extracted Text:** {extracted_text if extracted_text else "No text found"}
**Design & Efficiency Insights**
- **Traffic Flow & Accessibility**: Are room transitions efficient?
- **Lighting & Ventilation**: Where can natural light be optimized?
- **Space Utilization**: Are there underutilized or congested areas?
- **Expansion Feasibility**: Which walls could be removed for better space efficiency?
- **Modernization Potential**: Can smart home features be integrated?
Provide **a structured, expert-level architectural assessment**.
"""
response = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[{"role": "system", "content": prompt}],
max_tokens=500
)
ai_reply = response.choices[0].message.content
# Update chat history (New Format)
chat_history.clear()
chat_history.append({"role": "assistant", "content": ai_reply}) # New format
# Generate AI Voice
latest_audio_file = text_to_speech(ai_reply)
return edges_pil, chat_history, latest_audio_file
### πŸ”Š **Text-to-Speech AI Response**
def text_to_speech(text):
"""Convert AI response to speech using gTTS and return an audio file path."""
temp_dir = tempfile.gettempdir() # Get system temp folder
file_path = os.path.join(temp_dir, "speech_output.mp3") # Fixed filename
# Remove old file if exists
if os.path.exists(file_path):
os.remove(file_path)
# Generate speech
tts = gTTS(text=text, lang="en")
tts.save(file_path)
return file_path
### πŸ’¬ **AI Chatbot for Floorplan Analysis**
def chat_with_ai(user_input):
"""Handles user chat with AI."""
global latest_audio_file
floorplan_context = f"**Floorplan Summary**: {last_floorplan_context['features']}" if last_floorplan_context["features"] != "No floorplan uploaded yet." else ""
updated_input = f"""
User Question: {user_input}
{floorplan_context}
Provide an **expert-level architectural response** considering previous chat history.
"""
# AI Response with Context
response = groq_client.chat.completions.create(
model="llama3-70b-8192",
messages=[{"role": "user", "content": updated_input}],
max_tokens=500
)
ai_reply = response.choices[0].message.content
# Append to chat history (New Format)
chat_history.append({"role": "user", "content": user_input})
chat_history.append({"role": "assistant", "content": ai_reply})
# Generate voice response for latest AI reply
latest_audio_file = text_to_speech(ai_reply)
return chat_history, latest_audio_file # Return updated chat & voice
### **πŸ–₯ Gradio UI - Light Themed & Modernized**
with gr.Blocks() as demo:
gr.Markdown("# 🏠 Virtual Architect - AI Floorplan Chat (Voice Enabled)")
with gr.Row():
with gr.Column():
image_input = gr.Image(type="pil", label="Upload Floorplan")
analyze_btn = gr.Button("Analyze Floorplan")
with gr.Column():
result_image = gr.Image(type="pil", label="Edge Detection Output")
chatbox = gr.Chatbot(label="AI Chat (Starts with Floorplan Analysis)", type="messages")
# **SINGLE AI VOICE RESPONSE COMPONENT**
ai_voice_response = gr.Audio(label="AI Voice Response")
# AI recommendation appears in chatbox (Single Voice Response)
analyze_btn.click(analyze_floorplan, inputs=image_input, outputs=[result_image, chatbox, ai_voice_response])
# Text input directly under chatbox
user_input = gr.Textbox(label="Ask a Question Here")
send_btn = gr.Button("Send")
send_btn.click(chat_with_ai, inputs=user_input, outputs=[chatbox, ai_voice_response])
# Launch Gradio App (Fixes Theme Issue)
demo.launch()