kanada / codeing-ai-code
roop0726's picture
Create codeing-ai-code
b06f030 verified
Raw History Blame Contribute Delete
21.7 kB
import os
import time
import json
import shutil
import tarfile
import zipfile
import stat
import subprocess
import threading
from pathlib import Path
import requests
import gradio as gr
from huggingface_hub import hf_hub_download
APP_DIR = Path("/app")
MODEL_DIR = APP_DIR / "models"
MODEL_DIR.mkdir(parents=True, exist_ok=True)
MODEL_REPO = "Qwen/Qwen2.5-Coder-3B-Instruct-GGUF"
MODEL_FILE = "qwen2.5-coder-3b-instruct-q4_k_m.gguf"
MODEL_PATH = MODEL_DIR / MODEL_FILE
LLAMA_DIR = APP_DIR / "llama-server"
LLAMA_EXTRACT_DIR = APP_DIR / "llama-extracted"
LLAMA_SERVER = LLAMA_DIR / "llama-server"
SERVER_HOST = "127.0.0.1"
SERVER_PORT = 8080
GRADIO_HOST = "0.0.0.0"
GRADIO_PORT = 7860
API_KEY = "local-space-key"
PARALLEL_USERS = 4
CONTEXT_PER_USER = 2048
TOTAL_CONTEXT = PARALLEL_USERS * CONTEXT_PER_USER
CPU_THREADS = int(
os.environ.get("CPU_THREADS", "4")
)
CPU_THREADS_BATCH = int(
os.environ.get(
"CPU_THREADS_BATCH",
str(CPU_THREADS)
)
)
BATCH_SIZE = int(
os.environ.get("BATCH_SIZE", "512")
)
MAX_TOKENS = int(
os.environ.get("MAX_TOKENS", "512")
)
TEMPERATURE = float(
os.environ.get("TEMPERATURE", "0.2")
)
TOP_P = float(
os.environ.get("TOP_P", "0.9")
)
server_process = None
server_lock = threading.Lock()
def download_model():
if MODEL_PATH.exists():
size_gb = (
MODEL_PATH.stat().st_size
/ 1024
/ 1024
/ 1024
)
print(
f"[MODEL] Already exists: {MODEL_PATH}"
)
print(
f"[MODEL] Size: {size_gb:.2f} GB"
)
return str(MODEL_PATH)
print(
"[MODEL] Downloading Qwen2.5-Coder-3B Q4_K_M..."
)
hf_token = os.environ.get("HF_TOKEN")
kwargs = {
"repo_id": MODEL_REPO,
"filename": MODEL_FILE,
"local_dir": str(MODEL_DIR),
}
if hf_token:
kwargs["token"] = hf_token
downloaded = hf_hub_download(
**kwargs
)
print(
f"[MODEL] Download complete: {downloaded}"
)
return downloaded
def find_llama_server(directory):
directory = Path(directory)
for path in directory.rglob(
"llama-server"
):
if path.is_file():
try:
path.chmod(
path.stat().st_mode
| stat.S_IXUSR
| stat.S_IXGRP
| stat.S_IXOTH
)
except Exception:
pass
return path
return None
def find_cpu_asset():
api_url = (
"https://api.github.com/"
"repos/ggml-org/llama.cpp/releases"
)
headers = {
"Accept":
"application/vnd.github+json",
"User-Agent":
"hf-space-qwen-llama-server"
}
print(
"[LLAMA] Searching llama.cpp releases..."
)
response = requests.get(
api_url,
params={
"per_page": 20
},
headers=headers,
timeout=30
)
response.raise_for_status()
releases = response.json()
if not isinstance(
releases,
list
):
raise RuntimeError(
"Invalid GitHub releases response."
)
stable = []
for release in releases:
if not release.get(
"draft",
False
) and not release.get(
"prerelease",
False
):
stable.append(release)
releases = stable + [
r for r in releases
if r not in stable
]
for release in releases:
tag = release.get(
"tag_name",
"unknown"
)
assets = release.get(
"assets",
[]
)
print(
f"[LLAMA] Checking {tag}"
)
for asset in assets:
name = asset.get(
"name",
""
)
lower = name.lower()
special = any(
x in lower
for x in (
"cuda",
"vulkan",
"rocm",
"openvino",
"sycl",
"metal"
)
)
current_cpu = (
"ubuntu-x64" in lower
and lower.endswith(
".tar.gz"
)
)
old_cpu = (
"ubuntu" in lower
and "x64" in lower
and (
"cpu" in lower
or "bin-" in lower
)
and lower.endswith(
(
".tar.gz",
".zip"
)
)
)
if (
not special
and (
current_cpu
or old_cpu
)
):
print(
f"[LLAMA] Found CPU build: {name}"
)
return asset
print(
"[LLAMA] No compatible CPU build found."
)
for release in releases[:5]:
print(
"Release:",
release.get(
"tag_name",
"unknown"
)
)
for asset in release.get(
"assets",
[]
):
print(
" ",
asset.get(
"name",
""
)
)
raise RuntimeError(
"Could not find Ubuntu x64 CPU "
"llama.cpp release asset."
)
def download_llama_server():
if LLAMA_SERVER.exists():
try:
LLAMA_SERVER.chmod(
LLAMA_SERVER.stat().st_mode
| stat.S_IXUSR
| stat.S_IXGRP
| stat.S_IXOTH
)
except Exception:
pass
print(
f"[LLAMA] Existing server found: "
f"{LLAMA_SERVER}"
)
return str(
LLAMA_SERVER
)
print(
"[LLAMA] Downloading prebuilt llama.cpp server..."
)
asset = find_cpu_asset()
asset_name = asset[
"name"
]
download_url = asset[
"browser_download_url"
]
archive_path = (
APP_DIR /
asset_name
)
print(
f"[LLAMA] Selected: {asset_name}"
)
if not archive_path.exists():
print(
"[LLAMA] Downloading archive..."
)
headers = {
"User-Agent":
"hf-space-qwen-llama-server"
}
with requests.get(
download_url,
headers=headers,
stream=True,
timeout=120
) as response:
response.raise_for_status()
total = int(
response.headers.get(
"content-length",
0
)
)
downloaded = 0
last_print = 0
with open(
archive_path,
"wb"
) as f:
for chunk in response.iter_content(
chunk_size=1024 * 1024
):
if not chunk:
continue
f.write(chunk)
downloaded += len(
chunk
)
if total:
now = time.time()
if now - last_print >= 0.5:
percent = (
downloaded
* 100
/ total
)
print(
f"\r[LLAMA] "
f"{percent:5.1f}% "
f"{downloaded / 1024 / 1024:.1f} MB / "
f"{total / 1024 / 1024:.1f} MB",
end="",
flush=True
)
last_print = now
print()
print(
"[LLAMA] Archive download complete."
)
else:
print(
"[LLAMA] Archive already exists."
)
if LLAMA_EXTRACT_DIR.exists():
shutil.rmtree(
LLAMA_EXTRACT_DIR
)
LLAMA_EXTRACT_DIR.mkdir(
parents=True,
exist_ok=True
)
print(
"[LLAMA] Extracting..."
)
if asset_name.lower().endswith(
".tar.gz"
):
with tarfile.open(
archive_path,
"r:gz"
) as tar:
tar.extractall(
LLAMA_EXTRACT_DIR
)
elif asset_name.lower().endswith(
".zip"
):
with zipfile.ZipFile(
archive_path,
"r"
) as z:
z.extractall(
LLAMA_EXTRACT_DIR
)
else:
raise RuntimeError(
f"Unsupported archive: {asset_name}"
)
found = find_llama_server(
LLAMA_EXTRACT_DIR
)
if found is None:
for path in LLAMA_EXTRACT_DIR.rglob(
"*"
):
if path.is_file():
print(
path
)
raise RuntimeError(
"llama-server was not found "
"inside the archive."
)
print(
f"[LLAMA] Found: {found}"
)
source_dir = found.parent
LLAMA_DIR.mkdir(
parents=True,
exist_ok=True
)
for item in source_dir.iterdir():
destination = (
LLAMA_DIR /
item.name
)
if item.is_dir():
if destination.exists():
shutil.rmtree(
destination
)
shutil.copytree(
item,
destination
)
else:
shutil.copy2(
item,
destination
)
final_server = (
LLAMA_DIR /
found.name
)
if not final_server.exists():
raise RuntimeError(
"Failed to install llama-server."
)
final_server.chmod(
final_server.stat().st_mode
| stat.S_IXUSR
| stat.S_IXGRP
| stat.S_IXOTH
)
library_dirs = []
for root, dirs, files in os.walk(
LLAMA_DIR
):
for filename in files:
if (
filename.endswith(".so")
or ".so." in filename
):
library_dirs.append(
root
)
break
library_dirs = list(
dict.fromkeys(
library_dirs
)
)
if library_dirs:
old_ld = os.environ.get(
"LD_LIBRARY_PATH",
""
)
new_ld = ":".join(
library_dirs
)
if old_ld:
os.environ[
"LD_LIBRARY_PATH"
] = (
new_ld
+ ":"
+ old_ld
)
else:
os.environ[
"LD_LIBRARY_PATH"
] = new_ld
print(
"[LLAMA] Libraries configured."
)
print(
f"[LLAMA] Server installed: "
f"{final_server}"
)
return str(
final_server
)
def start_llama_server():
global server_process
with server_lock:
if server_process is not None:
if (
server_process.poll()
is None
):
return
server_path = (
download_llama_server()
)
command = [
server_path,
"-m",
str(MODEL_PATH),
"-np",
str(PARALLEL_USERS),
"-c",
str(TOTAL_CONTEXT),
"--cont-batching",
"-ngl",
"0",
"-t",
str(CPU_THREADS),
"-tb",
str(CPU_THREADS_BATCH),
"-b",
str(BATCH_SIZE),
"--host",
SERVER_HOST,
"--port",
str(SERVER_PORT),
"--api-key",
API_KEY
]
print(
"[LLAMA] Starting server..."
)
server_process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
env=os.environ.copy()
)
def read_logs():
try:
for line in iter(
server_process.stdout.readline,
""
):
if line:
print(
"[llama.cpp]",
line.rstrip()
)
except Exception:
pass
threading.Thread(
target=read_logs,
daemon=True
).start()
health_url = (
f"http://{SERVER_HOST}:"
f"{SERVER_PORT}/health"
)
print(
"[LLAMA] Waiting for server..."
)
started = time.time()
while True:
if (
server_process is not None
and server_process.poll()
is not None
):
raise RuntimeError(
"llama-server stopped "
f"with code "
f"{server_process.returncode}"
)
try:
response = requests.get(
health_url,
timeout=2
)
if response.status_code in (
200,
204
):
print(
"[LLAMA] Server is ready."
)
return
except Exception:
pass
if (
time.time() - started
> 180
):
raise RuntimeError(
"Timed out waiting for llama-server."
)
time.sleep(1)
def clean_content(content):
if content is None:
return ""
if isinstance(
content,
str
):
return content
if isinstance(
content,
list
):
result = []
for item in content:
if isinstance(
item,
str
):
result.append(
item
)
elif isinstance(
item,
dict
):
if "text" in item:
result.append(
str(
item["text"]
)
)
elif "content" in item:
result.append(
str(
item["content"]
)
)
else:
result.append(
str(item)
)
return "\n".join(
x for x in result
if x
)
if isinstance(
content,
dict
):
if "text" in content:
return str(
content["text"]
)
if "content" in content:
return str(
content["content"]
)
return json.dumps(
content,
ensure_ascii=False
)
return str(content)
def build_messages(
message,
history
):
messages = []
history = history or []
recent_history = history[-10:]
for item in recent_history:
if not isinstance(
item,
dict
):
continue
role = item.get(
"role"
)
content = clean_content(
item.get(
"content",
""
)
)
if role in (
"user",
"assistant",
"system"
) and content:
messages.append({
"role":
role,
"content":
content
})
messages.append({
"role":
"user",
"content":
clean_content(
message
)
})
return messages
def generate_response(
message,
history
):
if not message:
return "Please enter a message."
messages = build_messages(
message,
history
)
url = (
f"http://{SERVER_HOST}:"
f"{SERVER_PORT}/v1/chat/completions"
)
payload = {
"model":
"qwen2.5-coder-3b",
"messages":
messages,
"temperature":
TEMPERATURE,
"top_p":
TOP_P,
"max_tokens":
MAX_TOKENS,
"stream":
False
}
headers = {
"Content-Type":
"application/json",
"Authorization":
f"Bearer {API_KEY}"
}
try:
response = requests.post(
url,
headers=headers,
json=payload,
timeout=300
)
except requests.RequestException as e:
return (
"Server connection error:\n\n"
f"{e}"
)
if response.status_code != 200:
try:
data = response.json()
return (
"llama.cpp error:\n\n"
+ json.dumps(
data,
indent=2,
ensure_ascii=False
)
)
except Exception:
return (
f"llama.cpp HTTP "
f"{response.status_code}\n\n"
f"{response.text}"
)
try:
data = response.json()
choices = data.get(
"choices",
[]
)
if not choices:
return "No response generated."
choice = choices[0]
message_data = choice.get(
"message",
{}
)
result = message_data.get(
"content",
""
)
if not result:
result = choice.get(
"text",
""
)
return result.strip()
except Exception as e:
return (
"Response parsing error:\n\n"
f"{e}\n\n"
f"{response.text}"
)
def create_ui():
demo = gr.ChatInterface(
fn=generate_response,
concurrency_limit=PARALLEL_USERS
)
return demo
def initialize():
print(
"============================================================"
)
print(
"Qwen2.5-Coder-3B llama.cpp server"
)
print(
"============================================================"
)
print(
f"[CONFIG] Users: {PARALLEL_USERS}"
)
print(
f"[CONFIG] Context/user: {CONTEXT_PER_USER}"
)
print(
f"[CONFIG] CPU threads: {CPU_THREADS}"
)
print(
f"[CONFIG] Batch threads: {CPU_THREADS_BATCH}"
)
print(
f"[CONFIG] Batch size: {BATCH_SIZE}"
)
print(
f"[CONFIG] Max tokens: {MAX_TOKENS}"
)
print(
"============================================================"
)
download_model()
download_llama_server()
start_llama_server()
print(
"============================================================"
)
print(
"INITIALIZATION COMPLETE"
)
print(
f"Model: {MODEL_FILE}"
)
print(
f"Users: {PARALLEL_USERS}"
)
print(
f"Context/user: {CONTEXT_PER_USER}"
)
print(
f"CPU threads: {CPU_THREADS}"
)
print(
"============================================================"
)
def shutdown():
global server_process
print(
"[SYSTEM] Shutting down..."
)
if server_process is None:
return
try:
if (
server_process.poll()
is None
):
server_process.terminate()
try:
server_process.wait(
timeout=5
)
except subprocess.TimeoutExpired:
server_process.kill()
except Exception as e:
print(
f"[SYSTEM] Shutdown error: {e}"
)
if __name__ == "__main__":
try:
initialize()
demo = create_ui()
demo.queue(
default_concurrency_limit=
PARALLEL_USERS
)
demo.launch(
server_name=
GRADIO_HOST,
server_port=
GRADIO_PORT,
show_error=True,
max_threads=
PARALLEL_USERS + 4,
share=False
)
except KeyboardInterrupt:
print(
"[SYSTEM] Interrupted."
)
except Exception as e:
print(
"============================================================"
)
print(
"STARTUP FAILED"
)
print(
repr(e)
)
print(
"============================================================"
)
raise
finally:
shutdown()