import openai from pinecone import Pinecone, ServerlessSpec import pandas as pd import gradio as gr from typing import List, Tuple # Function to get embeddings from OpenAI's model def get_embedding(text: str, openai_api_key: str, model: str = "text-embedding-ada-002") -> List[float]: openai.api_key = openai_api_key try: response = openai.Embedding.create( model=model, input=text ) return response['data'][0]['embedding'] except Exception as e: print(f"Error getting embedding: {e}") return [] # Function to process the uploaded CSV and store embeddings in Pinecone def process_csv(file, openai_api_key: str, pinecone_api_key: str, pinecone_env: str) -> str: try: df = pd.read_csv(file.name) # Initialize Pinecone pc = Pinecone(api_key=pinecone_api_key) index_name = "product-recommendations" # Check if index exists if index_name not in pc.list_indexes().names(): try: pc.create_index( name=index_name, dimension=1536, spec=ServerlessSpec(cloud="aws", region=pinecone_env) ) except Exception as e: print(f"Error creating Pinecone index: {e}") return "Failed to create Pinecone index." index = pc.Index(index_name) embeddings = [] for i, row in df.iterrows(): embedding = get_embedding(row['description'], openai_api_key) if embedding: embeddings.append((str(row['product_id']), embedding, {'product_name': row['product_name'], 'image_url': row['image_url']})) if embeddings: try: index.upsert(embeddings) except Exception as e: print(f"Error upserting embeddings to Pinecone: {e}") return "Failed to upsert embeddings." return "Product catalog processed and embeddings stored in Pinecone." except Exception as e: print(f"Error processing CSV file: {e}") return "Failed to process CSV file." # Recommendation logic def recommend_products(query: str, openai_api_key: str, pinecone_api_key: str, pinecone_env: str, top_k: int = 5) -> List[Tuple[str, str]]: query_embedding = get_embedding(query, openai_api_key) if not query_embedding: return [] try: # Initialize Pinecone pc = Pinecone(api_key=pinecone_api_key) index = pc.Index("product-recommendations") results = index.query(vector=query_embedding, top_k=top_k, include_metadata=True) recommended_products = [(match['metadata']['image_url'], f"{match['metadata']['product_name']} (Score: {match['score']})") for match in results['matches']] return recommended_products except Exception as e: print(f"Error querying Pinecone: {e}") return [] # Function to generate contextual message def generate_contextual_message(query: str, recommendations: List[Tuple[str, str]], openai_api_key: str) -> str: openai.api_key = openai_api_key product_names = [rec[1] for rec in recommendations] prompt = f"User query: {query}\nRecommended products: {', '.join(product_names)}\nGenerate a personalized message for the user based on these recommendations." try: response = openai.ChatCompletion.create( model="gpt-4", # or use "gpt-3.5-turbo" if preferred messages=[{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": prompt}] ) return response['choices'][0]['message']['content'] except Exception as e: print(f"Error generating contextual message: {e}") return "Failed to generate contextual message." # Gradio interface def handle_file_upload(file, openai_api_key, pinecone_api_key, pinecone_env): return process_csv(file, openai_api_key, pinecone_api_key, pinecone_env) def display_recommendations(user_input, openai_api_key, pinecone_api_key, pinecone_env): recommendations = recommend_products(user_input, openai_api_key, pinecone_api_key, pinecone_env) contextual_message = generate_contextual_message(user_input, recommendations, openai_api_key) return recommendations, contextual_message # Function to update outputs def update_outputs(query_input, openai_api_key, pinecone_api_key, pinecone_env, chat_history): recommendations, contextual_message = display_recommendations(query_input, openai_api_key, pinecone_api_key, pinecone_env) # Update chat history new_chat_history = chat_history + [("user", query_input),("assistant", contextual_message)] return recommendations, new_chat_history # Create Gradio Interface def build_interface(): with gr.Blocks() as interface: gr.Markdown("## Product Recommender System") with gr.Tab("API Keys"): openai_api_key_input = gr.Textbox(label="OpenAI API Key", type="password") pinecone_api_key_input = gr.Textbox(label="Pinecone API Key", type="password") pinecone_env_input = gr.Textbox(label="Pinecone Environment", placeholder="e.g., us-west1-gcp") with gr.Tab("Upload Catalog"): upload_button = gr.File(label="Upload CSV", type="filepath") output = gr.Textbox() upload_button.upload(handle_file_upload, inputs=[upload_button, openai_api_key_input, pinecone_api_key_input, pinecone_env_input], outputs=output) with gr.Tab("Get Recommendations"): with gr.Row(): with gr.Column(scale=1): chatbot = gr.Chatbot(label="Chat") query_input = gr.Textbox(label="Enter your product preference...", show_label=False, placeholder="Type your query here...") recommend_button = gr.Button("Get Recommendations") # Define state for chat history chat_history = gr.State([]) # Define outputs first with gr.Column(scale=1): recommendations_output = gr.Gallery(label="Recommendations") recommend_button.click( update_outputs, inputs=[query_input, openai_api_key_input, pinecone_api_key_input, pinecone_env_input, chat_history], outputs=[recommendations_output, chatbot] ) return interface # Run the interface if __name__ == "__main__": interface = build_interface() interface.launch()