import streamlit as st import requests import re from pypdf import PdfReader from transformers import T5Tokenizer, T5ForConditionalGeneration # Digi-Key API and credentials TOKEN_URL = "https://api.digikey.com/v1/oauth2/token" API_URL = "https://api.digikey.com/products/v4/search/keyword" CLIENT_ID = "K9d4a2AaGwQcoAvdNDZVYEOB3sqL4bMg" # Replace with your Digi-Key Client ID CLIENT_SECRET = "NxzuxY67eJssGDkA" # Replace with your Digi-Key Client Secret # Function to fetch access token @st.cache_data(ttl=3500) def fetch_access_token() -> str: headers = { "Content-Type": "application/x-www-form-urlencoded", } data = { "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "grant_type": "client_credentials", } response = requests.post(TOKEN_URL, headers=headers, data=data) if response.status_code == 200: token_data = response.json() return token_data["access_token"] else: st.error(f"Failed to retrieve access token: {response.status_code} - {response.text}") st.stop() # Function to make API requests to Digi-Key def search_digikey_components(keywords: str) -> dict: access_token = fetch_access_token() headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json", "X-DIGIKEY-Client-Id": CLIENT_ID, } payload = { "Keywords": keywords, "Limit": 50, "Offset": 0, "FilterOptionsRequest": { "MarketPlaceFilter": "NoFilter", }, "SortOptions": { "Field": "None", "SortOrder": "Ascending", }, } response = requests.post(API_URL, headers=headers, json=payload) if response.status_code == 200: return response.json() else: st.error(f"API request failed: {response.status_code} - {response.text}") return {} # Function to extract key specifications from a PDF datasheet def extract_specifications_from_pdf(pdf_url: str) -> str: try: response = requests.get(pdf_url) if response.status_code == 200: with open("datasheet.pdf", "wb") as file: file.write(response.content) # Extract text from the PDF reader = PdfReader("datasheet.pdf") text = "" for page in reader.pages: text += page.extract_text() # Use regex to find key specifications like voltage, resistance, power, etc. voltage = re.findall(r"(\d+\.?\d*)\s?(V|Volts)", text) # Voltage (e.g., "5V", "12 Volts") current = re.findall(r"(\d+\.?\d*)\s?(A|Amps)", text) # Current (e.g., "2A", "0.5 Amps") resistance = re.findall(r"(\d+\.?\d*)\s?(Ω|ohm)", text) # Resistance (e.g., "10Ω") power = re.findall(r"(\d+\.?\d*)\s?(W|Watts)", text) # Power (e.g., "5W", "100 Watts") # Format the specifications specs = "Specifications:\n" if voltage: specs += f"Voltage: {', '.join([f'{v} {unit}' for v, unit in voltage])}\n" if current: specs += f"Current: {', '.join([f'{c} {unit}' for c, unit in current])}\n" if resistance: specs += f"Resistance: {', '.join([f'{r} {unit}' for r, unit in resistance])}\n" if power: specs += f"Power: {', '.join([f'{p} {unit}' for p, unit in power])}\n" return specs if specs != "Specifications:\n" else "No key specifications found." else: return "Unable to fetch datasheet." except Exception as e: return f"Error extracting text: {str(e)}" # Load T5 model and tokenizer @st.cache_resource def load_t5_model(): tokenizer = T5Tokenizer.from_pretrained("t5-small") model = T5ForConditionalGeneration.from_pretrained("t5-small") return tokenizer, model # Generate advice for a component based on specifications def generate_advice(product: dict, tokenizer, model) -> str: # Fetch datasheet URL datasheet_url = product.get("DatasheetUrl") datasheet_text = "" if datasheet_url: datasheet_text = extract_specifications_from_pdf(datasheet_url) description = product.get("Description", {}).get("DetailedDescription", "No description available.") category = product.get("Category", {}).get("Name", "Unknown Category") manufacturer = product.get("Manufacturer", {}).get("Name", "Unknown Manufacturer") # Improved prompt: Focus only on specifications and product details prompt = f"Given the following specifications for the component: {datasheet_text}. Provide advice regarding its usage and key considerations based on its specifications. Description: {description}. Category: {category}. Manufacturer: {manufacturer}." inputs = tokenizer.encode(prompt, return_tensors="pt", max_length=512, truncation=True) outputs = model.generate(inputs, max_length=150, num_beams=4, temperature=1.5, top_k=50, early_stopping=True) advice = tokenizer.decode(outputs[0], skip_special_tokens=True) return advice # Streamlit app interface st.title("Component Selection Advisor") st.write( """ This app is an advanced tool for circuit designers, enabling efficient searches for electronic components using the Digi-Key API. It features AI-powered advice generated with a pretrained T5 model, providing insightful recommendations. Additionally, the app can extract key specifications from datasheets, ensuring users have all the critical details for their component selection process. Experience a seamless and intelligent way to streamline your circuit design workflows. """ ) # Input for the user keywords = st.text_input("Enter the name or keyword of the component:", "") if keywords: st.write(f"Searching for components matching: `{keywords}`...") data = search_digikey_components(keywords) if "Products" in data and data["Products"]: st.header("Search Results") tokenizer, model = load_t5_model() for product in data["Products"]: st.subheader(product["Description"]["ProductDescription"]) st.write(f"**Manufacturer**: {product['Manufacturer']['Name']}") st.write(f"**Product Number**: {product['ManufacturerProductNumber']}") st.write(f"**Unit Price**: ${product['UnitPrice']}") st.write(f"[Datasheet]({product['DatasheetUrl']})") st.write(f"[Product Link]({product['ProductUrl']})") # Check if PhotoUrl exists and is not None if product.get("PhotoUrl"): st.image(product["PhotoUrl"], width=200) else: st.write("_Image not available_") # Generate advice based on specifications extracted from the datasheet advice = generate_advice(product, tokenizer, model) st.write(f"**AI Advice:** {advice}") st.write("---") else: st.warning("No components found. Try using different keywords.")