Vedant104 commited on
Commit
d7d2f96
Β·
verified Β·
1 Parent(s): eaae2ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -115
app.py CHANGED
@@ -268,90 +268,86 @@
268
 
269
  # demo.launch()
270
 
 
 
271
  import gradio as gr
272
  from transformers import pipeline
273
  import requests
274
- import os
275
  import pandas as pd
276
  import time
277
- import io
278
- from contextlib import redirect_stdout
279
 
280
  # =========================
281
- # ENV VARIABLES (use HF Secrets)
282
  # =========================
283
- client_id = "sb-cap1-3c4588e0trial-dev!t617058"
284
- client_secret = "acbe78be-ead5-4b12-b3b4-32fdb27d0f5f$hFj-hDXxwHkNHC-CAvv-OKSr3KH96nLL4KqwIg7M8D8="
285
- token_url = "https://3c4588e0trial.authentication.us10.hana.ondemand.com/oauth/token"
286
 
287
- cap_service_url_customers = "https://3c4588e0trial-dev-cap1-srv.cfapps.us10-001.hana.ondemand.com/odata/v4/sales/Customers?$top=2"
288
- cap_service_url_products = "https://3c4588e0trial-dev-cap1-srv.cfapps.us10-001.hana.ondemand.com/odata/v4/sales/Products?$top=2"
289
- cap_service_url_saleorders = "https://3c4588e0trial-dev-cap1-srv.cfapps.us10-001.hana.ondemand.com/odata/v4/sales/SalesOrders?$top=2"
290
- cap_service_url_saleorderitems = "https://3c4588e0trial-dev-cap1-srv.cfapps.us10-001.hana.ondemand.com/odata/v4/sales/SalesOrderItems?$top=2"
291
 
292
  # =========================
293
- # GLOBAL VARIABLES
294
  # =========================
295
  access_token = None
296
- cached_customers = None
297
- cached_products = None
298
- cached_salesorders = None
299
- cached_salesorderitems = None
300
  last_refresh = 0
301
 
302
  # =========================
303
- # LOAD MODEL (once) - Smaller & faster version recommended
304
  # =========================
305
  print("Loading model...")
306
  pipe = pipeline(
307
  "text-generation",
308
- model="Qwen/Qwen2.5-0.5B-Instruct", # Change to 0.5B for faster speed (still very good)
309
- # model="Qwen/Qwen2.5-1.5B-Instruct", # Uncomment if you prefer 1.5B
310
  device="cpu"
311
  )
312
 
313
  # =========================
314
- # TOKEN FUNCTION
315
  # =========================
316
- def generate_sap_xsuaa_token():
317
  global access_token
318
- print("Generating SAP token...")
319
- auth_response = requests.post(
320
  token_url,
321
  data={"grant_type": "client_credentials"},
322
  auth=(client_id, client_secret)
323
  )
324
- if auth_response.status_code != 200:
325
- print("Token Error:", auth_response.text)
326
  return None
327
- access_token = auth_response.json().get("access_token")
328
- print("Token generated!")
329
  return access_token
330
 
331
  # =========================
332
- # FETCH SAP DATA
333
  # =========================
334
- def fetch_sap_data():
335
  global access_token
 
336
  if not access_token:
337
- generate_sap_xsuaa_token()
338
-
339
  headers = {
340
  "Authorization": f"Bearer {access_token}",
341
  "Accept": "application/json"
342
  }
343
-
344
  res1 = requests.get(cap_service_url_customers, headers=headers)
345
  res2 = requests.get(cap_service_url_products, headers=headers)
346
  res3 = requests.get(cap_service_url_saleorders, headers=headers)
347
  res4 = requests.get(cap_service_url_saleorderitems, headers=headers)
348
 
349
  # Retry if token expired
350
- if res1.status_code in [400, 401, 403]:
351
- print("Token expired. Regenerating...")
352
  access_token = None
353
- generate_sap_xsuaa_token()
354
  headers["Authorization"] = f"Bearer {access_token}"
 
355
  res1 = requests.get(cap_service_url_customers, headers=headers)
356
  res2 = requests.get(cap_service_url_products, headers=headers)
357
  res3 = requests.get(cap_service_url_saleorders, headers=headers)
@@ -359,106 +355,116 @@ def fetch_sap_data():
359
 
360
  df_customers = pd.DataFrame(res1.json()["value"])
361
  df_products = pd.DataFrame(res2.json()["value"])
362
- df_saleorders = pd.DataFrame(res3.json()["value"])
363
- df_saleorderitems = pd.DataFrame(res4.json()["value"])
364
 
365
- # Keep only important columns
366
- df_customers = df_customers[["ID", "name", "country", "industry"]]
367
- df_products = df_products[["ID", "name", "category", "price", "currency"]]
368
- df_saleorders = df_saleorders[["ID", "customer_ID", "orderDate", "status"]]
369
- df_saleorderitems = df_saleorderitems[["ID", "parent_ID", "product_ID", "quantity", "netAmount"]]
370
 
371
- return df_customers, df_products, df_saleorders, df_saleorderitems
372
 
373
  # =========================
374
- # CACHE LOGIC (refresh every 5 minutes)
375
  # =========================
376
- def get_cached_data():
377
- global cached_customers, cached_products, cached_salesorders, cached_salesorderitems, last_refresh
378
- if time.time() - last_refresh > 300 or cached_customers is None: # 5 minutes
379
- print("Refreshing SAP data...")
380
- cached_customers, cached_products, cached_salesorders, cached_salesorderitems = fetch_sap_data()
381
  last_refresh = time.time()
382
- return cached_customers, cached_products, cached_salesorders, cached_salesorderitems
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
  # =========================
385
- # MAIN FUNCTION - LLM generates pandas code + execute
386
  # =========================
387
- def generate_response(user_prompt):
388
  try:
389
- # Get cached SAP data
390
- df_customers, df_products, df_saleorders, df_saleorderitems = get_cached_data()
391
-
392
- # System prompt for code generation (strict, no explanations)
393
- system_msg = """You are a pandas expert for SAP data.
394
- Output ONLY valid Python code. No explanations, no markdown, no ```python blocks.
395
- Use the DataFrames that already exist: df_saleorders, df_customers, df_products, df_saleorderitems.
396
- Always end with a print() that shows the result as a clean markdown table using .to_markdown(index=False).
397
- If no records match, just print: "No records found."""
398
-
399
- user_msg = f"""User question: {user_prompt} Write the pandas code to answer this question."""
400
-
401
- messages = [
402
- {"role": "system", "content": system_msg},
403
- {"role": "user", "content": user_msg}
404
- ]
405
-
406
- # Apply correct chat template
407
- prompt = pipe.tokenizer.apply_chat_template(
408
- messages, tokenize=False, add_generation_prompt=True
409
- )
410
-
411
- # Generate code (deterministic for accuracy)
412
- result = pipe(
413
- prompt,
414
- max_new_tokens=150,
415
- do_sample=False,
416
- temperature=0.0,
417
- return_full_text=False
418
- )
419
-
420
- generated_code = result[0]["generated_text"].strip()
421
-
422
- # Clean possible code fences
423
- if generated_code.startswith("```"):
424
- generated_code = generated_code.split("\n", 1)[1]
425
- if "```" in generated_code:
426
- generated_code = generated_code.split("```")[0]
427
-
428
- # Execute the generated code safely
429
- local_vars = {
430
- "df_customers": df_customers,
431
- "df_products": df_products,
432
- "df_saleorders": df_saleorders,
433
- "df_saleorderitems": df_saleorderitems,
434
- "pd": pd
435
- }
436
-
437
- output_buffer = io.StringIO()
438
- with redirect_stdout(output_buffer):
439
- exec(generated_code, {"__builtins__": {}}, local_vars)
440
-
441
- response = output_buffer.getvalue().strip()
442
- return response if response else "No records found."
443
 
444
  except Exception as e:
445
- return f"Error: {str(e)}\n\n(The generated code had an issue. Try rephrasing your question.)"
446
 
447
  # =========================
448
- # GRADIO UI + API
449
  # =========================
450
  with gr.Blocks() as demo:
451
- gr.Markdown("# SAP Assistant (Fast & Accurate)")
452
- user_input = gr.Textbox(label="User Question", placeholder="e.g. give me those orders where status is Completed")
453
- output = gr.Markdown(label="Response") # Changed to Markdown for better table rendering
 
 
 
 
 
 
454
  btn = gr.Button("Generate")
455
 
456
  btn.click(
457
  fn=generate_response,
458
- inputs=[user_input],
459
- outputs=output,
460
- api_name="predict"
461
  )
462
 
463
- demo.queue()
464
  demo.launch()
 
268
 
269
  # demo.launch()
270
 
271
+
272
+
273
  import gradio as gr
274
  from transformers import pipeline
275
  import requests
 
276
  import pandas as pd
277
  import time
 
 
278
 
279
  # =========================
280
+ # SAP CONFIG
281
  # =========================
282
+ client_id = "YOUR_CLIENT_ID"
283
+ client_secret = "YOUR_CLIENT_SECRET"
284
+ token_url = "YOUR_TOKEN_URL"
285
 
286
+ cap_service_url_customers = "YOUR_URL/Customers"
287
+ cap_service_url_products = "YOUR_URL/Products"
288
+ cap_service_url_saleorders = "YOUR_URL/SalesOrders"
289
+ cap_service_url_saleorderitems = "YOUR_URL/SalesOrderItems"
290
 
291
  # =========================
292
+ # GLOBAL CACHE
293
  # =========================
294
  access_token = None
295
+ cached_data = None
 
 
 
296
  last_refresh = 0
297
 
298
  # =========================
299
+ # LOAD SMALL FAST MODEL
300
  # =========================
301
  print("Loading model...")
302
  pipe = pipeline(
303
  "text-generation",
304
+ model="Qwen/Qwen2.5-0.5B-Instruct", # ⚑ faster than 1.5B
 
305
  device="cpu"
306
  )
307
 
308
  # =========================
309
+ # TOKEN GENERATION
310
  # =========================
311
+ def generate_token():
312
  global access_token
313
+
314
+ response = requests.post(
315
  token_url,
316
  data={"grant_type": "client_credentials"},
317
  auth=(client_id, client_secret)
318
  )
319
+
320
+ if response.status_code != 200:
321
  return None
322
+
323
+ access_token = response.json().get("access_token")
324
  return access_token
325
 
326
  # =========================
327
+ # FETCH DATA
328
  # =========================
329
+ def fetch_data():
330
  global access_token
331
+
332
  if not access_token:
333
+ generate_token()
334
+
335
  headers = {
336
  "Authorization": f"Bearer {access_token}",
337
  "Accept": "application/json"
338
  }
339
+
340
  res1 = requests.get(cap_service_url_customers, headers=headers)
341
  res2 = requests.get(cap_service_url_products, headers=headers)
342
  res3 = requests.get(cap_service_url_saleorders, headers=headers)
343
  res4 = requests.get(cap_service_url_saleorderitems, headers=headers)
344
 
345
  # Retry if token expired
346
+ if res1.status_code in [401, 403]:
 
347
  access_token = None
348
+ generate_token()
349
  headers["Authorization"] = f"Bearer {access_token}"
350
+
351
  res1 = requests.get(cap_service_url_customers, headers=headers)
352
  res2 = requests.get(cap_service_url_products, headers=headers)
353
  res3 = requests.get(cap_service_url_saleorders, headers=headers)
 
355
 
356
  df_customers = pd.DataFrame(res1.json()["value"])
357
  df_products = pd.DataFrame(res2.json()["value"])
358
+ df_orders = pd.DataFrame(res3.json()["value"])
359
+ df_items = pd.DataFrame(res4.json()["value"])
360
 
361
+ # Select columns
362
+ df_customers = df_customers[["ID","name","country","industry"]]
363
+ df_products = df_products[["ID","name","category","price","currency"]]
364
+ df_orders = df_orders[["ID","customer_ID","orderDate","status"]]
365
+ df_items = df_items[["ID","parent_ID","product_ID","quantity","netAmount"]]
366
 
367
+ return df_customers, df_products, df_orders, df_items
368
 
369
  # =========================
370
+ # CACHE
371
  # =========================
372
+ def get_data():
373
+ global cached_data, last_refresh
374
+
375
+ if cached_data is None or time.time() - last_refresh > 300:
376
+ cached_data = fetch_data()
377
  last_refresh = time.time()
378
+
379
+ return cached_data
380
+
381
+ # =========================
382
+ # FORMAT FUNCTION
383
+ # =========================
384
+ def format_table(df):
385
+ if df.empty:
386
+ return "❌ No data found"
387
+ return df.to_markdown(index=False)
388
+
389
+ # =========================
390
+ # LLM (ONLY FOR COMPLEX)
391
+ # =========================
392
+ def call_llm(question, context):
393
+ messages = [
394
+ {"role": "system", "content": "Answer strictly based on data. Be short."},
395
+ {"role": "user", "content": f"Data:\n{context}\n\nQuestion: {question}"}
396
+ ]
397
+
398
+ prompt = pipe.tokenizer.apply_chat_template(
399
+ messages,
400
+ tokenize=False,
401
+ add_generation_prompt=True
402
+ )
403
+
404
+ result = pipe(
405
+ prompt,
406
+ max_new_tokens=60,
407
+ do_sample=False # ⚑ fast + deterministic
408
+ )
409
+
410
+ return result[0]["generated_text"].strip()
411
 
412
  # =========================
413
+ # MAIN FUNCTION
414
  # =========================
415
+ def generate_response(user_input):
416
  try:
417
+ df_customers, df_products, df_orders, df_items = get_data()
418
+ query = user_input.lower()
419
+
420
+ # =====================
421
+ # DIRECT (NO LLM)
422
+ # =====================
423
+ if "customer" in query:
424
+ return "### πŸ‘₯ Customers\n\n" + format_table(df_customers)
425
+
426
+ elif "product" in query:
427
+ return "### πŸ“¦ Products\n\n" + format_table(df_products)
428
+
429
+ elif "order item" in query:
430
+ return "### 🧾 Order Items\n\n" + format_table(df_items)
431
+
432
+ elif "order" in query:
433
+ return "### πŸ“‘ Orders\n\n" + format_table(df_orders)
434
+
435
+ # =====================
436
+ # πŸ€– COMPLEX QUERY
437
+ # =====================
438
+ else:
439
+ # Send minimal context
440
+ context = df_orders.head(5).to_markdown(index=False)
441
+
442
+ answer = call_llm(user_input, context)
443
+
444
+ return f"### πŸ€– Answer\n\n{answer}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
 
446
  except Exception as e:
447
+ return f"❌ Error: {str(e)}"
448
 
449
  # =========================
450
+ # GRADIO UI
451
  # =========================
452
  with gr.Blocks() as demo:
453
+ gr.Markdown("# πŸš€ SAP Smart Assistant")
454
+
455
+ user_input = gr.Textbox(
456
+ label="Ask your question",
457
+ placeholder="e.g. show customers, list products..."
458
+ )
459
+
460
+ output = gr.Markdown(label="Response")
461
+
462
  btn = gr.Button("Generate")
463
 
464
  btn.click(
465
  fn=generate_response,
466
+ inputs=user_input,
467
+ outputs=output
 
468
  )
469
 
 
470
  demo.launch()