lamgamepro1 commited on
Commit
f7615cd
·
verified ·
1 Parent(s): cbac560

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -179
app.py CHANGED
@@ -1,191 +1,105 @@
1
- """NodeAI Genesis Pro - FULL Pro Version - Gradio 6.9.0 Compatible"""
2
  import gradio as gr
3
- from huggingface_hub import InferenceClient
4
- from supabase import create_client, Client
5
- import os, uuid, json, logging, re, time
6
- from datetime import datetime
7
- from typing import List, Dict, Tuple
8
- from collections import defaultdict
 
 
9
 
10
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
- logger = logging.getLogger(__name__)
 
12
 
13
- URL, KEY, HF_TOKEN = os.environ.get("SUPABASE_URL"), os.environ.get("SUPABASE_KEY"), os.environ.get("HUGGINGFACE_HUB_TOKEN")
14
- try:
15
- supabase = create_client(URL, KEY) if URL and KEY else None
16
- logger.info("✅ Supabase OK")
17
- except Exception as e:
18
- logger.error(f"Supabase: {e}")
19
- supabase = None
20
 
21
- MODELS = {
22
- "🚀 Qwen 2.5 7B": {"id": "Qwen/Qwen2.5-7B-Instruct", "speed": "Fast", "quality": "High"},
23
- "⚡ Mistral 7B": {"id": "mistralai/Mistral-7B-Instruct-v0.2", "speed": "Very Fast", "quality": "Good"},
24
- "🔥 LLaMA 2 7B": {"id": "meta-llama/Llama-2-7b-chat-hf", "speed": "Fast", "quality": "High"},
25
- "🎯 Qwen 72B": {"id": "Qwen/Qwen2.5-72B-Instruct", "speed": "Slow", "quality": "Premium"},
26
- }
 
 
 
 
 
27
 
28
- PROMPTS = {
29
- "🤖 Default": "You are NodeAI Genesis Pro. Be helpful, creative, honest, and concise. Explain complex topics clearly.",
30
- "📚 Researcher": "Expert analyst. Provide detailed analysis with sources. Break down complex topics. Think critically.",
31
- "💻 Developer": "Senior programmer. Provide clean, optimized code. Explain approaches. Consider edge cases.",
32
- "📝 Writer": "Professional writer. Create engaging, well-written, grammatically perfect content.",
33
- "🎯 Coach": "Personal mentor. Provide motivational, actionable advice. Focus on growth.",
34
- "🔬 Data Scientist": "ML expert. Explain statistics clearly. Provide code examples. Discuss ethics.",
35
- "🎓 Teacher": "Educator. Explain clearly. Break into steps. Use examples. Encourage learning.",
36
- }
37
-
38
- CSS = """
39
- * { transition: all 0.3s ease; }
40
- footer, .built-with, header { display: none !important; }
41
- .gradio-container { max-width: 100%; background: linear-gradient(135deg, #0f172a, #1e293b); color: #e2e8f0; }
42
- body { background: #0f172a !important; }
43
- .sidebar-node { background: rgba(15,23,42,0.95); border-right: 1px solid rgba(56,189,248,0.2); padding: 24px; max-height: 100vh; overflow-y: auto; }
44
- .logo { background: linear-gradient(135deg, #38bdf8, #8b5cf6, #ec4899); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 28px; font-weight: 900; text-align: center; margin: 20px 0; letter-spacing: 2px; }
45
- button { background: linear-gradient(135deg, #38bdf8, #8b5cf6) !important; border: none !important; color: white !important; padding: 12px 20px !important; border-radius: 10px !important; box-shadow: 0 4px 20px rgba(56,189,248,0.3) !important; }
46
- button:hover { transform: translateY(-3px) !important; box-shadow: 0 8px 30px rgba(56,189,248,0.5) !important; }
47
- .gradio-chatbot { background: rgba(30,41,59,0.8); border: 1px solid rgba(56,189,248,0.15); border-radius: 16px; padding: 20px; }
48
- input, textarea { background: rgba(30,41,59,0.9) !important; border: 1px solid rgba(56,189,248,0.2) !important; color: #e2e8f0 !important; border-radius: 10px !important; padding: 14px !important; }
49
- input:focus, textarea:focus { border-color: #38bdf8 !important; box-shadow: 0 0 15px rgba(56,189,248,0.3) !important; }
50
- .gradio-dropdown select { background: rgba(30,41,59,0.9) !important; border: 1px solid rgba(56,189,248,0.2) !important; color: #e2e8f0 !important; }
51
- .gradio-dataset { background: rgba(30,41,59,0.7); border: 1px solid rgba(56,189,248,0.1); border-radius: 10px; max-height: 400px; overflow-y: auto; }
52
- .gradio-markdown h1, .gradio-markdown h2, .gradio-markdown h3 { color: #38bdf8; }
53
- ::-webkit-scrollbar { width: 10px; }
54
- ::-webkit-scrollbar-track { background: rgba(56,189,248,0.05); }
55
- ::-webkit-scrollbar-thumb { background: linear-gradient(180deg, #38bdf8, #8b5cf6); border-radius: 5px; }
56
- .warning { text-align: center; color: #94a3b8; font-size: 12px; margin: 16px 0; padding: 14px; background: rgba(56,189,248,0.05); border-radius: 8px; border-left: 3px solid #38bdf8; }
57
- """
58
-
59
- class ChatMgr:
60
- def __init__(self):
61
- self.rate_limit = defaultdict(list)
62
- self.metrics = defaultdict(list)
63
-
64
- def is_limited(self, user, limit=30, window=60):
65
- now = datetime.now()
66
- key = f"r_{user}"
67
- self.rate_limit[key] = [ts for ts in self.rate_limit[key] if (now - ts).seconds < window]
68
- if len(self.rate_limit[key]) >= limit: return True
69
- self.rate_limit[key].append(now)
70
- return False
71
 
72
- def record(self, user, metric, val):
73
- self.metrics[user].append({"type": metric, "value": val})
74
- if len(self.metrics[user]) > 100: self.metrics[user].pop(0)
75
-
76
- def title(self, text): return ' '.join(re.sub(r'[^a-zA-Z0-9\s]', '', text).split()[:8])[:50] or "Chat"
77
-
78
- mgr = ChatMgr()
79
-
80
- def get_hist(profile):
81
- if not supabase or not profile: return [], gr.Dataset(samples=[])
82
- try:
83
- res = supabase.table("chats").select("*").eq("username", profile.username).order("last_updated", desc=True).limit(50).execute()
84
- data = res.data or []
85
- samples = [[f"💬 {d['title'][:35]}", f"{d.get('message_count', 0)} msgs | {d.get('model_used', 'N/A').split('/')[-1][:15]}"] for d in data]
86
- return data, gr.Dataset(samples=samples)
87
- except: return [], gr.Dataset(samples=[])
88
-
89
- def load_chat(evt, db):
90
- try: return db[evt.index]['history'], db[evt.index]['session_id']
91
- except: return [], str(uuid.uuid4())
92
-
93
- def save_chat(user, sid, title, hist, model):
94
- if not supabase or not user: return False
95
- try:
96
- msg_count = len([m for m in hist if m['role'] == 'user'])
97
- supabase.table("chats").upsert({
98
- "username": user, "session_id": sid, "title": title, "history": hist,
99
- "message_count": msg_count, "model_used": model,
100
- "last_updated": datetime.utcnow().isoformat(), "created_at": datetime.utcnow().isoformat()
101
- }, on_conflict="session_id").execute()
102
- return True
103
- except: return False
104
-
105
- def get_stats(profile):
106
- if not supabase or not profile: return "📊 No data"
107
  try:
108
- res = supabase.table("chats").select("message_count").eq("username", profile.username).execute()
109
- data = res.data or []
110
- total_msgs = sum(d.get('message_count', 0) for d in data)
111
- return f"📊 Chats: **{len(data)}** | Messages: **{total_msgs}** | Avg: **{total_msgs // max(len(data), 1)}**"
112
- except: return "📊 Error"
113
-
114
- def chat_engine(msg, hist, sid, model, prompt, profile):
115
- text = msg.get("text", "").strip() if isinstance(msg, dict) else str(msg).strip()
116
- if not text: yield gr.update(value={"text": ""}), hist, sid, "Empty"
117
- else:
118
- user = profile.username if profile else "guest"
119
- if mgr.is_limited(user):
120
- yield gr.update(value={"text": ""}), hist, sid, "Rate limited"
121
- else:
122
- start = time.time()
123
- try:
124
- model_id = MODELS[model]["id"] if model in MODELS else list(MODELS.values())[0]["id"]
125
- client = InferenceClient(model=model_id, token=HF_TOKEN)
126
- except:
127
- client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
128
-
129
- msgs = [{"role": "system", "content": PROMPTS.get(prompt, list(PROMPTS.values())[0])}]
130
- msgs.extend(hist[-15:])
131
- msgs.append({"role": "user", "content": text})
132
- new_hist = hist + [{"role": "user", "content": text}]
133
- ans = ""
134
-
135
- yield gr.update(value={"text": ""}, interactive=False), new_hist + [{"role": "assistant", "content": "..."}], sid, "..."
136
- try:
137
- for token in client.chat_completion(messages=msgs, max_tokens=2048, stream=True):
138
- if token.choices[0].delta.content:
139
- ans += token.choices[0].delta.content
140
- yield gr.update(value={"text": ""}, interactive=True), new_hist + [{"role": "assistant", "content": ans}], sid, f"{len(ans)}"
141
-
142
- final = new_hist + [{"role": "assistant", "content": ans}]
143
- if profile: save_chat(profile.username, sid, mgr.title(text), final, model)
144
- mgr.record(user, "response_time", time.time() - start)
145
- yield gr.update(value={"text": ""}, interactive=True), final, sid, "✅"
146
- except Exception as e:
147
- yield gr.update(value={"text": ""}, interactive=True), new_hist + [{"role": "assistant", "content": f"Error: {str(e)[:50]}"}], sid, "❌"
148
 
149
- with gr.Blocks(theme=gr.themes.Slate()) as demo:
150
- sid = gr.State(str(uuid.uuid4()))
151
- db = gr.State([])
 
 
 
 
 
152
 
153
- with gr.Row(equal_height=False):
154
- with gr.Column(scale=1, elem_classes="sidebar-node"):
155
- gr.HTML("<div class='logo'>⚡ NODEAI PRO</div>")
156
- profile = gr.LoginButton(value="🔐 Login", size="sm")
157
-
158
- with gr.Row():
159
- gr.Button("➕ New", variant="primary", scale=1, size="sm")
160
- gr.Button("🗑️ Delete", scale=1, size="sm")
161
-
162
- gr.Markdown("### 🤖 Model")
163
- model = gr.Dropdown(list(MODELS.keys()), value=list(MODELS.keys())[0], show_label=False)
164
-
165
- gr.Markdown("### 🎯 Personality")
166
- prompt = gr.Dropdown(list(PROMPTS.keys()), value=list(PROMPTS.keys())[0], show_label=False)
167
-
168
- gr.Markdown("### 📚 History")
169
- hist_list = gr.Dataset(components=[gr.Textbox(visible=False)]*2, samples=[], type="index")
170
-
171
- gr.Markdown("### 📊 Stats")
172
- stats = gr.Markdown("Ready")
173
- gr.HTML("<div class='warning'>🔒 Your data is private & encrypted</div>")
174
 
175
- with gr.Column(scale=4):
176
- gr.HTML("<div style='text-align:center;margin:20px;'><h1 style='color:#38bdf8;'>🚀 NodeAI Genesis Pro</h1><p style='color:#94a3b8;'>Enterprise AI Chat • Multi-Model • Real-time Streaming</p></div>")
177
- chat = gr.Chatbot(show_label=False, height="65vh")
178
-
179
- with gr.Row():
180
- status = gr.Textbox(value="Ready", interactive=False, scale=2)
181
- model_info = gr.Textbox(value="", interactive=False, scale=1)
182
-
183
- inp = gr.MultimodalTextbox(show_label=False, placeholder="Ask anything... (Ctrl+Enter)")
184
- gr.HTML("<div class='warning'>⚡ Streaming responses • Auto-saves</div>")
185
-
186
- demo.load(lambda p: get_hist(p), [profile], [db, hist_list]).then(lambda p: get_stats(p), [profile], [stats])
187
- hist_list.select(lambda e, d: load_chat(e, d), [hist_list, db], [chat, sid])
188
- inp.submit(chat_engine, [inp, chat, sid, model, prompt, profile], [inp, chat, sid, status]).then(lambda p: get_hist(p), [profile], [db, hist_list]).then(lambda p: get_stats(p), [profile], [stats])
189
 
190
  if __name__ == "__main__":
191
- demo.queue().launch(css=CSS, share=False)
 
 
1
  import gradio as gr
2
+ from transformers import (
3
+ LlavaNextProcessor, LlavaNextForConditionalGeneration,
4
+ AutoTokenizer, AutoProcessor
5
+ )
6
+ from PIL import Image
7
+ import torch
8
+ import os
9
+ from huggingface_hub import login
10
 
11
+ # HF_TOKEN tự động từ HF Spaces secrets
12
+ if "HF_TOKEN" in os.environ:
13
+ login(token=os.environ["HF_TOKEN"])
14
 
15
+ model_id = "lamgamepro1/SaitenOne-1.0"
 
 
 
 
 
 
16
 
17
+ # Load model (cache cho lần sau)
18
+ print("🔄 Loading model...")
19
+ processor = LlavaNextProcessor.from_pretrained(model_id, trust_remote_code=True)
20
+ model = LlavaNextForConditionalGeneration.from_pretrained(
21
+ model_id,
22
+ torch_dtype=torch.bfloat16,
23
+ device_map="auto",
24
+ trust_remote_code=True
25
+ )
26
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
27
+ print("✅ Model loaded!")
28
 
29
+ def predict_chat(image, text, max_tokens=256):
30
+ if image is None:
31
+ return "❌ Vui lòng upload ảnh!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  try:
34
+ # Messages multimodal
35
+ messages = [{
36
+ "role": "user",
37
+ "content": [
38
+ {"type": "image"},
39
+ {"type": "text", "text": text or "Mô tả chi tiết ảnh này?"}
40
+ ]
41
+ }]
42
+
43
+ # Process input
44
+ text_inputs = processor.apply_chat_template(
45
+ messages,
46
+ add_generation_prompt=True,
47
+ return_tensors="pt"
48
+ )
49
+ image_inputs = processor.image_processor(image, return_tensors="pt")["pixel_values"]
50
+
51
+ # Generate
52
+ with torch.no_grad():
53
+ inputs = {
54
+ "input_ids": text_inputs.to(model.device),
55
+ "pixel_values": image_inputs.to(model.device),
56
+ "max_new_tokens": max_tokens,
57
+ "temperature": 0.7,
58
+ "do_sample": True,
59
+ "pad_token_id": tokenizer.eos_token_id
60
+ }
61
+ output = model.generate(**inputs)
62
+ response = processor.decode(output[0], skip_special_tokens=True)
63
+
64
+ return response.split("assistant")[-1].strip()
65
+
66
+ except Exception as e:
67
+ return f"❌ Lỗi: {str(e)}"
 
 
 
 
 
 
68
 
69
+ # Gradio Interface
70
+ with gr.Blocks(
71
+ title="SaitenOne-1.0 Vision Chat",
72
+ theme=gr.themes.Soft()
73
+ ) as demo:
74
+
75
+ gr.Markdown("# 🖼️ SaitenOne-1.0 Vision Chat")
76
+ gr.Markdown("Upload ảnh + hỏi → AI phân tích ngay!")
77
 
78
+ with gr.Row():
79
+ with gr.Column(scale=1):
80
+ image_input = gr.Image(type="pil", label="📸 Upload ảnh")
81
+ text_input = gr.Textbox(
82
+ label="❓ Câu hỏi",
83
+ placeholder="Ảnh này chứa gì? Có mấy người? Mô tả chi tiết...",
84
+ lines=2
85
+ )
86
+ max_tokens = gr.Slider(128, 512, value=256, label="📝 Max tokens")
87
+ btn = gr.Button("🚀 Phân tích", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ with gr.Column(scale=1):
90
+ output = gr.Textbox(label="🤖 Kết quả", lines=10)
91
+
92
+ # Examples
93
+ gr.Examples(
94
+ examples=[
95
+ ["ảnh mèo", "Đây là con gì?"],
96
+ ["ảnh người", "Có bao nhiêu người trong ảnh?"],
97
+ ["ảnh đồ vật", "Mô tả chi tiết những vật thể trong ảnh"],
98
+ ],
99
+ inputs=[image_input, text_input]
100
+ )
101
+
102
+ btn.click(predict_chat, [image_input, text_input, max_tokens], output)
103
 
104
  if __name__ == "__main__":
105
+ demo.launch()