PD03 commited on
Commit
4ef7ee9
Β·
verified Β·
1 Parent(s): 899df39

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +332 -79
app.py CHANGED
@@ -14,10 +14,29 @@ client = openai.OpenAI()
14
  # SAP API Configuration
15
  SAP_API_KEY = os.getenv("SAP_API_KEY")
16
  BASE_URL = "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  class SAPBusinessPartnerAgent:
19
  def __init__(self):
20
  self.conversation_history = []
 
21
 
22
  def parse_search_query(self, query: str) -> Dict[str, Any]:
23
  """Parse natural language query into SAP API parameters using OpenAI"""
@@ -33,14 +52,16 @@ class SAPBusinessPartnerAgent:
33
  - IsMarkedForArchiving
34
  - SearchTerm1, SearchTerm2
35
 
 
 
36
  Return JSON with OData query parameters.
37
 
38
  Examples:
39
- - "Find customer ABC Corp" β†’ {"$filter": "contains(BusinessPartnerFullName,'ABC Corp')", "$top": "10"}
40
  - "Show me organizations" β†’ {"$filter": "BusinessPartnerCategory eq '2'", "$top": "10"}
41
  - "Active partners only" β†’ {"$filter": "IsMarkedForArchiving eq false", "$top": "10"}
42
 
43
- Always include $top with a reasonable limit (max 20).
44
  """
45
 
46
  try:
@@ -54,21 +75,25 @@ class SAPBusinessPartnerAgent:
54
  )
55
 
56
  result = json.loads(response.choices[0].message.content)
57
- # Ensure we have basic parameters
58
  if "$top" not in result:
59
- result["$top"] = "10"
60
  return result
61
 
62
  except Exception as e:
63
- # Fallback to basic search
 
 
 
 
 
64
  return {
65
  "$filter": f"contains(BusinessPartnerFullName,'{query}')",
66
  "$top": "10"
67
  }
68
 
69
- def call_sap_api(self, entity_set: str, params: Dict[str, Any]) -> Dict[str, Any]:
70
  """Execute SAP API call"""
71
- url = f"{BASE_URL}/{entity_set}"
72
 
73
  # Build query parameters
74
  query_params = {
@@ -100,38 +125,262 @@ class SAPBusinessPartnerAgent:
100
 
101
  def get_mock_data(self, entity_set: str) -> Dict[str, Any]:
102
  """Return mock SAP data for demo purposes"""
103
- mock_data = {
104
- "d": {
105
- "results": [
106
- {
107
- "BusinessPartner": "1000000001",
108
- "BusinessPartnerFullName": "Demo Customer Corp",
109
- "BusinessPartnerCategory": "2",
110
- "CreationDate": "/Date(1640995200000)/",
111
- "IsMarkedForArchiving": False,
112
- "SearchTerm1": "DEMO"
113
- },
114
- {
115
- "BusinessPartner": "1000000002",
116
- "BusinessPartnerFullName": "Sample Supplier Ltd",
117
- "BusinessPartnerCategory": "2",
118
- "CreationDate": "/Date(1641081600000)/",
119
- "IsMarkedForArchiving": False,
120
- "SearchTerm1": "SAMPLE"
121
- },
122
- {
123
- "BusinessPartner": "1000000003",
124
- "BusinessPartnerFullName": "Test Industries Inc",
125
- "BusinessPartnerCategory": "2",
126
- "CreationDate": "/Date(1641168000000)/",
127
- "IsMarkedForArchiving": False,
128
- "SearchTerm1": "TEST"
129
- }
130
- ],
131
- "__count": "3"
132
  }
133
- }
134
- return mock_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  def format_business_partner_response(self, response: Dict, original_query: str) -> str:
137
  """Format business partner API response into readable text"""
@@ -167,13 +416,6 @@ class SAPBusinessPartnerAgent:
167
  formatted_response += f"- **Type:** {category_text}\n"
168
  formatted_response += f"- **Status:** {status}\n\n"
169
 
170
- # Add helpful suggestions
171
- formatted_response += "---\n"
172
- formatted_response += "πŸ’‘ **What you can do next:**\n"
173
- formatted_response += "- Ask for specific partner details\n"
174
- formatted_response += "- Search for customers or suppliers\n"
175
- formatted_response += "- Find partners by location or industry\n"
176
-
177
  return formatted_response
178
  else:
179
  return f"⚠️ Received unexpected response format for: '{original_query}'"
@@ -203,20 +445,27 @@ class SAPBusinessPartnerAgent:
203
  history.append([user_query, None])
204
 
205
  try:
206
- # Determine intent and process accordingly
207
- if any(keyword in user_query.lower() for keyword in ['search', 'find', 'show', 'list', 'get']):
 
 
208
  response = self.search_business_partners(user_query)
209
  else:
210
  # Use OpenAI to understand intent and provide guidance
211
  system_prompt = """
212
- You are a SAP Business Partner Assistant. The user is asking about business partner management.
 
 
 
 
 
213
 
214
- If they're asking for:
215
- - Search/find operations: Guide them to use search terms
216
- - Help/guidance: Explain what you can do
217
- - Specific features: Explain SAP Business Partner capabilities
218
 
219
- Be helpful and guide them to ask specific questions about business partners.
220
  """
221
 
222
  ai_response = client.chat.completions.create(
@@ -233,7 +482,7 @@ class SAPBusinessPartnerAgent:
233
  history[-1][1] = response
234
 
235
  except Exception as e:
236
- error_response = f"❌ Sorry, I encountered an error: {str(e)}\n\nTry asking: 'Find business partners with name Demo'"
237
  history[-1][1] = error_response
238
 
239
  return "", history
@@ -244,7 +493,7 @@ sap_agent = SAPBusinessPartnerAgent()
244
  # Create Gradio interface
245
  def create_interface():
246
  with gr.Blocks(
247
- title="SAP Business Partner Agent",
248
  theme=gr.themes.Soft(),
249
  css="""
250
  .gradio-container {
@@ -265,7 +514,7 @@ def create_interface():
265
  gr.HTML("""
266
  <div class="agent-header">
267
  <h1>πŸ€– SAP Business Partner Agent</h1>
268
- <p>Intelligent assistant for SAP Business Partner master data management</p>
269
  </div>
270
  """)
271
 
@@ -273,14 +522,14 @@ def create_interface():
273
  with gr.Row():
274
  with gr.Column(scale=4):
275
  chatbot = gr.Chatbot(
276
- height=500,
277
  label="Chat with SAP Business Partner Agent",
278
- placeholder="Start by asking about business partners..."
279
  )
280
 
281
  with gr.Row():
282
  msg = gr.Textbox(
283
- placeholder="Ask me about business partners (e.g., 'Find partners with name Demo')",
284
  label="Your Message",
285
  scale=4
286
  )
@@ -289,9 +538,9 @@ def create_interface():
289
  # Example buttons
290
  gr.Markdown("### πŸ’‘ Quick Examples:")
291
  with gr.Row():
292
- example1 = gr.Button("Find Demo partners", size="sm")
293
- example2 = gr.Button("Show organizations", size="sm")
294
- example3 = gr.Button("List active partners", size="sm")
295
  clear_btn = gr.Button("Clear Chat", size="sm", variant="secondary")
296
 
297
  # Sidebar with information
@@ -299,27 +548,31 @@ def create_interface():
299
  gr.Markdown("""
300
  ### πŸ”§ Agent Capabilities
301
 
 
 
 
 
 
302
  **Search & Retrieve:**
303
- - Find business partners by name
304
- - Filter by partner type
305
- - Search by various criteria
306
 
307
  **Partner Types:**
308
  - πŸ‘€ Persons
309
  - 🏒 Organizations
310
  - 🏭 Groups
311
 
312
- **Data Sources:**
313
- - SAP Business Partner API
314
- - Real-time SAP data
315
- - Customer information
316
- - Supplier details
317
 
318
- ### πŸ“ Sample Queries
319
- - "Find partners named ABC"
320
- - "Show me all organizations"
321
- - "List active business partners"
322
- - "Search for suppliers"
323
  """)
324
 
325
  # Event handlers
@@ -336,15 +589,15 @@ def create_interface():
336
  )
337
 
338
  # Example button events
339
- example1.click(lambda: "Find partners with name Demo", outputs=msg)
340
- example2.click(lambda: "Show me organizations", outputs=msg)
341
- example3.click(lambda: "List active partners only", outputs=msg)
342
  clear_btn.click(lambda: [], outputs=chatbot)
343
 
344
  # Footer
345
  gr.Markdown("""
346
  ---
347
- **SAP Business Partner Agent** | Powered by OpenAI & SAP APIs | Built for Hugging Face Spaces
348
  """)
349
 
350
  return demo
 
14
  # SAP API Configuration
15
  SAP_API_KEY = os.getenv("SAP_API_KEY")
16
  BASE_URL = "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER"
17
+ CREDIT_API_URL = "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_CRDTMBUSINESSPARTNER"
18
+
19
+ class WorkflowStep(BaseModel):
20
+ """Model for workflow step tracking"""
21
+ step_number: int
22
+ description: str
23
+ status: str # pending, in_progress, completed, failed
24
+ result: Any = None
25
+ timestamp: datetime = datetime.now()
26
+
27
+ class MultiStepWorkflow(BaseModel):
28
+ """Model for tracking multi-step workflows"""
29
+ workflow_id: str
30
+ name: str
31
+ steps: List[WorkflowStep]
32
+ current_step: int = 0
33
+ status: str = "pending" # pending, running, completed, failed
34
+ final_result: Any = None
35
 
36
  class SAPBusinessPartnerAgent:
37
  def __init__(self):
38
  self.conversation_history = []
39
+ self.active_workflows = {}
40
 
41
  def parse_search_query(self, query: str) -> Dict[str, Any]:
42
  """Parse natural language query into SAP API parameters using OpenAI"""
 
52
  - IsMarkedForArchiving
53
  - SearchTerm1, SearchTerm2
54
 
55
+ For country-specific queries, use contains() with country names.
56
+
57
  Return JSON with OData query parameters.
58
 
59
  Examples:
60
+ - "Find customers in Germany" β†’ {"$filter": "contains(BusinessPartnerFullName,'Germany') or contains(SearchTerm1,'DE')", "$top": "20"}
61
  - "Show me organizations" β†’ {"$filter": "BusinessPartnerCategory eq '2'", "$top": "10"}
62
  - "Active partners only" β†’ {"$filter": "IsMarkedForArchiving eq false", "$top": "10"}
63
 
64
+ Always include $top with a reasonable limit (max 50 for workflows).
65
  """
66
 
67
  try:
 
75
  )
76
 
77
  result = json.loads(response.choices[0].message.content)
 
78
  if "$top" not in result:
79
+ result["$top"] = "20"
80
  return result
81
 
82
  except Exception as e:
83
+ # Fallback for Germany search
84
+ if "germany" in query.lower():
85
+ return {
86
+ "$filter": "contains(BusinessPartnerFullName,'Germany')",
87
+ "$top": "20"
88
+ }
89
  return {
90
  "$filter": f"contains(BusinessPartnerFullName,'{query}')",
91
  "$top": "10"
92
  }
93
 
94
+ def call_sap_api(self, entity_set: str, params: Dict[str, Any], base_url: str = None) -> Dict[str, Any]:
95
  """Execute SAP API call"""
96
+ url = f"{base_url or BASE_URL}/{entity_set}"
97
 
98
  # Build query parameters
99
  query_params = {
 
125
 
126
  def get_mock_data(self, entity_set: str) -> Dict[str, Any]:
127
  """Return mock SAP data for demo purposes"""
128
+ if entity_set == "CreditManagementAccount":
129
+ return {
130
+ "d": {
131
+ "results": [
132
+ {
133
+ "BusinessPartner": "1000000001",
134
+ "CreditLimitAmount": "50000.00",
135
+ "Currency": "EUR",
136
+ "CreditLimitValidFrom": "/Date(1640995200000)/",
137
+ "CreditLimitValidTo": "/Date(1672531200000)/",
138
+ "CreditExposureAmount": "25000.00"
139
+ },
140
+ {
141
+ "BusinessPartner": "1000000002",
142
+ "CreditLimitAmount": "75000.00",
143
+ "Currency": "EUR",
144
+ "CreditLimitValidFrom": "/Date(1640995200000)/",
145
+ "CreditLimitValidTo": "/Date(1672531200000)/",
146
+ "CreditExposureAmount": "15000.00"
147
+ }
148
+ ],
149
+ "__count": "2"
150
+ }
 
 
 
 
 
 
151
  }
152
+ else:
153
+ return {
154
+ "d": {
155
+ "results": [
156
+ {
157
+ "BusinessPartner": "1000000001",
158
+ "BusinessPartnerFullName": "Munich Manufacturing GmbH",
159
+ "BusinessPartnerCategory": "2",
160
+ "CreationDate": "/Date(1640995200000)/",
161
+ "IsMarkedForArchiving": False,
162
+ "SearchTerm1": "MUNICH"
163
+ },
164
+ {
165
+ "BusinessPartner": "1000000002",
166
+ "BusinessPartnerFullName": "Berlin Tech Solutions AG",
167
+ "BusinessPartnerCategory": "2",
168
+ "CreationDate": "/Date(1641081600000)/",
169
+ "IsMarkedForArchiving": False,
170
+ "SearchTerm1": "BERLIN"
171
+ },
172
+ {
173
+ "BusinessPartner": "1000000003",
174
+ "BusinessPartnerFullName": "Hamburg Logistics Ltd",
175
+ "BusinessPartnerCategory": "2",
176
+ "CreationDate": "/Date(1641168000000)/",
177
+ "IsMarkedForArchiving": False,
178
+ "SearchTerm1": "HAMBURG"
179
+ }
180
+ ],
181
+ "__count": "3"
182
+ }
183
+ }
184
+
185
+ def execute_multi_step_workflow(self, workflow_type: str, query: str) -> str:
186
+ """Execute multi-step workflows with progress tracking"""
187
+
188
+ if workflow_type == "credit_analysis":
189
+ return self.execute_credit_analysis_workflow(query)
190
+ else:
191
+ return f"❌ Unknown workflow type: {workflow_type}"
192
+
193
+ def execute_credit_analysis_workflow(self, query: str) -> str:
194
+ """Execute the credit limit analysis workflow"""
195
+ workflow_id = f"credit_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
196
+
197
+ # Define workflow steps
198
+ workflow = MultiStepWorkflow(
199
+ workflow_id=workflow_id,
200
+ name="Credit Limit Analysis for German Customers",
201
+ steps=[
202
+ WorkflowStep(step_number=1, description="Search for customers in Germany", status="pending"),
203
+ WorkflowStep(step_number=2, description="Extract customer IDs", status="pending"),
204
+ WorkflowStep(step_number=3, description="Fetch credit limits for each customer", status="pending"),
205
+ WorkflowStep(step_number=4, description="Analyze and summarize findings", status="pending")
206
+ ]
207
+ )
208
+
209
+ self.active_workflows[workflow_id] = workflow
210
+
211
+ try:
212
+ # Step 1: Search for customers in Germany
213
+ workflow.steps[0].status = "in_progress"
214
+ workflow.current_step = 1
215
+
216
+ # Parse the Germany search query
217
+ if "germany" not in query.lower():
218
+ query = "Find customers in Germany"
219
+
220
+ params = self.parse_search_query(query)
221
+ customers_response = self.call_sap_api("A_BusinessPartner", params)
222
+
223
+ workflow.steps[0].status = "completed"
224
+ workflow.steps[0].result = customers_response
225
+
226
+ # Step 2: Extract customer IDs
227
+ workflow.steps[1].status = "in_progress"
228
+ workflow.current_step = 2
229
+
230
+ customers = customers_response.get('d', {}).get('results', [])
231
+ if not customers:
232
+ workflow.status = "failed"
233
+ return "❌ No customers found in Germany"
234
+
235
+ customer_ids = [customer['BusinessPartner'] for customer in customers]
236
+ workflow.steps[1].status = "completed"
237
+ workflow.steps[1].result = customer_ids
238
+
239
+ # Step 3: Fetch credit limits
240
+ workflow.steps[2].status = "in_progress"
241
+ workflow.current_step = 3
242
+
243
+ credit_data = []
244
+ for customer_id in customer_ids:
245
+ credit_params = {
246
+ "$filter": f"BusinessPartner eq '{customer_id}'",
247
+ "$top": "1"
248
+ }
249
+ credit_response = self.call_sap_api("CreditManagementAccount", credit_params, CREDIT_API_URL)
250
+
251
+ credit_results = credit_response.get('d', {}).get('results', [])
252
+ if credit_results:
253
+ credit_info = credit_results[0]
254
+ # Match credit info with customer info
255
+ customer_info = next((c for c in customers if c['BusinessPartner'] == customer_id), {})
256
+
257
+ credit_data.append({
258
+ 'customer_id': customer_id,
259
+ 'customer_name': customer_info.get('BusinessPartnerFullName', 'Unknown'),
260
+ 'credit_limit': credit_info.get('CreditLimitAmount', '0'),
261
+ 'currency': credit_info.get('Currency', 'EUR'),
262
+ 'exposure': credit_info.get('CreditExposureAmount', '0'),
263
+ 'utilization': self.calculate_utilization(
264
+ credit_info.get('CreditExposureAmount', '0'),
265
+ credit_info.get('CreditLimitAmount', '0')
266
+ )
267
+ })
268
+
269
+ workflow.steps[2].status = "completed"
270
+ workflow.steps[2].result = credit_data
271
+
272
+ # Step 4: Analyze and summarize
273
+ workflow.steps[3].status = "in_progress"
274
+ workflow.current_step = 4
275
+
276
+ summary = self.generate_credit_analysis_summary(credit_data, customers)
277
+
278
+ workflow.steps[3].status = "completed"
279
+ workflow.steps[3].result = summary
280
+ workflow.status = "completed"
281
+ workflow.final_result = summary
282
+
283
+ return summary
284
+
285
+ except Exception as e:
286
+ workflow.status = "failed"
287
+ return f"❌ Workflow failed at step {workflow.current_step}: {str(e)}"
288
+
289
+ def calculate_utilization(self, exposure: str, limit: str) -> float:
290
+ """Calculate credit utilization percentage"""
291
+ try:
292
+ exposure_val = float(exposure)
293
+ limit_val = float(limit)
294
+ if limit_val > 0:
295
+ return round((exposure_val / limit_val) * 100, 2)
296
+ return 0.0
297
+ except:
298
+ return 0.0
299
+
300
+ def generate_credit_analysis_summary(self, credit_data: List[Dict], customers: List[Dict]) -> str:
301
+ """Generate comprehensive credit analysis summary"""
302
+
303
+ if not credit_data:
304
+ return "❌ No credit data found for German customers"
305
+
306
+ # Calculate statistics
307
+ total_customers = len(customers)
308
+ customers_with_credit = len(credit_data)
309
+ total_credit_limit = sum(float(item['credit_limit']) for item in credit_data)
310
+ total_exposure = sum(float(item['exposure']) for item in credit_data)
311
+ avg_utilization = sum(item['utilization'] for item in credit_data) / len(credit_data)
312
+
313
+ # Find high-risk customers (>80% utilization)
314
+ high_risk = [item for item in credit_data if item['utilization'] > 80]
315
+ low_risk = [item for item in credit_data if item['utilization'] < 30]
316
+
317
+ # Generate summary
318
+ summary = f"""## πŸ“Š Credit Limit Analysis - German Customers
319
+
320
+ ### πŸ” **Workflow Execution Summary**
321
+ βœ… **Step 1:** Found {total_customers} German customers
322
+ βœ… **Step 2:** Extracted customer IDs
323
+ βœ… **Step 3:** Retrieved credit data for {customers_with_credit} customers
324
+ βœ… **Step 4:** Completed analysis and summary
325
+
326
+ ### πŸ“ˆ **Key Financial Metrics**
327
+ - **Total Credit Limits:** €{total_credit_limit:,.2f}
328
+ - **Total Credit Exposure:** €{total_exposure:,.2f}
329
+ - **Average Utilization:** {avg_utilization:.1f}%
330
+ - **Overall Exposure Ratio:** {(total_exposure/total_credit_limit*100):.1f}%
331
+
332
+ ### 🚨 **Risk Analysis**
333
+
334
+ #### High Risk Customers (>80% utilization):
335
+ """
336
+
337
+ if high_risk:
338
+ for customer in high_risk:
339
+ summary += f"""
340
+ **{customer['customer_name']}** (ID: {customer['customer_id']})
341
+ - Credit Limit: €{float(customer['credit_limit']):,.2f}
342
+ - Current Exposure: €{float(customer['exposure']):,.2f}
343
+ - Utilization: **{customer['utilization']}%** ⚠️
344
+ """
345
+ else:
346
+ summary += "\nβœ… No high-risk customers found\n"
347
+
348
+ summary += f"""
349
+ #### Low Risk Customers (<30% utilization):
350
+ """
351
+
352
+ if low_risk:
353
+ for customer in low_risk[:3]: # Show top 3
354
+ summary += f"""
355
+ **{customer['customer_name']}** (ID: {customer['customer_id']})
356
+ - Credit Limit: €{float(customer['credit_limit']):,.2f}
357
+ - Utilization: {customer['utilization']}% βœ…
358
+ """
359
+ if len(low_risk) > 3:
360
+ summary += f"\n... and {len(low_risk) - 3} more low-risk customers\n"
361
+ else:
362
+ summary += "\n⚠️ No low-risk customers found\n"
363
+
364
+ summary += f"""
365
+ ### πŸ’‘ **Recommendations**
366
+ 1. **Monitor High-Risk Accounts:** Review customers with >80% utilization
367
+ 2. **Credit Line Reviews:** Consider adjusting limits based on utilization patterns
368
+ 3. **Payment Terms:** Evaluate payment terms for high-exposure customers
369
+ 4. **Regular Monitoring:** Set up alerts for utilization threshold breaches
370
+
371
+ ### πŸ“‹ **Detailed Customer List**
372
+ """
373
+
374
+ for i, customer in enumerate(credit_data, 1):
375
+ risk_indicator = "πŸ”΄" if customer['utilization'] > 80 else "🟑" if customer['utilization'] > 50 else "🟒"
376
+ summary += f"""
377
+ {i}. {risk_indicator} **{customer['customer_name']}**
378
+ - ID: {customer['customer_id']}
379
+ - Credit Limit: €{float(customer['credit_limit']):,.2f}
380
+ - Exposure: €{float(customer['exposure']):,.2f} ({customer['utilization']}%)
381
+ """
382
+
383
+ return summary
384
 
385
  def format_business_partner_response(self, response: Dict, original_query: str) -> str:
386
  """Format business partner API response into readable text"""
 
416
  formatted_response += f"- **Type:** {category_text}\n"
417
  formatted_response += f"- **Status:** {status}\n\n"
418
 
 
 
 
 
 
 
 
419
  return formatted_response
420
  else:
421
  return f"⚠️ Received unexpected response format for: '{original_query}'"
 
445
  history.append([user_query, None])
446
 
447
  try:
448
+ # Check for multi-step workflow requests
449
+ if any(keyword in user_query.lower() for keyword in ['credit limit', 'credit analysis', 'germany credit', 'german customers credit']):
450
+ response = self.execute_multi_step_workflow("credit_analysis", user_query)
451
+ elif any(keyword in user_query.lower() for keyword in ['search', 'find', 'show', 'list', 'get']):
452
  response = self.search_business_partners(user_query)
453
  else:
454
  # Use OpenAI to understand intent and provide guidance
455
  system_prompt = """
456
+ You are a SAP Business Partner Assistant with multi-step workflow capabilities.
457
+
458
+ Available capabilities:
459
+ 1. Search business partners
460
+ 2. Credit limit analysis workflows
461
+ 3. Multi-step customer analysis
462
 
463
+ Guide users to:
464
+ - Use search terms for finding partners
465
+ - Ask for "credit analysis for German customers" for workflows
466
+ - Request specific business partner operations
467
 
468
+ Be helpful and explain what you can do.
469
  """
470
 
471
  ai_response = client.chat.completions.create(
 
482
  history[-1][1] = response
483
 
484
  except Exception as e:
485
+ error_response = f"❌ Sorry, I encountered an error: {str(e)}\n\nTry asking: 'Run credit analysis for German customers'"
486
  history[-1][1] = error_response
487
 
488
  return "", history
 
493
  # Create Gradio interface
494
  def create_interface():
495
  with gr.Blocks(
496
+ title="SAP Business Partner Agent with Workflows",
497
  theme=gr.themes.Soft(),
498
  css="""
499
  .gradio-container {
 
514
  gr.HTML("""
515
  <div class="agent-header">
516
  <h1>πŸ€– SAP Business Partner Agent</h1>
517
+ <p>Intelligent assistant with multi-step workflow capabilities</p>
518
  </div>
519
  """)
520
 
 
522
  with gr.Row():
523
  with gr.Column(scale=4):
524
  chatbot = gr.Chatbot(
525
+ height=600,
526
  label="Chat with SAP Business Partner Agent",
527
+ placeholder="Start by asking about business partners or request a workflow..."
528
  )
529
 
530
  with gr.Row():
531
  msg = gr.Textbox(
532
+ placeholder="Try: 'Run credit analysis for German customers' or 'Find partners with name Demo'",
533
  label="Your Message",
534
  scale=4
535
  )
 
538
  # Example buttons
539
  gr.Markdown("### πŸ’‘ Quick Examples:")
540
  with gr.Row():
541
+ example1 = gr.Button("Credit Analysis Workflow", size="sm", variant="primary")
542
+ example2 = gr.Button("Find German customers", size="sm")
543
+ example3 = gr.Button("Search Demo partners", size="sm")
544
  clear_btn = gr.Button("Clear Chat", size="sm", variant="secondary")
545
 
546
  # Sidebar with information
 
548
  gr.Markdown("""
549
  ### πŸ”§ Agent Capabilities
550
 
551
+ **Multi-Step Workflows:**
552
+ - 🏦 Credit limit analysis
553
+ - πŸ“Š Risk assessment
554
+ - πŸ”„ Sequential API calls
555
+
556
  **Search & Retrieve:**
557
+ - Find business partners
558
+ - Filter by criteria
559
+ - Location-based search
560
 
561
  **Partner Types:**
562
  - πŸ‘€ Persons
563
  - 🏒 Organizations
564
  - 🏭 Groups
565
 
566
+ ### πŸš€ Advanced Features
567
+ - **Workflow Tracking:** Step-by-step progress
568
+ - **Error Handling:** Graceful failure recovery
569
+ - **Data Integration:** Multiple SAP APIs
570
+ - **Smart Analysis:** AI-powered insights
571
 
572
+ ### πŸ“ Workflow Examples
573
+ - "Run credit analysis for German customers"
574
+ - "Analyze credit limits for suppliers"
575
+ - "Find high-risk customers"
 
576
  """)
577
 
578
  # Event handlers
 
589
  )
590
 
591
  # Example button events
592
+ example1.click(lambda: "Run credit analysis for German customers", outputs=msg)
593
+ example2.click(lambda: "Find customers in Germany", outputs=msg)
594
+ example3.click(lambda: "Find partners with name Demo", outputs=msg)
595
  clear_btn.click(lambda: [], outputs=chatbot)
596
 
597
  # Footer
598
  gr.Markdown("""
599
  ---
600
+ **SAP Business Partner Agent with Multi-Step Workflows** | Powered by OpenAI & SAP APIs | Built for Advanced Agentic AI Learning
601
  """)
602
 
603
  return demo