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__":
|