# ============================================================================= # AGIBOT A3 - Voice Control | configuration # ============================================================================= # Copy this file to `.env` and edit that copy. Nothing in the source code needs # to change to switch between the simulator and the real robot. # # Restart the server after editing, or press "Reload config" in the dashboard. # ============================================================================= # ----------------------------------------------------------------------------- # 1. WEB SERVER (this PC) # ----------------------------------------------------------------------------- # 127.0.0.1 = only this PC can open the dashboard (recommended). # 0.0.0.0 = other devices on your LAN can open it too (tablet, phone). HOST=127.0.0.1 PORT=8000 LOG_LEVEL=info # Only needed if you serve the frontend from a different origin. Usually empty. CORS_ORIGINS= # ----------------------------------------------------------------------------- # 2. ROBOT MODE <<< THIS IS THE SWITCH >>> # ----------------------------------------------------------------------------- # mock = simulated robot, no hardware required (default; use this today) # real = talk to a physical AGIBOT A3 over the network ROBOT_MODE=mock ROBOT_NAME=AGIBOT A3 ROBOT_MODEL=AgiBot A3 # ----------------------------------------------------------------------------- # 3. ROBOT ADDRESS <<< PUT THE ROBOT IP HERE WHEN YOU HAVE IT >>> # ----------------------------------------------------------------------------- # Leave ROBOT_IP empty while ROBOT_MODE=mock. # When the robot is powered on and on the same LAN: # ROBOT_MODE=real # ROBOT_IP=192.168.1.50 <- the robot's actual IP on YOUR network # ROBOT_PORT=59301 <- AgiBot's documented A3 TTS RPC port (HDU) # # NOTE: AgiBot's own examples use 10.42.10.10 - that is the robot's INTERNAL # address for its head unit (HDU) and is not reachable from your PC. Use the # HDU's address on your WiFi/LAN. Find it with: python scripts/discover_robot.py ROBOT_IP= ROBOT_PORT=59301 ROBOT_USE_TLS=false # Timing (seconds). Keep connect timeout short so the UI never feels stuck. ROBOT_CONNECT_TIMEOUT=3.0 ROBOT_REQUEST_TIMEOUT=8.0 ROBOT_HEALTH_INTERVAL=5.0 ROBOT_RECONNECT_MIN_DELAY=1.0 ROBOT_RECONNECT_MAX_DELAY=15.0 # ----------------------------------------------------------------------------- # 4. HOW TO TALK TO THE A3 # ----------------------------------------------------------------------------- # Only used when ROBOT_MODE=real. # # aimdk - AgiBot's documented A3 speech RPC <<< USE THIS, it is the default >>> # http - a generic HTTP/REST endpoint you specify yourself # ws - a WebSocket endpoint you specify yourself # ros2 - a ROS 2 topic or service (requires ROS 2 on this PC) # ssh - run a command on the robot over SSH (last-resort fallback) # # The `aimdk` transport implements the interface AgiBot documents for the A3: # POST http://:59301/rpc/aimdk.protocol.TTSService/PlayTTS # Content-Type: application/json # {"text": "...", "priority_level": "INTERACTION_L6", "domain": "...", # "trace_id": "...", "is_interrupted": true} # Docs: https://open.agibot.com/docs/en/aimdk/a3/v3_2/dev_guide/07-02-audio_play # # The defaults below come from that documentation, but they are still settings # rather than hard-coded values: AgiBot does not guarantee ports or names across # firmware, and there is no endpoint-discovery API. If your unit differs, change # it here - never in the source. See docs/AGIBOT_A3_INTEGRATION.md. A3_TRANSPORT=aimdk # --- 4a. AimDK transport (recommended) --------------------------------------- # Uses ROBOT_IP and ROBOT_PORT above. A3_AIMDK_SERVICE=aimdk.protocol.TTSService A3_AIMDK_PLAY_METHOD=PlayTTS A3_AIMDK_STOP_METHOD=StopTTSTraceId A3_AIMDK_STATUS_METHOD=GetAudioStatus # Playback priority. Only INTERACTION_L6 appears in AgiBot's A3 examples. A3_AIMDK_PRIORITY=INTERACTION_L6 # Free-form caller tag sent with each request, so robot-side logs show who spoke. A3_AIMDK_DOMAIN=voice_control # true = a new utterance interrupts whatever is currently playing. A3_AIMDK_INTERRUPT=true # Hard request limit documented by AgiBot: 1024 BYTES of UTF-8 (not characters). # Longer text is split automatically on sentence boundaries and sent in order. A3_AIMDK_MAX_BYTES=1024 # --- 4b. Generic HTTP / REST transport --------------------------------------- # Only needed if your unit does NOT use the AimDK interface above. # Path is relative to http://ROBOT_IP:ROBOT_PORT # Example shape only - replace with the documented endpoint: # A3_HTTP_SPEAK_PATH=/api/v1/tts/speak A3_HTTP_SPEAK_PATH= A3_HTTP_SPEAK_METHOD=POST # JSON body template. {text} is replaced with the operator's text. # Placeholders: {text} {id} {voice} {language} {volume} {speed} # A key whose value resolves to nothing is dropped from the request. A3_HTTP_SPEAK_PAYLOAD={"text": "{text}"} # Optional: endpoint that interrupts speech. A3_HTTP_STOP_PATH= A3_HTTP_STOP_METHOD=POST A3_HTTP_STOP_PAYLOAD={} # Optional: cheap endpoint polled for the connection indicator. # If left empty the app falls back to a TCP connect test on ROBOT_PORT. A3_HTTP_STATUS_PATH= A3_HTTP_STATUS_METHOD=GET # Optional: extra headers and auth. A3_HTTP_HEADERS={} A3_HTTP_AUTH_TOKEN= # Optional: dotted path to a success flag in the JSON response, e.g. "code" or # "result.success". Leave empty to trust the HTTP status code alone. A3_HTTP_SUCCESS_FIELD= # --- 4c. WebSocket transport -------------------------------------------------- A3_WS_PATH= A3_WS_SPEAK_PAYLOAD={"text": "{text}"} A3_WS_STOP_PAYLOAD={} A3_WS_PING_INTERVAL=20 # Optional: how the robot announces "finished speaking". With these set, the # dashboard shows real completion instead of an estimate. # A3_WS_DONE_FIELD=event # A3_WS_DONE_VALUE=speech_end A3_WS_DONE_FIELD= A3_WS_DONE_VALUE= # --- 4d. ROS 2 transport ------------------------------------------------------ # Requires ROS 2 installed on this PC and the same ROS_DOMAIN_ID as the robot. A3_ROS_DOMAIN_ID=0 A3_ROS_SPEAK_TOPIC= A3_ROS_SPEAK_MSG_TYPE=std_msgs/msg/String A3_ROS_SPEAK_MSG_FIELD=data A3_ROS_STOP_TOPIC= A3_ROS_USE_SERVICE=false A3_ROS_SERVICE_NAME= A3_ROS_SERVICE_TYPE= # --- 4e. SSH transport (last resort) -------------------------------------------- # Runs a command on the robot's own Linux computer. {text} is shell-quoted. # A3_SSH_SPEAK_COMMAND= {text} A3_SSH_USER=root A3_SSH_PORT=22 A3_SSH_KEY_PATH= A3_SSH_PASSWORD= A3_SSH_SPEAK_COMMAND= A3_SSH_STOP_COMMAND= A3_SSH_PROBE_COMMAND=true # --- 4f. Optional TTS parameters (sent only when set) ------------------------- A3_VOICE= A3_LANGUAGE= A3_VOLUME= A3_SPEED= # ----------------------------------------------------------------------------- # 5. SPEECH BEHAVIOUR # ----------------------------------------------------------------------------- SPEECH_MAX_LENGTH=1000 SPEECH_MIN_LENGTH=1 # true = pressing Speak while talking interrupts and says the new text # false = pressing Speak while talking is rejected with "already speaking" SPEECH_ALLOW_INTERRUPT=true SPEECH_HISTORY_LIMIT=100 # ----------------------------------------------------------------------------- # 6. MOCK ROBOT (ROBOT_MODE=mock only) # ----------------------------------------------------------------------------- MOCK_CONNECT_DELAY_MS=350 MOCK_NETWORK_LATENCY_MS=45 MOCK_PROCESSING_MS=180 MOCK_WORDS_PER_MINUTE=150 # Set to 0.2 to make 1 in 5 utterances fail, for testing error handling. MOCK_FAILURE_RATE=0.0 # Set to true to make the simulated link drop occasionally, for testing reconnect. MOCK_FLAKY_CONNECTION=false # --- PC speaker playback (simulator only) ------------------------------------ # true = the simulator actually SPEAKS the text through this laptop's speakers, # so you can rehearse a demo before the robot is on the network. # When this is on, the real audio drives the UI: "Completed" appears exactly when # the sound stops, and Stop cuts the voice mid-word. # # Windows uses the built-in SAPI voices - nothing to install. # macOS uses `say`. Linux needs: sudo apt install espeak-ng MOCK_LOCAL_AUDIO=true # Which PC voice to use (matched against the voice name, case-insensitive). # python scripts/voices.py list what is installed # python scripts/voices.py --demo hear each one # # NOTE: this is the SIMULATOR's voice, not the robot's - the real A3 synthesises # speech on-board. The robot's configured voice is "Yunxiao": a MALE TEENAGER, # multi-language. Windows ships no teenage voice, so the closest approximation is # its lighter adult male voice (Mark) pitched up a little. It is a stand-in, not # a match. Run `python scripts/voices.py --demo` to hear the alternatives. MOCK_VOICE=Mark # Speaking rate, -10 (slowest) to 10 (fastest). Try -1 or -2 for a noisy room. MOCK_SPEECH_RATE=0 # Volume, 0-100. MOCK_SPEECH_VOLUME=100 # Pitch, -10 (deepest) to 10 (highest). Left at 0: raising it makes the voice # sound affected rather than natural, which is the opposite of what a service # robot should sound like. MOCK_SPEECH_PITCH=0 # ----------------------------------------------------------------------------- # 7. GEMINI CLOUD VOICE (simulator only - nothing here touches the real robot) # ----------------------------------------------------------------------------- # The built-in Windows voice is instant but robotic. Gemini gives the simulator a # natural neural voice, at the cost of a network round trip. # # system = built-in OS voice - instant, robotic # gemini = Gemini neural voice - natural, ~4s to synthesise new text MOCK_VOICE_ENGINE=system # Get a key at https://aistudio.google.com/apikey GEMINI_API_KEY= GEMINI_TTS_MODEL=gemini-3.1-flash-tts-preview # Prebuilt voice. Iapetus ("Clear") is the default: professional and straight, # which is how a tour-guide robot actually speaks. Charon ("Informative") is the # same register but deeper and more adult - swap it in if you prefer that. # Puck / Fenrir read younger but bouncier. Hear them all: # python scripts/voices.py GEMINI_VOICE=Iapetus # Optional acting direction. LEAVE THIS EMPTY. Anything here makes the model # *perform* the line instead of simply saying it, which sounds theatrical and # fake for a service robot. Only set it for a deliberate stage character. GEMINI_TTS_STYLE= # 0 = never split. Every line is spoken as ONE clip, in one continuous take. # Set a character count (e.g. 280) only if you want very long paragraphs to # start speaking before the whole thing is synthesised - the pieces are then # synthesised separately, and the join between them can be audible. GEMINI_CHUNK_CHARS=0 # LATENCY: new text takes ~4s (short) to ~8s (paragraph) to synthesise. Audio is # cached on disk in .voice-cache/, so a repeated line is INSTANT and stays # instant across restarts. Before a live demo, warm your lines: # python scripts/warm_voice.py --file demo_lines.txt # If Gemini is unreachable the simulator falls back to the built-in voice, so a # network problem never leaves you with silence.