1yahoo commited on
Commit
ec00cab
·
verified ·
1 Parent(s): aee06c0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -84
app.py CHANGED
@@ -5,19 +5,19 @@ import chromadb
5
  import gradio as gr
6
  from fastapi import FastAPI, Request, File, UploadFile, BackgroundTasks
7
  from fastapi.responses import StreamingResponse, HTMLResponse
8
- from fastapi.middleware.cors import CORSMiddleware
9
  from openai import OpenAI
10
  from chromadb.utils import embedding_functions
11
 
12
- # --- المحرك الخلفي (FastAPI) ---
13
  app = FastAPI()
14
 
15
- # إعداد الذاكرة الدائمة
16
  STORAGE_PATH = "/data/neural_memory" if os.path.exists("/data") else "./neural_memory"
17
  chroma_client = chromadb.PersistentClient(path=STORAGE_PATH)
18
  default_ef = embedding_functions.DefaultEmbeddingFunction()
19
- collection = chroma_client.get_or_create_collection(name="user_vault_v1", embedding_function=default_ef)
20
 
 
21
  @app.get("/", response_class=HTMLResponse)
22
  async def get_ui():
23
  return """
@@ -25,105 +25,88 @@ async def get_ui():
25
  <html lang="ar" dir="rtl">
26
  <head>
27
  <meta charset="UTF-8">
28
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
29
  <title>Deep Neural Vault</title>
30
  <script src="https://cdn.tailwindcss.com"></script>
31
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
32
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
33
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
34
  <style>
35
- body { background: #020617; color: #f8fafc; margin: 0; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
36
- .mobile-safe-area { height: 100%; display: flex; flex-direction: column; position: relative; }
37
- .chat-stream { flex: 1; overflow-y: auto; padding-bottom: 80px; -webkit-overflow-scrolling: touch; }
38
- .input-area { position: absolute; bottom: 0; left: 0; right: 0; padding: 12px; background: linear-gradient(transparent, #020617 20%); }
39
- .sidebar-drawer { position: fixed; top: 0; right: 0; bottom: 0; w: 80%; background: #0f172a; z-index: 1000; transition: transform 0.3s ease; shadow: -10px 0 30px rgba(0,0,0,0.5); }
40
  </style>
41
  </head>
42
  <body>
43
- <div id="root" class="mobile-safe-area"></div>
44
  <script type="text/babel">
45
  const { useState, useEffect, useRef } = React;
46
-
47
  function App() {
48
  const [messages, setMessages] = useState([]);
49
  const [input, setInput] = useState("");
50
- const [isSideOpen, setSideOpen] = useState(false);
51
- const [status, setStatus] = useState("idle");
52
 
53
  const send = async () => {
54
  if(!input.trim()) return;
55
- const newMsgs = [...messages, {role: 'user', content: input}];
56
- setMessages(newMsgs);
57
  setInput("");
58
- setStatus("thinking");
59
-
60
- try {
61
- const res = await fetch('/v1/chat/completions', {
62
- method: 'POST',
63
- headers: {'Content-Type': 'application/json'},
64
- body: JSON.stringify({ messages: newMsgs })
65
- });
66
- const reader = res.body.getReader();
67
- let currentBotMsg = { role: 'assistant', content: "" };
68
- setMessages(prev => [...prev, currentBotMsg]);
69
-
70
- while(true) {
71
- const {done, value} = await reader.read();
72
- if(done) break;
73
- const text = new TextDecoder().decode(value).replace(/data: /g, '');
74
- if(text.includes("[DONE]")) break;
75
- currentBotMsg.content += text;
76
- setMessages(prev => [...prev.slice(0, -1), {...currentBotMsg}]);
77
- }
78
- } catch(e) { console.error(e); }
79
- setStatus("idle");
80
  };
81
 
82
  return (
83
- <div className="h-full flex flex-col">
84
- <header className="p-4 border-b border-white/10 flex justify-between items-center bg-slate-900/50">
85
- <button onClick={() => setSideOpen(true)} className="text-indigo-400">☰</button>
86
- <span className="text-xs font-bold tracking-widest">NEURAL VAULT</span>
87
- <div className={`w-2 h-2 rounded-full ${status === 'idle' ? 'bg-emerald-500' : 'bg-indigo-500 animate-pulse'}`}></div>
88
  </header>
89
 
90
  <div className="chat-stream p-4 space-y-4">
91
  {messages.map((m, i) => (
92
  <div key={i} className={`flex ${m.role === 'user' ? 'justify-start' : 'justify-end'}`}>
93
- <div className={`max-w-[85%] p-3 rounded-2xl text-sm ${m.role === 'user' ? 'bg-slate-800' : 'bg-indigo-600/20 border border-indigo-500/30'}`}>
94
  {m.content}
95
  </div>
96
  </div>
97
  ))}
98
  </div>
99
 
100
- <div className="input-area">
101
- <div className="max-w-xl mx-auto flex gap-2 bg-slate-900 border border-white/10 rounded-xl p-1 shadow-xl">
102
- <input
103
- className="flex-1 bg-transparent px-3 py-2 outline-none text-sm"
104
- placeholder="اسأل..."
105
- value={input}
106
- onChange={e => setInput(e.target.value)}
107
- onKeyDown={e => e.key === 'Enter' && send()}
108
- />
109
- <button onClick={send} className="bg-indigo-600 p-2 rounded-lg">
110
- <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
111
- </button>
112
  </div>
113
  </div>
114
 
115
- {/* Sidebar Drawer */}
116
- <aside className={`sidebar-drawer p-6 ${isSideOpen ? 'translate-x-0' : 'translate-x-full'}`}>
117
- <div className="flex justify-between mb-8">
118
- <h2 className="font-bold">الحساب والذاكرة</h2>
119
- <button onClick={() => setSideOpen(false)}>✕</button>
120
  </div>
121
- <div className="space-y-6">
122
- <div className="p-4 bg-indigo-600/10 rounded-xl border border-indigo-500/20 text-xs">
123
- <p>نظام الاستهلاك: <b>Featherless API</b></p>
124
- <p className="mt-2 text-slate-400">سيتم الخصم من رصيدك في HF عند تسجيل الدخول.</p>
125
- </div>
126
- <input type="file" className="block w-full text-xs text-slate-500 file:bg-slate-800 file:text-white file:border-0 file:py-2 file:px-4 file:rounded-lg" />
127
  </div>
128
  </aside>
129
  </div>
@@ -136,23 +119,18 @@ async def get_ui():
136
  </html>
137
  """
138
 
139
- # --- منطق تسجيل الدخول واستهلاك الرصيد (مستوحى من ملفك) ---
140
- def get_client(token: str = None):
141
- # نستخدم التوكن الخاص بالمستخدم إذا سجل دخوله، وإلا نستخدم توكن النظام
142
- api_key = token if token else os.getenv("HF_TOKEN")
143
- return OpenAI(
144
- base_url="https://router.huggingface.co/hf-inference/v1",
145
- api_key=api_key
146
- )
147
-
148
  @app.post("/v1/chat/completions")
149
  async def chat_endpoint(request: Request):
150
  body = await request.json()
151
- # [span_2](start_span)هنا يتم ربط الطلب بـ featherless-ai كما في ملف app(2).py[span_2](end_span)
152
- local_client = get_client()
 
 
 
153
 
154
  def stream_gen():
155
- response = local_client.chat.completions.create(
156
  model="huihui-ai/Qwen2.5-72B-Instruct-abliterated",
157
  messages=body.get("messages", []),
158
  stream=True
@@ -164,14 +142,14 @@ async def chat_endpoint(request: Request):
164
 
165
  return StreamingResponse(stream_gen(), media_type="text/event-stream")
166
 
167
- # إطلاق واجهة Gradio كطبقة دخول اختيارية لتأكيد الهوية
168
  with gr.Blocks() as auth_layer:
169
- gr.Markdown("# تسجيل الدخول")
170
- login_btn = gr.LoginButton("تسجيل الدخول باستخدام Hugging Face")
171
- gr.Markdown("بعد تسجيل الدخول، سيتم استخدام رصيدك الشخصي للعمليات.")
172
 
173
  # تشغيل النظام
 
 
174
  if __name__ == "__main__":
175
  import uvicorn
176
  uvicorn.run(app, host="0.0.0.0", port=7860)
177
-
 
5
  import gradio as gr
6
  from fastapi import FastAPI, Request, File, UploadFile, BackgroundTasks
7
  from fastapi.responses import StreamingResponse, HTMLResponse
 
8
  from openai import OpenAI
9
  from chromadb.utils import embedding_functions
10
 
11
+ # --- المحرك الخلفي ---
12
  app = FastAPI()
13
 
14
+ # إعداد الذاكرة
15
  STORAGE_PATH = "/data/neural_memory" if os.path.exists("/data") else "./neural_memory"
16
  chroma_client = chromadb.PersistentClient(path=STORAGE_PATH)
17
  default_ef = embedding_functions.DefaultEmbeddingFunction()
18
+ collection = chroma_client.get_or_create_collection(name="user_vault_v2", embedding_function=default_ef)
19
 
20
+ # الواجهة المتجاوبة للهاتف
21
  @app.get("/", response_class=HTMLResponse)
22
  async def get_ui():
23
  return """
 
25
  <html lang="ar" dir="rtl">
26
  <head>
27
  <meta charset="UTF-8">
28
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
29
  <title>Deep Neural Vault</title>
30
  <script src="https://cdn.tailwindcss.com"></script>
31
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
32
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
33
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
34
  <style>
35
+ body { background: #020617; color: #f8fafc; margin: 0; padding: 0; height: 100dvh; overflow: hidden; width: 100vw; position: fixed; }
36
+ .chat-stream { height: calc(100dvh - 140px); overflow-y: auto; -webkit-overflow-scrolling: touch; padding-bottom: 20px; }
37
+ .input-box { position: fixed; bottom: 0; left: 0; right: 0; padding: 15px; background: #020617; border-top: 1px solid rgba(255,255,255,0.05); }
38
+ @media (max-width: 768px) { .sidebar { width: 85% !important; transform: translateX(100%); position: fixed; top:0; right:0; height:100%; z-index: 1000; transition: transform 0.3s ease; background: #0f172a; } .sidebar.open { transform: translateX(0); } }
 
39
  </style>
40
  </head>
41
  <body>
42
+ <div id="root"></div>
43
  <script type="text/babel">
44
  const { useState, useEffect, useRef } = React;
 
45
  function App() {
46
  const [messages, setMessages] = useState([]);
47
  const [input, setInput] = useState("");
48
+ const [isOpen, setIsOpen] = useState(false);
 
49
 
50
  const send = async () => {
51
  if(!input.trim()) return;
52
+ const userMsg = {role: 'user', content: input};
53
+ setMessages(p => [...p, userMsg]);
54
  setInput("");
55
+
56
+ const res = await fetch('/v1/chat/completions', {
57
+ method: 'POST',
58
+ headers: {'Content-Type': 'application/json'},
59
+ body: JSON.stringify({ messages: [...messages, userMsg] })
60
+ });
61
+
62
+ const reader = res.body.getReader();
63
+ let botMsg = { role: 'assistant', content: "" };
64
+ setMessages(p => [...p, botMsg]);
65
+
66
+ while(true) {
67
+ const {done, value} = await reader.read();
68
+ if(done) break;
69
+ const chunk = new TextDecoder().decode(value).replace(/data: /g, '');
70
+ if(chunk.includes("[DONE]")) break;
71
+ botMsg.content += chunk;
72
+ setMessages(p => [...p.slice(0, -1), {...botMsg}]);
73
+ }
 
 
 
74
  };
75
 
76
  return (
77
+ <div className="flex flex-col h-full w-full">
78
+ <header className="p-4 border-b border-white/10 flex justify-between items-center bg-slate-900/80 backdrop-blur-md">
79
+ <button onClick={() => setIsOpen(true)} className="text-indigo-400 text-xl">☰</button>
80
+ <h1 className="text-sm font-black">NEURAL VAULT</h1>
81
+ <div className="w-2 h-2 rounded-full bg-emerald-500"></div>
82
  </header>
83
 
84
  <div className="chat-stream p-4 space-y-4">
85
  {messages.map((m, i) => (
86
  <div key={i} className={`flex ${m.role === 'user' ? 'justify-start' : 'justify-end'}`}>
87
+ <div className={`max-w-[85%] p-3 rounded-2xl text-sm ${m.role === 'user' ? 'bg-slate-800' : 'bg-indigo-600/20 border border-indigo-500/30 text-indigo-100'}`}>
88
  {m.content}
89
  </div>
90
  </div>
91
  ))}
92
  </div>
93
 
94
+ <div className="input-box">
95
+ <div className="max-w-xl mx-auto flex gap-2">
96
+ <input className="flex-1 bg-slate-900 border border-white/10 rounded-xl px-4 py-3 outline-none text-sm" placeholder="تكلم..." value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} />
97
+ <button onClick={send} className="bg-indigo-600 px-4 rounded-xl">↑</button>
 
 
 
 
 
 
 
 
98
  </div>
99
  </div>
100
 
101
+ {/* Sidebar */}
102
+ <aside className={`sidebar p-6 shadow-2xl ${isOpen ? 'open' : ''}`}>
103
+ <div className="flex justify-between items-center mb-10">
104
+ <span className="font-bold">الإعدادات</span>
105
+ <button onClick={() => setIsOpen(false)}>✕</button>
106
  </div>
107
+ <div className="bg-indigo-600/10 p-4 rounded-xl text-[10px] text-slate-400 leading-loose">
108
+ <p>يتم الآن استهلاك الرصيد عبر: <b>Featherless Provider</b></p>
109
+ <p className="mt-2 uppercase">رابط المحرك: Active </p>
 
 
 
110
  </div>
111
  </aside>
112
  </div>
 
119
  </html>
120
  """
121
 
122
+ # --- نظام تسجيل الدخول (OAuth) لربط الرصيد ---
 
 
 
 
 
 
 
 
123
  @app.post("/v1/chat/completions")
124
  async def chat_endpoint(request: Request):
125
  body = await request.json()
126
+ # استخدام الرابط الحديث والصحيح لتجنب خطأ 410
127
+ client = OpenAI(
128
+ base_url="https://router.huggingface.co/hf-inference/v1",
129
+ api_key=os.getenv("HF_TOKEN")
130
+ )
131
 
132
  def stream_gen():
133
+ response = client.chat.completions.create(
134
  model="huihui-ai/Qwen2.5-72B-Instruct-abliterated",
135
  messages=body.get("messages", []),
136
  stream=True
 
142
 
143
  return StreamingResponse(stream_gen(), media_type="text/event-stream")
144
 
145
+ # طبقة تسجيل الدخول من ملف app(2).py
146
  with gr.Blocks() as auth_layer:
147
+ gr.Markdown("# بوابة الدخول")
148
+ gr.LoginButton()
 
149
 
150
  # تشغيل النظام
151
+ app = gr.mount_gradio_app(app, auth_layer, path="/auth")
152
+
153
  if __name__ == "__main__":
154
  import uvicorn
155
  uvicorn.run(app, host="0.0.0.0", port=7860)