vachaspathi commited on
Commit
4bad339
·
verified ·
1 Parent(s): 3f5bedc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -176
app.py CHANGED
@@ -1,185 +1,31 @@
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
- REFRESH_TOKEN = "1000.fcbd3eb6544c48591ceb462eefe439e1.e6dacb8875fec5fa150596fa44eb9326"
22
- ORGANIZATION_ID = "60058860935"
23
-
24
- # REGION: India
25
- AUTH_URL = "https://accounts.zoho.in/oauth/v2/token"
26
- API_BASE = "https://www.zohoapis.in/books/v3"
27
-
28
- # AI MODEL
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 Access 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_vendor(vendor_name, headers):
51
- if not vendor_name or len(str(vendor_name)) < 2: vendor_name = "MCP Vendor"
52
- print(f"🔎 Checking Vendor: {vendor_name}")
53
-
54
- # 1. Search
55
- search_url = f"{API_BASE}/contacts"
56
- try:
57
- params = {"organization_id": ORGANIZATION_ID, "contact_name_contains": vendor_name, "contact_type": "vendor"}
58
- resp = requests.get(search_url, headers=headers, params=params)
59
- contacts = resp.json().get("contacts", [])
60
- if contacts: return contacts[0]["contact_id"], "Found Existing"
61
- except: pass
62
-
63
- # 2. Create
64
- print("🆕 Creating New Vendor...")
65
- create_payload = {"contact_name": vendor_name, "contact_type": "vendor"}
66
- create_resp = requests.post(search_url, headers=headers, params={"organization_id": ORGANIZATION_ID}, json=create_payload)
67
-
68
- if create_resp.status_code == 201:
69
- return create_resp.json().get("contact", {}).get("contact_id"), "Created New"
70
- else:
71
- return None, f"Zoho Contact Error: {create_resp.text}"
72
-
73
- def push_bill_to_zoho(payload):
74
- """Creates a BILL (Expense) instead of Invoice (Sales)"""
75
- headers, error = get_zoho_headers()
76
- if error: return error
77
-
78
- # 1. Vendor Logic
79
- vid, v_status = find_or_create_vendor(payload.get("vendor_name_raw"), headers)
80
- if not vid: return f"❌ Vendor Error: {v_status}"
81
-
82
- # 2. Construct BILL Payload
83
- # We need a Bill Number. If AI missed it, generate a random one.
84
- bill_num = payload.get("invoice_number")
85
- if not bill_num or str(bill_num).lower() == "null":
86
- bill_num = f"INV-{random.randint(1000,9999)}"
87
-
88
- final_json = {
89
- "vendor_id": vid,
90
- "bill_number": str(bill_num),
91
- "date": payload.get("date", datetime.date.today().strftime("%Y-%m-%d")),
92
- "line_items": payload.get("line_items", []),
93
- "status": "draft"
94
  }
95
-
96
- # 3. Push to /bills
97
- print(f"🚀 Creating Bill for {vid}...")
98
- url = f"{API_BASE}/bills?organization_id={ORGANIZATION_ID}"
99
- resp = requests.post(url, headers=headers, json=final_json)
100
-
101
- if resp.status_code == 201:
102
- bill = resp.json().get("bill", {})
103
- return f"✅ SUCCESS! Bill Created.\nNumber: {bill.get('bill_number')}\nVendor: {v_status}\nLink: https://books.zoho.in/app/{ORGANIZATION_ID}#/bills/{bill.get('bill_id')}"
104
  else:
105
- return f"❌ Zoho Error: {resp.text}"
106
-
107
- # ==========================================
108
- # 3. AI & ORCHESTRATOR
109
- # ==========================================
110
- print(">>> Loading AI...")
111
- try:
112
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
113
- model = AutoModelForCausalLM.from_pretrained(MODEL_ID, device_map="cpu", torch_dtype=torch.float32, low_cpu_mem_usage=True)
114
- except: model = None
115
-
116
- def perform_ocr(file_obj):
117
- if file_obj is None: return "", 0, None
118
- try:
119
- filename = os.path.basename(file_obj)
120
- if filename.lower().endswith(".pdf"):
121
- image = convert_from_path(file_obj, first_page=1, last_page=1)[0]
122
- else:
123
- image = Image.open(file_obj).convert("RGB")
124
- return pytesseract.image_to_string(image), 0.9, image
125
- except: return "", 0, None
126
-
127
- def query_ai(text):
128
- if not model: return {"vendor_name": "Unknown", "total": 0}
129
-
130
- prompt = f"<|im_start|>user\nExtract JSON: vendor_name, invoice_number, invoice_date (YYYY-MM-DD), total, item_desc\nText:\n{text[:1000]}<|im_end|>\n<|im_start|>assistant\n```json"
131
- inputs = tokenizer(prompt, return_tensors="pt")
132
- out = model.generate(**inputs, max_new_tokens=200)
133
-
134
- try:
135
- # Parse the JSON String
136
- json_text = tokenizer.decode(out[0]).split("```json")[1].split("```")[0].strip()
137
- data = json.loads(json_text)
138
-
139
- # --- THE FIX: Handle List vs Dict ---
140
- if isinstance(data, list):
141
- if len(data) > 0: return data[0] # Return first item if it's a list
142
- else: return {"vendor_name": "Unknown", "total": 0}
143
-
144
- return data # Return dict as is
145
-
146
- except Exception as e:
147
- print(f"AI Parsing Error: {e}")
148
- return {"vendor_name": "Unknown", "total": 0}
149
-
150
- def run(file):
151
- text, score, img = perform_ocr(file)
152
- data = query_ai(text)
153
-
154
- # Ensure data is a dict before using .get()
155
- if not isinstance(data, dict):
156
- data = {"vendor_name": "Unknown", "total": 0}
157
-
158
- try: rate = float(str(data.get("total","0")).replace(",","").replace("INR","").strip())
159
- except: rate = 0
160
-
161
- payload = {
162
- "vendor_name_raw": data.get("vendor_name"),
163
- "invoice_number": data.get("invoice_number"),
164
- "date": data.get("invoice_date"),
165
- "line_items": [{"name": data.get("item_desc", "Service"), "rate": rate}]
166
- }
167
-
168
- result = push_bill_to_zoho(payload)
169
- return img, result
170
 
171
- # ==========================================
172
- # 4. UI
173
- # ==========================================
174
- with gr.Blocks(title="Zoho Invoice MCP") as demo:
175
- gr.Markdown("## 🧾 MCP Agent -> Zoho Books (Bills)")
176
- with gr.Row():
177
- f_in = gr.File(label="Upload Vendor Invoice")
178
- btn = gr.Button("Process Bill", variant="primary")
179
- out_img = gr.Image(label="Preview", height=300)
180
- out_res = gr.Textbox(label="Status")
181
-
182
- btn.click(run, f_in, [out_img, out_res])
183
 
184
- if __name__ == "__main__":
185
- demo.launch()
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
2
  import requests
 
 
3
 
4
+ # --- YOUR CREDENTIALS ---
 
 
5
  CLIENT_ID = "1000.SIMKGAO5719K0TQ0QZQ31ZU57RLFNQ"
6
  CLIENT_SECRET = "60b329b4fe51930abee900cba6524ec7332cd67e06"
7
+ REDIRECT_URI = "http://www.google.com"
8
+
9
+ def get_token(code):
10
+ url = "https://accounts.zoho.in/oauth/v2/token"
11
+ params = {
12
+ "code": code,
13
+ "client_id": CLIENT_ID,
14
+ "client_secret": CLIENT_SECRET,
15
+ "redirect_uri": REDIRECT_URI,
16
+ "grant_type": "authorization_code"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
+ resp = requests.post(url, data=params)
19
+ if resp.status_code == 200:
20
+ return f" NEW REFRESH TOKEN:\n{resp.json().get('refresh_token')}"
 
 
 
 
 
 
21
  else:
22
+ return f"❌ Error: {resp.text}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ with gr.Blocks() as demo:
25
+ gr.Markdown("## 🔑 Zoho Token Fixer (Full Access)")
26
+ code_in = gr.Textbox(label="Paste New 'ZohoBooks.fullaccess.ALL' Code")
27
+ btn = gr.Button("Get Master Token")
28
+ out = gr.Textbox(label="Result")
29
+ btn.click(get_token, code_in, out)
 
 
 
 
 
 
30
 
31
+ demo.launch()