deploy/mainnet: add PiperTTS (private) + supplier-tts (audio.synthesize.piper.v1)
Mirrors deploy/testnet/docker-compose.supplier-tts.yml and the simulation PiperTTS stack, co-located on vector-marketplace as a private internal service on marketplace-mainnet-net (no Traefik labels, no public DNS for Piper itself). Supplier reaches Piper at http://marketplace-mainnet-tts-piper:8000. Voice: en_US-lessac-high. New supplier wallet + on-chain advert are published out-of-band by the operator per the runbook header. Files: - deploy/mainnet/docker-compose.tts-piper.yml openedai-speech-min, private - deploy/mainnet/docker-compose.supplier-tts.yml CAPABILITY_KIND=tts supplier - deploy/mainnet/install-voice-extras.sh voice download + yaml mapping - deploy/mainnet/voice-mappings.py idempotent yaml editor - supplier/.env.tts.example operator env template - .gitignore whitelist .env.*.example Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,10 +4,11 @@ dist
|
|||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
# Environments — never commit; .env.example is the published template
|
# Environments — never commit; .env.example / .env.*.example are templates
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
||||||
|
!.env.*.example
|
||||||
|
|
||||||
# Local data / caches (matches at any depth — covers
|
# Local data / caches (matches at any depth — covers
|
||||||
# deploy/simulation/data/, indexer/data/, etc.)
|
# deploy/simulation/data/, indexer/data/, etc.)
|
||||||
|
|||||||
81
deploy/mainnet/docker-compose.supplier-tts.yml
Normal file
81
deploy/mainnet/docker-compose.supplier-tts.yml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# deploy/mainnet/docker-compose.supplier-tts.yml — TTS Supplier — MAINNET
|
||||||
|
#
|
||||||
|
# Third mainnet supplier, dedicated to capability `audio.synthesize.piper.v1`.
|
||||||
|
# Reaches the colocated PRIVATE PiperTTS container at the docker-DNS name
|
||||||
|
# `marketplace-mainnet-tts-piper:8000`. Traefik publishes it at
|
||||||
|
# `mp-suppliers-tts.vector.apexfusion.org`. Coexists with the ollama-backed
|
||||||
|
# (docker-compose.supplier.yml) and ChatGPT-backed (docker-compose.supplier-gpt.yml)
|
||||||
|
# suppliers.
|
||||||
|
#
|
||||||
|
# Pre-flight networks (must already exist):
|
||||||
|
# docker network create marketplace-mainnet-net # one-shot
|
||||||
|
# # traefik-net is created by the Traefik project
|
||||||
|
#
|
||||||
|
# Pre-flight services:
|
||||||
|
# docker compose -f docker-compose.tts-piper.yml up -d
|
||||||
|
# bash deploy/mainnet/install-voice-extras.sh # one-shot voice install
|
||||||
|
#
|
||||||
|
# Bring up:
|
||||||
|
# docker compose -f deploy/mainnet/docker-compose.supplier-tts.yml up -d --build
|
||||||
|
|
||||||
|
name: marketplace-mainnet-supplier-tts
|
||||||
|
|
||||||
|
services:
|
||||||
|
supplier:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: supplier/Dockerfile
|
||||||
|
container_name: marketplace-mainnet-supplier-tts
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
# Self-contained env for the TTS variant — kept separate from the
|
||||||
|
# canonical ../../supplier/.env (ollama-backed) and ../../supplier/.env.gpt
|
||||||
|
# (ChatGPT-backed). Holds this supplier's distinct SUPPLIER_PRIV_KEY_HEX,
|
||||||
|
# ADVERT_REF, ADVERT_*, and the shared mainnet plumbing duplicated
|
||||||
|
# in full (NETWORK_ID, OGMIOS_URL, VECTOR_ZERO_TIME_MS, ref-script
|
||||||
|
# UTxOs, LIVE_CHAIN). No env_file ordering / override magic.
|
||||||
|
- path: ../../supplier/.env.tts
|
||||||
|
required: false
|
||||||
|
environment:
|
||||||
|
CAPABILITY_KIND: "tts"
|
||||||
|
# Internal docker-DNS — Piper is private on marketplace-mainnet-net,
|
||||||
|
# no public hostname for it.
|
||||||
|
PIPER_URL: "http://marketplace-mainnet-tts-piper:8000"
|
||||||
|
PORT: "8080"
|
||||||
|
# Enable LiveOgmiosProvider so submitTx/awaitTx actually broadcast.
|
||||||
|
# Mirrors the other mainnet supplier composes; without this the
|
||||||
|
# supplier silently falls back to ReadOnlyOgmiosProvider and
|
||||||
|
# Claim/Submit never reach chain.
|
||||||
|
LIVE_CHAIN: "1"
|
||||||
|
# NETWORK_ID and OGMIOS_URL intentionally not pinned here — they MUST
|
||||||
|
# come from the operator-provided supplier/.env.tts on a mainnet host.
|
||||||
|
# Setting them via compose would be a footgun: a stray re-up on
|
||||||
|
# testnet hardware could silently re-tag the supplier as mainnet.
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/healthz >/dev/null || exit 1"]
|
||||||
|
interval: 20s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 15s
|
||||||
|
networks:
|
||||||
|
- marketplace-mainnet-net
|
||||||
|
- traefik-net
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=traefik-net"
|
||||||
|
- "traefik.http.routers.mp-suppliers-tts-mainnet.entrypoints=web"
|
||||||
|
- "traefik.http.routers.mp-suppliers-tts-mainnet.rule=Host(`mp-suppliers-tts.vector.apexfusion.org`)"
|
||||||
|
- "traefik.http.services.mp-suppliers-tts-mainnet.loadbalancer.server.port=8080"
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
marketplace-mainnet-net:
|
||||||
|
external: true
|
||||||
|
name: marketplace-mainnet-net
|
||||||
|
traefik-net:
|
||||||
|
external: true
|
||||||
|
name: traefik-net
|
||||||
61
deploy/mainnet/docker-compose.tts-piper.yml
Normal file
61
deploy/mainnet/docker-compose.tts-piper.yml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# deploy/mainnet/docker-compose.tts-piper.yml — PiperTTS (PRIVATE) — MAINNET
|
||||||
|
#
|
||||||
|
# OpenAI-shape /v1/audio/speech served by openedai-speech-min, reachable
|
||||||
|
# ONLY from inside marketplace-mainnet-net. No Traefik labels, no public
|
||||||
|
# DNS — the colocated marketplace-mainnet-supplier-tts container hits it at
|
||||||
|
# http://marketplace-mainnet-tts-piper:8000
|
||||||
|
#
|
||||||
|
# Mirrors deploy/simulation/docker-compose.tts-piper.yml, but private:
|
||||||
|
# the simulation host exposes Piper publicly via Traefik+Cloudflare;
|
||||||
|
# mainnet keeps it on-net only since only the colocated TTS supplier
|
||||||
|
# consumes it.
|
||||||
|
#
|
||||||
|
# Pre-flight networks (must already exist):
|
||||||
|
# docker network create marketplace-mainnet-net # one-shot
|
||||||
|
#
|
||||||
|
# Bring up:
|
||||||
|
# docker compose -f deploy/mainnet/docker-compose.tts-piper.yml up -d
|
||||||
|
# bash deploy/mainnet/install-voice-extras.sh # download voices + yaml mapping
|
||||||
|
|
||||||
|
name: marketplace-mainnet-tts-piper
|
||||||
|
|
||||||
|
services:
|
||||||
|
tts-piper:
|
||||||
|
image: ghcr.io/matatonic/openedai-speech-min:latest
|
||||||
|
container_name: marketplace-mainnet-tts-piper
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
# Pre-load Piper's highest-quality American-English voice so first
|
||||||
|
# /v1/audio/speech doesn't pay the model-download tax. Other voices
|
||||||
|
# can be added via install-voice-extras.sh + voice-mappings.py.
|
||||||
|
PRELOAD_MODEL: en_US-lessac-high
|
||||||
|
PORT: "8000"
|
||||||
|
volumes:
|
||||||
|
# Host bind mounts (not Docker named volumes) so the operator can
|
||||||
|
# ls/du/back up the downloaded Piper voices directly. Paths relative
|
||||||
|
# to THIS compose file, i.e. deploy/mainnet/data/tts-piper/{voices,config}
|
||||||
|
# from the repo root. install-voice-extras.sh creates them.
|
||||||
|
- ./data/tts-piper/voices:/app/voices
|
||||||
|
- ./data/tts-piper/config:/app/config
|
||||||
|
healthcheck:
|
||||||
|
# /v1/models is the OpenAI-shape model list; a 200 here proves the
|
||||||
|
# server is up and at least one voice is loaded. Image ships with
|
||||||
|
# curl (and python3) but NOT wget — using wget here marks the
|
||||||
|
# container unhealthy on every probe.
|
||||||
|
test: ["CMD-SHELL", "curl -fsS http://localhost:8000/v1/models >/dev/null || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 90s
|
||||||
|
networks:
|
||||||
|
- marketplace-mainnet-net # PRIVATE — no traefik-net join
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
marketplace-mainnet-net:
|
||||||
|
external: true
|
||||||
|
name: marketplace-mainnet-net
|
||||||
74
deploy/mainnet/install-voice-extras.sh
Executable file
74
deploy/mainnet/install-voice-extras.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# install-voice-extras.sh — runs ON THE HOST (vector-marketplace, as root)
|
||||||
|
# after `docker compose -f deploy/mainnet/docker-compose.tts-piper.yml up -d`
|
||||||
|
# to install Piper voices and yaml mappings beyond what the
|
||||||
|
# openedai-speech-min image ships with.
|
||||||
|
#
|
||||||
|
# Idempotent: every step is a no-op if it already finished previously.
|
||||||
|
# Safe to re-run after a host wipe — a fresh `data/` dir gets the same
|
||||||
|
# voices back.
|
||||||
|
#
|
||||||
|
# Mirrors deploy/simulation/install-voice-extras.sh; differs only in:
|
||||||
|
# - CONTAINER name (mainnet-prefixed)
|
||||||
|
# - resolves VOICES_DIR + voice-mappings.py relative to deploy/mainnet/
|
||||||
|
#
|
||||||
|
# What it does (in order):
|
||||||
|
# 1. Ensure the bind-mount voice files are present (curl -sSL with `[ -s ]` guard).
|
||||||
|
# 2. Copy voice-mappings.py into the container and execute it as root.
|
||||||
|
# The script edits /app/config/voice_to_speaker.yaml (host bind-mount) to
|
||||||
|
# add custom voice aliases. It prints "modified" or "unchanged" — we
|
||||||
|
# restart only on the former.
|
||||||
|
# 3. Restart the container if either step changed something.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash deploy/mainnet/install-voice-extras.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MAINNET_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
VOICES_DIR="$MAINNET_DIR/data/tts-piper/voices"
|
||||||
|
CONTAINER="marketplace-mainnet-tts-piper"
|
||||||
|
|
||||||
|
mkdir -p "$VOICES_DIR"
|
||||||
|
changes=0
|
||||||
|
|
||||||
|
# --- 1. Voice files to install (filename → URL) ---
|
||||||
|
# Add entries here when you want another voice baked into the deploy.
|
||||||
|
# Each .onnx pairs with a .onnx.json — both must be downloaded.
|
||||||
|
voices=(
|
||||||
|
"en_US-lessac-high.onnx|https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/high/en_US-lessac-high.onnx"
|
||||||
|
"en_US-lessac-high.onnx.json|https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/lessac/high/en_US-lessac-high.onnx.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
for entry in "${voices[@]}"; do
|
||||||
|
fn="${entry%%|*}"
|
||||||
|
url="${entry##*|}"
|
||||||
|
if [ -s "$VOICES_DIR/$fn" ]; then
|
||||||
|
echo "voice: already installed — $fn"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "voice: downloading $fn"
|
||||||
|
# `--fail` so HTTP 4xx/5xx aborts (HF returns html on 404 by default).
|
||||||
|
# Download to a tmp file then mv, so a partial download from a network
|
||||||
|
# blip doesn't leave a half-file that the next run treats as installed.
|
||||||
|
tmp="$VOICES_DIR/.${fn}.partial"
|
||||||
|
curl -sSL --fail --output "$tmp" "$url"
|
||||||
|
mv "$tmp" "$VOICES_DIR/$fn"
|
||||||
|
changes=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 2. Yaml mapping additions inside the container ---
|
||||||
|
docker cp "$MAINNET_DIR/voice-mappings.py" "$CONTAINER:/tmp/voice-mappings.py" >/dev/null
|
||||||
|
mapping_output="$(docker exec "$CONTAINER" python3 /tmp/voice-mappings.py)"
|
||||||
|
echo "mapping: $mapping_output"
|
||||||
|
if [[ "$mapping_output" == modified* ]]; then
|
||||||
|
changes=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 3. Restart only if anything changed ---
|
||||||
|
if [ "$changes" -eq 1 ]; then
|
||||||
|
echo "→ restarting $CONTAINER to pick up new voices/mappings"
|
||||||
|
docker restart "$CONTAINER" >/dev/null
|
||||||
|
else
|
||||||
|
echo "✓ voice extras already up to date — no restart needed"
|
||||||
|
fi
|
||||||
60
deploy/mainnet/voice-mappings.py
Normal file
60
deploy/mainnet/voice-mappings.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# voice-mappings.py — idempotently apply project-specific voice aliases to
|
||||||
|
# /app/config/voice_to_speaker.yaml inside the marketplace-mainnet-tts-piper container.
|
||||||
|
#
|
||||||
|
# Why this exists:
|
||||||
|
# The openedai-speech-min image populates voice_to_speaker.yaml on first
|
||||||
|
# start with its OWN defaults (alloy/echo/fable/onyx/nova/shimmer mapped
|
||||||
|
# onto the bundled LibriTTS + northern-english-male voices). Voices we
|
||||||
|
# install ourselves (e.g. en_US-lessac-high) need a name in that yaml so
|
||||||
|
# the OpenAI-shape `voice` field can resolve to them. This script adds
|
||||||
|
# those entries — and only those — without disturbing the defaults.
|
||||||
|
#
|
||||||
|
# Idempotency contract:
|
||||||
|
# Reads the yaml, compares each desired entry against what's there, only
|
||||||
|
# rewrites if at least one entry is missing or stale. Prints "modified"
|
||||||
|
# on write, "unchanged" otherwise — install-voice-extras.sh greps for
|
||||||
|
# "modified" to decide whether to restart the container.
|
||||||
|
#
|
||||||
|
# Run via:
|
||||||
|
# docker cp voice-mappings.py marketplace-mainnet-tts-piper:/tmp/voice-mappings.py
|
||||||
|
# docker exec marketplace-mainnet-tts-piper python3 /tmp/voice-mappings.py
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
CONFIG_PATH = "/app/config/voice_to_speaker.yaml"
|
||||||
|
|
||||||
|
# Mappings to ensure exist under `tts-1`. Adding more voices later is a
|
||||||
|
# matter of dropping the .onnx + .onnx.json into voices/ (handled by
|
||||||
|
# install-voice-extras.sh) and adding an entry here.
|
||||||
|
DESIRED_TTS1 = {
|
||||||
|
# en_US-lessac-high — high-quality American female single-speaker voice.
|
||||||
|
# Single-speaker model, so no `speaker:` key.
|
||||||
|
"lessac": {"model": "voices/en_US-lessac-high.onnx"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
with open(CONFIG_PATH) as f:
|
||||||
|
cfg = yaml.safe_load(f) or {}
|
||||||
|
|
||||||
|
cfg.setdefault("tts-1", {})
|
||||||
|
|
||||||
|
modified_keys = []
|
||||||
|
for name, mapping in DESIRED_TTS1.items():
|
||||||
|
if cfg["tts-1"].get(name) != mapping:
|
||||||
|
cfg["tts-1"][name] = mapping
|
||||||
|
modified_keys.append(name)
|
||||||
|
|
||||||
|
if modified_keys:
|
||||||
|
with open(CONFIG_PATH, "w") as f:
|
||||||
|
yaml.safe_dump(cfg, f, sort_keys=False)
|
||||||
|
print(f"modified — applied: {', '.join(modified_keys)}")
|
||||||
|
else:
|
||||||
|
print("unchanged — all mappings already present")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
85
supplier/.env.tts.example
Normal file
85
supplier/.env.tts.example
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# supplier/.env.tts.example — TTS supplier (audio.synthesize.piper.v1) — MAINNET
|
||||||
|
#
|
||||||
|
# Copy to supplier/.env.tts on the vector-marketplace host (chmod 600),
|
||||||
|
# fill secrets, then follow the runbook in deploy/mainnet/docker-compose.supplier-tts.yml
|
||||||
|
# header. .env.tts is gitignored — NEVER commit a populated copy.
|
||||||
|
#
|
||||||
|
# To generate a fresh Ed25519 wallet:
|
||||||
|
# docker compose -f deploy/mainnet/docker-compose.supplier-tts.yml run --rm \
|
||||||
|
# --entrypoint sh supplier \
|
||||||
|
# -c "node_modules/.bin/tsx supplier/src/cli/gen-keypair.ts --network 1"
|
||||||
|
# Fund the printed addr1... with ~5 AP3X mainnet via the Vector faucet/exchange,
|
||||||
|
# THEN paste the privateKeyHex below.
|
||||||
|
|
||||||
|
# ─── Required ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# 64-char hex Ed25519 private key seed for the TTS supplier wallet. SECRET.
|
||||||
|
SUPPLIER_PRIV_KEY_HEX=PASTE_64_HEX_CHARS_HERE
|
||||||
|
|
||||||
|
# Cardano network ID. "1" = mainnet. Do NOT change this on the mainnet host.
|
||||||
|
NETWORK_ID=1
|
||||||
|
|
||||||
|
# Public Vector mainnet Ogmios. HTTPS for builders/queries; the supplier
|
||||||
|
# uses HTTP fetch (no WebSocket), so wss:// silently errors with
|
||||||
|
# "unknown scheme".
|
||||||
|
OGMIOS_URL=https://ogmios.vector.mainnet.apexfusion.org
|
||||||
|
|
||||||
|
# Vector mainnet genesis time (ms). lucid-evolution's slot-config reads
|
||||||
|
# this at module load — see packages/shared/src/tx/internal/lucidContext.ts
|
||||||
|
# header for the historical footgun.
|
||||||
|
VECTOR_ZERO_TIME_MS=1756485600000
|
||||||
|
|
||||||
|
# Shared mainnet CIP-33 reference scripts (published once; reused across all
|
||||||
|
# mainnet suppliers/buyers).
|
||||||
|
ESCROW_REF_UTXO=c8d84c6d67ec67a1efe5e9c6c06d53020e05d1bb96d1c55ecb1eb7d5010c4d54#0
|
||||||
|
ADVERT_REF_UTXO=c8d84c6d67ec67a1efe5e9c6c06d53020e05d1bb96d1c55ecb1eb7d5010c4d54#1
|
||||||
|
|
||||||
|
# Opt in to real Ogmios submitTx/awaitTx. Any value other than literal "1"
|
||||||
|
# leaves the supplier in ReadOnly mode (safety net).
|
||||||
|
LIVE_CHAIN=1
|
||||||
|
|
||||||
|
# OutputReference of THIS supplier's on-chain advertisement UTxO.
|
||||||
|
# Filled in AFTER running supplier/src/cli/post-advert.ts (see runbook step i).
|
||||||
|
# Format: "<64-hex-tx-hash>#<int-output-index>"
|
||||||
|
ADVERT_REF=PASTE_TXHASH_HERE#0
|
||||||
|
|
||||||
|
# ─── Advert content (read by post-advert.ts; also stored on-chain) ────────
|
||||||
|
|
||||||
|
# Capability published in the advertisement. Buyers filter on this string
|
||||||
|
# when picking a TTS supplier.
|
||||||
|
ADVERT_CAPABILITY_ID=audio.synthesize.piper.v1
|
||||||
|
|
||||||
|
# Informational model label. The actual voice is selected per-request in
|
||||||
|
# the body (`voice: lessac` etc.); this string just helps buyers identify
|
||||||
|
# the supplier in dashboards/UIs.
|
||||||
|
ADVERT_MODEL=piper-en_US-lessac-high
|
||||||
|
|
||||||
|
# Token budget — metadata-only for TTS. The runtime always reports 0 tokens
|
||||||
|
# in receipts (see supplier/src/jobRunner.ts `runTtsJob`). Verify against
|
||||||
|
# the live testnet TTS advert before publishing if you want strict parity:
|
||||||
|
# curl https://mp-indexer.vector.testnet.apexfusion.org/suppliers \
|
||||||
|
# | jq '.[] | select(.capability_id=="audio.synthesize.piper.v1") | .max_output_tokens'
|
||||||
|
ADVERT_MAX_OUTPUT_TOKENS=0
|
||||||
|
|
||||||
|
# Maximum processing time the supplier guarantees per synthesis (ms).
|
||||||
|
ADVERT_MAX_PROCESSING_MS=60000
|
||||||
|
|
||||||
|
# Flat price per synthesis in AP3X lovelace.
|
||||||
|
ADVERT_PRICE_LOVELACE=2000000
|
||||||
|
|
||||||
|
# Supplier bond locked into the advert UTxO (lovelace).
|
||||||
|
ADVERT_SUPPLIER_BOND_LOVELACE=1000000
|
||||||
|
|
||||||
|
# Buyer bond required per escrow (lovelace).
|
||||||
|
ADVERT_BUYER_BOND_LOVELACE=1000000
|
||||||
|
|
||||||
|
# HTTPS endpoint buyers will call. Must match the Traefik Host rule in
|
||||||
|
# deploy/mainnet/docker-compose.supplier-tts.yml.
|
||||||
|
ADVERT_ENDPOINT_URL=https://mp-suppliers-tts.vector.apexfusion.org
|
||||||
|
|
||||||
|
# Optional off-chain detail pointer (IPFS / HTTPS URI). Leave empty for v1.
|
||||||
|
ADVERT_DETAIL_URI=
|
||||||
|
|
||||||
|
# Optional sha256 of the detail JSON (64 hex chars). If empty, defaults to
|
||||||
|
# sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
|
||||||
|
ADVERT_DETAIL_HASH=
|
||||||
Reference in New Issue
Block a user