voice_audio_multi/tests/fixtures/native_model_manager_server.py
Fabio c36510c21e
Some checks failed
Linux Build / Linux cpu (push) Has been cancelled
Linux Build / Linux cpu-clang (push) Has been cancelled
Linux Build / Linux vulkan (push) Has been cancelled
mac-build / macOS CPU (push) Has been cancelled
Nix Build / Nix (cpu) (push) Has been cancelled
Nix Build / Nix (vulkan) (push) Has been cancelled
windows-build / Windows CPU (push) Has been cancelled
Initial import: audio.cpp with Orange Pi documentation
2026-11-04 19:05:22 +01:00

160 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""Local HTTP fixture for server_model_installer_test; never used at runtime."""
import argparse
import hashlib
import json
import threading
import time
import urllib.parse
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
FILES = {
"/org/repo/resolve/main/Demo/model-q8.gguf": b"q8-model-payload",
"/org/repo/resolve/main/Demo/model-f16.gguf": b"f16-model-payload",
"/org/repo/resolve/main/Demo/shared.json": b'{"shared":true}\n',
"/org/repo/resolve/main/Slow/model.gguf": b"s" * (16 * 1024 * 1024),
"/org/repo/resolve/main/Slow/sibling.gguf": b"t" * (16 * 1024 * 1024),
}
# ModelScope-style repo: default branch is master, and the file-list API is
# the source of truth for per-file size and sha256.
MS_REPO = "ms/repo"
MS_REVISION = "master"
MS_FILES = {
"Demo/model-q8.gguf": b"q8-model-payload",
"Demo/shared.json": b'{"shared":true}\n',
}
def ms_listing_payload():
files = [
{
"Path": path,
"Size": len(payload),
"Sha256": hashlib.sha256(payload).hexdigest(),
"Type": "blob",
}
for path, payload in sorted(MS_FILES.items())
]
return json.dumps({"Code": 200, "Success": True, "Data": {"Files": files}}).encode()
class Handler(BaseHTTPRequestHandler):
def do_HEAD(self):
self.respond(False)
def do_GET(self):
self.respond(True)
def respond(self, body):
parsed = urllib.parse.urlsplit(self.path)
if parsed.path.startswith("/api/v1/models/"):
if not self.check_ms_auth():
return
self.respond_ms_listing(parsed, body)
return
if parsed.path.startswith("/models/"):
if not self.check_ms_auth():
return
self.respond_ms_resolve(parsed.path, body)
return
payload = FILES.get(self.path)
if payload is None:
self.send_error(404)
return
self.send_response(200)
self.send_header("Content-Length", str(len(payload)))
self.send_header("ETag", '"fixture-etag-' + str(len(payload)) + '"')
self.send_header("X-Repo-Commit", "fixture-commit")
self.end_headers()
self.write_payload(payload, body)
def check_ms_auth(self):
# ModelScope requests must never carry the Hugging Face credential;
# when --ms-token is given they must carry exactly that token.
auth = self.headers.get("Authorization", "")
hf_token = self.server.hf_token
ms_token = self.server.ms_token
if hf_token and auth == "Bearer " + hf_token:
self.send_error(403, "HF token leaked into a ModelScope request")
self.count_request()
return False
if ms_token and auth != "Bearer " + ms_token:
self.send_error(401, "ModelScope request missing its own token")
self.count_request()
return False
return True
def respond_ms_listing(self, parsed, body):
prefix = "/api/v1/models/" + MS_REPO + "/repo/files"
query = urllib.parse.parse_qs(parsed.query)
revision = query.get("Revision", [""])[0]
if parsed.path != prefix or revision != MS_REVISION:
self.send_error(404)
return
payload = ms_listing_payload()
self.send_response(200)
self.send_header("Content-Length", str(len(payload)))
self.send_header("Content-Type", "application/json")
self.end_headers()
self.write_payload(payload, body)
def respond_ms_resolve(self, path, body):
prefix = "/models/" + MS_REPO + "/resolve/" + MS_REVISION + "/"
if not path.startswith(prefix):
self.send_error(404)
return
payload = MS_FILES.get(path[len(prefix):])
if payload is None:
self.send_error(404)
return
etag = hashlib.sha256(payload).hexdigest()
self.send_response(200)
# Like real ModelScope resolve responses: no Content-Length and no
# ETag on HEAD, only X-Linked-Etag.
self.send_header("X-Linked-Etag", etag)
if body:
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.write_payload(payload, body)
def write_payload(self, payload, body):
if body:
try:
for offset in range(0, len(payload), 64 * 1024):
self.wfile.write(payload[offset : offset + 64 * 1024])
self.wfile.flush()
if len(payload) > 1024 * 1024:
time.sleep(0.003)
if len(payload) < 1024:
time.sleep(0.03)
except (BrokenPipeError, ConnectionResetError):
pass
self.count_request()
def count_request(self):
with self.server.remaining_lock:
self.server.remaining -= 1
if self.server.remaining <= 0:
threading.Thread(target=self.server.shutdown, daemon=True).start()
def log_message(self, *_args):
pass
parser = argparse.ArgumentParser()
parser.add_argument("--requests", type=int, default=14)
parser.add_argument("--port", type=int, default=18991)
parser.add_argument("--hf-token", default="")
parser.add_argument("--ms-token", default="")
args = parser.parse_args()
server = ThreadingHTTPServer(("127.0.0.1", args.port), Handler)
server.remaining = args.requests
server.remaining_lock = threading.Lock()
server.hf_token = args.hf_token
server.ms_token = args.ms_token
timeout = threading.Timer(30, server.shutdown)
timeout.daemon = True
timeout.start()
server.serve_forever()