# tutor-admin **Repository Path**: manzhenhua/tutor-admin ## Basic Information - **Project Name**: tutor-admin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-31 - **Last Updated**: 2025-09-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Build a Duolingo Clone With Nextjs, React, Drizzle, Stripe (2024) ![Duolingo thumb (1)](https://github.com/AntonioErdeljac/next14-duolingo-clone/assets/23248726/d58e4b55-bb09-456f-978e-f5f31e81b870) This is a repository for a "Build a Duolingo Clone With Nextjs, React, Drizzle, Stripe (2024)" youtube video. [VIDEO TUTORIAL](https://www.youtube.com/watch?v=dP75Khfy4s4) Key Features: - ๐ŸŒ Next.js 14 & server actions - ๐Ÿ—ฃ AI Voices using Elevenlabs AI - ๐ŸŽจ Beautiful component system using Shadcn UI - ๐ŸŽญ Amazing characters thanks to KenneyNL - ๐Ÿ” Auth using Authing - ๐Ÿ”Š Sound effects - โค๏ธ Hearts system - ๐ŸŒŸ Points / XP system - ๐Ÿ’” No hearts left popup - ๐Ÿšช Exit confirmation popup - ๐Ÿ”„ Practice old lessons to regain hearts - ๐Ÿ† Leaderboard - ๐Ÿ—บ Quests milestones - ๐Ÿ› Shop system to exchange points with hearts - ๐Ÿ’ณ Pro tier for unlimited hearts using Stripe - ๐Ÿ  Landing page - ๐Ÿ“Š Admin dashboard React Admin - ๐ŸŒง ORM using DrizzleORM - ๐Ÿ’พ PostgresDB using NeonDB - ๐Ÿš€ Deployment on Vercel - ๐Ÿ“ฑ Mobile responsiveness - ๐Ÿค– DeepSeek AI Embeddings integration - ๐ŸŽฅ AI Video Control Tools integration ### Prerequisites **Node version 14.x** ### Cloning the repository ```shell git clone https://github.com/AntonioErdeljac/next14-duolingo-clone.git ``` ### Install packages ```shell npm i ``` ### Setup .env file ```js AUTHING_DOMAIN = ""; AUTHING_APP_ID = ""; AUTHING_APP_SECRET = ""; AUTHING_REDIRECT_URI = "http://localhost:3000/callback"; DATABASE_URL = "postgresql://..."; STRIPE_API_KEY = ""; NEXT_PUBLIC_APP_URL = "http://localhost:3000"; STRIPE_WEBHOOK_SECRET = ""; DEEPSEEK_API_KEY = "your_deepseek_api_key_here"; ``` ### Setup Drizzle ORM ```shell npm run db:push ``` ### Seed the app ```shell npm run db:seed ``` or ```shell npm run db:prod ``` ### Start the app ```shell npm run dev ``` ## DeepSeek AI Embeddings ๅŠŸ่ƒฝ ๆœฌ้กน็›ฎ้›†ๆˆไบ† DeepSeek ็š„ AI embedding ๆจกๅž‹๏ผŒๆไพ›ๅผบๅคง็š„ๆ–‡ๆœฌๅ‘้‡ๅŒ–ๅŠŸ่ƒฝใ€‚ ### ๅŠŸ่ƒฝ็‰นๆ€ง - ๐Ÿ”ค **ๅ•ไธชๆ–‡ๆœฌ Embedding**: ๅฐ†ๅ•ไธชๆ–‡ๆœฌ่ฝฌๆขไธบๅ‘้‡่กจ็คบ - ๐Ÿ“ฆ **ๆ‰น้‡ๆ–‡ๆœฌ Embeddings**: ้ซ˜ๆ•ˆๅค„็†ๅคšไธชๆ–‡ๆœฌ็š„ๅ‘้‡ๅŒ– - ๐Ÿ“Š **็›ธไผผๅบฆ่ฎก็ฎ—**: ่ฎก็ฎ—ไธคไธชๆ–‡ๆœฌๅ‘้‡ไน‹้—ด็š„ไฝ™ๅผฆ็›ธไผผๅบฆ - ๐Ÿ” **็›ธไผผๆ–‡ๆœฌๆŸฅๆ‰พ**: ๅœจๆ–‡ๆœฌ้›†ๅˆไธญๆŸฅๆ‰พๆœ€็›ธไผผ็š„ๆ–‡ๆœฌ - ๐ŸŽฏ **ๆ–‡ๆœฌ่š็ฑป**: ๅŸบไบŽ็›ธไผผๅบฆๅฏนๆ–‡ๆœฌ่ฟ›่กŒ่‡ชๅŠจ่š็ฑป ### ๅฟซ้€Ÿๅผ€ๅง‹ 1. **ๅฎ‰่ฃ…ไพ่ต–** (ๅทฒๅŒ…ๅซๅœจ้กน็›ฎไธญ) ```bash npm install @ai-sdk/deepseek ai ``` 2. **้…็ฝฎ็Žฏๅขƒๅ˜้‡** ```env DEEPSEEK_API_KEY=your_deepseek_api_key_here ``` 3. **ๆต‹่ฏ•ๅŠŸ่ƒฝ** ```bash npm run test:embeddings ``` 4. **่ฎฟ้—ฎๆต‹่ฏ•้กต้ข** ``` http://localhost:3000/embeddings-test ``` ### API ไฝฟ็”จ็คบไพ‹ ```typescript import { generateEmbedding, findMostSimilar } from "@/lib/embeddings"; // ็”Ÿๆˆๅ•ไธชๆ–‡ๆœฌ็š„ embedding const result = await generateEmbedding("Hello world"); console.log(result.embedding); // ๅ‘้‡ๆ•ฐ็ป„ // ๆŸฅๆ‰พ็›ธไผผๆ–‡ๆœฌ const similar = await findMostSimilar("Hello", [ "Hi", "Goodbye", "Hello world", ]); console.log(similar.bestMatch); // ๆœ€็›ธไผผ็š„ๆ–‡ๆœฌ ``` ### REST API ๆŽฅๅฃ ``` POST /api/embeddings ``` ๆ”ฏๆŒ็š„ๆ“ไฝœ๏ผš - `generate`: ็”Ÿๆˆๅ•ไธช embedding - `generateBatch`: ๆ‰น้‡็”Ÿๆˆ embeddings - `similarity`: ่ฎก็ฎ—็›ธไผผๅบฆ - `findSimilar`: ๆŸฅๆ‰พ็›ธไผผๆ–‡ๆœฌ - `cluster`: ๆ–‡ๆœฌ่š็ฑป ่ฏฆ็ป†ๆ–‡ๆกฃ่ฏทๅ‚่€ƒ: [docs/embeddings-usage.md](docs/embeddings-usage.md) ## AI ่ง†้ข‘ๆŽงๅˆถๅทฅๅ…ทๅŠŸ่ƒฝ ๆœฌ้กน็›ฎ้›†ๆˆไบ†ๅŸบไบŽ AI SDK Tools ็š„่ง†้ข‘ๆŽงๅˆถๅŠŸ่ƒฝ๏ผŒๆ”ฏๆŒ้€š่ฟ‡่‡ช็„ถ่ฏญ่จ€ๆŽงๅˆถ่ง†้ข‘ๆ’ญๆ”พใ€‚ ### ๅŠŸ่ƒฝ็‰นๆ€ง - ๐ŸŽฌ **ๆ’ญๆ”พๆŽงๅˆถ**: ๆ’ญๆ”พใ€ๆš‚ๅœใ€ๅœๆญข่ง†้ข‘ - โฐ **ๆ—ถ้—ดๆŽงๅˆถ**: ่ทณ่ฝฌๅˆฐๆŒ‡ๅฎšๆ—ถ้—ด็‚น - ๐Ÿ”Š **้Ÿณ้‡ๆŽงๅˆถ**: ่ฎพ็ฝฎ้Ÿณ้‡ใ€้™้Ÿณ/ๅ–ๆถˆ้™้Ÿณ - ๐Ÿ”„ **ๅŒๆญฅๆŽงๅˆถ**: ๅŒๆญฅไธคไธช่ง†้ข‘็š„ๆ’ญๆ”พ่ฟ›ๅบฆ - ๐Ÿ“Š **็Šถๆ€ๆŸฅ่ฏข**: ่Žทๅ–่ง†้ข‘ๆ’ญๆ”พ็Šถๆ€ ### ๅฟซ้€Ÿๅผ€ๅง‹ 1. **่ฎฟ้—ฎๆต‹่ฏ•้กต้ข** ``` http://localhost:3000/video-ai-test ``` 2. **ไฝฟ็”จ่‡ช็„ถ่ฏญ่จ€ๆŽงๅˆถ** ``` "ๆ’ญๆ”พ่ฏพ็จ‹่ง†้ข‘" "ๆš‚ๅœไธคไธช่ง†้ข‘" "่ทณ่ฝฌๅˆฐ็ฌฌ30็ง’" "่ฎพ็ฝฎ้Ÿณ้‡ไธบ0.5" "่Žทๅ–่ง†้ข‘็Šถๆ€" ``` ### ๆŠ€ๆœฏๅฎž็Žฐ ๅŸบไบŽ [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) ๅฎž็Žฐ๏ผŒไฝฟ็”จ DeepSeek ๆจกๅž‹ๅ’Œ่‡ชๅฎšไน‰่ง†้ข‘ๆŽงๅˆถๅทฅๅ…ทใ€‚ ่ฏฆ็ป†ๆ–‡ๆกฃ่ฏทๅ‚่€ƒ: [docs/video-control-tools.md](docs/video-control-tools.md) # ่ฏพ็จ‹่ฏฆๆƒ…้กต ่ฟ™ๆ˜ฏไธ€ไธชๅŸบไบŽ Next.js ๅ’Œ TypeScript ๆž„ๅปบ็š„ๅœจ็บฟๅญฆไน ๅนณๅฐ๏ผŒๅŒ…ๅซ่ฏพ็จ‹่ฏฆๆƒ…้กตๅŠŸ่ƒฝใ€‚ ## ๅŠŸ่ƒฝ็‰นๆ€ง ### ่ฏพ็จ‹่ฏฆๆƒ…้กต (`app/lesson/[id]/page.tsx`) ่ฏพ็จ‹่ฏฆๆƒ…้กตๅŒ…ๅซไปฅไธ‹ไธป่ฆๅŠŸ่ƒฝ๏ผš 1. **่ง†้ข‘ๆ’ญๆ”พๅ™จ** - ๆ”ฏๆŒๆ’ญๆ”พใ€ๆš‚ๅœใ€้Ÿณ้‡ๆŽงๅˆถ - ่ฟ›ๅบฆๆกๆŽงๅˆถ - ๅ…จๅฑๆจกๅผ - ่‡ชๅฎšไน‰ๆŽงๅˆถๆ  2. **ๆต‹่ฏ•่ฎญ็ปƒ** - ๅคš้€‰้ข˜็›ฎๆต‹่ฏ• - ๅฎžๆ—ถ่ฟ›ๅบฆๆ˜พ็คบ - ้ข˜็›ฎๅฏผ่ˆช - ็ป“ๆžœ็ปŸ่ฎก - ้‡ๆ–ฐๆต‹่ฏ•ๅŠŸ่ƒฝ 3. **ๅฏน่ฏๅŠŸ่ƒฝ** - ๅปบ่ฎฎ้—ฎ้ข˜ๅˆ—่กจ - ๆ–‡ๆœฌ่พ“ๅ…ฅๆก† - ่ฏญ้Ÿณ่พ“ๅ…ฅๆ”ฏๆŒ 4. **ๅ“ๅบ”ๅผ่ฎพ่ฎก** - ๆกŒ้ข็ซฏๅ’Œ็งปๅŠจ็ซฏ้€‚้… - ๅทฆไพงไธป่ฆๅ†…ๅฎนๅŒบๅŸŸ - ๅณไพงๅฏน่ฏๅŒบๅŸŸ ## ็ป„ไปถ็ป“ๆž„ ### ไธป่ฆ็ป„ไปถ - `VideoPlayer` (`components/video-player.tsx`) - ่‡ชๅฎšไน‰่ง†้ข‘ๆ’ญๆ”พๅ™จ - `CourseQuiz` (`components/course-quiz.tsx`) - ่ฏพ็จ‹ๆต‹่ฏ•็ป„ไปถ - `Button`, `Card`, `Progress` - UI ็ป„ไปถ ### ้กต้ขๅธƒๅฑ€ ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๆ ‡็ญพ้กตๅฏผ่ˆช โ”‚ โ”‚ [่ง†้ข‘] [ๆต‹่ฏ•] [ๆŽจ่ๆœ‰็คผ] โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ่ฟ›ๅบฆๆก โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ ่ง†้ข‘ๆ’ญๆ”พๅ™จ โ”‚ ๅฏน่ฏๅŒบๅŸŸ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ ๅปบ่ฎฎ้—ฎ้ข˜ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ ่พ“ๅ…ฅๆก† โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ## ๆŠ€ๆœฏๆ ˆ - **ๆก†ๆžถ**: Next.js 14 - **่ฏญ่จ€**: TypeScript - **ๆ ทๅผ**: Tailwind CSS - **ๅ›พๆ ‡**: Lucide React - **็Šถๆ€็ฎก็†**: React Hooks - **ๆ•ฐๆฎๅบ“**: Drizzle ORM (PostgreSQL) ## ๅฎ‰่ฃ…ๅ’Œ่ฟ่กŒ 1. ๅฎ‰่ฃ…ไพ่ต–๏ผš ```bash npm install ``` 2. ่ฟ่กŒๅผ€ๅ‘ๆœๅŠกๅ™จ๏ผš ```bash npm run dev ``` 3. ่ฎฟ้—ฎ่ฏพ็จ‹่ฏฆๆƒ…้กต๏ผš ``` http://localhost:3000/lesson/1 ``` ## ๆ•ฐๆฎๆจกๅž‹ ่ฏพ็จ‹่ฏฆๆƒ…้กตไฝฟ็”จไปฅไธ‹ๆ•ฐๆฎ็ป“ๆž„๏ผš ```typescript interface Lesson { id: number; title: string; videoUrl: string; duration: string; challenges: Challenge[]; } interface Challenge { id: number; question: string; options: ChallengeOption[]; completed: boolean; } interface ChallengeOption { id: number; text: string; correct: boolean; } ``` ## ่‡ชๅฎšไน‰้…็ฝฎ ### ่ง†้ข‘ๆ’ญๆ”พๅ™จ ๅฏไปฅ้€š่ฟ‡ไฟฎๆ”น `VideoPlayer` ็ป„ไปถๆฅ่‡ชๅฎšไน‰๏ผš - ๆŽงๅˆถๆ ๆ ทๅผ - ๆ’ญๆ”พๅ™จไธป้ข˜ - ๅฟซๆท้”ฎๆ”ฏๆŒ - ๆ’ญๆ”พๅˆ—่กจๅŠŸ่ƒฝ ### ๆต‹่ฏ•็ป„ไปถ `CourseQuiz` ็ป„ไปถๆ”ฏๆŒ๏ผš - ่‡ชๅฎšไน‰้ข˜็›ฎ็ฑปๅž‹ - ่ฎกๅˆ†่ง„ๅˆ™ - ๆ—ถ้—ด้™ๅˆถ - ็ป“ๆžœๅฑ•็คบ ## ่ดก็Œฎ ๆฌข่ฟŽๆไบค Issue ๅ’Œ Pull Request ๆฅๆ”น่ฟ›่ฟ™ไธช้กน็›ฎใ€‚ ## ่ฎธๅฏ่ฏ MIT License