Spaces:
Unmid
/
Runtime error

Nafiul Huda commited on
Commit
86a95b5
·
verified ·
1 Parent(s): 9fc3aad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -199
app.py CHANGED
@@ -1,96 +1,20 @@
1
- import subprocess
2
- import time
3
- import requests
4
- import threading
5
  from flask import Flask, render_template, request, jsonify, Response
6
- import signal
7
- import sys
8
- import os
9
 
10
  app = Flask(__name__)
11
 
12
- # ── Config ──────────────────────────────────────────────────────────
13
- LLAMA_SERVER_HOST = "127.0.0.1"
14
- LLAMA_SERVER_PORT = 8080
15
- MODEL_PATH = "/opt/models/smollm2-1.7b-instruct-q4_k_m.gguf"
16
-
17
- # Find the correct binary path (name changed across versions)
18
- POSSIBLE_BINS = [
19
- "/opt/llama.cpp/build/bin/llama-server",
20
- "/opt/llama.cpp/build/bin/server",
21
- "/opt/llama.cpp/build/server",
22
- ]
23
-
24
- LLAMA_BIN = None
25
- for path in POSSIBLE_BINS:
26
- if os.path.isfile(path):
27
- LLAMA_BIN = path
28
- break
29
-
30
- if LLAMA_BIN is None:
31
- print("ERROR: Could not find llama server binary!")
32
- # Try to find it dynamically
33
- result = subprocess.run(
34
- ["find", "/opt/llama.cpp/build", "-name", "*server*", "-type", "f"],
35
- capture_output=True, text=True
36
- )
37
- print(f"Available server-like files:\n{result.stdout}")
38
- sys.exit(1)
39
-
40
- print(f"Using binary: {LLAMA_BIN}")
41
-
42
- llama_process = None
43
-
44
-
45
- def start_llama_server():
46
- """Start llama.cpp server as a subprocess."""
47
- global llama_process
48
-
49
- cmd = [
50
- LLAMA_BIN,
51
- "-m", MODEL_PATH,
52
- "--host", LLAMA_SERVER_HOST,
53
- "--port", str(LLAMA_SERVER_PORT),
54
- "-c", "2048", # context size
55
- "-t", "4", # threads (HF free spaces usually have 2-4 cores)
56
- "--mlock", # lock model in RAM
57
- ]
58
-
59
- print(f"Starting llama.cpp server: {' '.join(cmd)}")
60
- llama_process = subprocess.Popen(
61
- cmd,
62
- stdout=subprocess.PIPE,
63
- stderr=subprocess.STDOUT,
64
- text=True,
65
- )
66
-
67
- # Stream llama.cpp logs in background
68
- def stream_logs():
69
- for line in llama_process.stdout:
70
- print(f"[llama.cpp] {line}", end="")
71
-
72
- threading.Thread(target=stream_logs, daemon=True).start()
73
-
74
-
75
- def wait_for_server(timeout=120):
76
- """Wait until the llama.cpp server is ready."""
77
- url = f"http://{LLAMA_SERVER_HOST}:{LLAMA_SERVER_PORT}/health"
78
- start = time.time()
79
- while time.time() - start < timeout:
80
- try:
81
- r = requests.get(url, timeout=2)
82
- if r.status_code == 200:
83
- print("llama.cpp server is ready!")
84
- return True
85
- except requests.ConnectionError:
86
- pass
87
- time.sleep(2)
88
- print("Timeout waiting for llama.cpp server")
89
- return False
90
 
91
 
92
- # ── Routes ──────────────────────────────────────────────────────────
93
-
94
  @app.route("/")
95
  def index():
96
  return render_template("index.html")
@@ -98,138 +22,58 @@ def index():
98
 
99
  @app.route("/chat", methods=["POST"])
100
  def chat():
101
- """Non-streaming chat endpoint."""
102
  data = request.json
103
- user_message = data.get("message", "").strip()
104
-
105
- if not user_message:
106
  return jsonify({"error": "Empty message"}), 400
107
 
108
- # Build prompt (SmolLM2-Instruct format)
109
- prompt = (
110
- f"<|im_start|>system\n"
111
- f"You are a helpful assistant.<|im_end|>\n"
112
- f"<|im_start|>user\n"
113
- f"{user_message}<|im_end|>\n"
114
- f"<|im_start|>assistant\n"
 
115
  )
116
 
117
- payload = {
118
- "prompt": prompt,
119
- "n_predict": 512,
120
- "temperature": 0.7,
121
- "top_p": 0.9,
122
- "stop": ["<|im_end|>", "<|im_start|>"],
123
- "stream": False,
124
- }
125
-
126
- try:
127
- resp = requests.post(
128
- f"http://{LLAMA_SERVER_HOST}:{LLAMA_SERVER_PORT}/completion",
129
- json=payload,
130
- timeout=120,
131
- )
132
- result = resp.json()
133
- return jsonify({"response": result.get("content", "").strip()})
134
- except Exception as e:
135
- return jsonify({"error": str(e)}), 500
136
 
137
 
138
  @app.route("/chat/stream", methods=["POST"])
139
  def chat_stream():
140
- """Streaming chat endpoint using SSE."""
141
  data = request.json
142
- user_message = data.get("message", "").strip()
143
-
144
- if not user_message:
145
  return jsonify({"error": "Empty message"}), 400
146
 
147
- prompt = (
148
- f"<|im_start|>system\n"
149
- f"You are a helpful assistant.<|im_end|>\n"
150
- f"<|im_start|>user\n"
151
- f"{user_message}<|im_end|>\n"
152
- f"<|im_start|>assistant\n"
153
- )
 
 
 
154
 
155
- payload = {
156
- "prompt": prompt,
157
- "n_predict": 512,
158
- "temperature": 0.7,
159
- "top_p": 0.9,
160
- "stop": ["<|im_end|>", "<|im_start|>"],
161
- "stream": True,
162
- }
163
 
164
- def generate():
165
- try:
166
- with requests.post(
167
- f"http://{LLAMA_SERVER_HOST}:{LLAMA_SERVER_PORT}/completion",
168
- json=payload,
169
- stream=True,
170
- timeout=120,
171
- ) as resp:
172
- import json as json_module
173
- for line in resp.iter_lines():
174
- if line:
175
- decoded = line.decode("utf-8")
176
- if decoded.startswith("data: "):
177
- json_str = decoded[6:]
178
- if json_str.strip() == "[DONE]":
179
- yield f"data: [DONE]\n\n"
180
- break
181
- try:
182
- chunk = json_module.loads(json_str)
183
- content = chunk.get("content", "")
184
- if content:
185
- yield f"data: {json_module.dumps({'content': content})}\n\n"
186
- if chunk.get("stop", False):
187
- yield f"data: [DONE]\n\n"
188
- break
189
- except json_module.JSONDecodeError:
190
- pass
191
- except Exception as e:
192
- import json as json_module
193
- yield f"data: {json_module.dumps({'error': str(e)})}\n\n"
194
 
195
  return Response(generate(), mimetype="text/event-stream")
196
 
197
 
198
  @app.route("/health")
199
  def health():
200
- try:
201
- r = requests.get(
202
- f"http://{LLAMA_SERVER_HOST}:{LLAMA_SERVER_PORT}/health",
203
- timeout=5,
204
- )
205
- return jsonify({"flask": "ok", "llama": r.json()})
206
- except Exception:
207
- return jsonify({"flask": "ok", "llama": "not ready"}), 503
208
-
209
-
210
- # ── Cleanup ─────────────────────────────────────────────────────────
211
-
212
- def cleanup(signum=None, frame=None):
213
- global llama_process
214
- if llama_process:
215
- print("Shutting down llama.cpp server...")
216
- llama_process.terminate()
217
- llama_process.wait()
218
- sys.exit(0)
219
-
220
-
221
- signal.signal(signal.SIGTERM, cleanup)
222
- signal.signal(signal.SIGINT, cleanup)
223
-
224
 
225
- # ── Main ────────────────────────────────────────────────────────────
226
 
227
  if __name__ == "__main__":
228
- start_llama_server()
229
-
230
- if wait_for_server(timeout=180):
231
- print("Starting Flask on port 7860...")
232
- app.run(host="0.0.0.0", port=7860, debug=False)
233
- else:
234
- print("Failed to start llama.cpp server. Exiting.")
235
- cleanup()
 
 
 
 
 
1
  from flask import Flask, render_template, request, jsonify, Response
2
+ from llama_cpp import Llama
3
+ import json
 
4
 
5
  app = Flask(__name__)
6
 
7
+ # ── Load model once at startup (takes ~2-5 seconds) ──
8
+ print("Loading model...")
9
+ llm = Llama(
10
+ model_path="/opt/models/model.gguf",
11
+ n_ctx=2048,
12
+ n_threads=4,
13
+ verbose=False,
14
+ )
15
+ print("Model loaded!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
 
 
 
18
  @app.route("/")
19
  def index():
20
  return render_template("index.html")
 
22
 
23
  @app.route("/chat", methods=["POST"])
24
  def chat():
 
25
  data = request.json
26
+ msg = data.get("message", "").strip()
27
+ if not msg:
 
28
  return jsonify({"error": "Empty message"}), 400
29
 
30
+ output = llm.create_chat_completion(
31
+ messages=[
32
+ {"role": "system", "content": "You are a helpful assistant."},
33
+ {"role": "user", "content": msg},
34
+ ],
35
+ max_tokens=512,
36
+ temperature=0.7,
37
+ stream=False,
38
  )
39
 
40
+ reply = output["choices"][0]["message"]["content"]
41
+ return jsonify({"response": reply})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
 
44
  @app.route("/chat/stream", methods=["POST"])
45
  def chat_stream():
 
46
  data = request.json
47
+ msg = data.get("message", "").strip()
48
+ if not msg:
 
49
  return jsonify({"error": "Empty message"}), 400
50
 
51
+ def generate():
52
+ stream = llm.create_chat_completion(
53
+ messages=[
54
+ {"role": "system", "content": "You are a helpful assistant."},
55
+ {"role": "user", "content": msg},
56
+ ],
57
+ max_tokens=512,
58
+ temperature=0.7,
59
+ stream=True,
60
+ )
61
 
62
+ for chunk in stream:
63
+ delta = chunk["choices"][0].get("delta", {})
64
+ content = delta.get("content", "")
65
+ if content:
66
+ yield f"data: {json.dumps({'content': content})}\n\n"
 
 
 
67
 
68
+ yield "data: [DONE]\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  return Response(generate(), mimetype="text/event-stream")
71
 
72
 
73
  @app.route("/health")
74
  def health():
75
+ return jsonify({"status": "ok"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
 
77
 
78
  if __name__ == "__main__":
79
+ app.run(host="0.0.0.0", port=7860)