|
|
import gradio as gr |
|
|
import openpyxl |
|
|
import PyPDF2 |
|
|
import pandas as pd |
|
|
from PIL import Image |
|
|
import pytesseract |
|
|
import io |
|
|
import os |
|
|
from huggingface_hub import InferenceClient |
|
|
|
|
|
|
|
|
hf_token = os.environ.get("HF_TOKEN") |
|
|
|
|
|
|
|
|
def extract_transactions(file): |
|
|
"""Extract raw text content from various supported file formats.""" |
|
|
filename = file.name.lower() |
|
|
|
|
|
try: |
|
|
if filename.endswith((".xlsx", ".xls")): |
|
|
workbook = openpyxl.load_workbook(file, data_only=True) |
|
|
sheet = workbook.active |
|
|
return "\n".join( |
|
|
"\t".join(str(cell.value or "") for cell in row) |
|
|
for row in sheet.iter_rows() |
|
|
) |
|
|
|
|
|
elif filename.endswith(".csv"): |
|
|
df = pd.read_csv(file) |
|
|
return df.to_string(index=False) |
|
|
|
|
|
elif filename.endswith(".pdf"): |
|
|
reader = PyPDF2.PdfReader(file) |
|
|
return "\n".join(page.extract_text() or "" for page in reader.pages) |
|
|
|
|
|
elif filename.endswith((".jpg", ".jpeg", ".png")): |
|
|
image = Image.open(io.BytesIO(file.read())) |
|
|
return pytesseract.image_to_string(image) |
|
|
|
|
|
else: |
|
|
raise ValueError("Unsupported file format.") |
|
|
|
|
|
except Exception as e: |
|
|
raise ValueError(f"Error processing {file.name}: {e}") |
|
|
|
|
|
|
|
|
def reconcile_statements(erp_file, bank_file): |
|
|
yield "β³ Processing your request... Please wait.", "" |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
erp_statement = extract_transactions(erp_file) |
|
|
bank_statement = extract_transactions(bank_file) |
|
|
print("ERP statement is: ") |
|
|
print(erp_statement) |
|
|
|
|
|
print("Bank statement is: ") |
|
|
print(bank_statement) |
|
|
|
|
|
|
|
|
|
|
|
prompt = f"""You are a financial analyst specializing in account reconciliations. Your task is to compare two data sets: one from an ERP system and the other from a bank statement. |
|
|
|
|
|
The goal is to identify which transactions match across both data sets, and which transactions are unmatched or potentially erroneous. |
|
|
|
|
|
Each dataset contains transaction entries with **Date**, **Amount**, and **Description**. |
|
|
|
|
|
ERP descriptions may include prefixes like "Vendor Payment - ", while the bank descriptions are simpler (e.g., "Utilities" instead of "Vendor Payment - Utilities"). Please normalize these for accurate comparison. |
|
|
|
|
|
--- |
|
|
|
|
|
Please follow this format in your response: |
|
|
|
|
|
1. π **Introduction** |
|
|
Briefly explain what reconciliation means and how you'll approach it. |
|
|
|
|
|
2. π **Unmatched ERP Transactions** |
|
|
List any transactions found in the ERP file but not in the Bank file. |
|
|
|
|
|
3. π¦ **Unmatched Bank Transactions** |
|
|
List any transactions found in the Bank file but not in the ERP file. |
|
|
|
|
|
4. β
**Matched Transactions (optional, summary only)** |
|
|
How many matched successfully? |
|
|
|
|
|
5. π§Ύ **Summary & Suggested Next Steps** |
|
|
Explain what the discrepancies might mean and what the user should do next. |
|
|
|
|
|
--- |
|
|
|
|
|
Here is the ERP data: |
|
|
{erp_statement} |
|
|
|
|
|
--- |
|
|
|
|
|
Here is the Bank data: |
|
|
{bank_statement} |
|
|
|
|
|
--- |
|
|
|
|
|
Generate a clean and professional reconciliation report, structured as described above. Make sure the response is easy to read.""" |
|
|
|
|
|
|
|
|
client = InferenceClient(provider="together", api_key=hf_token) |
|
|
completion = client.chat.completions.create( |
|
|
model="deepseek-ai/DeepSeek-R1", |
|
|
messages=[{"role": "user", "content": prompt}], |
|
|
max_tokens=100000 |
|
|
) |
|
|
|
|
|
if completion.choices: |
|
|
reconciliation_results = completion.choices[0].message.get('content', '') |
|
|
print(reconciliation_results) |
|
|
else: |
|
|
reconciliation_results = "β οΈ No response received from the model." |
|
|
|
|
|
output = f""" |
|
|
<div style="font-family: 'Segoe UI', ..."> |
|
|
<h2>π Reconciliation Results</h2> |
|
|
<div style="..."> |
|
|
<pre>{reconciliation_results}</pre> |
|
|
</div> |
|
|
</div> |
|
|
""" |
|
|
yield "β
Processing complete!", output |
|
|
|
|
|
except Exception as e: |
|
|
yield f"β Error: {e}", f"<h1>Error</h1><p>{e}</p>" |
|
|
|
|
|
with gr.Blocks(css=""" |
|
|
#company-logo { |
|
|
width: 25%; |
|
|
margin: auto; |
|
|
display: block; |
|
|
} |
|
|
""") as iface: |
|
|
gr.Image("logo_Icon.png", elem_id="company-logo", label="Beiing Human") |
|
|
status_text = gr.Markdown("π Upload your files to begin reconciliation.") |
|
|
with gr.Row(): |
|
|
erp_input = gr.File(label="π Upload ERP Statement", type="filepath") |
|
|
bank_input = gr.File(label="π Upload Bank Statement", type="filepath") |
|
|
submit_btn = gr.Button("π Start Reconciliation") |
|
|
result_output = gr.HTML() |
|
|
|
|
|
submit_btn.click( |
|
|
fn=reconcile_statements, |
|
|
inputs=[erp_input, bank_input], |
|
|
outputs=[status_text, result_output] |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
iface.launch(debug=True, share=True) |