PD03 commited on
Commit
899df39
Β·
verified Β·
1 Parent(s): 0f901c6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +355 -0
app.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import openai
3
+ import requests
4
+ import json
5
+ import os
6
+ from typing import Dict, List, Any
7
+ from datetime import datetime
8
+ from pydantic import BaseModel
9
+
10
+ # Set up OpenAI client
11
+ openai.api_key = os.getenv("OPENAI_API_KEY")
12
+ client = openai.OpenAI()
13
+
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"""
24
+ system_prompt = """
25
+ Parse this business partner search query into SAP OData parameters.
26
+
27
+ Available fields for A_BusinessPartner:
28
+ - BusinessPartner (ID)
29
+ - BusinessPartnerFullName (Name)
30
+ - BusinessPartnerCategory (1=Person, 2=Organization, 3=Group)
31
+ - BusinessPartnerGrouping
32
+ - CreationDate
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:
47
+ response = client.chat.completions.create(
48
+ model="gpt-4o-mini",
49
+ messages=[
50
+ {"role": "system", "content": system_prompt},
51
+ {"role": "user", "content": f"Query: {query}"}
52
+ ],
53
+ response_format={"type": "json_object"}
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 = {
75
+ "$format": "json",
76
+ "$inlinecount": "allpages"
77
+ }
78
+
79
+ # Add user parameters
80
+ for key, value in params.items():
81
+ query_params[key] = value
82
+
83
+ headers = {
84
+ "Accept": "application/json",
85
+ "APIKey": SAP_API_KEY or "demo_key"
86
+ }
87
+
88
+ try:
89
+ response = requests.get(url, params=query_params, headers=headers, timeout=30)
90
+
91
+ if response.status_code == 200:
92
+ return response.json()
93
+ else:
94
+ # Return mock data for demo if API fails
95
+ return self.get_mock_data(entity_set)
96
+
97
+ except Exception as e:
98
+ # Return mock data for demo
99
+ return self.get_mock_data(entity_set)
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"""
138
+ try:
139
+ if 'd' in response and 'results' in response['d']:
140
+ results = response['d']['results']
141
+ total_count = response['d'].get('__count', len(results))
142
+
143
+ if not results:
144
+ return f"❌ No business partners found for: '{original_query}'"
145
+
146
+ # Format the response
147
+ formatted_response = f"## πŸ“Š Business Partner Search Results\n\n"
148
+ formatted_response += f"**Query:** {original_query}\n"
149
+ formatted_response += f"**Found:** {total_count} business partner(s)\n\n"
150
+
151
+ for i, partner in enumerate(results, 1):
152
+ bp_id = partner.get('BusinessPartner', 'N/A')
153
+ bp_name = partner.get('BusinessPartnerFullName', 'N/A')
154
+ bp_category = partner.get('BusinessPartnerCategory', 'N/A')
155
+ is_archived = partner.get('IsMarkedForArchiving', False)
156
+
157
+ category_text = {
158
+ '1': 'πŸ‘€ Person',
159
+ '2': '🏒 Organization',
160
+ '3': '🏭 Group'
161
+ }.get(bp_category, '❓ Unknown')
162
+
163
+ status = '🟒 Active' if not is_archived else 'πŸ”΄ Archived'
164
+
165
+ formatted_response += f"### {i}. {bp_name}\n"
166
+ formatted_response += f"- **ID:** {bp_id}\n"
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}'"
180
+
181
+ except Exception as e:
182
+ return f"❌ Error formatting response: {str(e)}"
183
+
184
+ def search_business_partners(self, query: str) -> str:
185
+ """Main search function for business partners"""
186
+ try:
187
+ # Parse the query
188
+ params = self.parse_search_query(query)
189
+
190
+ # Call SAP API
191
+ response = self.call_sap_api("A_BusinessPartner", params)
192
+
193
+ # Format response
194
+ return self.format_business_partner_response(response, query)
195
+
196
+ except Exception as e:
197
+ return f"❌ Error searching business partners: {str(e)}"
198
+
199
+ def process_user_query(self, user_query: str, history: List) -> tuple:
200
+ """Process user query and return response with updated history"""
201
+
202
+ # Add user message to history
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(
223
+ model="gpt-4o-mini",
224
+ messages=[
225
+ {"role": "system", "content": system_prompt},
226
+ {"role": "user", "content": user_query}
227
+ ]
228
+ )
229
+
230
+ response = ai_response.choices[0].message.content
231
+
232
+ # Update history with response
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
240
+
241
+ # Initialize the agent
242
+ sap_agent = SAPBusinessPartnerAgent()
243
+
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 {
251
+ max-width: 1200px !important;
252
+ }
253
+ .agent-header {
254
+ text-align: center;
255
+ background: linear-gradient(90deg, #0070f3, #00d4ff);
256
+ color: white;
257
+ padding: 20px;
258
+ border-radius: 10px;
259
+ margin-bottom: 20px;
260
+ }
261
+ """
262
+ ) as demo:
263
+
264
+ # Header
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
+
272
+ # Main chat 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
+ )
287
+ submit_btn = gr.Button("Send", variant="primary", scale=1)
288
+
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
298
+ with gr.Column(scale=1):
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
326
+ msg.submit(
327
+ sap_agent.process_user_query,
328
+ inputs=[msg, chatbot],
329
+ outputs=[msg, chatbot]
330
+ )
331
+
332
+ submit_btn.click(
333
+ sap_agent.process_user_query,
334
+ inputs=[msg, chatbot],
335
+ outputs=[msg, chatbot]
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
351
+
352
+ # Launch the app
353
+ if __name__ == "__main__":
354
+ demo = create_interface()
355
+ demo.launch()