nileshhanotia commited on
Commit
39485d9
·
verified ·
1 Parent(s): ffe25a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -285
app.py CHANGED
@@ -1,307 +1,126 @@
1
  import streamlit as st
2
- import requests
3
- import json
4
- import re
 
5
  import logging
6
- from typing import Dict, Any, Optional
7
 
8
- # Setup logging
9
  logging.basicConfig(level=logging.INFO)
 
10
 
11
- # API Configuration
12
- GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
13
- GROQ_API_KEY = "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"
14
- GROQ_HEADERS = {
15
- "Authorization": f"Bearer {GROQ_API_KEY}",
16
- "Content-Type": "application/json",
17
- }
18
 
19
- # Shopify Configuration
20
- STORE_NAME = "agkd0n-fa" # Your store name
21
- API_VERSION = "2024-04" # Current API version
22
- SHOPIFY_URL = f"https://{STORE_NAME}.myshopify.com/admin/api/{API_VERSION}/graphql.json"
23
- SHOPIFY_ACCESS_TOKEN = "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"
24
- SHOPIFY_HEADERS = {
25
- "Content-Type": "application/json",
26
- "X-Shopify-Access-Token": SHOPIFY_ACCESS_TOKEN,
27
- }
28
-
29
- def fetch_graphql_schema() -> Dict[str, Any]:
30
- """Fetch the GraphQL schema from Shopify."""
31
- introspection_query = """
32
- {
33
- "__schema" {
34
- "types" {
35
- "name"
36
- }
37
- }
38
- }
39
- """
40
- try:
41
- response = requests.post(
42
- SHOPIFY_URL,
43
- headers=SHOPIFY_HEADERS,
44
- json={"query": introspection_query}
45
- )
46
- response.raise_for_status()
47
- return response.json()
48
- except Exception as e:
49
- logging.error(f"Error fetching schema: {str(e)}")
50
- return {"error": str(e)}
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- def convert_to_graphql_query(natural_language: str) -> str:
54
- """Convert natural language to a GraphQL query using the Groq API."""
55
- # Enhanced prompt with Shopify Admin API specific guidance
56
- prompt = f"""
57
- Create a Shopify Admin API GraphQL query for this request: "{natural_language}"
58
 
59
- Follow these Shopify Admin API rules:
60
- 1. For text searches in product queries:
61
- - Use the query parameter with these prefixes:
62
- * title: for product titles
63
- * description: for product descriptions
64
- * tag: for product tags
65
- * product_type: for product types
66
- - Example: query: "title:shirt OR description:cotton"
67
-
68
- 2. For price filters:
69
- - Use variants.price for exact price
70
- - Use variants.price:<number for maximum price
71
- - Use variants.price:>number for minimum price
72
- - Example: query: "variants.price:<50.00"
73
-
74
- 3. Include these fields in the response:
75
- - id
76
- - title
77
- - description
78
- - productType
79
- - priceRangeV2 with minVariantPrice (amount and currencyCode)
80
- - images (first: 1) with url
81
-
82
- 4. Use proper pagination with first: 250
83
 
84
- Return only the complete GraphQL query, no explanations.
85
- """
 
 
86
 
87
- payload = {
88
- "model": "llama3-8b-8192",
89
- "messages": [{"role": "user", "content": prompt}],
90
- "temperature": 0.1,
91
- "max_tokens": 500,
92
- }
93
-
94
  try:
95
- response = requests.post(GROQ_API_URL, headers=GROQ_HEADERS, json=payload)
96
- response.raise_for_status()
97
-
98
- query = response.json()['choices'][0]['message']['content'].strip()
99
- return clean_query(query)
100
  except Exception as e:
101
- logging.error(f"Query generation error: {str(e)}")
102
- return get_default_query()
103
 
104
- def clean_query(query: str) -> str:
105
- """Clean and format the GraphQL query."""
106
- # Remove code block markers and quotes
107
- query = re.sub(r'```(?:graphql)?\s*|\s*```|^["\']\s*|\s*["\']$', '', query)
108
-
109
- # Extract the query content
110
- query_match = re.search(r'({[\s\S]*})', query)
111
- if not query_match:
112
- return get_default_query()
113
-
114
- query = query_match.group(1)
115
-
116
- # Ensure the query has all required fields
117
- if not all(field in query for field in ['id', 'title', 'description', 'productType', 'priceRangeV2', 'images']):
118
- return get_default_query()
119
-
120
- # Format the query
121
- try:
122
- formatted_query = format_query(query)
123
- return formatted_query
124
- except Exception as e:
125
- logging.error(f"Query formatting error: {str(e)}")
126
- return get_default_query()
127
 
128
- def format_query(query: str) -> str:
129
- """Format the GraphQL query with proper indentation."""
130
- depth = 0
131
- formatted = []
132
- lines = query.split('\n')
133
-
134
- for line in lines:
135
- line = line.strip()
136
-
137
- # Adjust depth based on brackets
138
- if '}' in line:
139
- depth -= 1
140
-
141
- # Add indentation
142
- if line:
143
- formatted.append(' ' * depth + line)
144
-
145
- # Increase depth for next line if needed
146
- if '{' in line:
147
- depth += 1
148
-
149
- return '\n'.join(formatted)
150
 
151
- def get_default_query() -> str:
152
- """Return a default working query with all required fields."""
153
- return """
154
- {
155
- products(first: 250) {
156
- edges {
157
- node {
158
- id
159
- title
160
- description
161
- productType
162
- priceRangeV2 {
163
- minVariantPrice {
164
- amount
165
- currencyCode
166
- }
167
- }
168
- images(first: 1) {
169
- edges {
170
- node {
171
- url
172
- }
173
- }
174
- }
175
- }
176
- }
177
- }
178
- }
179
- """.strip()
180
 
181
- def execute_query(query: str) -> Dict[str, Any]:
182
- """Execute a GraphQL query against the Shopify Admin API."""
183
- try:
184
- response = requests.post(
185
- SHOPIFY_URL,
186
- headers=SHOPIFY_HEADERS,
187
- json={"query": query}
188
- )
189
- response.raise_for_status()
190
- return response.json()
191
- except Exception as e:
192
- logging.error(f"Query execution error: {str(e)}")
193
- return {"error": str(e)}
194
 
195
- def format_response(response: Dict[str, Any]) -> Dict[str, Any]:
196
- """Format the API response for display."""
197
- if "errors" in response:
198
- error_message = response["errors"][0]["message"]
199
- logging.error(f"Shopify API returned an error: {error_message}")
200
- return {"error": error_message}
201
-
202
- try:
203
- products_data = response.get("data", {}).get("products", {}).get("edges", [])
204
- if not products_data:
205
- return {"error": "No products found in response"}
206
-
207
- formatted = {"products": []}
208
- for edge in products_data:
209
- node = edge.get("node", {})
210
- product = {
211
- "title": node.get("title", ""),
212
- "description": node.get("description", ""),
213
- "productType": node.get("productType", ""),
214
- "price": None,
215
- "image": None
216
- }
217
- price_range = node.get("priceRangeV2", {}).get("minVariantPrice", {})
218
- if price_range:
219
- amount = price_range.get("amount")
220
- currency = price_range.get("currencyCode")
221
- if amount and currency:
222
- product["price"] = f"{float(amount):.2f} {currency}"
223
-
224
- images = node.get("images", {}).get("edges", [])
225
- if images:
226
- product["image"] = images[0].get("node", {}).get("url")
227
-
228
- formatted["products"].append(product)
229
-
230
- return formatted
231
- except Exception as e:
232
- logging.error(f"Response formatting error: {str(e)}")
233
- return {"error": str(e)}
234
 
235
- def main():
236
- st.title("Shopify Product Search")
237
-
238
- # Fetch schema for dynamic query generation
239
- schema = fetch_graphql_schema()
240
-
241
- if "error" in schema:
242
- st.error(f"Failed to fetch schema: {schema['error']}")
243
- return
244
-
245
- # Display the available types or fields for user to choose from
246
- types = schema.get("data", {}).get("__schema", {}).get("types", [])
247
- st.subheader("Available Types in Shopify GraphQL Schema:")
248
- for type_info in types:
249
- st.write(type_info["name"])
250
 
251
- st.markdown("""
252
- ### Example Queries:
253
- - Show all products
254
- - Find products under $50
255
- - Search for products with "cotton" in description
256
- - Find products tagged as "summer"
257
- - Search for specific product types
258
- """)
259
-
260
- query = st.text_input(
261
- "What products are you looking for?",
262
- placeholder="e.g., Find t-shirts under $50"
263
- )
264
 
265
- if query and st.button("Search"):
266
- try:
267
- with st.spinner("Generating query..."):
268
- graphql_query = convert_to_graphql_query(query)
269
-
270
- with st.expander("View GraphQL Query"):
271
- st.code(graphql_query, language='graphql')
272
-
273
- with st.spinner("Searching products..."):
274
- response = execute_query(graphql_query)
275
-
276
- if "errors" in response:
277
- st.error("Query Error")
278
- st.json(response["errors"])
279
- return
280
-
281
- formatted = format_response(response)
282
-
283
- if "error" in formatted:
284
- st.error(formatted["error"])
285
- return
286
-
287
- if formatted["products"]:
288
- st.subheader(f"Found {len(formatted['products'])} products")
289
- for product in formatted["products"]:
290
- with st.container():
291
- cols = st.columns([1, 2])
292
- with cols[0]:
293
- if product["image"]:
294
- st.image(product["image"])
295
- with cols[1]:
296
- st.markdown(f"**{product['title']}**")
297
- st.write(f"Type: {product['productType']}")
298
- if product["price"]:
299
- st.write(f"Price: {product['price']}")
300
- st.write(product["description"])
301
- st.divider()
302
- else:
303
- st.warning("No products found.")
304
 
305
- except Exception as e:
306
- st.error(f"An error occurred: {str(e)}")
307
- logging.exception("Main execution error")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import os
4
+ from dotenv import load_dotenv
5
+ from transformers import AutoTokenizer, AutoModelForCausalLM
6
  import logging
 
7
 
8
+ # Set up logging
9
  logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
 
12
+ class LLMService:
13
+ def __init__(self, db_path):
14
+ self.db_path = db_path
15
+ # Load tokenizer and model
16
+ self.tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-72B-Instruct")
17
+ self.model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-72B-Instruct")
 
18
 
19
+ def convert_to_sql_query(self, natural_query):
20
+ try:
21
+ # Tokenize input
22
+ inputs = self.tokenizer(f"Translate this to SQL: {natural_query}", return_tensors="pt")
23
+ # Generate output
24
+ outputs = self.model.generate(**inputs, max_length=512, num_beams=5)
25
+ # Decode output
26
+ sql_query = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
27
+ return {"success": True, "query": sql_query}
28
+ except Exception as e:
29
+ logger.error(f"Error generating SQL query: {e}")
30
+ return {"success": False, "error": str(e)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ def execute_query(self, sql_query):
33
+ try:
34
+ import sqlite3
35
+ conn = sqlite3.connect(self.db_path)
36
+ cursor = conn.cursor()
37
+ cursor.execute(sql_query)
38
+ results = cursor.fetchall()
39
+ columns = [desc[0] for desc in cursor.description]
40
+ conn.close()
41
+ return {"success": True, "results": results, "columns": columns}
42
+ except Exception as e:
43
+ logger.error(f"Error executing SQL query: {e}")
44
+ return {"success": False, "error": str(e)}
45
 
46
+ def main():
47
+ st.title("Natural Language to SQL Query Converter")
48
+ st.write("Enter your question about the database in natural language.")
 
 
49
 
50
+ # Load environment variables
51
+ load_dotenv()
52
+ db_path = os.getenv("DB_PATH")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ if not db_path:
55
+ st.error("Missing database path in environment variables.")
56
+ logger.error("DB path not found in environment variables.")
57
+ return
58
 
59
+ # Initialize LLM Service
 
 
 
 
 
 
60
  try:
61
+ llm_service = LLMService(db_path=db_path)
 
 
 
 
62
  except Exception as e:
63
+ st.error(f"Error initializing service: {str(e)}")
64
+ return
65
 
66
+ # Input for natural language query
67
+ natural_query = st.text_area("Enter your query", "Show me all albums by artist 'Queen'", height=100)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ if st.button("Generate and Execute Query"):
70
+ if not natural_query.strip():
71
+ st.warning("Please enter a valid query.")
72
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ # Convert to SQL
75
+ with st.spinner("Generating SQL query..."):
76
+ sql_result = llm_service.convert_to_sql_query(natural_query)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
+ if not sql_result["success"]:
79
+ st.error(f"Error generating SQL query: {sql_result['error']}")
80
+ return
 
 
 
 
 
 
 
 
 
 
81
 
82
+ # Display generated SQL
83
+ st.subheader("Generated SQL Query:")
84
+ st.code(sql_result["query"], language="sql")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
+ # Execute query
87
+ with st.spinner("Executing query..."):
88
+ query_result = llm_service.execute_query(sql_result["query"])
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
+ if not query_result["success"]:
91
+ st.error(f"Error executing query: {query_result['error']}")
92
+ return
 
 
 
 
 
 
 
 
 
 
93
 
94
+ # Check if there are results
95
+ if query_result["results"]:
96
+ df = pd.DataFrame(query_result["results"], columns=query_result["columns"])
97
+
98
+ # Create a collapsible DataFrame using Streamlit's expander
99
+ with st.expander("Click to view query results as a DataFrame"):
100
+ st.dataframe(df)
101
+
102
+ # Extract product details from the JSON result and display them
103
+ json_results = df.to_dict(orient='records')
104
+ if "title" in json_results[0] and "images" in json_results[0] and "price" in json_results[0]:
105
+ st.subheader("Product Details:")
106
+ for product in json_results:
107
+ price = product.get("price", "N/A")
108
+ title = product.get("handle", "N/A")
109
+ src = product.get("src", "N/A")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ # Display product details in a neat format using columns for alignment
112
+ with st.container():
113
+ col1, col2, col3 = st.columns([1, 2, 3]) # Adjust column widths as needed
114
+
115
+ with col1:
116
+ st.image(src, use_container_width=True) # Display product image with container width
117
+ with col2:
118
+ st.write(f"**Price:** {price}") # Display price
119
+ st.write(f"**Title:** {title}") # Display title
120
+ with col3:
121
+ st.write(f"**Image Source:** [Link]( {src} )") # Link to the image if needed
122
+ else:
123
+ st.info("No results found.")
124
+
125
+ if __name__ == "__main__":
126
+ main()