Spaces:
Sleeping
Sleeping
File size: 9,763 Bytes
3752fd0 37c5983 3752fd0 245ee60 3752fd0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
import os
import io
import base64
import json
import re
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import streamlit as st
from openai import OpenAI
# Set your API key and instantiate the client (make sure your OpenAI client is imported/defined)
from dotenv import load_dotenv
load_dotenv()
client = OpenAI() # Assumes you have an OpenAI client available
# The prompt used to instruct the model
prompt = """
You are an expert road quality analyst. You will be shown an image of a road segment. Your task is to thoroughly inspect the condition of the road surface in the image and provide a detailed evaluation.
Your output must be in the form of a JSON object with the following structure:
{
"description": "<A detailed analysis of the visible road surface condition. Describe texture, cracks, potholes, construction quality, and overall appearance.>",
"label": "<One of: 'Excellent', 'Adequate', 'Basic', 'Poor', or 'Not Constructed'>",
"score": <A numerical value from the following scale: 5, 3, 2, 1, or 0>
}
### Use the following scoring rubric to assign both the 'label' and the 'score':
- **5 – Excellent**: The road surface is in pristine condition, with no visible damage. It may be a newly constructed or expressway-type road with smooth asphalt and no visible cracks, potholes, or any other surface imperfections. It is **ideal for fast, high-volume traffic**.
- **3 – Adequate**: The road is constructed and mostly functional. There are a few minor defects such as small cracks or potholes, but the road is still in **generally good condition**. It is suitable for use but could use maintenance to address minor issues.
- **2 – Basic**: The road shows clear signs of wear and construction defects, such as visible potholes, cracks, or surface degradation. The **road is still usable but needs repair**, and it may be difficult or uncomfortable to drive on for extended periods.
- **1 – Poor**: The road has **major issues** such as large potholes, severe cracks, or other types of significant damage that make it **hard to use**. While the road may still be passable, it poses risks to vehicles and drivers due to the level of deterioration.
- **0 – Not Constructed**: The road is **incomplete or not constructed**. This could include images of roads with severe mud, large holes, missing surface material, or roads that are **barely passable or not usable** for normal traffic. It is **not fit for use** and potentially dangerous.
### Specific Classification Criteria:
- **0 (Not Constructed)**: Roads that are missing large sections, filled with severe mud, or have very large holes making them essentially unusable or extremely hazardous.
- **1 (Poor)**: Roads with major potholes, severe cracks, or significant surface degradation where it is barely usable. The road is **dangerous for normal traffic**.
- **2 (Basic)**: Roads with **multiple defects**, such as potholes, cracks, or surface degradation. These roads are **difficult to drive on** but are still passable.
- **3 (Adequate)**: Roads that are **mostly intact** with only a few minor defects, such as small potholes or cracks, but still in **acceptable condition** for regular use.
- **5 (Excellent)**: Pristine roads, like expressways or newly constructed highways, that are **in perfect condition** with no visible damage, cracks, or potholes.
Make sure your response contains **only the JSON output**, with no extra text or commentary.
"""
# prompt = '''You are an expert road quality analyst. You will be provided with an image of a road segment. Your task is to perform a detailed visual analysis of the road surface and output your evaluation as a JSON object strictly in the format below, with no extra commentary:
# {
# "description": "<A detailed analysis of the visible road surface condition. Describe texture, cracks, potholes, construction quality, and overall appearance.>",
# "label": "<One of: 'Excellent', 'Adequate', 'Basic', 'Poor', or 'Not Constructed'>",
# "score": <A numerical value from the following scale: 5, 3, 2, 1, or 0>
# }
# Scoring Rubric:
# - **5 – Excellent**: The road surface is pristine, with no damage. It may be a newly constructed highway or expressway with smooth asphalt and no visible cracks, potholes, or imperfections. Ideal for fast, high-volume traffic.
# - **3 – Adequate**: The road is properly constructed and mostly functional. There might be a few minor defects like small cracks or potholes, but overall it is in generally good condition. Some minor maintenance could be beneficial.
# - **2 – Basic**: The road shows signs of wear and some construction defects, such as moderate cracks, potholes, or surface degradation. It remains passable but clearly needs repair. **For example, dirt roads that look flat and generally good should be classified as 'Basic' with a score of 2.**
# - **1 – Poor**: The road has major issues including large potholes, severe cracks, or significant surface degradation that make it hazardous. Although passable in some cases, it poses a risk to vehicles and drivers.
# - **0 – Not Constructed**: The road is incomplete or appears unconstructed. This includes images showing severe gaps, extensive mud, or missing sections, making the road extremely unsafe or unusable.
# Important Instructions:
# - **Consistency:** The "label" field must be exactly one of the specified text values ('Excellent', 'Adequate', 'Basic', 'Poor', or 'Not Constructed'). Do not output a numerical value as the label.
# - **Accurate Mapping:** The "score" field must correspond exactly to the assigned label based on the rubric. For instance, if you determine the road condition is "Basic", the score must be 2.
# - **Visual-Only Analysis:** Your evaluation must be based solely on what is visible in the provided image. Do not infer conditions beyond what the image shows.
# - **Output Format:** Only output a valid JSON object adhering to the above format—no additional text, explanation, or markdown formatting.
# Follow these instructions precisely to ensure accuracy and to minimize hallucinations.
# '''
# Function to create a base64 image URL from an uploaded file
def make_links_from_file(uploaded_file):
# Ensure we're reading from the start
uploaded_file.seek(0)
with Image.open(uploaded_file) as img:
img = img.convert("RGB")
if img.width > 512 or img.height > 512:
img.thumbnail((512, 512))
buffer = io.BytesIO()
img.save(buffer, format="PNG")
encoded_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
return f"data:image/png;base64,{encoded_image}"
# Function to get the response from the model
def get_response(prompt, img_url, model="gpt-4o-mini"):
if model == "gpt-4o":
print("Using gpt-4o model")
messages = [
{
"role": "user",
"content": [
{ "type": "text", "text": prompt },
{
"type": "image_url",
"image_url": {"url": img_url}
},
],
}
]
else:
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {"url": img_url}}
]
}
]
response = client.chat.completions.create(
model=model,
messages=messages
)
return response
# Function to clean the output (removes markdown formatting and parses JSON)
def clean_response(output):
raw_output = output.choices[0].message.content.strip()
cleaned_output = re.sub(r"^```(?:json)?\s*|\s*```$", "", raw_output.strip())
data = json.loads(cleaned_output)
return data
# Function to display the image with an overlay and description
def show_outs(img, data):
fig, ax = plt.subplots(figsize=(10, 6))
ax.imshow(img)
ax.axis('off')
label_text = f"Label: {data['label']} | Score: {data['score']}"
ax.add_patch(patches.Rectangle((0, 0), 1, 0.1, transform=ax.transAxes,
color='black', alpha=0.5))
ax.text(0.01, 0.03, label_text, transform=ax.transAxes,
fontsize=14, color='white', fontweight='bold', va='center')
plt.tight_layout()
st.pyplot(fig)
plt.close(fig)
st.write("\n📝 Road Surface Description:\n")
st.write(data.get("description", "No description provided."))
# Modified inference pipeline that works with an uploaded file
def inference_pipeline_uploaded(uploaded_file, prompt, model):
img_url = make_links_from_file(uploaded_file)
st.write("Fetching Response...")
output = get_response(prompt, img_url, model)
data = clean_response(output)
# Reset file pointer and reopen image for display
uploaded_file.seek(0)
img = Image.open(uploaded_file).convert("RGB")
if img.width > 512 or img.height > 512:
img.thumbnail((512, 512))
img_array = np.array(img)
show_outs(img_array, data)
# Main app layout
st.title("Road Quality Analysis")
st.write("Upload an image of a road segment for analysis.")
# Toggle between models using a radio button
model_choice = st.radio("Select Model", options=["GPT 40", "GPT 40 mini"])
model = "gpt-4o-2024-08-06" if model_choice == "GPT 40" else "gpt-4o-mini"
# Image file uploader
uploaded_file = st.file_uploader("Choose an image file", type=["jpg", "jpeg", "png"])
if uploaded_file is not None:
st.image(uploaded_file, caption="Uploaded Road Segment", use_column_width=True)
if st.button("Run Analysis"):
inference_pipeline_uploaded(uploaded_file, prompt, model)
|