vachaspathi commited on
Commit
c0f6ba9
·
verified ·
1 Parent(s): 1eae4d5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -156
app.py CHANGED
@@ -1,171 +1,43 @@
 
1
  import gradio as gr
2
- import torch
3
- from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
4
- from threading import Thread
5
- import os
6
- import pytesseract
7
- from pdf2image import convert_from_path
8
- from PIL import Image
9
- import trafilatura
10
- import datetime
11
- import json
12
- import requests
13
- import re
14
- import random
15
 
16
- # ==========================================
17
- # 1. CREDENTIALS
18
- # ==========================================
19
- CLIENT_ID = "1000.SIMKGAO5719K0TQ0QZQ31ZU57RLFNQ"
20
- CLIENT_SECRET = "60b329b4fe51930abee900cba6524ec7332cd67e06"
21
-
22
- # *** USE YOUR 'FULL ACCESS' REFRESH TOKEN HERE ***
23
- REFRESH_TOKEN = "1000.fcbd3eb6544c48591ceb462eefe439e1.e6dacb8875fec5fa150596fa44eb9326"
24
- ORGANIZATION_ID = "60058878536" # Your Zoho Books Free Org
25
-
26
- # CORRECT API FOR YOUR ACCOUNT (Books, not Invoice)
27
- AUTH_URL = "https://accounts.zoho.in/oauth/v2/token"
28
- API_BASE = "https://www.zohoapis.in/books/v3"
29
- MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
30
-
31
- # ==========================================
32
- # 2. ZOHO CONNECTIVITY
33
- # ==========================================
34
- def get_zoho_headers():
35
- try:
36
- print("🔄 Refreshing Token...")
37
- params = {
38
- "refresh_token": REFRESH_TOKEN,
39
- "client_id": CLIENT_ID,
40
- "client_secret": CLIENT_SECRET,
41
- "grant_type": "refresh_token",
42
- "redirect_uri": "http://www.google.com"
43
- }
44
- resp = requests.post(AUTH_URL, data=params)
45
- if resp.status_code != 200: return None, f"Auth Failed: {resp.text}"
46
- return {"Authorization": f"Zoho-oauthtoken {resp.json().get('access_token')}"}, None
47
- except Exception as e:
48
- return None, str(e)
49
-
50
- def find_or_create_customer(name, headers):
51
- """Creates a CUSTOMER (Required for Sales Invoices)"""
52
- if not name or len(str(name)) < 2: name = "MCP Customer"
53
-
54
- # 1. Search
55
- search_url = f"{API_BASE}/contacts"
56
- try:
57
- params = {
58
- "organization_id": ORGANIZATION_ID,
59
- "contact_name_contains": name,
60
- "contact_type": "customer" # <--- IMPORTANT: Customer, not Vendor
61
- }
62
- resp = requests.get(search_url, headers=headers, params=params)
63
- contacts = resp.json().get("contacts", [])
64
- if contacts:
65
- print(f"✅ Found Customer: {contacts[0]['contact_name']}")
66
- return contacts[0]["contact_id"], "Existing"
67
- except: pass
68
-
69
- # 2. Create
70
- print(f"🆕 Creating Customer: {name}")
71
- create_payload = {
72
- "contact_name": name,
73
- "contact_type": "customer"
74
- }
75
- create_resp = requests.post(search_url, headers=headers, params={"organization_id": ORGANIZATION_ID}, json=create_payload)
76
-
77
- if create_resp.status_code == 201:
78
- return create_resp.json().get("contact", {}).get("contact_id"), "Created New"
79
- else:
80
- return None, f"Contact Error: {create_resp.text}"
81
-
82
- def push_invoice_to_zoho(payload):
83
- headers, error = get_zoho_headers()
84
- if error: return error
85
-
86
- # 1. Get Customer
87
- cid, c_status = find_or_create_customer(payload.get("vendor_name_raw"), headers)
88
- if not cid: return f"❌ Customer Logic Failed: {c_status}"
89
-
90
- # 2. Construct Sales Invoice
91
- final_json = {
92
- "customer_id": cid,
93
- "date": payload.get("date", datetime.date.today().strftime("%Y-%m-%d")),
94
- "line_items": payload.get("line_items", []),
95
- "status": "draft"
96
- }
97
-
98
- # 3. Push
99
- print(f"🚀 Creating Sales Invoice for {cid}...")
100
- url = f"{API_BASE}/invoices?organization_id={ORGANIZATION_ID}"
101
- resp = requests.post(url, headers=headers, json=final_json)
102
 
103
- if resp.status_code == 201:
104
- inv = resp.json().get("invoice", {})
105
- link = f"https://books.zoho.in/app/{ORGANIZATION_ID}#/invoices/{inv.get('invoice_id')}"
106
- return f"✅ SUCCESS! Invoice Created.\nNumber: {inv.get('invoice_number')}\nCustomer: {c_status}\nLink: {link}"
107
- else:
108
- return f"❌ Zoho API Error: {resp.text}"
109
-
110
- # ==========================================
111
- # 3. AI & ORCHESTRATOR
112
- # ==========================================
113
- print(">>> Loading AI...")
114
- try:
115
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
116
- model = AutoModelForCausalLM.from_pretrained(MODEL_ID, device_map="cpu", torch_dtype=torch.float32, low_cpu_mem_usage=True)
117
- except: model = None
118
-
119
- def perform_ocr(file_obj):
120
- if file_obj is None: return "", 0, None
121
- try:
122
- filename = os.path.basename(file_obj)
123
- if filename.lower().endswith(".pdf"):
124
- image = convert_from_path(file_obj, first_page=1, last_page=1)[0]
125
- else:
126
- image = Image.open(file_obj).convert("RGB")
127
- return pytesseract.image_to_string(image), 0.9, image
128
- except: return "", 0, None
129
-
130
- def query_ai(text):
131
- if not model: return {"vendor_name": "Unknown", "total": 0}
132
 
133
- prompt = f"<|im_start|>user\nExtract JSON: vendor_name, invoice_date (YYYY-MM-DD), total, item_desc\nText:\n{text[:1000]}<|im_end|>\n<|im_start|>assistant\n```json"
134
- inputs = tokenizer(prompt, return_tensors="pt")
135
- out = model.generate(**inputs, max_new_tokens=200)
136
- try:
137
- json_str = tokenizer.decode(out[0]).split("```json")[1].split("```")[0].strip()
138
- data = json.loads(json_str)
139
- return data[0] if isinstance(data, list) else data
140
- except:
141
- return {"vendor_name": "Unknown", "total": 0}
142
-
143
- def run(file):
144
- text, score, img = perform_ocr(file)
145
- data = query_ai(text)
146
 
147
- try: rate = float(str(data.get("total","0")).replace(",","").replace("INR","").strip())
148
- except: rate = 0
149
-
150
  payload = {
151
- "vendor_name_raw": data.get("vendor_name"),
152
  "date": data.get("invoice_date"),
153
  "line_items": [{"name": data.get("item_desc", "Service"), "rate": rate}]
154
  }
155
 
156
- return img, push_invoice_to_zoho(payload)
 
 
 
157
 
158
- # ==========================================
159
- # 4. UI
160
- # ==========================================
161
- with gr.Blocks(title="Zoho Books Invoice Agent") as demo:
162
- gr.Markdown("## 🧾 MCP Agent -> Zoho Books (Sales Invoice)")
163
  with gr.Row():
164
- f_in = gr.File(label="Upload Document")
165
- btn = gr.Button("Create Invoice", variant="primary")
166
- out_img = gr.Image(label="View", height=300)
167
- out_res = gr.Textbox(label="Status")
168
- btn.click(run, f_in, [out_img, out_res])
 
 
169
 
170
  if __name__ == "__main__":
171
  demo.launch()
 
1
+ # app.py
2
  import gradio as gr
3
+ import ai_engine
4
+ import zoho_client
5
+ import utils
 
 
 
 
 
 
 
 
 
 
6
 
7
+ def process_pipeline(file):
8
+ # 1. OCR
9
+ text, img = ai_engine.perform_ocr(file)
10
+ if not text: return None, "❌ OCR Failed. Upload a valid image/PDF."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ # 2. AI Extraction
13
+ data = ai_engine.extract_json(text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # 3. Data Cleaning (Using utils)
16
+ rate = utils.clean_amount(data.get("total"))
 
 
 
 
 
 
 
 
 
 
 
17
 
 
 
 
18
  payload = {
19
+ "vendor_name": data.get("vendor_name"),
20
  "date": data.get("invoice_date"),
21
  "line_items": [{"name": data.get("item_desc", "Service"), "rate": rate}]
22
  }
23
 
24
+ # 4. Push to Zoho
25
+ result = zoho_client.push_invoice(payload)
26
+
27
+ return img, result
28
 
29
+ # UI Setup
30
+ with gr.Blocks(title="Modular Zoho Agent") as demo:
31
+ gr.Markdown("## 🧾 Zoho Books Agent (Modular)")
32
+
 
33
  with gr.Row():
34
+ f_in = gr.File(label="Upload Invoice")
35
+ btn = gr.Button("Process", variant="primary")
36
+
37
+ out_img = gr.Image(label="Preview", height=300)
38
+ out_res = gr.Textbox(label="Result")
39
+
40
+ btn.click(process_pipeline, f_in, [out_img, out_res])
41
 
42
  if __name__ == "__main__":
43
  demo.launch()