Eyadddddddd commited on
Commit
d2736bf
·
verified ·
1 Parent(s): 1f8c17f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -138
app.py CHANGED
@@ -1,161 +1,178 @@
1
  import os
2
- import requests
 
3
  import gradio as gr
 
4
  from pdf2image import convert_from_path
5
  from PIL import Image
6
- import base64
7
- import io
8
 
9
- # -----------------------------
10
- # ENVIRONMENT VARIABLES
11
- # -----------------------------
12
- GROQ_API_KEY = os.getenv("GROQ_API_KEY")
13
- HF_TOKEN = os.getenv("HF_TOKEN")
14
 
 
15
  if not GROQ_API_KEY:
16
- raise ValueError("GROQ_API_KEY is not set.")
17
- if not HF_TOKEN:
18
- raise ValueError("HF_TOKEN is not set.")
19
-
20
- # -----------------------------
21
- # API ENDPOINTS
22
- # -----------------------------
23
- GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
24
- HF_ROUTER_URL = "https://router.huggingface.co"
25
 
26
- VISION_MODEL = "LiquidAI/LFM2.5-VL-1.6B-GGUF"
27
  TEXT_MODEL = "llama-3.1-8b-instant"
28
 
29
- # -----------------------------
30
- # TEXT (GROQ)
31
- # -----------------------------
32
- def groq_chat(user_msg, history, mode):
33
- system_prompt = {
34
- "Normal": "You are NeoHelper, a helpful assistant.",
35
- "School": "You explain concepts simply for students.",
36
- "Shopping": "You help compare products and give buying advice.",
37
- "Gaming": "You speak like a gamer and give gaming tips.",
38
- }.get(mode, "You are NeoHelper.")
39
-
40
- messages = [{"role": "system", "content": system_prompt}]
41
- if history:
42
- for pair in history:
43
- if isinstance(pair, list) and len(pair) == 2:
44
- user, bot = pair
45
- if user:
46
- messages.append({"role": "user", "content": user})
47
- if bot:
48
- messages.append({"role": "assistant", "content": bot})
49
- messages.append({"role": "user", "content": user_msg})
50
-
51
- payload = {
52
- "model": TEXT_MODEL,
53
- "messages": messages,
54
- "max_tokens": 300,
55
- "temperature": 0.4
56
- }
57
-
58
- headers = {
59
- "Authorization": f"Bearer {GROQ_API_KEY}",
60
- "Content-Type": "application/json"
61
- }
62
-
63
- response = requests.post(GROQ_URL, json=payload, headers=headers, timeout=30)
64
- response.raise_for_status()
65
- data = response.json()
66
- return data["choices"][0]["message"]["content"]
67
-
68
- # -----------------------------
69
- # VISION (LIQUIDAI via HF Router)
70
- # -----------------------------
71
- def analyze_with_liquid_ai(image, prompt):
72
- buf = io.BytesIO()
73
- image.save(buf, format="PNG")
74
- img_b64 = base64.b64encode(buf.getvalue()).decode()
75
-
76
- payload = {
77
- "model": VISION_MODEL,
78
- "inputs": {
79
- "prompt": prompt,
80
- "image": img_b64
81
- },
82
- "parameters": {
83
- "max_new_tokens": 256,
84
- "temperature": 0.2
85
- }
86
- }
87
-
88
- headers = {
89
- "Authorization": f"Bearer {HF_TOKEN}",
90
- "Content-Type": "application/json"
91
- }
92
-
93
- response = requests.post(HF_ROUTER_URL, json=payload, headers=headers, timeout=60)
94
- response.raise_for_status()
95
- data = response.json()
96
-
97
- if isinstance(data, list) and "generated_text" in data[0]:
98
- return data[0]["generated_text"]
99
- return str(data)
100
-
101
- # -----------------------------
102
- # FILE HANDLER
103
- # -----------------------------
104
- def handle_file(file, prompt):
105
  if file is None:
106
- return "No file uploaded."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
- path = file.name
109
- if path.lower().endswith(".pdf"):
110
- pages = convert_from_path(path)
111
- if not pages:
112
- return "PDF conversion failed."
113
- return analyze_with_liquid_ai(pages[0], prompt)
114
-
115
- img = Image.open(path).convert("RGB")
116
- return analyze_with_liquid_ai(img, prompt)
117
-
118
- # -----------------------------
119
- # UI
120
- # -----------------------------
121
  def build_ui():
122
- with gr.Blocks() as ui:
123
- gr.Markdown("# **NeoHelper — Groq Text + LiquidAI Vision (Remote)**")
124
 
125
  with gr.Row():
126
- with gr.Column(scale=3):
127
- chatbot = gr.Chatbot(height=520)
128
- with gr.Row():
129
- user_input = gr.Textbox(placeholder="Type your message…", scale=4)
130
- send_btn = gr.Button("Send", scale=1)
131
- file_input = gr.File(label="Upload PNG / JPG / PDF")
132
-
133
  with gr.Column(scale=1):
134
- mode = gr.Radio(
135
- ["Normal", "School", "Shopping", "Gaming"],
136
- value="Normal",
137
- label="Mode"
 
 
 
 
 
138
  )
139
 
140
- def process(user_msg, history, mode):
141
- reply = groq_chat(user_msg, history, mode)
142
- history = history or []
143
- history.append([user_msg, reply])
144
- return history, ""
145
-
146
- send_btn.click(process, inputs=[user_input, chatbot, mode], outputs=[chatbot, user_input])
147
-
148
- def on_file(f, h, m):
149
- result = handle_file(f, "Please describe the content and extract any text.")
150
- h = h or []
151
- h.append([f.name, result])
152
- return h, None
153
 
154
- file_input.change(on_file, inputs=[file_input, chatbot, mode], outputs=[chatbot, file_input])
 
 
 
 
155
 
156
- return ui
157
 
158
- app = build_ui()
159
 
160
  if __name__ == "__main__":
161
- app.launch(server_name="0.0.0.0", server_port=7860, theme="gradio/soft")
 
 
1
  import os
2
+ from typing import List, Optional, Tuple, Any
3
+
4
  import gradio as gr
5
+ from groq import Groq
6
  from pdf2image import convert_from_path
7
  from PIL import Image
 
 
8
 
9
+ from llava13b_runtime import analyze_image
 
 
 
 
10
 
11
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
12
  if not GROQ_API_KEY:
13
+ raise ValueError("GROQ_API_KEY environment variable is not set.")
 
 
 
 
 
 
 
 
14
 
15
+ groq_client = Groq(api_key=GROQ_API_KEY)
16
  TEXT_MODEL = "llama-3.1-8b-instant"
17
 
18
+ MODE_PROMPTS = {
19
+ "Normal Chat": (
20
+ "You are NeoHelper, Eyad’s branded assistant. "
21
+ "Be concise, friendly, and helpful."
22
+ ),
23
+ "School Helper": (
24
+ "You are NeoHelper, a school helper for a Grade 5 student. "
25
+ "Explain clearly, step by step, using simple language."
26
+ ),
27
+ "Shopping Assistant": (
28
+ "You are NeoHelper, a shopping assistant in Saudi Arabia. "
29
+ "Compare specs, prices, and value clearly and briefly."
30
+ ),
31
+ "Gaming Help": (
32
+ "You are NeoHelper, an energetic gaming helper. "
33
+ "Give practical tips, fixes, and short, clear steps."
34
+ ),
35
+ }
36
+
37
+ def extract_images_from_pdf(pdf_path: str):
38
+ try:
39
+ return convert_from_path(pdf_path)
40
+ except:
41
+ return None
42
+ def call_groq_text(message, system_prompt):
43
+ try:
44
+ resp = groq_client.chat.completions.create(
45
+ model=TEXT_MODEL,
46
+ messages=[
47
+ {"role": "system", "content": system_prompt},
48
+ {"role": "user", "content": message},
49
+ ],
50
+ max_tokens=900,
51
+ )
52
+ return resp.choices[0].message.content
53
+ except Exception as e:
54
+ return f"⚠️ Text model error: {str(e)}"
55
+
56
+ def summarize_pdf_analyses(analyses, system_prompt):
57
+ joined = "\n\n--- PAGE BREAK ---\n\n".join(analyses)
58
+ prompt = (
59
+ "Summarize these PDF page analyses into one clear explanation for a student. "
60
+ "Be structured, simple, and concise:\n\n"
61
+ f"{joined}"
62
+ )
63
+ return call_groq_text(prompt, system_prompt)
64
+
65
+ def resolve_gradio_file(file):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if file is None:
67
+ return None, None
68
+
69
+ if isinstance(file, dict):
70
+ path = file.get("path") or file.get("name")
71
+ name = file.get("orig_name") or path
72
+ return path, name
73
+
74
+ path = getattr(file, "name", None)
75
+ name = getattr(file, "orig_name", path)
76
+ return path, name
77
+
78
+ def neohelper_chat(message, history, file, mode):
79
+ if history is None:
80
+ history = []
81
+
82
+ system_prompt = MODE_PROMPTS.get(mode, MODE_PROMPTS["Normal Chat"])
83
+
84
+ if message is None:
85
+ message = ""
86
+ message = message.strip()
87
+
88
+ if isinstance(file, list):
89
+ file = file[0] if file else None
90
+
91
+ file_path, orig_name = resolve_gradio_file(file)
92
+
93
+ # TEXT ONLY
94
+ if not file_path:
95
+ reply = call_groq_text(message, system_prompt) if message else "Please type a question or upload a file."
96
+ history.append({"role": "user", "content": message})
97
+ history.append({"role": "assistant", "content": reply})
98
+ return history, ""
99
+
100
+ ext = (orig_name or file_path).lower()
101
+
102
+ # IMAGE
103
+ if ext.endswith((".png", ".jpg", ".jpeg", ".webp", ".bmp")):
104
+ try:
105
+ prompt = message or "Explain this image in a simple way for a student."
106
+ img = Image.open(file_path).convert("RGB")
107
+ reply = analyze_image(img, prompt)
108
+ except Exception as e:
109
+ reply = f"⚠️ Error analyzing image: {str(e)}"
110
+
111
+ history.append({"role": "user", "content": message or f"[Image: {orig_name}]"})
112
+ history.append({"role": "assistant", "content": reply})
113
+ return history, ""
114
+
115
+ # PDF
116
+ if ext.endswith(".pdf"):
117
+ try:
118
+ pages = extract_images_from_pdf(file_path)
119
+ if not pages:
120
+ reply = "This PDF contains no pages I can analyze."
121
+ else:
122
+ analyses = []
123
+ for idx, img in enumerate(pages, start=1):
124
+ prompt = message or f"Explain page {idx} simply."
125
+ analyses.append(f"Page {idx}:\n{analyze_image(img, prompt)}")
126
+ reply = summarize_pdf_analyses(analyses, system_prompt)
127
+ except Exception as e:
128
+ reply = f"⚠️ Error processing PDF: {str(e)}"
129
+
130
+ history.append({"role": "user", "content": message or f"[PDF: {orig_name}]"})
131
+ history.append({"role": "assistant", "content": reply})
132
+ return history, ""
133
+
134
+ reply = "Unsupported file type. Please upload an image or a PDF."
135
+ history.append({"role": "user", "content": message})
136
+ history.append({"role": "assistant", "content": reply})
137
+ return history, ""
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  def build_ui():
140
+ with gr.Blocks(title="NeoHelper") as demo:
141
+ gr.Markdown("# 🧠 NeoHelper")
142
 
143
  with gr.Row():
 
 
 
 
 
 
 
144
  with gr.Column(scale=1):
145
+ mode_dd = gr.Dropdown(
146
+ choices=list(MODE_PROMPTS.keys()),
147
+ value="Normal Chat",
148
+ label="Mode",
149
+ )
150
+ file_input = gr.File(
151
+ label="Upload image or PDF",
152
+ file_types=["image", ".pdf"],
153
+ file_count="single",
154
  )
155
 
156
+ with gr.Column(scale=3):
157
+ chatbot = gr.Chatbot(
158
+ label="NeoHelper",
159
+ show_label=False,
160
+ height=500,
161
+ )
162
+ msg = gr.Textbox(label="Message", lines=3)
163
+ send_btn = gr.Button("Send")
164
+ clear_btn = gr.Button("Clear")
 
 
 
 
165
 
166
+ send_btn.click(
167
+ neohelper_chat,
168
+ inputs=[msg, chatbot, file_input, mode_dd],
169
+ outputs=[chatbot, msg],
170
+ )
171
 
172
+ clear_btn.click(lambda: ([], ""), None, [chatbot, msg])
173
 
174
+ return demo
175
 
176
  if __name__ == "__main__":
177
+ app = build_ui()
178
+ app.launch(share=False, ssr_mode=False)