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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -22
app.py CHANGED
@@ -1,31 +1,168 @@
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()
 
 
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 & CONFIG
18
+ # ==========================================
19
  CLIENT_ID = "1000.SIMKGAO5719K0TQ0QZQ31ZU57RLFNQ"
20
  CLIENT_SECRET = "60b329b4fe51930abee900cba6524ec7332cd67e06"
21
+
22
+ # *** PASTE YOUR NEW "FULL ACCESS" TOKEN HERE ***
23
+ REFRESH_TOKEN = "1000.78971de3425fc7c86da12ecaedac5b58.4f3bb2afcf196ee05569ac5482570173"
24
+
25
+ # *** YOUR ORG ID ***
26
+ ORGANIZATION_ID = "60058860935"
27
+
28
+ # REGION & API
29
+ AUTH_URL = "https://accounts.zoho.in/oauth/v2/token"
30
+ API_BASE = "https://www.zohoapis.in/books/v3"
31
+ MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"
32
+
33
+ # ==========================================
34
+ # 2. ZOHO CONNECTIVITY
35
+ # ==========================================
36
+ def get_zoho_headers():
37
+ try:
38
+ print("🔄 Refreshing Token...")
39
+ params = {
40
+ "refresh_token": REFRESH_TOKEN,
41
+ "client_id": CLIENT_ID,
42
+ "client_secret": CLIENT_SECRET,
43
+ "grant_type": "refresh_token",
44
+ "redirect_uri": "http://www.google.com"
45
+ }
46
+ resp = requests.post(AUTH_URL, data=params)
47
+ if resp.status_code != 200: return None, f"Auth Failed: {resp.text}"
48
+ return {"Authorization": f"Zoho-oauthtoken {resp.json().get('access_token')}"}, None
49
+ except Exception as e:
50
+ return None, str(e)
51
+
52
+ def find_or_create_vendor(vendor_name, headers):
53
+ if not vendor_name or len(str(vendor_name)) < 2: vendor_name = "MCP Vendor"
54
+
55
+ # 1. Search
56
+ search_url = f"{API_BASE}/contacts"
57
+ try:
58
+ params = {"organization_id": ORGANIZATION_ID, "contact_name_contains": vendor_name, "contact_type": "vendor"}
59
+ resp = requests.get(search_url, headers=headers, params=params)
60
+ contacts = resp.json().get("contacts", [])
61
+ if contacts: return contacts[0]["contact_id"], "Found Existing"
62
+ except: pass
63
+
64
+ # 2. Create
65
+ print(f"🆕 Creating Vendor: {vendor_name}")
66
+ create_payload = {"contact_name": vendor_name, "contact_type": "vendor"}
67
+ create_resp = requests.post(search_url, headers=headers, params={"organization_id": ORGANIZATION_ID}, json=create_payload)
68
+
69
+ if create_resp.status_code == 201:
70
+ return create_resp.json().get("contact", {}).get("contact_id"), "Created New"
71
+ else:
72
+ return None, f"Contact Error: {create_resp.text}"
73
+
74
+ def push_bill_to_zoho(payload):
75
+ headers, error = get_zoho_headers()
76
+ if error: return error
77
+
78
+ # 1. Vendor
79
+ vid, v_status = find_or_create_vendor(payload.get("vendor_name_raw"), headers)
80
+ if not vid: return f"❌ Vendor Logic Failed: {v_status}"
81
+
82
+ # 2. Bill Payload
83
+ bill_num = payload.get("invoice_number")
84
+ if not bill_num or str(bill_num).lower() == "null":
85
+ bill_num = f"MCP-{random.randint(1000,9999)}"
86
+
87
+ final_json = {
88
+ "vendor_id": vid,
89
+ "bill_number": str(bill_num),
90
+ "date": payload.get("date", datetime.date.today().strftime("%Y-%m-%d")),
91
+ "line_items": payload.get("line_items", []),
92
+ "status": "draft"
93
  }
94
+
95
+ # 3. Push
96
+ url = f"{API_BASE}/bills?organization_id={ORGANIZATION_ID}"
97
+ resp = requests.post(url, headers=headers, json=final_json)
98
+
99
+ if resp.status_code == 201:
100
+ bill = resp.json().get("bill", {})
101
+ link = f"https://books.zoho.in/app/{ORGANIZATION_ID}#/bills/{bill.get('bill_id')}"
102
+ return f"✅ SUCCESS! Bill Created.\nVendor: {v_status}\nLink: {link}"
103
  else:
104
+ return f"❌ Zoho API Error: {resp.text}"
105
+
106
+ # ==========================================
107
+ # 3. AI ENGINE
108
+ # ==========================================
109
+ try:
110
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
111
+ model = AutoModelForCausalLM.from_pretrained(MODEL_ID, device_map="cpu", torch_dtype=torch.float32, low_cpu_mem_usage=True)
112
+ except: model = None
113
+
114
+ def perform_ocr(file_obj):
115
+ if file_obj is None: return "", 0, None
116
+ try:
117
+ filename = os.path.basename(file_obj)
118
+ if filename.lower().endswith(".pdf"):
119
+ image = convert_from_path(file_obj, first_page=1, last_page=1)[0]
120
+ else:
121
+ image = Image.open(file_obj).convert("RGB")
122
+ return pytesseract.image_to_string(image), 0.9, image
123
+ except: return "", 0, None
124
+
125
+ def query_ai(text):
126
+ if not model: return {"vendor_name": "Unknown", "total": 0}
127
+
128
+ 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"
129
+ inputs = tokenizer(prompt, return_tensors="pt")
130
+ out = model.generate(**inputs, max_new_tokens=200)
131
+
132
+ try:
133
+ json_str = tokenizer.decode(out[0]).split("```json")[1].split("```")[0].strip()
134
+ data = json.loads(json_str)
135
+ return data[0] if isinstance(data, list) else data
136
+ except:
137
+ return {"vendor_name": "Unknown", "total": 0}
138
+
139
+ def run(file):
140
+ text, score, img = perform_ocr(file)
141
+ data = query_ai(text)
142
+
143
+ try: rate = float(str(data.get("total","0")).replace(",","").replace("INR","").strip())
144
+ except: rate = 0
145
+
146
+ payload = {
147
+ "vendor_name_raw": data.get("vendor_name"),
148
+ "invoice_number": data.get("invoice_number"),
149
+ "date": data.get("invoice_date"),
150
+ "line_items": [{"name": data.get("item_desc", "Service"), "rate": rate}]
151
+ }
152
+
153
+ return img, push_bill_to_zoho(payload)
154
 
155
+ # ==========================================
156
+ # 4. UI
157
+ # ==========================================
158
+ with gr.Blocks(title="Zoho Bill Agent") as demo:
159
+ gr.Markdown("## 🧾 MCP Agent -> Zoho Bills")
160
+ with gr.Row():
161
+ f_in = gr.File(label="Vendor Invoice")
162
+ btn = gr.Button("Process Bill", variant="primary")
163
+ out_img = gr.Image(label="View", height=300)
164
+ out_res = gr.Textbox(label="Status")
165
+ btn.click(run, f_in, [out_img, out_res])
166
 
167
+ if __name__ == "__main__":
168
+ demo.launch()