Repository navigation
Feat/three motion lines/detail technical method - #9
Conversation
…fast motion planning
Updated text to clarify video playback without downloading.
Preserve SentiAvatar/ARDY while adding independently timed motion and cloned speech tracks. Route MotionCraft through official T2M/S2G checkpoints, decode SynTalker latent sequences continuously, and reconcile VRM hands and floor clearance. Publish 16 complete VRM-Model-1 demos, README galleries, technical documentation, and verification evidence. Validated with 1110 Python tests (34 skipped), 142 web tests, production build, lint, documentation checks, and real browser/media runs.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5390f11e39
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| class SpeechClip(Contract): | ||
| id: str = Field(min_length=1, max_length=80) | ||
| text: str = Field(min_length=1, max_length=2000) |
There was a problem hiding this comment.
Split performance speech to the TTS request limit
When a MotionCraft or SynTalker plan contains a speech clip longer than the configured gateway limit, this contract accepts it but UnifiedCharacterSession.synthesize sends the entire text in one /audio/speech/stream request. Every bundled gateway rejects inputs above 200 characters, and the documented Audio8 setup further limits them to 150, so a valid 151–2000-character clip causes the whole asynchronously prepared performance to enter error without producing playback. Constrain clips to the selected provider's limit or split them while preserving their timeline placement.
Useful? React with 👍 / 👎.
| return None | ||
| patterns = ( | ||
| r"(?:做一段|进行|完成|编排|用|表演|总长|总时长|一段)\s*(?:大?约)?\s*(\d+(?:\.\d+)?)\s*秒(?!后)", | ||
| r"(?:a|an|for|lasting|total duration of)\s+(?:about\s+)?(\d+(?:\.\d+)?)\s*[- ]?\s*(?:seconds?|s)\b", |
There was a problem hiding this comment.
Restrict duration extraction to motion requests
The English pattern treats every standalone phrase such as for 20 seconds as an exact motion duration, even when the user says “speak for 20 seconds” or “wait for 10 seconds, then wave.” UnifiedMotionProvider.plan subsequently requires plan.motion_end to equal that value and retries or rejects an otherwise correct independent-track plan, forcing unwanted motion or the wrong action timing. Require nearby motion/performance wording instead of matching the generic for alternative.
Useful? React with 👍 / 👎.
| ] | ||
| root, rotations = smooth_native_pose(root, rotations) | ||
| root += np.array( | ||
| [body.position.x, body.position.y + (body.pelvis_height or 1), body.position.z] |
There was a problem hiding this comment.
Preserve a measured zero pelvis height
When the renderer or API supplies the valid pelvis_height=0 value allowed by BodyState, body.pelvis_height or 1 replaces that measurement with one meter. Starting a unified performance from a floor-level pose therefore shifts the generated root upward and reports the wrong hip height to playback; default to 1 only when the value is None.
Useful? React with 👍 / 👎.
| await asyncio.sleep(min(10, self.config.lease_seconds / 2)) | ||
| for session_id, session in list(self.sessions.items()): | ||
| if monotonic() - session.last_seen > self.config.lease_seconds: | ||
| await self.remove(session_id) |
There was a problem hiding this comment.
Recheck sessions before expiring snapshot entries
If closing one expired session suspends while cancelling its active task, another request can delete a later session that is still present in this snapshot. The subsequent remove(session_id) then raises KeyError from sessions.pop, terminating the reaper task permanently; abandoned sessions will no longer expire and can leave new sessions blocked by max_sessions. Recheck or conditionally pop each ID before removal.
Useful? React with 👍 / 👎.
| quote = "".join((intent.duration_evidence or "").split()) | ||
| start = normalized.find(quote) if quote else -1 | ||
| if start < 0: | ||
| raise ValueError("Duration evidence must quote the current user message") |
There was a problem hiding this comment.
Verify quoted evidence matches the requested duration
The intent validator only proves that duration_evidence occurs in the latest message; it never checks that its numeric meaning equals requested_seconds. If the model returns requested_seconds=100 with the genuine quote “10 seconds,” the quote passes and the compiled body program runs to the incorrect 100-second budget. Bind the parsed duration and unit from the quoted text to the numeric field before adopting the plan.
Useful? React with 👍 / 👎.
| await self._cancel() | ||
| self._submitted_plan = plan | ||
| self._start("explicit_performance") |
There was a problem hiding this comment.
Reset metrics before each explicit performance
Submitting a second plan through /{session_id}/performances cancels the old task but does not reset the per-response metrics that CharacterSession.message normally clears. The new run therefore adds its TTS time to the previous run and retains the previous first_audio_seconds, corrupting diagnostics and benchmark evidence for every repeated explicit performance in one session. Clear the per-performance metrics before starting this task.
Useful? React with 👍 / 👎.
No description provided.