share feature#10
Conversation
|
@Maviya13 is attempting to deploy a commit to the piyushdhoka's projects Team on Vercel. A member of the Team first needs to authorize it. |
Summary of ChangesHello @Maviya13, 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 delivers a significant new feature that empowers users to share their generated animations and chat histories with others. It involves a full-stack implementation, from database schema modifications and new backend API routes to dedicated frontend pages and interactive UI components, ensuring a seamless sharing experience and tracking of public content engagement. Highlights
Changelog
Activity
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new sharing feature for videos and chats, which is a great addition. The implementation spans both the backend and frontend, including new API endpoints, database schema changes, and public-facing pages. My review focuses on several key areas: improving database query atomicity to prevent race conditions, enhancing API performance with background tasks, increasing frontend component reusability and UI consistency, and standardizing logging and error handling. Addressing these points will make the new feature more robust, performant, and maintainable.
| async def increment_video_views(video_id: str) -> bool: | ||
| """Increment view count for a video.""" | ||
| client = get_supabase() | ||
|
|
||
| try: | ||
| # Get current view count | ||
| video = client.table("videos").select("view_count").eq("id", video_id).single().execute() | ||
| if not video.data: | ||
| return False | ||
|
|
||
| current_views = video.data.get("view_count", 0) | ||
|
|
||
| # Increment | ||
| client.table("videos").update({ | ||
| "view_count": current_views + 1, | ||
| "updated_at": datetime.now(timezone.utc).isoformat() | ||
| }).eq("id", video_id).execute() | ||
|
|
||
| return True | ||
| except Exception as e: | ||
| print(f"[Views] Failed to increment video views: {e}") | ||
| return False |
There was a problem hiding this comment.
This function implements a 'read-then-write' pattern to increment the view count, which can lead to a race condition under concurrent requests. Two requests could read the same value, increment it, and write back, resulting in a lost view count. This should be an atomic operation.
I recommend creating a PostgreSQL RPC function that performs an atomic update, like UPDATE videos SET view_count = view_count + 1 WHERE id = video_id;. You can then call this function from your service, similar to how deduct_user_credit is implemented. This will guarantee atomicity and prevent incorrect view counts.
| async def increment_chat_views(chat_id: str) -> bool: | ||
| """Increment view count for a chat.""" | ||
| client = get_supabase() | ||
|
|
||
| try: | ||
| # Get current view count | ||
| chat = client.table("chats").select("view_count").eq("id", chat_id).single().execute() | ||
| if not chat.data: | ||
| return False | ||
|
|
||
| current_views = chat.data.get("view_count", 0) | ||
|
|
||
| # Increment | ||
| client.table("chats").update({ | ||
| "view_count": current_views + 1, | ||
| "updated_at": datetime.now(timezone.utc).isoformat() | ||
| }).eq("id", chat_id).execute() | ||
|
|
||
| return True | ||
| except Exception as e: | ||
| print(f"[Views] Failed to increment chat views: {e}") | ||
| return False |
There was a problem hiding this comment.
This function has the same race condition issue as increment_video_views. It reads the current view count and then writes an updated value, which is not an atomic operation. To ensure data integrity, especially with concurrent access, this should be handled atomically in the database.
Please create a dedicated RPC function in PostgreSQL to handle the increment, for example: UPDATE chats SET view_count = view_count + 1 WHERE id = chat_id;. Calling this RPC will ensure each view is correctly and safely counted.
| increment_video_views, | ||
| increment_chat_views | ||
| ) | ||
|
|
| <header className="border-b border-white/10 backdrop-blur-sm"> | ||
| <div className="container mx-auto px-4 py-4"> | ||
| <Link href="/" className="inline-flex items-center gap-2 text-xl font-bold text-white"> | ||
| <img src="/logo.png" alt="MovingLines" className="h-8 w-8" /> |
There was a problem hiding this comment.
For better performance and to adhere to Next.js best practices, you should use the next/image component instead of the standard <img> tag. The Image component provides automatic image optimization, resizing, and lazy loading, which will improve your page's load times. You'll also need to import it.
| <img src="/logo.png" alt="MovingLines" className="h-8 w-8" /> | |
| <Image src="/logo.png" alt="MovingLines" width={32} height={32} /> |
| @@ -0,0 +1,51 @@ | |||
| from fastapi import APIRouter, HTTPException | |||
There was a problem hiding this comment.
| @@ -0,0 +1,140 @@ | |||
| import { Metadata } from 'next' | |||
| <div onClick={(e) => e.stopPropagation()}> | ||
| <ShareChatButton | ||
| chatId={chat.id} | ||
| isPublic={false} // Will be populated after migration | ||
| viewCount={0} | ||
| onShareToggle={() => { | ||
| // Optionally reload chats to refresh share status | ||
| }} | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
The current implementation of the share button, by rendering a <Button> inside a <div>, breaks the visual and keyboard navigation consistency of the DropdownMenu.
A better approach would be to refactor ShareChatButton to be a composable component that wraps its children with the Dialog and DialogTrigger. This would allow you to use a standard DropdownMenuItem here, preserving the menu's look, feel, and accessibility.
Example of the improved usage here:
<ShareChatButton chatId={chat.id} isPublic={chat.isPublic} ...>
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
<Share className="h-3.5 w-3.5" />
Share
</DropdownMenuItem>
</ShareChatButton>This would require modifying ShareChatButton.tsx to accept and render children inside the DialogTrigger.
| isPublic={false} // Will be populated after migration | ||
| viewCount={0} |
There was a problem hiding this comment.
The isPublic and viewCount props are currently hardcoded. The comment indicates this is temporary, but to complete the feature, you should update the Chat interface in this file to include is_public and view_count, and then pass the actual values from the chat object. This will ensure the share button reflects the correct state.
| isPublic={false} // Will be populated after migration | |
| viewCount={0} | |
| isPublic={chat.isPublic} | |
| viewCount={chat.viewCount} |
| } | ||
| } catch (error) { | ||
| console.error('Failed to toggle sharing:', error) | ||
| alert('Failed to update sharing settings. Please try again.') |
There was a problem hiding this comment.
| } | ||
| } catch (error) { | ||
| console.error('Failed to toggle sharing:', error) | ||
| alert('Failed to update sharing settings. Please try again.') |
No description provided.