graphql / app.py
nileshhanotia's picture
Create app.py
92cbbe3 verified
raw
history blame
9.99 kB
import streamlit as st
import requests
import json
import re
import logging
from typing import Dict, Any, Optional
# Setup logging
logging.basicConfig(level=logging.INFO)
# API Configuration
GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
GROQ_API_KEY = "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"
GROQ_HEADERS = {
"Authorization": f"Bearer {GROQ_API_KEY}",
"Content-Type": "application/json",
}
# Shopify Configuration
STORE_NAME = "agkd0n-fa" # Your store name
API_VERSION = "2024-04" # Current API version
SHOPIFY_URL = f"https://{STORE_NAME}.myshopify.com/admin/api/{API_VERSION}/graphql.json"
SHOPIFY_ACCESS_TOKEN = "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"
SHOPIFY_HEADERS = {
"Content-Type": "application/json",
"X-Shopify-Access-Token": SHOPIFY_ACCESS_TOKEN,
}
def fetch_graphql_schema() -> Dict[str, Any]:
"""Fetch the GraphQL schema from Shopify."""
introspection_query = """
{
"__schema" {
"types" {
"name"
}
}
}
"""
try:
response = requests.post(
SHOPIFY_URL,
headers=SHOPIFY_HEADERS,
json={"query": introspection_query}
)
response.raise_for_status()
return response.json()
except Exception as e:
logging.error(f"Error fetching schema: {str(e)}")
return {"error": str(e)}
def convert_to_graphql_query(natural_language: str) -> str:
"""Convert natural language to a GraphQL query using the Groq API."""
# Enhanced prompt with Shopify Admin API specific guidance
prompt = f"""
Create a Shopify Admin API GraphQL query for this request: "{natural_language}"
Follow these Shopify Admin API rules:
1. For text searches in product queries:
- Use the query parameter with these prefixes:
* title: for product titles
* description: for product descriptions
* tag: for product tags
* product_type: for product types
- Example: query: "title:shirt OR description:cotton"
2. For price filters:
- Use variants.price for exact price
- Use variants.price:<number for maximum price
- Use variants.price:>number for minimum price
- Example: query: "variants.price:<50.00"
3. Include these fields in the response:
- id
- title
- description
- productType
- priceRangeV2 with minVariantPrice (amount and currencyCode)
- images (first: 1) with url
4. Use proper pagination with first: 250
Return only the complete GraphQL query, no explanations.
"""
payload = {
"model": "llama3-8b-8192",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.1,
"max_tokens": 500,
}
try:
response = requests.post(GROQ_API_URL, headers=GROQ_HEADERS, json=payload)
response.raise_for_status()
query = response.json()['choices'][0]['message']['content'].strip()
return clean_query(query)
except Exception as e:
logging.error(f"Query generation error: {str(e)}")
return get_default_query()
def clean_query(query: str) -> str:
"""Clean and format the GraphQL query."""
# Remove code block markers and quotes
query = re.sub(r'```(?:graphql)?\s*|\s*```|^["\']\s*|\s*["\']$', '', query)
# Extract the query content
query_match = re.search(r'({[\s\S]*})', query)
if not query_match:
return get_default_query()
query = query_match.group(1)
# Ensure the query has all required fields
if not all(field in query for field in ['id', 'title', 'description', 'productType', 'priceRangeV2', 'images']):
return get_default_query()
# Format the query
try:
formatted_query = format_query(query)
return formatted_query
except Exception as e:
logging.error(f"Query formatting error: {str(e)}")
return get_default_query()
def format_query(query: str) -> str:
"""Format the GraphQL query with proper indentation."""
depth = 0
formatted = []
lines = query.split('\n')
for line in lines:
line = line.strip()
# Adjust depth based on brackets
if '}' in line:
depth -= 1
# Add indentation
if line:
formatted.append(' ' * depth + line)
# Increase depth for next line if needed
if '{' in line:
depth += 1
return '\n'.join(formatted)
def get_default_query() -> str:
"""Return a default working query with all required fields."""
return """
{
products(first: 250) {
edges {
node {
id
title
description
productType
priceRangeV2 {
minVariantPrice {
amount
currencyCode
}
}
images(first: 1) {
edges {
node {
url
}
}
}
}
}
}
}
""".strip()
def execute_query(query: str) -> Dict[str, Any]:
"""Execute a GraphQL query against the Shopify Admin API."""
try:
response = requests.post(
SHOPIFY_URL,
headers=SHOPIFY_HEADERS,
json={"query": query}
)
response.raise_for_status()
return response.json()
except Exception as e:
logging.error(f"Query execution error: {str(e)}")
return {"error": str(e)}
def format_response(response: Dict[str, Any]) -> Dict[str, Any]:
"""Format the API response for display."""
if "errors" in response:
error_message = response["errors"][0]["message"]
logging.error(f"Shopify API returned an error: {error_message}")
return {"error": error_message}
try:
products_data = response.get("data", {}).get("products", {}).get("edges", [])
if not products_data:
return {"error": "No products found in response"}
formatted = {"products": []}
for edge in products_data:
node = edge.get("node", {})
product = {
"title": node.get("title", ""),
"description": node.get("description", ""),
"productType": node.get("productType", ""),
"price": None,
"image": None
}
price_range = node.get("priceRangeV2", {}).get("minVariantPrice", {})
if price_range:
amount = price_range.get("amount")
currency = price_range.get("currencyCode")
if amount and currency:
product["price"] = f"{float(amount):.2f} {currency}"
images = node.get("images", {}).get("edges", [])
if images:
product["image"] = images[0].get("node", {}).get("url")
formatted["products"].append(product)
return formatted
except Exception as e:
logging.error(f"Response formatting error: {str(e)}")
return {"error": str(e)}
def main():
st.title("Shopify Product Search")
# Fetch schema for dynamic query generation
schema = fetch_graphql_schema()
if "error" in schema:
st.error(f"Failed to fetch schema: {schema['error']}")
return
# Display the available types or fields for user to choose from
types = schema.get("data", {}).get("__schema", {}).get("types", [])
st.subheader("Available Types in Shopify GraphQL Schema:")
for type_info in types:
st.write(type_info["name"])
st.markdown("""
### Example Queries:
- Show all products
- Find products under $50
- Search for products with "cotton" in description
- Find products tagged as "summer"
- Search for specific product types
""")
query = st.text_input(
"What products are you looking for?",
placeholder="e.g., Find t-shirts under $50"
)
if query and st.button("Search"):
try:
with st.spinner("Generating query..."):
graphql_query = convert_to_graphql_query(query)
with st.expander("View GraphQL Query"):
st.code(graphql_query, language='graphql')
with st.spinner("Searching products..."):
response = execute_query(graphql_query)
if "errors" in response:
st.error("Query Error")
st.json(response["errors"])
return
formatted = format_response(response)
if "error" in formatted:
st.error(formatted["error"])
return
if formatted["products"]:
st.subheader(f"Found {len(formatted['products'])} products")
for product in formatted["products"]:
with st.container():
cols = st.columns([1, 2])
with cols[0]:
if product["image"]:
st.image(product["image"])
with cols[1]:
st.markdown(f"**{product['title']}**")
st.write(f"Type: {product['productType']}")
if product["price"]:
st.write(f"Price: {product['price']}")
st.write(product["description"])
st.divider()
else:
st.warning("No products found.")
except Exception as e:
st.error(f"An error occurred: {str(e)}")
logging.exception("Main execution error")