vachaspathi commited on
Commit
b6000fa
·
verified ·
1 Parent(s): 3f041f9

Create app.py

Browse files

(The "Orchestrator". Connects the UI -> Tools -> Qwen.)

Files changed (1) hide show
  1. app.py +114 -0
app.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import gradio as gr
3
+ import torch
4
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
5
+ from threading import Thread
6
+
7
+ # Import our custom modules
8
+ import guardrails
9
+ import tools_processing
10
+
11
+ # --- 1. CONFIGURATION ---
12
+ MODEL_ID = "Qwen/Qwen2.5-1.5B-Instruct" # The Brain
13
+
14
+ print(">>> INITIALIZING ORCHESTRATOR...")
15
+ print(">>> LOADING QWEN (This takes 1 min)...")
16
+
17
+ try:
18
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
19
+ model = AutoModelForCausalLM.from_pretrained(
20
+ MODEL_ID,
21
+ torch_dtype=torch.float32,
22
+ device_map="cpu"
23
+ )
24
+ print(">>> QWEN LOADED. SYSTEMS ONLINE.")
25
+ except Exception as e:
26
+ print(f"CRITICAL ERROR: {e}")
27
+
28
+ # --- 2. THE ORCHESTRATOR LOGIC ---
29
+ def run_orchestrator(message, history, file_upload, url_input):
30
+ """
31
+ The Central Nervous System.
32
+ 1. Checks for inputs (Files vs Links).
33
+ 2. Runs Tools (OCR / Scraper).
34
+ 3. Builds Context.
35
+ 4. Streams Qwen Response.
36
+ """
37
+
38
+ # A. Run Tools
39
+ extracted_invoice_text = ""
40
+ external_context = ""
41
+
42
+ # Tool: Web Scraper
43
+ if url_input:
44
+ external_context = tools_processing.scrape_public_link(url_input)
45
+
46
+ # Tool: OCR
47
+ if file_upload:
48
+ # Note: In a chat flow, we might have processed this already.
49
+ # For simplicity, we re-process or check state.
50
+ _, extracted_invoice_text = tools_processing.perform_ocr(file_upload)
51
+
52
+ # B. Build Prompt with Guardrails
53
+ # If we have file text, we inject it. If not, we assume user is just chatting.
54
+ system_block = guardrails.get_guardrails(external_context, extracted_invoice_text)
55
+
56
+ # C. Prepare LLM Input
57
+ # Combine System Prompt + Chat History + Latest Message
58
+ full_conversation = f"{system_block}\n"
59
+
60
+ for user_msg, bot_msg in history:
61
+ full_conversation += f"<|im_start|>user\n{user_msg}<|im_end|>\n<|im_start|>assistant\n{bot_msg}<|im_end|>\n"
62
+
63
+ full_conversation += f"<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n"
64
+
65
+ # D. Stream Generation (Low Latency)
66
+ inputs = tokenizer(full_conversation, return_tensors="pt")
67
+ streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
68
+
69
+ generation_kwargs = dict(
70
+ inputs,
71
+ streamer=streamer,
72
+ max_new_tokens=512,
73
+ temperature=0.7
74
+ )
75
+
76
+ thread = Thread(target=model.generate, kwargs=generation_kwargs)
77
+ thread.start()
78
+
79
+ partial_response = ""
80
+ for new_text in streamer:
81
+ partial_response += new_text
82
+ yield partial_response
83
+
84
+ # --- 3. UI SETUP ---
85
+ def process_file_display(file):
86
+ """Helper to show the image after upload"""
87
+ img, _ = tools_processing.perform_ocr(file)
88
+ return img
89
+
90
+ with gr.Blocks(theme=gr.themes.Soft(), title="MCP Invoice Orchestrator") as demo:
91
+ gr.Markdown("## 🧠 MCP Invoice Orchestrator (Powered by Qwen)")
92
+ gr.Markdown("Upload an invoice + Add a Notion Link. The Agent will enforce your rules.")
93
+
94
+ with gr.Row():
95
+ # Left: Tools
96
+ with gr.Column(scale=1):
97
+ file_in = gr.File(label="📄 Invoice (PDF/Img)")
98
+ img_preview = gr.Image(label="Scan Preview", height=250)
99
+ url_in = gr.Textbox(label="🔗 Notion Public Link (Context)", placeholder="https://notion.so/public-page...")
100
+
101
+ # Update preview on upload
102
+ file_in.upload(process_file_display, inputs=file_in, outputs=img_preview)
103
+
104
+ # Right: Chat Interface
105
+ with gr.Column(scale=2):
106
+ chatbot = gr.ChatInterface(
107
+ fn=run_orchestrator,
108
+ additional_inputs=[file_in, url_in],
109
+ examples=[[x["query"]] for x in guardrails.CHAT_STARTERS],
110
+ title="Agent Interaction"
111
+ )
112
+
113
+ if __name__ == "__main__":
114
+ demo.launch()