rairo commited on
Commit
59723f0
·
1 Parent(s): 0be6e8b

Update Llama_Utility.py

Browse files
Files changed (1) hide show
  1. Llama_Utility.py +294 -0
Llama_Utility.py CHANGED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import os
3
+ from datetime import datetime
4
+ import openai
5
+ from google.cloud import firestore
6
+ from dotenv import load_dotenv
7
+ import pandas as pd
8
+ import ast
9
+ import json
10
+ from pandasai.responses.response_parser import ResponseParser
11
+ # Load environment variables and configure Firestore
12
+ load_dotenv()
13
+ db = firestore.Client.from_service_account_json("firestore-key.json")
14
+ from langchain_google_genai import ChatGoogleGenerativeAI
15
+ # Initialize the ChatSambaNovaCloud LLM client (using the latest model)
16
+ from langchain_community.chat_models.sambanova import ChatSambaNovaCloud
17
+ import google.generativeai as genai
18
+
19
+ llm = ChatSambaNovaCloud(
20
+ model="Meta-Llama-3.1-70B-Instruct",
21
+ max_tokens=1024,
22
+ temperature=0.7,
23
+ top_k=1,
24
+ top_p=0.01,
25
+ )
26
+
27
+
28
+
29
+ # Response parser for formatting outputs from pandasai
30
+ class FlaskResponse(ResponseParser):
31
+ def __init__(self, context) -> None:
32
+ super().__init__(context)
33
+
34
+ def format_dataframe(self, result):
35
+ return result['value'].to_html()
36
+
37
+ def format_plot(self, result):
38
+ # Save the plot using savefig
39
+ try:
40
+
41
+ img_path = result['value']
42
+
43
+
44
+ except ValueError:
45
+ img_path = str(result['value'])
46
+ print("value error!", img_path)
47
+
48
+ print("response_class_path:", img_path)
49
+ return img_path
50
+
51
+ def format_other(self, result):
52
+ return str(result['value'])
53
+
54
+ def generateResponse(prompt, model='Meta-Llama-3.1-70B-Instruct'):
55
+ # Templates for extracting transaction information
56
+ relevant_info_template = """
57
+ Intent: The CRUD operation (create, read, update, delete)
58
+ Transaction Type: e.g. Purchase, Sale, Inventory
59
+ Details: A list of key detail fields extracted.
60
+ """
61
+ sample_single_transaction_template = """
62
+ *Intent*: Create
63
+ *Transaction Type*: Purchase
64
+ *Details*: - Item: Car, - Quantity: 1, - Cost: 10000, etc.
65
+ """
66
+ sample_multi_transaction_template = """
67
+ *Intent*: Create
68
+ Transaction 1:
69
+ *Transaction Type*: Purchase
70
+ *Details*: - Item: Car, - Quantity: 1, etc.
71
+ Transaction 2:
72
+ *Transaction Type*: Sale
73
+ *Details*: - Item: Chair, - Quantity: 2, etc.
74
+ """
75
+ response = openai.OpenAI(
76
+ api_key=os.environ.get("SAMBANOVA_API_KEY"),
77
+ base_url="https://api.sambanova.ai/v1",
78
+ ).chat.completions.create(
79
+ model=model,
80
+ messages=[
81
+ {"role": "system", "content":
82
+ f"You are a helpful assistant that classifies transactions. Format your output with these guidelines: {relevant_info_template} "
83
+ f"Sample single transaction: {sample_single_transaction_template} "
84
+ f"Sample multi-transaction: {sample_multi_transaction_template}"},
85
+ {"role": "user", "content": prompt}
86
+ ]
87
+ )
88
+ try:
89
+ response_text = response.choices[0].message.content
90
+ except Exception as e:
91
+ print(f'An error occurred: {str(e)}')
92
+ response_text = None
93
+ return response_text
94
+
95
+ def parse_value(value):
96
+ value = value.strip()
97
+ try:
98
+ # Try to detect currency symbols or codes
99
+ currency_match = re.search(r"([A-Z]{3}|\$|€|£)", value)
100
+ currency = currency_match.group(1) if currency_match else None
101
+
102
+ # Remove currency symbols/codes for numeric conversion
103
+ cleaned_value = re.sub(r"([A-Z]{3}|\$|€|£)", "", value).replace(",", "").strip()
104
+
105
+ if "%" in cleaned_value:
106
+ return float(cleaned_value.replace("%", "")), currency
107
+ elif cleaned_value.replace(".", "", 1).isdigit():
108
+ return float(cleaned_value) if "." in cleaned_value else int(cleaned_value), currency
109
+ return value, currency
110
+ except ValueError:
111
+ return value, None
112
+
113
+ def extract_transaction_details(text):
114
+ details = {}
115
+ transaction_currency = None # Default currency
116
+ # Use regex to extract key: value pairs (handles bold formatting if present)
117
+ detail_matches = re.findall(
118
+ r"-\s*\*{0,2}([\w\s]+)\*{0,2}:\s*([\w\s,.$%-]+?)(?:\s*[\n]|$)",
119
+ text,
120
+ re.DOTALL
121
+ )
122
+ for field, value in detail_matches:
123
+ field_key = field.strip().lower().replace(" ", "_")
124
+ parsed_value, detected_currency = parse_value(value)
125
+ if detected_currency and not transaction_currency:
126
+ transaction_currency = detected_currency
127
+ details[field_key] = parsed_value
128
+ if transaction_currency:
129
+ details["currency"] = transaction_currency
130
+ return details
131
+
132
+ def parse_ai_response(response_text):
133
+ data = {
134
+ "intent": None,
135
+ "transaction_type": None,
136
+ "details": {},
137
+ "created_at": datetime.now().isoformat()
138
+ }
139
+ intent_match = re.search(r"\*Intent\*:\s*(\w+)", response_text)
140
+ if intent_match:
141
+ data["intent"] = intent_match.group(1)
142
+ transaction_type_match = re.search(r"\*Transaction Type\*:\s*(\w+)", response_text)
143
+ if transaction_type_match:
144
+ data["transaction_type"] = transaction_type_match.group(1)
145
+ data["details"] = extract_transaction_details(response_text)
146
+ return data
147
+
148
+ def parse_multiple_transactions(response_text):
149
+ transactions = []
150
+ # Split the response into sections by "Transaction <number>:"
151
+ transaction_sections = re.split(r"Transaction \d+:", response_text, flags=re.IGNORECASE)
152
+ transaction_sections = [section.strip() for section in transaction_sections if section.strip()]
153
+ # If the first section does not contain transaction info, remove it
154
+ if transaction_sections and not re.search(r"\*Transaction Type\*", transaction_sections[0], re.IGNORECASE):
155
+ transaction_sections.pop(0)
156
+ intent_match = re.search(r"\*Intent\*:\s*(\w+)", response_text)
157
+ intent = intent_match.group(1) if intent_match else None
158
+ for section in transaction_sections:
159
+ data = {
160
+ "intent": intent,
161
+ "transaction_type": None,
162
+ "details": {},
163
+ "created_at": datetime.now().isoformat()
164
+ }
165
+ transaction_type_match = re.search(r"\*Transaction Type\*:\s*(\w+)", section)
166
+ if transaction_type_match:
167
+ data["transaction_type"] = transaction_type_match.group(1)
168
+ data["details"] = extract_transaction_details(section)
169
+ transactions.append(data)
170
+ return transactions
171
+
172
+ def read_datalake(user_phone, user_question):
173
+ inventory_ref = db.collection("users").document(user_phone).collection("inventory")
174
+ sales_ref = db.collection("users").document(user_phone).collection("sales")
175
+ inventory_list = [doc.to_dict() for doc in inventory_ref.stream()]
176
+ sales_list = [doc.to_dict() for doc in sales_ref.stream()]
177
+ inventory_df = pd.DataFrame(inventory_list)
178
+ sales_df = pd.DataFrame(sales_list)
179
+ from pandasai import SmartDatalake
180
+ lake = SmartDatalake(
181
+ [inventory_df, sales_df],
182
+ config={
183
+ "llm": llm,
184
+ "custom_whitelisted_dependencies": ["ast"],
185
+ "response_parser": FlaskResponse,
186
+ "enable_cache": False,
187
+ "save_logs": False
188
+ }
189
+ )
190
+ response = lake.chat(user_question)
191
+ return response
192
+
193
+ def create_inventory(user_phone, transaction_data):
194
+ for transaction in transaction_data:
195
+ item_name = transaction['details'].get('item')
196
+ if item_name:
197
+ doc_ref = db.collection("users").document(user_phone).collection("inventory").document(item_name)
198
+ doc_ref.set(transaction)
199
+ return True
200
+
201
+ def create_sale(user_phone, transaction_data):
202
+ for transaction in transaction_data:
203
+ item_name = transaction['details'].get('item')
204
+ if not item_name:
205
+ continue
206
+ inventory = fetch_transaction(user_phone, item_name)
207
+ if inventory and inventory['details'].get('quantity') is not None:
208
+ new_stock = inventory['details'].get('quantity') - transaction['details'].get('quantity', 0)
209
+ inventory['details']['quantity'] = new_stock
210
+ inv_ref = db.collection("users").document(user_phone).collection("inventory").document(item_name)
211
+ inv_ref.set(inventory)
212
+ sale_ref = db.collection("users").document(user_phone).collection("sales").document(item_name)
213
+ sale_ref.set(transaction)
214
+ return True
215
+
216
+ def update_transaction(user_phone, transaction_id, update_data):
217
+ doc_ref = db.collection("users").document(user_phone).collection("transactions").document(transaction_id)
218
+ doc_ref.update(update_data)
219
+ return True
220
+
221
+ def fetch_transaction(user_phone, transaction_id=None):
222
+ if transaction_id:
223
+ doc_ref = db.collection("users").document(user_phone).collection("inventory").document(transaction_id)
224
+ transaction = doc_ref.get()
225
+ if transaction.exists:
226
+ return transaction.to_dict()
227
+ return None
228
+ else:
229
+ collection_ref = db.collection("users").document(user_phone).collection("inventory")
230
+ transactions = [doc.to_dict() for doc in collection_ref.stream()]
231
+ return transactions
232
+
233
+ def delete_transaction(user_phone, transaction_data):
234
+ # Assume transaction id defaults to the item name in transaction details
235
+ transaction_id = transaction_data[0]['details'].get('item')
236
+ transaction_type = transaction_data[0]['transaction_type']
237
+ if transaction_type:
238
+ transaction_type = transaction_type.lower()
239
+ else:
240
+ transaction_type = "inventory"
241
+ doc_ref = db.collection("users").document(user_phone).collection(transaction_type).document(transaction_id)
242
+ item_doc = doc_ref.get()
243
+ if item_doc.exists:
244
+ doc_ref.delete()
245
+ return True
246
+ else:
247
+ return False
248
+
249
+ def persist_temporary_transaction(transactions, mobile):
250
+ temp_ref = db.collection("users").document(mobile).collection("temp_transactions").document('pending-user-action')
251
+ data = {
252
+ "transactions": transactions,
253
+ "status": "pending",
254
+ "created_at": datetime.now().isoformat()
255
+ }
256
+ temp_ref.set(data)
257
+ return True
258
+
259
+ def process_intent(parsed_trans_data, mobile):
260
+ """
261
+ Process the detected intent and handle transactions accordingly.
262
+ - For 'create', it differentiates between purchase/inventory and sale.
263
+ - For 'delete', it attempts to delete the transaction.
264
+ - Returns a message indicating the result.
265
+ """
266
+ intent = parsed_trans_data[0]['intent'].lower() if parsed_trans_data and parsed_trans_data[0].get('intent') else None
267
+ trans_type = parsed_trans_data[0]['transaction_type'].lower() if parsed_trans_data and parsed_trans_data[0].get('transaction_type') else None
268
+
269
+ if intent == 'create':
270
+ if trans_type in ('purchase', 'purchases', 'inventory'):
271
+ if create_inventory(mobile, parsed_trans_data):
272
+ firestore_msg = "Transaction recorded successfully!"
273
+ else:
274
+ firestore_msg = "Sorry, could not record transaction!"
275
+ elif trans_type in ('sale', 'sales'):
276
+ if create_sale(mobile, parsed_trans_data):
277
+ firestore_msg = "Transaction recorded successfully!"
278
+ else:
279
+ firestore_msg = "Sorry, could not record transaction!"
280
+ else:
281
+ firestore_msg = f"Transaction type '{trans_type}' is not supported for create operations."
282
+ elif intent == 'update':
283
+ # Update logic would be implemented here.
284
+ firestore_msg = "Update operation not implemented yet."
285
+ elif intent == 'delete':
286
+ item = parsed_trans_data[0]['details'].get('item', 'item')
287
+ item_deleted = delete_transaction(mobile, parsed_trans_data)
288
+ if item_deleted:
289
+ firestore_msg = f"You successfully deleted {item} from {trans_type}!"
290
+ else:
291
+ firestore_msg = f"Sorry, could not delete {item} from {trans_type}!"
292
+ else:
293
+ firestore_msg = f"The detected intent, {intent}, is not currently supported!"
294
+ return firestore_msg