Download api/predict.py from Unit4IAI/Fuse-MD: direct link, hf CLI and curl.
- Browser
- Download file 3.88 kB
-
https://huggingface.co/spaces/Unit4IAI/Fuse-MD/resolve/main/api/predict.py
- Command line
-
hf download hf://spaces/Unit4IAI/Fuse-MD/api/predict.py
-
curl -L -o predict.py https://huggingface.co/spaces/Unit4IAI/Fuse-MD/resolve/main/api/predict.py
3.88 kB
| import argparse | |
| import json | |
| import sys | |
| import urllib.error | |
| import urllib.parse | |
| import urllib.request | |
| import uuid | |
| from pathlib import Path | |
| from typing import Optional | |
| from local_config import load_local_api_config | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser( | |
| description="Send a local prediction request to the Fuse-MD FastAPI server." | |
| ) | |
| parser.add_argument( | |
| "--image", | |
| required=True, | |
| help="Path to the image file to upload.", | |
| ) | |
| parser.add_argument( | |
| "--text", | |
| required=True, | |
| help="Text or OCR transcription for the meme.", | |
| ) | |
| parser.add_argument( | |
| "--threshold", | |
| type=float, | |
| help="Optional threshold override for this request.", | |
| ) | |
| parser.add_argument( | |
| "--url", | |
| help="Prediction endpoint URL. Defaults to the local API URL from api/local_config.py.", | |
| ) | |
| return parser.parse_args() | |
| def default_predict_url() -> str: | |
| config = load_local_api_config() | |
| return f"http://{config.host}:{config.port}/predict" | |
| def encode_multipart_form( | |
| *, | |
| text: str, | |
| image_path: Path, | |
| image_bytes: bytes, | |
| threshold: Optional[float], | |
| ) -> tuple[bytes, str]: | |
| boundary = f"fusemd-{uuid.uuid4().hex}" | |
| lines: list[bytes] = [] | |
| def add_field(name: str, value: str) -> None: | |
| lines.extend( | |
| [ | |
| f"--{boundary}".encode("utf-8"), | |
| f'Content-Disposition: form-data; name="{name}"'.encode("utf-8"), | |
| b"", | |
| value.encode("utf-8"), | |
| ] | |
| ) | |
| add_field("text", text) | |
| if threshold is not None: | |
| add_field("threshold", str(threshold)) | |
| lines.extend( | |
| [ | |
| f"--{boundary}".encode("utf-8"), | |
| ( | |
| f'Content-Disposition: form-data; name="image"; filename="{image_path.name}"' | |
| ).encode("utf-8"), | |
| b"Content-Type: application/octet-stream", | |
| b"", | |
| image_bytes, | |
| f"--{boundary}--".encode("utf-8"), | |
| b"", | |
| ] | |
| ) | |
| body = b"\r\n".join(lines) | |
| return body, boundary | |
| def main() -> int: | |
| args = parse_args() | |
| image_path = Path(args.image) | |
| if not image_path.is_absolute(): | |
| image_path = (Path.cwd() / image_path).resolve() | |
| if not image_path.exists(): | |
| print(f"Image not found: {image_path}") | |
| return 1 | |
| if not image_path.is_file(): | |
| print(f"Image path is not a file: {image_path}") | |
| return 1 | |
| image_bytes = image_path.read_bytes() | |
| url = args.url or default_predict_url() | |
| body, boundary = encode_multipart_form( | |
| text=args.text, | |
| image_path=image_path, | |
| image_bytes=image_bytes, | |
| threshold=args.threshold, | |
| ) | |
| request = urllib.request.Request( | |
| url=url, | |
| data=body, | |
| method="POST", | |
| headers={ | |
| "Content-Type": f"multipart/form-data; boundary={boundary}", | |
| "Content-Length": str(len(body)), | |
| }, | |
| ) | |
| try: | |
| with urllib.request.urlopen(request) as response: | |
| payload = json.loads(response.read().decode("utf-8")) | |
| print(json.dumps(payload, indent=2)) | |
| return 0 | |
| except urllib.error.HTTPError as exc: | |
| detail = exc.read().decode("utf-8", errors="replace") | |
| print(f"API request failed with status {exc.code}.") | |
| print(detail) | |
| return 1 | |
| except urllib.error.URLError as exc: | |
| parsed = urllib.parse.urlparse(url) | |
| base_url = f"{parsed.scheme}://{parsed.netloc}" if parsed.scheme and parsed.netloc else url | |
| print(f"Could not connect to Fuse-MD API at {base_url}.") | |
| print("Start it first with: python api/run_api.py") | |
| print(f"Connection error: {exc.reason}") | |
| return 1 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |