OrbitMC commited on
Commit
7319988
Β·
verified Β·
1 Parent(s): 68a3e6f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -99
app.py CHANGED
@@ -1,10 +1,11 @@
1
  import os
2
- import psutil
3
  import time
4
- import numpy as np
5
- import multiprocessing
6
  import gradio as gr
7
- import spaces # <-- Keep the import
 
8
 
9
  # 1. DUMMY GPU FUNCTION: satisfies the Hugging Face startup checker
10
  # without wasting runtime resources or intercepting user execution.
@@ -16,114 +17,115 @@ def dummy_gpu():
16
  # Automatically execute it once right away during script interpretation
17
  dummy_gpu()
18
 
19
- def get_cpu_model():
20
- try:
21
- with open("/proc/cpuinfo", "r") as f:
22
- for line in f:
23
- if "model name" in line:
24
- return line.split(":")[1].strip()
25
- except Exception as e:
26
- return f"Could not read CPU model: {str(e)}"
27
- return "Unknown CPU Model"
28
 
29
- def get_container_cpu_cores():
30
- try:
31
- with open("/sys/fs/cgroup/cpu/cpu.cfs_quota_us", "r") as f:
32
- quota = int(f.read().strip())
33
- with open("/sys/fs/cgroup/cpu/cpu.cfs_period_us", "r") as f:
34
- period = int(f.read().strip())
35
- if quota > 0 and period > 0:
36
- return quota / period
37
- except Exception:
38
- pass
39
- try:
40
- with open("/sys/fs/cgroup/cpu.max", "r") as f:
41
- parts = f.read().strip().split()
42
- if len(parts) == 2 and parts[0] != "max":
43
- return int(parts[0]) / int(parts[1])
44
- except Exception:
45
- pass
46
- return os.cpu_count() or 1
47
 
48
- def get_container_ram_limit():
49
- for path in ["/sys/fs/cgroup/memory/memory.limit_in_bytes", "/sys/fs/cgroup/memory.max"]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  try:
51
- with open(path, "r") as f:
52
- limit = int(f.read().strip())
53
- if limit < 9223372036854771712:
54
- return limit / (1024 ** 2)
55
- except Exception:
56
- continue
57
- return psutil.virtual_memory().total / (1024 ** 2)
 
58
 
59
- def stress_cpu_core(duration):
60
- timeout = time.time() + duration
61
- while time.time() < timeout:
62
- _ = 123456789.0 * 987654321.0
63
 
64
- # NO @spaces.GPU DECORATOR HERE -> This runs purely on the space's base CPU container
65
- def run_heavy_benchmark():
66
- log = []
 
 
 
 
67
 
68
- cpu_model = get_cpu_model()
69
- reported_cores = os.cpu_count() or 1
70
- cgroup_cores = get_container_cpu_cores()
71
- allocated_ram = get_container_ram_limit()
72
 
73
- log.append("=== HOST & CONTAINER INITIAL SPECS ===")
74
- log.append(f"CPU Model: {cpu_model}")
75
- log.append(f"Total Cores Visible: {reported_cores}")
76
- log.append(f"Cgroup Core Limit: {cgroup_cores:.2f}")
77
- log.append(f"Total Allowed RAM Space: {allocated_ram:.1f} MB\n")
78
 
79
- log.append("=== RAM STRESS TEST (Targeting 20 GB) ===")
80
  try:
81
- log.append("Allocating continuous NumPy array...")
82
- elements = 2500000000
83
- ram_hog = np.empty(elements, dtype=np.float64)
84
- ram_hog.fill(7.0)
 
85
 
86
- process = psutil.Process(os.getpid())
87
- current_ram = process.memory_info().rss / (1024 ** 2)
88
- log.append(f"βœ… Success! Managed to hold RAM without crash.")
89
- log.append(f"Active App RAM State: {current_ram:.1f} MB")
90
-
91
- del ram_hog
92
- log.append("Array successfully garbage collected.\n")
93
- except MemoryError:
94
- log.append("❌ Failed: Hit container hard Memory OOM ceiling.\n")
 
 
 
 
 
 
 
 
95
  except Exception as e:
96
- log.append(f"❌ Failed with unexpected exception: {str(e)}\n")
97
-
98
- log.append("=== CPU MAX OUT TEST ===")
99
- log.append(f"Spawning {reported_cores} distinct processes to bypass GIL...")
100
-
101
- processes = []
102
- stress_duration = 6
103
-
104
- for _ in range(reported_cores):
105
- p = multiprocessing.Process(target=stress_cpu_core, args=(stress_duration,))
106
- processes.append(p)
107
- p.start()
108
-
109
- time.sleep(2.0)
110
- system_cpu = psutil.cpu_percent(interval=0.5)
111
- log.append(f"Live measured core utilization: {system_cpu}%")
112
-
113
- for p in processes:
114
- p.join()
115
-
116
- log.append("All stress tasks safely completed.")
117
- return "\n".join(log)
118
 
 
119
  with gr.Blocks() as demo:
120
- gr.Markdown("## Hugging Face Native CPU & Core Resource Profile Tester")
121
-
122
- run_btn = gr.Button("Execute Deep Diagnostics", variant="primary")
123
- output_log = gr.Textbox(label="System Standard Output Log", lines=16)
124
 
125
- run_btn.click(fn=run_heavy_benchmark, outputs=output_log)
 
 
 
126
 
127
  if __name__ == "__main__":
128
- multiprocessing.freeze_support()
129
- demo.launch(server_name="0.0.0.0")
 
1
  import os
2
+ import subprocess
3
  import time
4
+ import requests
5
+ import json
6
  import gradio as gr
7
+ import spaces
8
+ from huggingface_hub import hf_hub_download
9
 
10
  # 1. DUMMY GPU FUNCTION: satisfies the Hugging Face startup checker
11
  # without wasting runtime resources or intercepting user execution.
 
17
  # Automatically execute it once right away during script interpretation
18
  dummy_gpu()
19
 
20
+ # 2. DOWNLOAD MODEL & COMPILE LLAMA.CPP SERVER
21
+ def setup_environment():
22
+ print("Downloading model...")
23
+ repo = "Abiray/MiniCPM5-1B-GGUF"
24
+ filename = "minicpm5-1b-Q6_K.gguf"
25
+ model_path = hf_hub_download(repo_id=repo, filename=filename)
26
+ print(f"Model downloaded to: {model_path}")
 
 
27
 
28
+ if not os.path.exists("llama.cpp/llama-server"):
29
+ print("llama-server binary not found. Cloning and compiling llama.cpp...")
30
+ subprocess.run("git clone https://github.com/ggerganov/llama.cpp.git", shell=True)
31
+ # Compile only the server binary to save time
32
+ subprocess.run("cd llama.cpp && make -j4 llama-server", shell=True)
33
+ print("Compilation finished!")
34
+ else:
35
+ print("llama.cpp already compiled.")
36
+
37
+ return model_path
 
 
 
 
 
 
 
 
38
 
39
+ # 3. START BACKGROUND SERVER
40
+ def start_server(model_path):
41
+ # Using the exact parameters from your Dockerfile but pointing to local 8080 port
42
+ # so Gradio can occupy the main 7860 port safely.
43
+ cmd = [
44
+ "./llama.cpp/llama-server",
45
+ "-m", model_path,
46
+ "--host", "127.0.0.1",
47
+ "--port", "8080",
48
+ "-t", "2",
49
+ "--cache-type-k", "q8_0",
50
+ "--cache-type-v", "iq4_nl",
51
+ "-c", "131072",
52
+ "-n", "32000"
53
+ ]
54
+
55
+ print("Booting local llama-server with command:")
56
+ print(" ".join(cmd))
57
+
58
+ # Spawn server process in the background
59
+ server_process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
60
+
61
+ # Wait for the server to be healthy
62
+ print("Waiting for llama-server to initialize (this may take a moment due to the 131k context KV cache allocation)...")
63
+ for _ in range(120):
64
  try:
65
+ response = requests.get("http://127.0.0.1:8080/health")
66
+ if response.status_code == 200:
67
+ print("llama-server is up and running!")
68
+ return server_process
69
+ except requests.exceptions.ConnectionError:
70
+ time.sleep(2)
71
+
72
+ raise RuntimeError("Server failed to start within the timeout period. You may be hitting an OOM error due to the 131072 context size.")
73
 
74
+ model_filepath = setup_environment()
75
+ start_server(model_filepath)
 
 
76
 
77
+ # 4. GRADIO UI TO INTERACT WITH LOCAL SERVER
78
+ def chat_with_llama(message, history):
79
+ # Format history for OpenAI-compatible API
80
+ messages = [{"role": "system", "content": "You are a helpful AI assistant."}]
81
+ for user_msg, assistant_msg in history:
82
+ messages.append({"role": "user", "content": user_msg})
83
+ messages.append({"role": "assistant", "content": assistant_msg})
84
 
85
+ messages.append({"role": "user", "content": message})
 
 
 
86
 
87
+ payload = {
88
+ "messages": messages,
89
+ "stream": True,
90
+ "temperature": 0.7
91
+ }
92
 
 
93
  try:
94
+ response = requests.post(
95
+ "http://127.0.0.1:8080/v1/chat/completions",
96
+ json=payload,
97
+ stream=True
98
+ )
99
 
100
+ partial_response = ""
101
+ for line in response.iter_lines():
102
+ if line:
103
+ decoded_line = line.decode('utf-8')
104
+ if decoded_line.startswith("data: "):
105
+ data_str = decoded_line[6:]
106
+ if data_str == "[DONE]":
107
+ break
108
+ try:
109
+ data = json.loads(data_str)
110
+ if "choices" in data and len(data["choices"]) > 0:
111
+ delta = data["choices"][0].get("delta", {})
112
+ if "content" in delta:
113
+ partial_response += delta["content"]
114
+ yield partial_response
115
+ except json.JSONDecodeError:
116
+ continue
117
  except Exception as e:
118
+ yield f"Error communicating with local server: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
+ # 5. LAUNCH GRADIO APP
121
  with gr.Blocks() as demo:
122
+ gr.Markdown("# Native CPU `llama.cpp` Execution on ZeroGPU Space")
123
+ gr.Markdown(f"Running **MiniCPM5-1B-GGUF** natively using `llama-server` behind the scenes! Bypassing GPU logic entirely.")
 
 
124
 
125
+ gr.ChatInterface(
126
+ fn=chat_with_llama,
127
+ examples=["Who are you?", "Write a python script to reverse a string.", "Explain quantum computing."],
128
+ )
129
 
130
  if __name__ == "__main__":
131
+ demo.launch(server_name="0.0.0.0", server_port=7860)