Spaces:
Running on Zero
Running on Zero
Download src/tracing.py from whosouravsharma/diffusiondb-sd15-lora: direct link, hf CLI and curl.
- Browser
- Download file 8.06 kB
-
https://huggingface.co/spaces/whosouravsharma/diffusiondb-sd15-lora/resolve/main/src/tracing.py
- Command line
-
hf download hf://spaces/whosouravsharma/diffusiondb-sd15-lora/src/tracing.py
-
curl -L -o tracing.py https://huggingface.co/spaces/whosouravsharma/diffusiondb-sd15-lora/resolve/main/src/tracing.py
8.06 kB
| """Optional LangSmith tracing and structured logging for the UI Space. | |
| Mirrors the inference Space's src/tracing.py: everything here degrades to a | |
| no-op. If `langsmith` is not installed, or LANGSMITH_TRACING is not "true", | |
| the decorator becomes an identity function and the helpers do nothing. | |
| export LANGSMITH_TRACING=true | |
| export LANGSMITH_API_KEY=<key> | |
| export LANGSMITH_PROJECT=diffusiondb-sd15-lora-inference | |
| This is the only place that can see the actual visitor. The inference Space | |
| is called server-to-server from here, so from its side every request appears | |
| to come from this Space; the caller's address exists only in this process. | |
| Visitor IP and IP-derived location are personal data in the EU/UK and several | |
| US states. LANGSMITH_LOG_IP=off drops the raw address while keeping the | |
| coarse city/region/country, which is usually enough for analytics. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import os | |
| import time | |
| from typing import Any, Callable | |
| logger = logging.getLogger("diffusiondb.ui") | |
| try: | |
| from src import geo | |
| except ImportError: # written separately; treat as simply unavailable | |
| geo = None | |
| def _env_flag(name: str, default: str = "") -> bool: | |
| return os.environ.get(name, default).strip().lower() in {"1", "true", "yes", "on"} | |
| TRACING_ENABLED = _env_flag("LANGSMITH_TRACING") | |
| LOG_IP = os.environ.get("LANGSMITH_LOG_IP", "on").strip().lower() not in { | |
| "0", "false", "no", "off", | |
| } | |
| _langsmith: Any = None | |
| if TRACING_ENABLED: | |
| try: | |
| import langsmith as _langsmith # noqa: F401 | |
| except ImportError: | |
| logger.warning( | |
| "LANGSMITH_TRACING is set but the langsmith package is not " | |
| "installed; running untraced. pip install langsmith" | |
| ) | |
| _langsmith = None | |
| else: | |
| if not os.environ.get("LANGSMITH_API_KEY"): | |
| logger.warning("LANGSMITH_TRACING is set but LANGSMITH_API_KEY is empty.") | |
| TRACING_ACTIVE = _langsmith is not None | |
| def traceable(**decorator_kwargs: Any) -> Callable: | |
| """`langsmith.traceable` when tracing is on, identity decorator otherwise.""" | |
| if not TRACING_ACTIVE: | |
| def passthrough(func: Callable) -> Callable: | |
| return func | |
| return passthrough | |
| return _langsmith.traceable(**decorator_kwargs) | |
| def add_trace_metadata(**fields: Any) -> None: | |
| """Attach key/values to the run currently in scope. No-op when untraced.""" | |
| if not TRACING_ACTIVE or not fields: | |
| return | |
| try: | |
| run = _langsmith.get_current_run_tree() | |
| if run is not None: | |
| run.extra.setdefault("metadata", {}).update(fields) | |
| except Exception: # never let telemetry break a generation | |
| logger.debug("could not attach trace metadata", exc_info=True) | |
| def _header(request: Any, name: str) -> str: | |
| """Case-insensitive header read that tolerates any request shape.""" | |
| try: | |
| headers = getattr(request, "headers", None) or {} | |
| getter = getattr(headers, "get", None) | |
| if getter is not None: | |
| value = getter(name) or getter(name.title()) | |
| if value: | |
| return str(value) | |
| lowered = {str(k).lower(): v for k, v in dict(headers).items()} | |
| return str(lowered.get(name.lower(), "") or "") | |
| except Exception: | |
| return "" | |
| def caller_ip(request: Any) -> str: | |
| """The visitor's address, not the proxy's. | |
| Spaces sit behind a reverse proxy, so request.client.host is always the | |
| proxy. The original address is the first entry of x-forwarded-for; the | |
| rest of that list is the proxy chain. | |
| """ | |
| forwarded = _header(request, "x-forwarded-for") | |
| if forwarded: | |
| return forwarded.split(",")[0].strip() | |
| real = _header(request, "x-real-ip") | |
| if real: | |
| return real.strip() | |
| try: | |
| return str(getattr(getattr(request, "client", None), "host", "") or "") | |
| except Exception: | |
| return "" | |
| def describe_caller(request: Any) -> dict: | |
| """Flat dict of what is known about the visitor. Never raises.""" | |
| if request is None: | |
| return {} | |
| try: | |
| info: dict[str, Any] = {} | |
| ip = caller_ip(request) | |
| if ip and LOG_IP: | |
| info["ip"] = ip | |
| if geo is not None and ip: | |
| # lookup() returns {} for private ranges and on any failure. | |
| info.update(geo.lookup(ip)) | |
| user_agent = _header(request, "user-agent") | |
| if user_agent: | |
| info["user_agent"] = user_agent[:200] | |
| language = _header(request, "accept-language") | |
| if language: | |
| info["language"] = language.split(",")[0].strip() | |
| session = getattr(request, "session_hash", None) | |
| if session: | |
| info["session"] = str(session) | |
| return info | |
| except Exception: | |
| logger.debug("could not describe caller", exc_info=True) | |
| return {} | |
| def _trace_inputs(inputs: dict) -> dict: | |
| """Drop the unserialisable client and the raw request object. | |
| The request carries every header; only the fields chosen by | |
| describe_caller belong in a trace, and they go on as metadata instead. | |
| """ | |
| return { | |
| key: value for key, value in inputs.items() | |
| if key not in {"client", "request"} | |
| } | |
| def _trace_outputs(result: Any) -> dict: | |
| """Record the seed, never the image. | |
| LangSmith calls this with None when the wrapped call raised, so a bare | |
| unpack here would log a processing error on top of every failure. | |
| """ | |
| if result is None: | |
| return {} | |
| try: | |
| _, seed = result | |
| return {"seed": seed} | |
| except Exception: | |
| return {} | |
| def distributed_headers() -> dict: | |
| """HTTP headers that let the backend join this trace. | |
| `langsmith-trace` carries the parent run id, `baggage` carries this run's | |
| metadata -- which is why the caller's city/region/country end up on the | |
| backend's own run as well as this one, rather than only here. | |
| Must be called AFTER add_trace_metadata, or baggage ships without it. | |
| """ | |
| if not TRACING_ACTIVE: | |
| return {} | |
| try: | |
| run = _langsmith.get_current_run_tree() | |
| return dict(run.to_headers()) if run is not None else {} | |
| except Exception: | |
| logger.debug("could not build distributed trace headers", exc_info=True) | |
| return {} | |
| def traced_predict(client, *, prompt, negative, steps, guidance, lora_scale, | |
| seed, request=None): | |
| """Call the inference Space, recording the request and who made it.""" | |
| caller = describe_caller(request) | |
| add_trace_metadata(**caller) | |
| args = (prompt, negative, steps, guidance, lora_scale, seed) | |
| headers = distributed_headers() | |
| started = time.perf_counter() | |
| try: | |
| image, used = client.predict(*args, api_name="/generate", | |
| headers=headers or None) | |
| except TypeError: | |
| # Older gradio_client has no per-call headers parameter. Losing the | |
| # linkage is not worth losing the generation over -- the two runs | |
| # just land as separate traces. | |
| logger.debug("gradio_client does not accept per-call headers") | |
| image, used = client.predict(*args, api_name="/generate") | |
| duration_ms = (time.perf_counter() - started) * 1000 | |
| logger.info( | |
| "ui request seed=%s steps=%s lora_scale=%s ms=%.0f %s", | |
| used, steps, lora_scale, duration_ms, | |
| " ".join(f"{key}={value}" for key, value in sorted(caller.items())), | |
| ) | |
| return image, used | |
| def configure_logging(level: str | None = None) -> None: | |
| """Single-line structured logs. Safe to call more than once.""" | |
| if logger.handlers: | |
| return | |
| handler = logging.StreamHandler() | |
| handler.setFormatter( | |
| logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s") | |
| ) | |
| logger.addHandler(handler) | |
| logger.setLevel(level or os.environ.get("LOG_LEVEL", "INFO").upper()) | |
| logger.propagate = False | |