Update app.py
Browse files
app.py
CHANGED
@@ -9,30 +9,12 @@ import gradio as gr
|
|
9 |
# Setup logging
|
10 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
11 |
|
12 |
-
#
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
TRANSFORMERS_AVAILABLE = False
|
19 |
-
AutoModelForCausalLM = None
|
20 |
-
AutoTokenizer = None
|
21 |
-
|
22 |
-
# Initialize AI model (t5-small for better accounting parsing; fallback to distilbert)
|
23 |
-
model_name = "t5-small" # Smaller model for free tier
|
24 |
-
if TRANSFORMERS_AVAILABLE:
|
25 |
-
try:
|
26 |
-
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
27 |
-
model = AutoModelForCausalLM.from_pretrained(model_name)
|
28 |
-
logging.info(f"Loaded model: {model_name}")
|
29 |
-
except Exception as e:
|
30 |
-
logging.error(f"Failed to load model {model_name}: {e}")
|
31 |
-
tokenizer = None
|
32 |
-
model = None
|
33 |
-
else:
|
34 |
-
tokenizer = None
|
35 |
-
model = None
|
36 |
|
37 |
# Database setup
|
38 |
conn = sqlite3.connect("erp.db", check_same_thread=False)
|
@@ -110,6 +92,7 @@ def initialize_chart_of_accounts():
|
|
110 |
|
111 |
# Enhanced fallback parser
|
112 |
def parse_prompt(prompt, state):
|
|
|
113 |
if model and tokenizer:
|
114 |
try:
|
115 |
input_text = f"""
|
@@ -124,7 +107,7 @@ def parse_prompt(prompt, state):
|
|
124 |
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
125 |
return json.loads(response), state
|
126 |
except Exception as e:
|
127 |
-
logging.
|
128 |
|
129 |
# Fallback parser
|
130 |
prompt_lower = prompt.lower().strip()
|
@@ -167,7 +150,7 @@ def parse_prompt(prompt, state):
|
|
167 |
credit_type = None
|
168 |
payment_method = None
|
169 |
|
170 |
-
#
|
171 |
if state.get("pending_prompt"):
|
172 |
follow_up = prompt_lower
|
173 |
if follow_up in ["cash", "credit", "bank"]:
|
@@ -205,15 +188,23 @@ def parse_prompt(prompt, state):
|
|
205 |
elif keyword == "owner's draw":
|
206 |
debit_account, debit_type = "Drawings", "Equity"
|
207 |
credit_account, credit_type = "Cash", "Asset"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
break
|
209 |
|
210 |
-
if "cash" in prompt_lower:
|
211 |
credit_account, credit_type = "Cash", "Asset"
|
212 |
payment_method = "cash"
|
213 |
-
elif "bank" in prompt_lower:
|
214 |
credit_account, credit_type = "Bank", "Asset"
|
215 |
payment_method = "bank"
|
216 |
-
elif "credit" in prompt_lower:
|
217 |
credit_account, credit_type = "Accounts Payable", "Liability"
|
218 |
payment_method = "credit"
|
219 |
elif debit_account and not credit_account:
|
@@ -233,6 +224,7 @@ def parse_prompt(prompt, state):
|
|
233 |
|
234 |
# Generate journal entry
|
235 |
def generate_journal_entry(parsed, state):
|
|
|
236 |
if "error" in parsed:
|
237 |
return parsed["error"], state
|
238 |
if parsed.get("status") == "clarify":
|
@@ -260,14 +252,18 @@ def generate_journal_entry(parsed, state):
|
|
260 |
entry_id = str(uuid.uuid4())
|
261 |
date = datetime.datetime.now().isoformat()
|
262 |
description = state.get("pending_prompt", "Transaction")
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
|
|
|
|
|
|
|
|
269 |
|
270 |
-
return f"Journal Entry Created: Debit {debit_account} ${amount}, Credit {credit_account} ${amount}",
|
271 |
|
272 |
# Generate T-account
|
273 |
def generate_t_account(account_name):
|
@@ -309,9 +305,10 @@ def generate_t_account(account_name):
|
|
309 |
def chat_function(message, history, state=None):
|
310 |
if state is None:
|
311 |
state = {}
|
|
|
|
|
312 |
|
313 |
-
|
314 |
-
initialize_chart_of_accounts()
|
315 |
|
316 |
# Handle T-account request
|
317 |
if message.lower().startswith("t-account "):
|
@@ -324,6 +321,13 @@ def chat_function(message, history, state=None):
|
|
324 |
parsed, state = parse_prompt(message, state)
|
325 |
response, state = generate_journal_entry(parsed, state)
|
326 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
return response, state
|
328 |
|
329 |
# Gradio interface
|
@@ -331,14 +335,14 @@ with gr.Blocks() as demo:
|
|
331 |
gr.Markdown("# AI ERP System")
|
332 |
gr.Markdown("Enter accounting prompts like 'Bought a laptop for $200' or 't-account Laptop'. The system will ask for clarification if needed.")
|
333 |
chatbot = gr.Chatbot()
|
334 |
-
msg = gr.Textbox(placeholder="Type your prompt here...")
|
335 |
clear = gr.Button("Clear")
|
336 |
|
337 |
# Maintain state
|
338 |
state = gr.State({})
|
339 |
|
340 |
-
msg.submit(chat_function, [msg, chatbot, state], [chatbot, state])
|
341 |
-
clear.click(lambda: None, None, chatbot, queue=False)
|
342 |
|
343 |
# Launch Gradio
|
344 |
if __name__ == "__main__":
|
|
|
9 |
# Setup logging
|
10 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
11 |
|
12 |
+
# Disable model loading on free tier due to memory constraints
|
13 |
+
TRANSFORMERS_AVAILABLE = False
|
14 |
+
AutoModelForCausalLM = None
|
15 |
+
AutoTokenizer = None
|
16 |
+
tokenizer = None
|
17 |
+
model = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
# Database setup
|
20 |
conn = sqlite3.connect("erp.db", check_same_thread=False)
|
|
|
92 |
|
93 |
# Enhanced fallback parser
|
94 |
def parse_prompt(prompt, state):
|
95 |
+
logging.info(f"Parsing prompt: {prompt}")
|
96 |
if model and tokenizer:
|
97 |
try:
|
98 |
input_text = f"""
|
|
|
107 |
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
108 |
return json.loads(response), state
|
109 |
except Exception as e:
|
110 |
+
logging.error(f"Model parsing failed: {e}")
|
111 |
|
112 |
# Fallback parser
|
113 |
prompt_lower = prompt.lower().strip()
|
|
|
150 |
credit_type = None
|
151 |
payment_method = None
|
152 |
|
153 |
+
# Handle follow-up response
|
154 |
if state.get("pending_prompt"):
|
155 |
follow_up = prompt_lower
|
156 |
if follow_up in ["cash", "credit", "bank"]:
|
|
|
188 |
elif keyword == "owner's draw":
|
189 |
debit_account, debit_type = "Drawings", "Equity"
|
190 |
credit_account, credit_type = "Cash", "Asset"
|
191 |
+
elif keyword == "paid":
|
192 |
+
if "rent" in prompt_lower:
|
193 |
+
debit_account, debit_type = "Rent Expense", "Expense"
|
194 |
+
elif "salary" in prompt_lower:
|
195 |
+
debit_account, debit_type = "Salary Expense", "Expense"
|
196 |
+
elif "office supplies" in prompt_lower:
|
197 |
+
debit_account, debit_type = "Office Supplies", "Expense"
|
198 |
+
credit_account, credit_type = "Cash", "Asset"
|
199 |
break
|
200 |
|
201 |
+
if "cash" in prompt_lower and not credit_account:
|
202 |
credit_account, credit_type = "Cash", "Asset"
|
203 |
payment_method = "cash"
|
204 |
+
elif "bank" in prompt_lower and not credit_account:
|
205 |
credit_account, credit_type = "Bank", "Asset"
|
206 |
payment_method = "bank"
|
207 |
+
elif "credit" in prompt_lower and not credit_account:
|
208 |
credit_account, credit_type = "Accounts Payable", "Liability"
|
209 |
payment_method = "credit"
|
210 |
elif debit_account and not credit_account:
|
|
|
224 |
|
225 |
# Generate journal entry
|
226 |
def generate_journal_entry(parsed, state):
|
227 |
+
logging.info(f"Generating journal entry with parsed: {parsed}")
|
228 |
if "error" in parsed:
|
229 |
return parsed["error"], state
|
230 |
if parsed.get("status") == "clarify":
|
|
|
252 |
entry_id = str(uuid.uuid4())
|
253 |
date = datetime.datetime.now().isoformat()
|
254 |
description = state.get("pending_prompt", "Transaction")
|
255 |
+
try:
|
256 |
+
cursor.execute("""
|
257 |
+
INSERT INTO journal_entries (entry_id, date, debit_account_id, credit_account_id, amount, description)
|
258 |
+
VALUES (?, ?, ?, ?, ?, ?)
|
259 |
+
""", (entry_id, date, debit_result[0], credit_result[0], amount, description))
|
260 |
+
conn.commit()
|
261 |
+
logging.info(f"Journal entry created: Debit {debit_account} ${amount}, Credit {credit_account} ${amount}")
|
262 |
+
except sqlite3.Error as e:
|
263 |
+
logging.error(f"Database error: {e}")
|
264 |
+
return "Database error occurred.", state
|
265 |
|
266 |
+
return f"Journal Entry Created: Debit {debit_account} ${amount}, Credit {credit_account} ${amount}", state
|
267 |
|
268 |
# Generate T-account
|
269 |
def generate_t_account(account_name):
|
|
|
305 |
def chat_function(message, history, state=None):
|
306 |
if state is None:
|
307 |
state = {}
|
308 |
+
initialize_chart_of_accounts()
|
309 |
+
logging.info("Initialized state and chart of accounts")
|
310 |
|
311 |
+
logging.info(f"Received message: {message}")
|
|
|
312 |
|
313 |
# Handle T-account request
|
314 |
if message.lower().startswith("t-account "):
|
|
|
321 |
parsed, state = parse_prompt(message, state)
|
322 |
response, state = generate_journal_entry(parsed, state)
|
323 |
|
324 |
+
# Append to history
|
325 |
+
if history is not None:
|
326 |
+
history.append((message, response))
|
327 |
+
else:
|
328 |
+
history = [(message, response)]
|
329 |
+
|
330 |
+
logging.info(f"Response: {response}")
|
331 |
return response, state
|
332 |
|
333 |
# Gradio interface
|
|
|
335 |
gr.Markdown("# AI ERP System")
|
336 |
gr.Markdown("Enter accounting prompts like 'Bought a laptop for $200' or 't-account Laptop'. The system will ask for clarification if needed.")
|
337 |
chatbot = gr.Chatbot()
|
338 |
+
msg = gr.Textbox(placeholder="Type your prompt here...", lines=2)
|
339 |
clear = gr.Button("Clear")
|
340 |
|
341 |
# Maintain state
|
342 |
state = gr.State({})
|
343 |
|
344 |
+
msg.submit(chat_function, [msg, chatbot, state], [chatbot, state], _js="() => {return false;}")
|
345 |
+
clear.click(lambda: (None, []), None, [chatbot, state], queue=False)
|
346 |
|
347 |
# Launch Gradio
|
348 |
if __name__ == "__main__":
|