-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Roberto
committed
Jan 1, 2025
0 parents
commit 5d87120
Showing
37 changed files
with
8,516 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/versions | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# env files (can opt-in for committing if needed) | ||
.env* | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
# PM AI Agent 🤖 | ||
|
||
A sophisticated Next.js application that transforms Loom video demonstrations into detailed user stories using AI. This tool helps Product Managers streamline their documentation process by automatically generating structured user stories from video content. The project was primarily developed (95%) by Cline AI, with only the initial scaffolding done manually. | ||
|
||
## Features | ||
|
||
### 1. Loom Video Processing | ||
- Upload video files with optional SRT subtitles | ||
- Built-in video player with frame selection capabilities | ||
- Automatic subtitle parsing and integration | ||
- Powered by FFmpeg for reliable video processing | ||
|
||
### 2. AI-Powered Story Generation | ||
- Utilizes Google's Gemini 1.5 Pro AI model | ||
- Analyzes video frames and subtitles to understand feature demonstrations | ||
- Generates comprehensive user stories in standard Agile format | ||
- Includes technical considerations and story points | ||
|
||
### 3. Story Management & Integration | ||
- Save and manage multiple user stories | ||
- Delete unwanted stories | ||
- Organized timeline view of generated content | ||
- Export stories to ClickUp with screenshots | ||
- Track export progress with visual indicators | ||
|
||
### 4. ClickUp Integration | ||
- Configure ClickUp API token in Integrations page | ||
- Export user stories directly to ClickUp spaces and lists | ||
- Automatic status handling using list defaults | ||
- Markdown-formatted story content | ||
- Scene screenshots uploaded as attachments | ||
- Progress tracking for multi-image uploads | ||
|
||
## Integrations | ||
|
||
### ClickUp Integration | ||
1. **Configuration** | ||
- Navigate to the Integrations page | ||
- Add your ClickUp API token | ||
- Token is securely stored and validated | ||
|
||
2. **Export Features** | ||
- Export stories directly to ClickUp | ||
- Select target space and list | ||
- Automatic status assignment | ||
- Scene screenshots included as attachments | ||
- Progress tracking for uploads | ||
|
||
3. **Task Format** | ||
- Structured user story content | ||
- Markdown formatting for readability | ||
- Metadata section with clip details | ||
- Notes section (if available) | ||
- Scene screenshots as visual context | ||
|
||
## How It Works | ||
|
||
1. **Upload Phase** | ||
- Download your Loom video demonstration with SRT subtitles | ||
- Upload the video and SRT file to the application | ||
- Automatic subtitle parsing and synchronization | ||
|
||
2. **Clip Selection** | ||
- Use the built-in video player to select relevant clips | ||
- Add context notes for better AI understanding | ||
- Frame-by-frame selection for precise feature demonstration capture | ||
|
||
3. **Story Generation** | ||
- AI analyzes selected video frames | ||
- Processes any available subtitles/dialogue | ||
- Generates structured user stories including: | ||
- User story title | ||
- User/Action/Benefit format | ||
- Acceptance criteria | ||
- Technical notes | ||
- Story point estimation | ||
|
||
## Technical Stack | ||
|
||
- **Framework**: Next.js 15.1.3 with TypeScript | ||
- **UI**: TailwindCSS with custom components | ||
- **Video Processing**: FFmpeg | ||
- **AI Integration**: | ||
- Google Generative AI (Gemini 1.5 Pro) | ||
- OpenAI (auxiliary processing) | ||
- **Subtitle Processing**: Subtitle parser for SRT files | ||
- **File Handling**: React Dropzone | ||
|
||
## Setup | ||
|
||
1. Clone the repository | ||
2. Install dependencies: | ||
```bash | ||
npm install | ||
``` | ||
3. Set up environment variables: | ||
```env | ||
# AI Services | ||
NEXT_PUBLIC_GEMINI_API_KEY=your_gemini_api_key | ||
# ClickUp Integration (Optional) | ||
# Configure through the Integrations page in the app | ||
# The token will be stored securely in the environment | ||
# CLICKUP_TOKEN=your_clickup_api_token | ||
``` | ||
4. Run the development server: | ||
```bash | ||
npm run dev | ||
``` | ||
|
||
## Usage | ||
|
||
1. **Start the Application** | ||
- Navigate to the application in your browser | ||
- You'll see the main interface with a file upload section | ||
|
||
2. **Upload Content** | ||
- Record your feature demonstration using Loom | ||
- Download both the video file and SRT subtitles from Loom | ||
- Drag and drop or select both files in the application | ||
- The video player will automatically load with synchronized subtitles | ||
|
||
3. **Select Clips** | ||
- Use the video player controls to navigate | ||
- Select key frames that demonstrate the feature | ||
- Add context notes to guide the AI | ||
|
||
4. **Generate Stories** | ||
- Click generate to create the user story | ||
- Review the generated content | ||
- Save or modify as needed | ||
|
||
5. **Export to ClickUp** (Optional) | ||
- Configure ClickUp integration in the Integrations page | ||
- Click the export icon on any generated story | ||
- Select the target space and list | ||
- Wait for the export to complete, including: | ||
* Story content with markdown formatting | ||
* Scene screenshots as attachments | ||
* Metadata and notes | ||
|
||
## Best Practices | ||
|
||
- Use clear, well-lit video demonstrations | ||
- Include relevant subtitles for better context | ||
- Select frames that clearly show feature transitions | ||
- Provide detailed context notes for better AI understanding | ||
- Review and edit generated stories as needed | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please feel free to submit a Pull Request. | ||
|
||
## License | ||
|
||
MIT License | ||
|
||
Copyright (c) 2024 PM AI Agent Contributors | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { NextResponse } from 'next/server'; | ||
import { ClickUpService } from '../../../../lib/clickup-service'; | ||
|
||
export async function POST(request: Request) { | ||
try { | ||
const { token } = await request.json(); | ||
|
||
if (!token) { | ||
return NextResponse.json( | ||
{ error: 'Token is required' }, | ||
{ status: 400 } | ||
); | ||
} | ||
|
||
// Validate the token by making a test request | ||
const clickupService = new ClickUpService(token); | ||
const isValid = await clickupService.validateToken(); | ||
|
||
if (!isValid) { | ||
return NextResponse.json( | ||
{ error: 'Invalid ClickUp token' }, | ||
{ status: 401 } | ||
); | ||
} | ||
|
||
// In a production environment, you would want to: | ||
// 1. Encrypt the token before storing | ||
// 2. Use a secure storage solution (e.g., database, secure key store) | ||
// 3. Associate the token with the current user's session | ||
// For demo purposes, we'll store in an environment variable | ||
process.env.CLICKUP_TOKEN = token; | ||
|
||
return NextResponse.json( | ||
{ message: 'ClickUp token saved successfully' }, | ||
{ status: 200 } | ||
); | ||
} catch (error) { | ||
console.error('Error saving ClickUp token:', error); | ||
return NextResponse.json( | ||
{ error: 'Failed to save ClickUp token' }, | ||
{ status: 500 } | ||
); | ||
} | ||
} | ||
|
||
export async function GET() { | ||
try { | ||
const token = process.env.CLICKUP_TOKEN; | ||
|
||
if (!token) { | ||
return NextResponse.json( | ||
{ error: 'No ClickUp token found' }, | ||
{ status: 404 } | ||
); | ||
} | ||
|
||
// Validate the stored token | ||
const clickupService = new ClickUpService(token); | ||
const isValid = await clickupService.validateToken(); | ||
|
||
if (!isValid) { | ||
return NextResponse.json( | ||
{ error: 'Stored ClickUp token is invalid' }, | ||
{ status: 401 } | ||
); | ||
} | ||
|
||
return NextResponse.json( | ||
{ message: 'ClickUp integration is configured' }, | ||
{ status: 200 } | ||
); | ||
} catch (error) { | ||
console.error('Error checking ClickUp token:', error); | ||
return NextResponse.json( | ||
{ error: 'Failed to check ClickUp token' }, | ||
{ status: 500 } | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { NextResponse } from 'next/server'; | ||
|
||
export async function GET() { | ||
try { | ||
const token = process.env.CLICKUP_TOKEN; | ||
|
||
if (!token) { | ||
return NextResponse.json( | ||
{ error: 'ClickUp token not configured' }, | ||
{ status: 404 } | ||
); | ||
} | ||
|
||
return NextResponse.json({ token }); | ||
} catch (error) { | ||
console.error('Error retrieving ClickUp token:', error); | ||
return NextResponse.json( | ||
{ error: 'Failed to retrieve ClickUp token' }, | ||
{ status: 500 } | ||
); | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
body { | ||
font-family: Arial, Helvetica, sans-serif; | ||
} | ||
|
||
@layer base { | ||
:root { | ||
--background: 0 0% 100%; | ||
--foreground: 0 0% 3.9%; | ||
--card: 0 0% 100%; | ||
--card-foreground: 0 0% 3.9%; | ||
--popover: 0 0% 100%; | ||
--popover-foreground: 0 0% 3.9%; | ||
--primary: 0 0% 9%; | ||
--primary-foreground: 0 0% 98%; | ||
--secondary: 0 0% 96.1%; | ||
--secondary-foreground: 0 0% 9%; | ||
--muted: 0 0% 96.1%; | ||
--muted-foreground: 0 0% 45.1%; | ||
--accent: 0 0% 96.1%; | ||
--accent-foreground: 0 0% 9%; | ||
--destructive: 0 84.2% 60.2%; | ||
--destructive-foreground: 0 0% 98%; | ||
--border: 0 0% 89.8%; | ||
--input: 0 0% 89.8%; | ||
--ring: 0 0% 3.9%; | ||
--chart-1: 12 76% 61%; | ||
--chart-2: 173 58% 39%; | ||
--chart-3: 197 37% 24%; | ||
--chart-4: 43 74% 66%; | ||
--chart-5: 27 87% 67%; | ||
--radius: 0.5rem; | ||
} | ||
.dark { | ||
--background: 0 0% 3.9%; | ||
--foreground: 0 0% 98%; | ||
--card: 0 0% 3.9%; | ||
--card-foreground: 0 0% 98%; | ||
--popover: 0 0% 3.9%; | ||
--popover-foreground: 0 0% 98%; | ||
--primary: 0 0% 98%; | ||
--primary-foreground: 0 0% 9%; | ||
--secondary: 0 0% 14.9%; | ||
--secondary-foreground: 0 0% 98%; | ||
--muted: 0 0% 14.9%; | ||
--muted-foreground: 0 0% 63.9%; | ||
--accent: 0 0% 14.9%; | ||
--accent-foreground: 0 0% 98%; | ||
--destructive: 0 62.8% 30.6%; | ||
--destructive-foreground: 0 0% 98%; | ||
--border: 0 0% 14.9%; | ||
--input: 0 0% 14.9%; | ||
--ring: 0 0% 83.1%; | ||
--chart-1: 220 70% 50%; | ||
--chart-2: 160 60% 45%; | ||
--chart-3: 30 80% 55%; | ||
--chart-4: 280 65% 60%; | ||
--chart-5: 340 75% 55%; | ||
} | ||
} | ||
|
||
@layer base { | ||
* { | ||
@apply border-border; | ||
} | ||
body { | ||
@apply bg-background text-foreground; | ||
} | ||
} |
Oops, something went wrong.