import streamlit as st from PIL import Image from transformers import AutoFeatureExtractor, AutoModelForImageClassification import torch from datetime import datetime import openai import pandas as pd import numpy as np from sklearn.metrics.pairwise import cosine_similarity from sklearn.preprocessing import LabelEncoder # Initialize OpenAI API key openai.api_key = st.secrets["GPT_TOKEN"] # Function to classify the car image using pre-trained model def classify_image(image): try: # Load the model and feature extractor model_name = "dima806/car_models_image_detection" feature_extractor = AutoFeatureExtractor.from_pretrained(model_name) model = AutoModelForImageClassification.from_pretrained(model_name) # Preprocess the image inputs = feature_extractor(images=image, return_tensors="pt") # Perform inference with torch.no_grad(): outputs = model(**inputs) # Get the predicted class logits = outputs.logits predicted_class_idx = logits.argmax(-1).item() # Get the class label and score predicted_class_label = model.config.id2label[predicted_class_idx] score = torch.nn.functional.softmax(logits, dim=-1)[0, predicted_class_idx].item() # Return the top prediction return [{'label': predicted_class_label, 'score': score}] except Exception as e: st.error(f"Classification error: {e}") return None # Function to get an overview of the car using OpenAI def get_car_overview(brand, model, year): prompt = f"Provide an overview of the following car:\nYear: {year}\nMake: {brand}\nModel: {model}\n" response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message['content'] # Load and preprocess the car data once (globally for the session) def load_car_data(): try: df = pd.read_csv('CTP_Model1.csv') # Replace with the path to your actual CSV file return df except Exception as e: st.error(f"Error loading CSV file: {e}") return None # Preprocess car data and encode categorical features def preprocess_car_data(df): label_encoders = {} # Encode categorical columns (make, model, trim, fuel, title_status, etc.) for col in ['make', 'model', 'trim', 'fuel', 'title_status', 'transmission', 'drive', 'size', 'type', 'paint_color']: le = LabelEncoder() df[col] = le.fit_transform(df[col]) label_encoders[col] = le # Handle NaN values by filling them with a placeholder (e.g., -1 for categorical columns) df.fillna(-1, inplace=True) return df, label_encoders # Calculate similarity between the classified car and entries in the CSV def find_closest_car(df, label_encoders, make, model, year): # Encode the user-provided make and model make_encoded = label_encoders['make'].transform([make])[0] model_encoded = label_encoders['model'].transform([model])[0] # Create a feature vector for the classified car (make, model, year) classified_car_vector = np.array([make_encoded, model_encoded, year]).reshape(1, -1) # Prepare the data for similarity calculation feature_columns = ['make', 'model', 'year'] df_feature_vectors = df[feature_columns].values # Handle NaN values before calculating similarity df_feature_vectors = np.nan_to_num(df_feature_vectors) # Converts NaN to 0 # Compute cosine similarity between the classified car and all entries in the CSV similarity_scores = cosine_similarity(classified_car_vector, df_feature_vectors) # Get the index of the closest match closest_match_idx = similarity_scores.argmax() # Return the closest match details return df.iloc[closest_match_idx] # Streamlit App st.title("Auto Appraise") st.write("Upload a car image or take a picture to get its brand, model, and overview!") # Initialize session_state image attribute if it doesn't exist if 'image' not in st.session_state: st.session_state.image = None # File uploader for image uploaded_file = st.file_uploader("Choose a car image", type=["jpg", "jpeg", "png"]) # Camera input as an alternative (optional) camera_image = st.camera_input("Or take a picture of the car") # Process the image (either uploaded or from camera) if uploaded_file is not None: st.write("Attempting to open uploaded file...") try: st.session_state.image = Image.open(uploaded_file) st.write("Image uploaded successfully.") except Exception as e: st.error(f"Error opening uploaded file: {str(e)}") elif camera_image is not None: st.write("Attempting to open camera image...") try: st.session_state.image = Image.open(camera_image) st.write("Image captured successfully.") except Exception as e: st.error(f"Error opening camera image: {str(e)}") # Display the processed image if st.session_state.image is not None: st.image(st.session_state.image, caption='Processed Image', use_container_width=True) current_year = datetime.now().year # Classify the car image with st.spinner('Analyzing image...'): car_classifications = classify_image(st.session_state.image) if car_classifications: st.write("Image classification successful.") st.subheader("Car Classification Results:") # for classification in car_classifications: # st.write(f"Model: {classification['label']}") # st.write(f"Confidence: {classification['score'] * 100:.2f}%") # Separate make and model from the classification result top_prediction = car_classifications[0]['label'] make_name, model_name = top_prediction.split(' ', 1) col1, col2= st.columns(2) col1.metric("Identified Car Make", make_name) col2.metric("Identified Car Model", model_name) # st.write(f"Identified Car Model: {make_name}") # st.write(f"Identified Car Model: {model_name}") # Find the closest match in the CSV based on the classification car_data = load_car_data() if car_data is not None: processed_car_data, label_encoders = preprocess_car_data(car_data) closest_car = find_closest_car(processed_car_data, label_encoders, make_name, model_name, current_year) a, b, c, d = st.columns(4) e, f, g = st.columns(3) a.metric("Year", closest_car['year']) b.metric("Price", closest_car['price']) c.metric("Condition", closest_car['condition']) d.metric("Fuel", closest_car['fuel']) e.metric("Transmission", closest_car['transmission']) f.metric("Drive", closest_car['drive']) g.metric("Type", closest_car['type']) # st.write(f"Closest match in database:") # st.write(f"Year: {closest_car['year']}") # st.write(f"Make: {label_encoders['make'].inverse_transform([closest_car['make']])[0]}") # st.write(f"Model: {label_encoders['model'].inverse_transform([closest_car['model']])[0]}") # st.write(f"Price: ${closest_car['price']}") # st.write(f"Condition: {closest_car['condition']}") # st.write(f"Fuel: {closest_car['fuel']}") # st.write(f"Transmission: {closest_car['transmission']}") # st.write(f"Drive: {closest_car['drive']}") # st.write(f"Type: {closest_car['type']}") st.divider() # Get additional information using GPT-3.5-turbo overview = get_car_overview(make_name, model_name, current_year) st.subheader("Car Overview:") st.write(overview) else: st.error("Could not classify the image. Please try again with a different image.") else: st.write("Please upload an image or take a picture to proceed.")