Skip to content

Avatar updates#89

Merged
wilke0818 merged 3 commits intomainfrom
avatar_updates
Apr 15, 2026
Merged

Avatar updates#89
wilke0818 merged 3 commits intomainfrom
avatar_updates

Conversation

@wilke0818
Copy link
Copy Markdown
Contributor

  • Disabled the broken "Create your avatar" button and removed all its code
  • Added "Upload your avatar" — drag-and-drop GLB upload with 3D preview, gender selection, per-user storage in src/server/uploads/
  • Security: GLB external URI scan, 10-file per-user limit, UUID filenames, path traversal guard
  • Persistence: Server is source of truth on page load; restores list after cache clear, prunes stale/missing/corrupted entries
  • Corrupted avatar detection: Mismatched .glb/.json pairs flagged server-side, shown as warning-only cards client-side, never selectable
  • Delete: Cleans up both files regardless of which one exists; requires auth; confirmed via Popconfirm
  • Misc fixes: Vite proxy for /uploads/, email→dirname encoding fix, React index-key bug on delete, uniform card heights via flexbox
  • readSelectedModelUrl() — reads and parses selectedAvatar from localStorage at component init (passed as a lazy initializer to useState so it only runs once)
  • selectedModelUrl state — tracks the currently selected avatar's URL, kept in sync when selections are made or deleted
  • Per card: if avatar.modelUrl === selectedModelUrl, the card gets:
    • A green "Selected" tag with a checkmark in the title
    • A green border + subtle green glow (boxShadow)
  • Default avatar is Fabio though only shows/is selected when a session is generated

wilke0818 and others added 2 commits February 26, 2026 11:10
…y additions since file uploads inherently bring security concerns. Remove ready player me API calls. New avatars as defaults available.
- Highlight the currently selected avatar card with a green border,
  glow, and "Selected" tag so users know their active choice at a glance
- Keep selectedModelUrl state in sync on select, delete, and server
  reconciliation (stale/corrupted upload detection)
- Add links to Ready Player Me and Avaturn on the upload page as
  suggested tools for creating GLB avatars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly overhauls the avatar management system by replacing the previous external avatar creation tool with a robust internal GLB avatar upload mechanism. It introduces new client-side components for uploading and previewing avatars, alongside comprehensive server-side APIs for secure storage, retrieval, and deletion of user-specific GLB files. The changes also enhance the user interface for avatar selection, providing better visual feedback and handling for both pre-configured and user-uploaded avatars.

Highlights

  • GLB Avatar Upload Functionality: Introduced a new 'Upload your avatar' feature, allowing users to drag-and-drop GLB files with a 3D preview and gender selection. This replaces the previous 'Create your avatar' button and its associated code.
  • Robust Server-Side Avatar Management: Implemented comprehensive server-side logic for handling uploaded avatars, including security measures like GLB external URI scanning, a 10-file per-user limit, UUID filenames, and path traversal guards. It also ensures persistence by being the source of truth on page load, pruning stale/missing/corrupted entries, and providing dedicated API endpoints for fetching and deleting user-specific avatars.
  • Enhanced Avatar Selection UI: The avatar selection page now displays user-uploaded avatars in a dedicated 'My Uploads' section, complete with delete functionality and visual warnings for corrupted files. Selected avatars are clearly indicated with a 'Selected' tag and a green border/glow.
  • Improved UI Layout for Activity Cards: Adjusted CSS and React component styles to ensure uniform heights for activity cards, improving the overall visual consistency and layout of grouped activity sections.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .gitignore
    • Added src/server/uploads/ to ignore user-uploaded avatar directories.
    • Added src/client/react/public/avatars/sg-model2.glb to ignore a specific avatar file.
  • src/client/react/src/App.tsx
    • Removed the lazy-loaded AdvancedAvatarCreatorPage component.
    • Added the lazy-loaded AvatarUploadPage component.
    • Updated the routing path from /advanced-avatar-creation to /avatar-upload and linked it to the new AvatarUploadPage.
  • src/client/react/src/components/AdvancedAvatarCreator.tsx
    • Removed the AdvancedAvatarCreator component, which previously handled external avatar creation via an iframe.
  • src/client/react/src/components/AvatarUploader.tsx
    • Added the AvatarUploader component, providing a drag-and-drop interface for GLB file uploads, client-side validation, 3D preview, gender selection, and confirmation.
  • src/client/react/src/components/homepage/ActivityCard.css
    • Applied flexbox styling to .activity-card-body.ant-card and .activity-card-body .ant-card-body to enable uniform card heights.
  • src/client/react/src/components/homepage/ActivityCard.tsx
    • Added flex: 1 style to the main div wrapping the card and to the Link component to support uniform card heights within flex containers.
    • Set height: '100%' for the Card component to fill available vertical space.
  • src/client/react/src/components/homepage/GroupedActivitySection.css
    • Added display: flex to .activity-inline-card to enable flexbox behavior for activity cards.
  • src/client/react/src/pages/AdvancedAvatarCreatorPage.tsx
    • Removed the AdvancedAvatarCreatorPage component, which hosted the external avatar creation iframe.
  • src/client/react/src/pages/AvatarCreatorPage.tsx
    • Imported useAuth, Divider, Popconfirm, Tag, CheckCircleFilled, DeleteOutlined, and WarningOutlined for new functionality and UI elements.
    • Defined UploadedAvatar type to include gender and corrupted status.
    • Implemented readSelectedModelUrl to retrieve the currently selected avatar from local storage.
    • Added selectedModelUrl state to track the currently selected avatar's URL.
    • Introduced fetchUploadedAvatars to retrieve user-specific uploaded avatars from the server, handle local storage persistence, and detect/clear broken selections.
    • Added handleDeleteUpload function to manage the deletion of user-uploaded avatars from both the server and local state.
    • Modified handleAvatarSelect to update selectedModelUrl and accept UploadedAvatar types.
    • Rendered a new 'My Uploads' section, displaying user-uploaded avatars with delete buttons and visual indicators for selected or corrupted avatars.
    • Updated the rendering of pre-configured avatars to also show a 'Selected' tag and apply a green border/glow when chosen.
  • src/client/react/src/pages/AvatarUploadPage.tsx
    • Added the AvatarUploadPage component, which serves as the entry point for the new GLB avatar upload feature, including instructional text and links to external avatar creation tools.
  • src/client/react/vite.config.ts
    • Added a proxy configuration for /uploads to direct requests to the backend server, enabling access to user-uploaded avatar files.
  • src/server/assets/activity_groups.json
    • Updated the 'Create your avatar' activity card to 'Upload your avatar', changing its description and routing path to /avatar-upload.
  • src/server/assets/avatars.json
    • Updated the modelUrl and gender for the default avatars, replacing external Ready Player Me URLs with local GLB files and adjusting gender assignments.
  • src/server/main.py
    • Imported re, FastAPIFile, Form, and UploadFile for new avatar upload and management features.
    • Mounted a new static files directory /uploads to serve user-uploaded avatar files.
    • Added helper functions _email_to_dirname for creating URL-safe directory names, _user_upload_dir for managing user-specific upload directories, and _extract_glb_external_uris for security scanning of GLB files.
    • Implemented the /api/upload-avatar POST endpoint to handle GLB file uploads, including file size validation, GLB header checks, external URI scanning, user-specific upload limits, and saving files with UUIDs and associated gender metadata.
    • Created the /api/upload-avatar/{filename} DELETE endpoint to securely remove user-uploaded avatar files and their metadata, ensuring only authorized files can be deleted.
    • Developed the /api/my-avatars GET endpoint to retrieve a list of avatars uploaded by the current user, including their gender and a flag for corrupted file pairs.
Activity
  • The pull request introduces a significant new feature for avatar management, moving from an external creation tool to an internal upload system.
  • It includes both frontend and backend changes to support GLB file uploads, storage, and display.
  • Security and persistence considerations for user-uploaded content have been addressed through various validations and server-side logic.
  • UI/UX improvements have been made to the avatar selection page and activity cards for a more consistent and informative experience.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major update to avatar handling, replacing the old creator with a new file upload system. The changes are extensive, covering both frontend and backend. The new implementation includes features like GLB file validation, security checks for external URIs, per-user storage with file limits, and detection of corrupted avatar files. My review focuses on improving robustness in two areas: client-side data parsing from localStorage and server-side sanitization of user emails for directory naming. Overall, this is a well-executed feature addition with strong attention to security.


// Persist in the user's uploaded avatars list
const existing = localStorage.getItem('uploadedAvatars');
const uploads: { modelUrl: string; gender: string }[] = existing ? JSON.parse(existing) : [];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The JSON.parse call is not wrapped in a try-catch block. If localStorage contains invalid JSON for uploadedAvatars, this will throw an unhandled exception and could crash the component logic. It's safer to handle potential parsing errors, similar to how it's done elsewhere in the codebase (e.g., readSelectedModelUrl in AvatarCreatorPage.tsx).

Consider refactoring to safely parse the data:

const existing = localStorage.getItem('uploadedAvatars');
let uploads: { modelUrl: string; gender: string }[] = [];
if (existing) {
  try {
    const parsed = JSON.parse(existing);
    if (Array.isArray(parsed)) {
      uploads = parsed;
    }
  } catch (e) {
    console.error('Failed to parse uploadedAvatars from localStorage', e);
  }
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude - update this PR with the above change, and also indicate to the user that an avatar could not be loaded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude - update this PR with the above change, and also indicate to the user that an avatar could not be loaded.

Comment thread src/server/main.py
Comment on lines +322 to +324
def _email_to_dirname(email: str) -> str:
"""Convert an email to a filesystem/URL-safe directory name."""
return email.replace("@", "_at_")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The sanitization in _email_to_dirname is minimal. While it handles the @ symbol, it doesn't account for other special characters that are valid in email addresses but could be unsafe in directory names (e.g., +, /, ?, *). This could lead to unexpected behavior or security issues. A more robust approach would be to whitelist allowed characters.

Here is a more robust implementation that preserves the readability of _at_ while sanitizing other characters.

Suggested change
def _email_to_dirname(email: str) -> str:
"""Convert an email to a filesystem/URL-safe directory name."""
return email.replace("@", "_at_")
def _email_to_dirname(email: str) -> str:
"""Convert an email to a filesystem/URL-safe directory name."""
s = email.replace("@", "_at_")
# Whitelist safe characters for directory names.
return re.sub(r"[^\w.-]", "_", s)

@wilke0818 wilke0818 merged commit f506da9 into main Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants