|
import os |
|
import base64 |
|
import gradio as gr |
|
from PIL import Image |
|
import io |
|
import json |
|
from groq import Groq |
|
import logging |
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
GROQ_API_KEY = os.environ.get("GROQ_API_KEY") |
|
if not GROQ_API_KEY: |
|
logger.error("GROQ_API_KEY is not set in environment variables") |
|
raise ValueError("GROQ_API_KEY is not set") |
|
|
|
|
|
client = Groq(api_key=GROQ_API_KEY) |
|
|
|
def encode_image(image): |
|
try: |
|
if isinstance(image, str): |
|
with open(image, "rb") as image_file: |
|
return base64.b64encode(image_file.read()).decode('utf-8') |
|
elif isinstance(image, Image.Image): |
|
buffered = io.BytesIO() |
|
image.save(buffered, format="PNG") |
|
return base64.b64encode(buffered.getvalue()).decode('utf-8') |
|
else: |
|
raise ValueError(f"Unsupported image type: {type(image)}") |
|
except Exception as e: |
|
logger.error(f"Error encoding image: {str(e)}") |
|
raise |
|
|
|
def analyze_construction_image(image): |
|
if image is None: |
|
logger.warning("No image provided") |
|
return [(None, "Error: No image uploaded")] |
|
|
|
try: |
|
logger.info("Starting image analysis") |
|
image_data_url = f"data:image/png;base64,{encode_image(image)}" |
|
|
|
messages = [ |
|
{ |
|
"role": "user", |
|
"content": [ |
|
{ |
|
"type": "text", |
|
"text": "Analyze this construction site image. Identify any issues or snags, categorize them, provide a detailed description, and suggest steps in numbered bullet points to resolve them. Format your response as a JSON object with keys 'snag_category', 'snag_description', and 'desnag_steps' (as an array)." |
|
}, |
|
{ |
|
"type": "image_url", |
|
"image_url": { |
|
"url": image_data_url |
|
} |
|
} |
|
] |
|
} |
|
] |
|
|
|
logger.info("Sending request to Groq API") |
|
completion = client.chat.completions.create( |
|
model="llama-3.2-90b-vision-preview", |
|
messages=messages, |
|
temperature=0.7, |
|
max_tokens=1000, |
|
top_p=1, |
|
stream=False, |
|
response_format={"type": "json_object"}, |
|
stop=None |
|
) |
|
|
|
logger.info("Received response from Groq API") |
|
result = completion.choices[0].message.content |
|
logger.debug(f"Raw API response: {result}") |
|
|
|
|
|
try: |
|
parsed_result = json.loads(result) |
|
except json.JSONDecodeError: |
|
logger.error("Failed to parse API response as JSON") |
|
return [(None, "Error: Invalid response format")] |
|
|
|
snag_category = parsed_result.get('snag_category', 'N/A') |
|
snag_description = parsed_result.get('snag_description', 'N/A') |
|
desnag_steps = '\n'.join(parsed_result.get('desnag_steps', ['N/A'])) |
|
|
|
logger.info("Analysis completed successfully") |
|
|
|
|
|
chat_history = [ |
|
(None, f"Image Analysis Results:\n\nSnag Category: {snag_category}\n\nSnag Description: {snag_description}\n\nSteps to Desnag:\n{desnag_steps}") |
|
] |
|
|
|
return chat_history |
|
except Exception as e: |
|
logger.error(f"Error during image analysis: {str(e)}") |
|
return [(None, f"Error: {str(e)}")] |
|
|
|
def chat_about_image(message, chat_history): |
|
try: |
|
|
|
messages = [ |
|
{"role": "system", "content": "You are an AI assistant specialized in analyzing construction site images and answering questions about them. Use the information from the initial analysis to answer user queries."}, |
|
] |
|
|
|
|
|
for human, ai in chat_history: |
|
if human: |
|
messages.append({"role": "user", "content": human}) |
|
if ai: |
|
messages.append({"role": "assistant", "content": ai}) |
|
|
|
|
|
messages.append({"role": "user", "content": message}) |
|
|
|
|
|
completion = client.chat.completions.create( |
|
model="llama-3.2-90b-vision-preview", |
|
messages=messages, |
|
temperature=0.7, |
|
max_tokens=500, |
|
top_p=1, |
|
stream=False, |
|
stop=None |
|
) |
|
|
|
response = completion.choices[0].message.content |
|
chat_history.append((message, response)) |
|
|
|
return "", chat_history |
|
except Exception as e: |
|
logger.error(f"Error during chat: {str(e)}") |
|
return "", chat_history + [(message, f"Error: {str(e)}")] |
|
|
|
|
|
with gr.Blocks() as iface: |
|
gr.Markdown("# Construction Image Analyzer with Chat") |
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
image_input = gr.Image(type="pil", label="Upload Construction Image") |
|
analyze_button = gr.Button("Analyze Image") |
|
with gr.Column(scale=2): |
|
chatbot = gr.Chatbot(label="Analysis Results and Chat") |
|
|
|
msg = gr.Textbox(label="Ask a question about the image and press Enter") |
|
clear = gr.Button("Clear Chat") |
|
|
|
analyze_button.click( |
|
analyze_construction_image, |
|
inputs=[image_input], |
|
outputs=[chatbot] |
|
) |
|
|
|
msg.submit(chat_about_image, [msg, chatbot], [msg, chatbot]) |
|
clear.click(lambda: None, None, chatbot, queue=False) |
|
|
|
|
|
if __name__ == "__main__": |
|
iface.launch(debug=True) |