├── .dockerignore ├── .env.example ├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.yml ├── frontend ├── .next │ ├── app-build-manifest.json │ ├── build-manifest.json │ ├── cache │ │ ├── .tsbuildinfo │ │ └── webpack │ │ │ ├── client-production │ │ │ ├── 0.pack │ │ │ ├── 1.pack │ │ │ ├── 2.pack │ │ │ ├── 3.pack │ │ │ ├── 4.pack │ │ │ ├── 5.pack │ │ │ ├── 6.pack │ │ │ ├── 7.pack │ │ │ ├── index.pack │ │ │ └── index.pack.old │ │ │ └── server-production │ │ │ ├── 0.pack │ │ │ ├── 1.pack │ │ │ ├── 2.pack │ │ │ ├── 3.pack │ │ │ ├── 4.pack │ │ │ ├── 5.pack │ │ │ ├── 6.pack │ │ │ ├── 7.pack │ │ │ ├── index.pack │ │ │ └── index.pack.old │ ├── package.json │ ├── react-loadable-manifest.json │ ├── server │ │ ├── app-paths-manifest.json │ │ ├── app │ │ │ ├── _not-found_client-reference-manifest.js │ │ │ ├── page.js │ │ │ └── page_client-reference-manifest.js │ │ ├── middleware-build-manifest.js │ │ ├── middleware-manifest.json │ │ ├── middleware-react-loadable-manifest.js │ │ ├── next-font-manifest.js │ │ ├── next-font-manifest.json │ │ ├── pages-manifest.json │ │ ├── server-reference-manifest.js │ │ ├── server-reference-manifest.json │ │ └── webpack-runtime.js │ ├── static │ │ └── media │ │ │ ├── 26a46d62cd723877-s.woff2 │ │ │ ├── 55c55f0601d81cf3-s.woff2 │ │ │ ├── 581909926a08bbc8-s.woff2 │ │ │ ├── 6d93bde91c0c2823-s.woff2 │ │ │ ├── 97e0cb1ae144a2a9-s.woff2 │ │ │ ├── a34f9d1faa5f3315-s.p.woff2 │ │ │ └── df0a9ae256c0569c-s.woff2 │ ├── trace │ └── types │ │ ├── app │ │ ├── layout.ts │ │ └── page.ts │ │ └── package.json ├── README.md ├── app │ ├── error.tsx │ ├── global-error.tsx │ ├── globals.css │ ├── layout.tsx │ ├── loading.tsx │ ├── not-found.tsx │ ├── page.tsx │ └── providers.tsx ├── bun.lockb ├── components │ ├── BookEditor.tsx │ ├── BookGenerator.tsx │ ├── BookViewer.tsx │ ├── ContentGenerator.tsx │ ├── ContentViewer.tsx │ └── ConversationHistory.tsx ├── next-env.d.ts ├── package.json ├── tailwind.config.js ├── tsconfig.json └── types │ ├── blog.ts │ └── book.ts ├── poetry.lock ├── pyproject.toml ├── requirements.txt ├── run_tests.py ├── server.py ├── src ├── __init__.py ├── __pycache__ │ └── make_mdx.cpython-312.pyc ├── blog │ ├── __init__.py │ ├── make_blog.py │ └── make_faq.py ├── blog_sections │ ├── __init__.py │ ├── code_examples_generator.py │ ├── conclusion_generator.py │ ├── faq_generator.py │ └── introduction_generator.py ├── book │ ├── __init__.py │ └── make_book.py ├── integrations │ ├── __init__.py │ ├── github.py │ ├── medium.py │ └── wordpress.py ├── planning │ ├── __init__.py │ ├── competitor_analysis.py │ ├── content_calendar.py │ ├── content_outline.py │ └── topic_clusters.py ├── post_processing │ ├── __init__.py │ ├── file_saver.py │ ├── format_converter.py │ ├── humanizer.py │ └── proofreader.py ├── research │ ├── __init__.py │ └── web_researcher.py ├── seo │ ├── __init__.py │ ├── image_alt_text.py │ ├── meta_description.py │ └── structured_data.py ├── text_generation │ ├── __init__.py │ └── core.py └── types │ ├── __init__.py │ ├── blog_sections.py │ ├── content.py │ ├── integrations.py │ ├── planning.py │ ├── post_processing.py │ ├── providers.py │ ├── research.py │ └── seo.py ├── tests ├── __init__.py ├── run_all_tests.py ├── test_blog.py ├── test_book.py ├── test_integrations.py └── test_planning.py └── troubleshooting.md /.dockerignore: -------------------------------------------------------------------------------- 1 | # Git 2 | .git 3 | .gitignore 4 | .gitattributes 5 | 6 | # Docker 7 | Dockerfile 8 | docker-compose.yml 9 | .dockerignore 10 | 11 | # Python 12 | __pycache__/ 13 | *.py[cod] 14 | *$py.class 15 | *.so 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # Virtual Environment 33 | venv/ 34 | ENV/ 35 | .env 36 | .venv 37 | env/ 38 | 39 | # Node.js 40 | frontend/node_modules/ 41 | frontend/.next/ 42 | frontend/out/ 43 | frontend/.cache/ 44 | frontend/npm-debug.log 45 | frontend/yarn-debug.log 46 | frontend/yarn-error.log 47 | 48 | # IDE 49 | .idea/ 50 | .vscode/ 51 | *.swp 52 | *.swo 53 | *~ 54 | 55 | # OS 56 | .DS_Store 57 | Thumbs.db 58 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ANTHROPIC_API_KEY=###YOUR KEY HERE 2 | SERP_API_KEY=### YOUR KEY HERE 3 | SEC_API_API_KEY=### YOUR KEY HERE 4 | OPENAI_API_KEY=### YOUR KEY HERE -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [gr8monk3ys] -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug report \U0001F41E" 3 | about: Create a bug report 4 | labels: bug 5 | 6 | --- 7 | 8 | ## Describe the bug 9 | A clear and concise description of what the bug is. 10 | 11 | ### Steps to reproduce 12 | Steps to reproduce the behavior. 13 | 14 | ### Expected behavior 15 | A clear and concise description of what you expected to happen. 16 | 17 | ### Environment 18 | - OS: [e.g. Arch Linux] 19 | - Other details that you think may affect. 20 | 21 | ### Additional context 22 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature request \U0001F680" 3 | about: Suggest an idea 4 | labels: enhancement 5 | 6 | --- 7 | 8 | ## Summary 9 | Brief explanation of the feature. 10 | 11 | ### Basic example 12 | Include a basic example or links here. 13 | 14 | ### Motivation 15 | Why are we doing this? What use cases does it support? What is the expected outcome? -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project-related files 2 | 3 | # Run logs 4 | backend/run_logs/* 5 | 6 | # Weird Docker setup related files 7 | backend/backend/* 8 | 9 | # Env vars 10 | frontend/.env.local 11 | .env 12 | frontend/node_modules/ 13 | 14 | # Mac files 15 | .DS_Store 16 | 17 | # Generated content 18 | content/blog/* 19 | content/books/* 20 | 21 | # Keep .gitkeep files 22 | !content/blog/.gitkeep 23 | !content/books/.gitkeep 24 | 25 | # Python 26 | __pycache__/ 27 | *.py[cod] 28 | *$py.class 29 | *.so 30 | .Python 31 | build/ 32 | develop-eggs/ 33 | dist/ 34 | downloads/ 35 | eggs/ 36 | .eggs/ 37 | lib64/ 38 | parts/ 39 | sdist/ 40 | var/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | 45 | # Virtual Environment 46 | venv/ 47 | ENV/ 48 | .venv 49 | env/ 50 | 51 | # Node.js 52 | frontend/.next/ 53 | frontend/out/ 54 | frontend/.cache/ 55 | frontend/npm-debug.log 56 | frontend/yarn-debug.log 57 | frontend/yarn-error.log 58 | frontend/tsconfig.tsbuildinfo 59 | 60 | # IDE 61 | .idea/ 62 | .vscode/ 63 | *.swp 64 | *.swo 65 | *~ 66 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.typeCheckingMode": "strict", 3 | "python.analysis.extraPaths": ["./backend"], 4 | "python.autoComplete.extraPaths": ["./backend"] 5 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-slim AS backend 2 | 3 | WORKDIR /app 4 | 5 | # Install Poetry 6 | RUN pip install poetry 7 | 8 | # Copy Poetry configuration files 9 | COPY pyproject.toml poetry.lock* ./ 10 | 11 | # Configure Poetry to not create a virtual environment 12 | RUN poetry config virtualenvs.create false 13 | 14 | # Install dependencies 15 | RUN poetry install --no-dev 16 | 17 | # Copy backend code 18 | COPY src/ ./src/ 19 | COPY server.py ./ 20 | COPY .env.example ./ 21 | 22 | # Expose backend port 23 | EXPOSE 8000 24 | 25 | # ------------------------------------------- 26 | FROM node:18-alpine AS frontend-build 27 | 28 | WORKDIR /app 29 | 30 | # Copy frontend files 31 | COPY frontend/package.json frontend/bun.lockb ./ 32 | 33 | # Install dependencies 34 | RUN npm install 35 | 36 | # Copy frontend source code 37 | COPY frontend/ ./ 38 | 39 | # Build frontend 40 | RUN npm run build 41 | 42 | # ------------------------------------------- 43 | FROM python:3.12-slim 44 | 45 | WORKDIR /app 46 | 47 | # Copy backend from the backend stage 48 | COPY --from=backend /app /app 49 | COPY --from=backend /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages 50 | 51 | # Copy built frontend from frontend-build stage 52 | COPY --from=frontend-build /app/.next /app/frontend/.next 53 | COPY --from=frontend-build /app/public /app/frontend/public 54 | COPY --from=frontend-build /app/node_modules /app/frontend/node_modules 55 | COPY --from=frontend-build /app/package.json /app/frontend/package.json 56 | 57 | # Install additional packages needed for the final image 58 | RUN apt-get update && apt-get install -y --no-install-recommends \ 59 | nodejs \ 60 | npm \ 61 | && rm -rf /var/lib/apt/lists/* 62 | 63 | # Create a script to start both services 64 | RUN echo '#!/bin/bash\n\ 65 | # Start the backend server in the background\n\ 66 | python server.py & \n\ 67 | # Change to the frontend directory and start the frontend server\n\ 68 | cd frontend && npm run start\n\ 69 | ' > /app/start.sh && chmod +x /app/start.sh 70 | 71 | # Expose ports 72 | EXPOSE 8000 3000 73 | 74 | # Set environment variables 75 | ENV PYTHONPATH=/app 76 | 77 | # Start both services 78 | CMD ["/app/start.sh"] 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✨ Blog AI Generation Tool 2 | 3 | Welcome to the **Blog AI Generation Tool** – a smart, AI-driven solution designed to streamline the process of writing blog posts and even entire books. Harness the power of **GPT-4** and advanced AI techniques to transform your ideas into well-structured, SEO-friendly content with minimal effort. 4 | 5 | ## 🌟 Key Features 6 | 7 | - **📝 Blog Post Generation**: Create structured, SEO-optimized blog posts with a single command. 8 | - **📚 Book Creation**: Generate full-length books with chapters, sections, and consistent style. 9 | - **📅 Content Planning**: Plan your content with calendars, topic clusters, and outlines. 10 | - **🔍 Competitor Analysis**: Analyze competitors to identify content gaps and opportunities. 11 | - **🔎 Web Research**: Conduct research to enhance content with accurate information. 12 | - **🔄 Post-Processing**: Proofread, humanize, and format your content for various platforms. 13 | - **🔌 Integrations**: Publish directly to WordPress, GitHub, and Medium. 14 | - **🤖 Modern AI Integration**: Built on GPT-4 for reliable, high-quality content output. 15 | 16 | ## 🗂️ Project Structure 17 | 18 | ``` 19 | blog-AI/ 20 | ├── src/ # Source code 21 | │ ├── blog/ # Blog generation modules 22 | │ ├── book/ # Book generation modules 23 | │ ├── blog_sections/ # Blog section generators 24 | │ ├── planning/ # Content planning tools 25 | │ │ ├── content_calendar.py # Content calendar generation 26 | │ │ ├── competitor_analysis.py # Competitor analysis 27 | │ │ ├── topic_clusters.py # Topic cluster generation 28 | │ │ └── content_outline.py # Content outline generation 29 | │ ├── research/ # Research tools 30 | │ ├── seo/ # SEO optimization tools 31 | │ ├── integrations/ # Publishing integrations 32 | │ │ ├── github.py # GitHub integration 33 | │ │ ├── medium.py # Medium integration 34 | │ │ └── wordpress.py # WordPress integration 35 | │ ├── post_processing/ # Content post-processing 36 | │ ├── text_generation/ # Text generation core 37 | │ └── types/ # Type definitions 38 | ├── tests/ # Test files 39 | ├── frontend/ # Web interface (Next.js) 40 | ├── .env # Environment configuration 41 | ├── .env.example # Example environment configuration 42 | ├── pyproject.toml # Project dependencies 43 | ├── LICENSE # License information 44 | └── README.md # Project documentation 45 | ``` 46 | 47 | ## 🚀 Getting Started 48 | 49 | 1. **Clone the repository**: 50 | ```bash 51 | git clone https://github.com/yourusername/blog-AI.git 52 | ``` 53 | 54 | 2. **Configure environment**: 55 | Create a `.env` file based on `.env.example` and add your API keys: 56 | ```bash 57 | # Required for basic functionality 58 | OPENAI_API_KEY=your_openai_api_key_here 59 | 60 | # Optional - for additional features 61 | ANTHROPIC_API_KEY=your_anthropic_api_key_here 62 | SERP_API_KEY=your_serp_api_key_here 63 | SEC_API_API_KEY=your_sec_api_key_here 64 | ``` 65 | 66 | 3. **Install dependencies**: 67 | Using Poetry (recommended): 68 | ```bash 69 | poetry install 70 | ``` 71 | 72 | Or using pip: 73 | ```bash 74 | pip install -r requirements.txt 75 | ``` 76 | 77 | 4. **Start the backend server** (required for the web interface): 78 | ```bash 79 | python server.py 80 | ``` 81 | This will start the server at http://localhost:8000 82 | 83 | 5. **Start the frontend** (optional, for web interface): 84 | ```bash 85 | cd frontend 86 | npm install 87 | npm run dev 88 | ``` 89 | This will start the frontend at http://localhost:3000 90 | 91 | 6. **You're all set!** The tool is now ready to generate content at your command. 92 | 93 | ## 🐳 Docker Setup 94 | 95 | You can also run the application using Docker, which simplifies the setup process: 96 | 97 | 1. **Build and start the containers**: 98 | ```bash 99 | docker-compose up -d 100 | ``` 101 | 102 | 2. **Configure environment**: 103 | Before starting the containers, make sure to create a `.env` file based on `.env.example` with your API keys. 104 | 105 | 3. **Access the application**: 106 | - Backend API: http://localhost:8000 107 | - Frontend: http://localhost:3000 108 | 109 | 4. **Stop the containers**: 110 | ```bash 111 | docker-compose down 112 | ``` 113 | 114 | ### Docker Commands 115 | 116 | - **View logs**: 117 | ```bash 118 | docker-compose logs -f 119 | ``` 120 | 121 | - **Rebuild the containers** (after making changes): 122 | ```bash 123 | docker-compose up -d --build 124 | ``` 125 | 126 | - **Run a command inside the container**: 127 | ```bash 128 | docker-compose exec blog-ai bash 129 | ``` 130 | 131 | ## 💻 Usage 132 | 133 | ### Generate a Blog Post 134 | 135 | ```bash 136 | python -m src.blog.make_blog "Your Blog Topic" --keywords "keyword1,keyword2" --research 137 | ``` 138 | 139 | This command creates a fully formatted blog post and saves it under the `content/blog/` directory. 140 | 141 | **Optional Parameters**: 142 | - `--keywords`: Comma-separated list of keywords to include 143 | - `--research`: Enable web research for more accurate content 144 | - `--tone`: Set the tone of the content (default: "informative") 145 | - `--output`: Specify the output filename and format (default: markdown) 146 | - `--proofread`: Enable proofreading 147 | - `--humanize`: Make the content more human-like 148 | 149 | ### Generate a Book 150 | 151 | ```bash 152 | python -m src.book.make_book "Your Book Topic" --chapters 5 --sections 3 --output "book_name.md" 153 | ``` 154 | 155 | **Optional Parameters**: 156 | - `--chapters`: Number of chapters to generate (default: 5) 157 | - `--sections`: Number of sections per chapter (default: 3) 158 | - `--keywords`: Comma-separated list of keywords to include 159 | - `--research`: Enable web research for more accurate content 160 | - `--tone`: Set the tone of the content (default: "informative") 161 | - `--output`: Specify the output filename and format 162 | - `--proofread`: Enable proofreading 163 | - `--humanize`: Make the content more human-like 164 | 165 | ### Content Planning 166 | 167 | ```bash 168 | # Generate a content calendar 169 | python -m src.planning.content_calendar "Your Niche" --timeframe month --frequency 7 170 | 171 | # Analyze competitors 172 | python -m src.planning.competitor_analysis "Your Niche" --competitors "Competitor1,Competitor2" 173 | 174 | # Generate topic clusters 175 | python -m src.planning.topic_clusters "Your Niche" --clusters 3 --subtopics 5 176 | 177 | # Create content outlines 178 | python -m src.planning.content_outline "Your Topic" --keywords "keyword1,keyword2" --sections 5 179 | ``` 180 | 181 | ### Publishing Integrations 182 | 183 | ```bash 184 | # Publish to WordPress 185 | python -m src.integrations.wordpress "Your Blog Post" --url "https://yourblog.com" --username "user" --password "pass" 186 | 187 | # Publish to GitHub 188 | python -m src.integrations.github "Your Blog Post" --repo "username/repo" --token "github_token" 189 | 190 | # Publish to Medium 191 | python -m src.integrations.medium "Your Blog Post" --token "medium_token" --tags "tag1,tag2" 192 | ``` 193 | 194 | ## 🧪 Testing 195 | 196 | Run the test suite to ensure everything is working correctly: 197 | 198 | ```bash 199 | python -m unittest discover tests 200 | ``` 201 | 202 | ## 🔧 Troubleshooting 203 | 204 | If you encounter any issues while setting up or using the Blog AI Generation Tool, please refer to the [Troubleshooting Guide](troubleshooting.md) for solutions to common problems. 205 | 206 | ## ⚙️ Dependencies 207 | 208 | - **openai**: OpenAI API client for text generation 209 | - **anthropic**: Anthropic API client for Claude models 210 | - **google-generativeai**: Google's Gemini API client 211 | - **requests**: HTTP requests for API interactions 212 | - **pydantic**: Data validation and settings management 213 | - **python-dotenv**: Environment variable management 214 | - **fastapi**: Backend API framework 215 | - **uvicorn**: ASGI server for FastAPI 216 | - **websockets**: WebSocket support for real-time communication 217 | 218 | ## 📜 License 219 | 220 | This project is available under the [MIT License](LICENSE). Feel free to explore, fork, and contribute! 221 | 222 | **Happy Writing!** 🎉 Turn your ideas into captivating blog posts or fully-fledged books with minimal hassle—just let the AI do the heavy lifting. 223 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | blog-ai: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | ports: 9 | - "8000:8000" # Backend API 10 | - "3000:3000" # Frontend 11 | volumes: 12 | - ./.env:/app/.env:ro # Mount .env file as read-only 13 | environment: 14 | - NODE_ENV=production 15 | restart: unless-stopped 16 | healthcheck: 17 | test: ["CMD", "curl", "-f", "http://localhost:8000"] 18 | interval: 30s 19 | timeout: 10s 20 | retries: 3 21 | start_period: 40s 22 | -------------------------------------------------------------------------------- /frontend/.next/app-build-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": { 3 | "/global-error": [ 4 | "static/chunks/webpack.js", 5 | "static/chunks/main-app.js", 6 | "static/chunks/app/global-error.js" 7 | ], 8 | "/page": [ 9 | "static/chunks/webpack.js", 10 | "static/chunks/main-app.js", 11 | "static/chunks/app/page.js" 12 | ], 13 | "/layout": [ 14 | "static/chunks/webpack.js", 15 | "static/chunks/main-app.js", 16 | "static/css/app/layout.css", 17 | "static/chunks/app/layout.js" 18 | ], 19 | "/error": [ 20 | "static/chunks/webpack.js", 21 | "static/chunks/main-app.js", 22 | "static/chunks/app/error.js" 23 | ], 24 | "/loading": [ 25 | "static/chunks/webpack.js", 26 | "static/chunks/main-app.js", 27 | "static/chunks/app/loading.js" 28 | ], 29 | "/not-found": [ 30 | "static/chunks/webpack.js", 31 | "static/chunks/main-app.js", 32 | "static/chunks/app/not-found.js" 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /frontend/.next/build-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "polyfillFiles": [ 3 | "static/chunks/polyfills.js" 4 | ], 5 | "devFiles": [], 6 | "ampDevFiles": [], 7 | "lowPriorityFiles": [ 8 | "static/development/_buildManifest.js", 9 | "static/development/_ssgManifest.js" 10 | ], 11 | "rootMainFiles": [ 12 | "static/chunks/webpack.js", 13 | "static/chunks/main-app.js" 14 | ], 15 | "pages": { 16 | "/_app": [] 17 | }, 18 | "ampFirstPages": [] 19 | } -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/0.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/0.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/1.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/1.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/2.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/2.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/3.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/3.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/4.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/4.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/5.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/5.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/6.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/6.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/7.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/7.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/index.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/index.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/client-production/index.pack.old: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/client-production/index.pack.old -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/0.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/0.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/1.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/1.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/2.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/2.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/3.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/3.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/4.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/4.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/5.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/5.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/6.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/6.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/7.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/7.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/index.pack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/index.pack -------------------------------------------------------------------------------- /frontend/.next/cache/webpack/server-production/index.pack.old: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/cache/webpack/server-production/index.pack.old -------------------------------------------------------------------------------- /frontend/.next/package.json: -------------------------------------------------------------------------------- 1 | {"type": "commonjs"} -------------------------------------------------------------------------------- /frontend/.next/react-loadable-manifest.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /frontend/.next/server/app-paths-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/page": "app/page.js" 3 | } -------------------------------------------------------------------------------- /frontend/.next/server/app/_not-found_client-reference-manifest.js: -------------------------------------------------------------------------------- 1 | globalThis.__RSC_MANIFEST=(globalThis.__RSC_MANIFEST||{});globalThis.__RSC_MANIFEST["/_not-found"]={"moduleLoading":{"prefix":"/_next/","crossOrigin":null},"ssrModuleMapping":{"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/global-error.tsx":{"*":{"id":"(ssr)/./app/global-error.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/page.tsx":{"*":{"id":"(ssr)/./app/page.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/error.tsx":{"*":{"id":"(ssr)/./app/error.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/link.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/link.js","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\app-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\app-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\error-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\error-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\layout-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\layout-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\not-found-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\not-found-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\render-from-template-context.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\render-from-template-context.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\static-generation-searchparams-bailout-provider.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\static-generation-searchparams-bailout-provider.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\global-error.tsx":{"id":"(app-pages-browser)/./app/global-error.tsx","name":"*","chunks":["app/global-error","static/chunks/app/global-error.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\page.tsx":{"id":"(app-pages-browser)/./app/page.tsx","name":"*","chunks":["app/page","static/chunks/app/page.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\font\\google\\target.css?{\"path\":\"app\\\\layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}":{"id":"(app-pages-browser)/./node_modules/next/font/google/target.css?{\"path\":\"app\\\\layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}","name":"*","chunks":["app/layout","static/chunks/app/layout.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\globals.css":{"id":"(app-pages-browser)/./app/globals.css","name":"*","chunks":["app/layout","static/chunks/app/layout.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\error.tsx":{"id":"(app-pages-browser)/./app/error.tsx","name":"*","chunks":["app/error","static/chunks/app/error.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\link.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/link.js","name":"*","chunks":["app/not-found","static/chunks/app/not-found.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\link.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/link.js","name":"*","chunks":["app/not-found","static/chunks/app/not-found.js"],"async":false}},"entryCSSFiles":{"C:\\_Code\\blog-AI\\frontend\\app\\global-error":[],"C:\\_Code\\blog-AI\\frontend\\app\\page":[],"C:\\_Code\\blog-AI\\frontend\\app\\layout":["static/css/app/layout.css"],"C:\\_Code\\blog-AI\\frontend\\app\\error":[],"C:\\_Code\\blog-AI\\frontend\\app\\loading":[],"C:\\_Code\\blog-AI\\frontend\\app\\not-found":[]}} -------------------------------------------------------------------------------- /frontend/.next/server/app/page_client-reference-manifest.js: -------------------------------------------------------------------------------- 1 | globalThis.__RSC_MANIFEST=(globalThis.__RSC_MANIFEST||{});globalThis.__RSC_MANIFEST["/page"]={"moduleLoading":{"prefix":"/_next/","crossOrigin":null},"ssrModuleMapping":{"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/global-error.tsx":{"*":{"id":"(ssr)/./app/global-error.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/page.tsx":{"*":{"id":"(ssr)/./app/page.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./app/error.tsx":{"*":{"id":"(ssr)/./app/error.tsx","name":"*","chunks":[],"async":false}},"(app-pages-browser)/./node_modules/next/dist/client/link.js":{"*":{"id":"(ssr)/./node_modules/next/dist/client/link.js","name":"*","chunks":[],"async":false}}},"edgeSSRModuleMapping":{},"clientModules":{"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\app-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\app-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/app-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\error-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\error-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/error-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\layout-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\layout-router.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/layout-router.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\not-found-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\not-found-boundary.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/not-found-boundary.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\render-from-template-context.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\render-from-template-context.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/render-from-template-context.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\components\\static-generation-searchparams-bailout-provider.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\components\\static-generation-searchparams-bailout-provider.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.js","name":"*","chunks":["app-pages-internals","static/chunks/app-pages-internals.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\global-error.tsx":{"id":"(app-pages-browser)/./app/global-error.tsx","name":"*","chunks":["app/global-error","static/chunks/app/global-error.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\page.tsx":{"id":"(app-pages-browser)/./app/page.tsx","name":"*","chunks":["app/page","static/chunks/app/page.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\font\\google\\target.css?{\"path\":\"app\\\\layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}":{"id":"(app-pages-browser)/./node_modules/next/font/google/target.css?{\"path\":\"app\\\\layout.tsx\",\"import\":\"Inter\",\"arguments\":[{\"subsets\":[\"latin\"]}],\"variableName\":\"inter\"}","name":"*","chunks":["app/layout","static/chunks/app/layout.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\globals.css":{"id":"(app-pages-browser)/./app/globals.css","name":"*","chunks":["app/layout","static/chunks/app/layout.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\app\\error.tsx":{"id":"(app-pages-browser)/./app/error.tsx","name":"*","chunks":["app/error","static/chunks/app/error.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\client\\link.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/link.js","name":"*","chunks":["app/not-found","static/chunks/app/not-found.js"],"async":false},"C:\\_Code\\blog-AI\\frontend\\node_modules\\next\\dist\\esm\\client\\link.js":{"id":"(app-pages-browser)/./node_modules/next/dist/client/link.js","name":"*","chunks":["app/not-found","static/chunks/app/not-found.js"],"async":false}},"entryCSSFiles":{"C:\\_Code\\blog-AI\\frontend\\app\\global-error":[],"C:\\_Code\\blog-AI\\frontend\\app\\page":[],"C:\\_Code\\blog-AI\\frontend\\app\\layout":["static/css/app/layout.css"],"C:\\_Code\\blog-AI\\frontend\\app\\error":[],"C:\\_Code\\blog-AI\\frontend\\app\\loading":[],"C:\\_Code\\blog-AI\\frontend\\app\\not-found":[]}} -------------------------------------------------------------------------------- /frontend/.next/server/middleware-build-manifest.js: -------------------------------------------------------------------------------- 1 | self.__BUILD_MANIFEST={"polyfillFiles":["static/chunks/polyfills.js"],"devFiles":[],"ampDevFiles":[],"lowPriorityFiles":["static/development/_buildManifest.js","static/development/_ssgManifest.js"],"rootMainFiles":["static/chunks/webpack.js","static/chunks/main-app.js"],"pages":{"/_app":[]},"ampFirstPages":[]} -------------------------------------------------------------------------------- /frontend/.next/server/middleware-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "sortedMiddleware": [], 3 | "middleware": {}, 4 | "functions": {}, 5 | "version": 2 6 | } -------------------------------------------------------------------------------- /frontend/.next/server/middleware-react-loadable-manifest.js: -------------------------------------------------------------------------------- 1 | self.__REACT_LOADABLE_MANIFEST="{}" -------------------------------------------------------------------------------- /frontend/.next/server/next-font-manifest.js: -------------------------------------------------------------------------------- 1 | self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}" -------------------------------------------------------------------------------- /frontend/.next/server/next-font-manifest.json: -------------------------------------------------------------------------------- 1 | {"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false} -------------------------------------------------------------------------------- /frontend/.next/server/pages-manifest.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /frontend/.next/server/server-reference-manifest.js: -------------------------------------------------------------------------------- 1 | self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"tnxMkYTI0JdqAObkVN7HhelqduG7xYr5+jOq7Ba6aMM=\"\n}" -------------------------------------------------------------------------------- /frontend/.next/server/server-reference-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": {}, 3 | "edge": {}, 4 | "encryptionKey": "tnxMkYTI0JdqAObkVN7HhelqduG7xYr5+jOq7Ba6aMM=" 5 | } -------------------------------------------------------------------------------- /frontend/.next/server/webpack-runtime.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ATTENTION: An "eval-source-map" devtool has been used. 3 | * This devtool is neither made for production nor for readable output files. 4 | * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. 5 | * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) 6 | * or disable the default devtool with "devtool: false". 7 | * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). 8 | */ 9 | /******/ (() => { // webpackBootstrap 10 | /******/ "use strict"; 11 | /******/ var __webpack_modules__ = ({}); 12 | /************************************************************************/ 13 | /******/ // The module cache 14 | /******/ var __webpack_module_cache__ = {}; 15 | /******/ 16 | /******/ // The require function 17 | /******/ function __webpack_require__(moduleId) { 18 | /******/ // Check if module is in cache 19 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; 20 | /******/ if (cachedModule !== undefined) { 21 | /******/ return cachedModule.exports; 22 | /******/ } 23 | /******/ // Create a new module (and put it into the cache) 24 | /******/ var module = __webpack_module_cache__[moduleId] = { 25 | /******/ id: moduleId, 26 | /******/ loaded: false, 27 | /******/ exports: {} 28 | /******/ }; 29 | /******/ 30 | /******/ // Execute the module function 31 | /******/ var threw = true; 32 | /******/ try { 33 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); 34 | /******/ threw = false; 35 | /******/ } finally { 36 | /******/ if(threw) delete __webpack_module_cache__[moduleId]; 37 | /******/ } 38 | /******/ 39 | /******/ // Flag the module as loaded 40 | /******/ module.loaded = true; 41 | /******/ 42 | /******/ // Return the exports of the module 43 | /******/ return module.exports; 44 | /******/ } 45 | /******/ 46 | /******/ // expose the modules object (__webpack_modules__) 47 | /******/ __webpack_require__.m = __webpack_modules__; 48 | /******/ 49 | /************************************************************************/ 50 | /******/ /* webpack/runtime/compat get default export */ 51 | /******/ (() => { 52 | /******/ // getDefaultExport function for compatibility with non-harmony modules 53 | /******/ __webpack_require__.n = (module) => { 54 | /******/ var getter = module && module.__esModule ? 55 | /******/ () => (module['default']) : 56 | /******/ () => (module); 57 | /******/ __webpack_require__.d(getter, { a: getter }); 58 | /******/ return getter; 59 | /******/ }; 60 | /******/ })(); 61 | /******/ 62 | /******/ /* webpack/runtime/create fake namespace object */ 63 | /******/ (() => { 64 | /******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); 65 | /******/ var leafPrototypes; 66 | /******/ // create a fake namespace object 67 | /******/ // mode & 1: value is a module id, require it 68 | /******/ // mode & 2: merge all properties of value into the ns 69 | /******/ // mode & 4: return value when already ns object 70 | /******/ // mode & 16: return value when it's Promise-like 71 | /******/ // mode & 8|1: behave like require 72 | /******/ __webpack_require__.t = function(value, mode) { 73 | /******/ if(mode & 1) value = this(value); 74 | /******/ if(mode & 8) return value; 75 | /******/ if(typeof value === 'object' && value) { 76 | /******/ if((mode & 4) && value.__esModule) return value; 77 | /******/ if((mode & 16) && typeof value.then === 'function') return value; 78 | /******/ } 79 | /******/ var ns = Object.create(null); 80 | /******/ __webpack_require__.r(ns); 81 | /******/ var def = {}; 82 | /******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; 83 | /******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { 84 | /******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); 85 | /******/ } 86 | /******/ def['default'] = () => (value); 87 | /******/ __webpack_require__.d(ns, def); 88 | /******/ return ns; 89 | /******/ }; 90 | /******/ })(); 91 | /******/ 92 | /******/ /* webpack/runtime/define property getters */ 93 | /******/ (() => { 94 | /******/ // define getter functions for harmony exports 95 | /******/ __webpack_require__.d = (exports, definition) => { 96 | /******/ for(var key in definition) { 97 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 98 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 99 | /******/ } 100 | /******/ } 101 | /******/ }; 102 | /******/ })(); 103 | /******/ 104 | /******/ /* webpack/runtime/ensure chunk */ 105 | /******/ (() => { 106 | /******/ __webpack_require__.f = {}; 107 | /******/ // This file contains only the entry chunk. 108 | /******/ // The chunk loading function for additional chunks 109 | /******/ __webpack_require__.e = (chunkId) => { 110 | /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { 111 | /******/ __webpack_require__.f[key](chunkId, promises); 112 | /******/ return promises; 113 | /******/ }, [])); 114 | /******/ }; 115 | /******/ })(); 116 | /******/ 117 | /******/ /* webpack/runtime/get javascript chunk filename */ 118 | /******/ (() => { 119 | /******/ // This function allow to reference async chunks and sibling chunks for the entrypoint 120 | /******/ __webpack_require__.u = (chunkId) => { 121 | /******/ // return url for filenames based on template 122 | /******/ return "" + chunkId + ".js"; 123 | /******/ }; 124 | /******/ })(); 125 | /******/ 126 | /******/ /* webpack/runtime/getFullHash */ 127 | /******/ (() => { 128 | /******/ __webpack_require__.h = () => ("4bbfca725791f486") 129 | /******/ })(); 130 | /******/ 131 | /******/ /* webpack/runtime/hasOwnProperty shorthand */ 132 | /******/ (() => { 133 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 134 | /******/ })(); 135 | /******/ 136 | /******/ /* webpack/runtime/make namespace object */ 137 | /******/ (() => { 138 | /******/ // define __esModule on exports 139 | /******/ __webpack_require__.r = (exports) => { 140 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 141 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 142 | /******/ } 143 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 144 | /******/ }; 145 | /******/ })(); 146 | /******/ 147 | /******/ /* webpack/runtime/node module decorator */ 148 | /******/ (() => { 149 | /******/ __webpack_require__.nmd = (module) => { 150 | /******/ module.paths = []; 151 | /******/ if (!module.children) module.children = []; 152 | /******/ return module; 153 | /******/ }; 154 | /******/ })(); 155 | /******/ 156 | /******/ /* webpack/runtime/startup entrypoint */ 157 | /******/ (() => { 158 | /******/ __webpack_require__.X = (result, chunkIds, fn) => { 159 | /******/ // arguments: chunkIds, moduleId are deprecated 160 | /******/ var moduleId = chunkIds; 161 | /******/ if(!fn) chunkIds = result, fn = () => (__webpack_require__(__webpack_require__.s = moduleId)); 162 | /******/ chunkIds.map(__webpack_require__.e, __webpack_require__) 163 | /******/ var r = fn(); 164 | /******/ return r === undefined ? result : r; 165 | /******/ } 166 | /******/ })(); 167 | /******/ 168 | /******/ /* webpack/runtime/require chunk loading */ 169 | /******/ (() => { 170 | /******/ // no baseURI 171 | /******/ 172 | /******/ // object to store loaded chunks 173 | /******/ // "1" means "loaded", otherwise not loaded yet 174 | /******/ var installedChunks = { 175 | /******/ "webpack-runtime": 1 176 | /******/ }; 177 | /******/ 178 | /******/ // no on chunks loaded 179 | /******/ 180 | /******/ var installChunk = (chunk) => { 181 | /******/ var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime; 182 | /******/ for(var moduleId in moreModules) { 183 | /******/ if(__webpack_require__.o(moreModules, moduleId)) { 184 | /******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; 185 | /******/ } 186 | /******/ } 187 | /******/ if(runtime) runtime(__webpack_require__); 188 | /******/ for(var i = 0; i < chunkIds.length; i++) 189 | /******/ installedChunks[chunkIds[i]] = 1; 190 | /******/ 191 | /******/ }; 192 | /******/ 193 | /******/ // require() chunk loading for javascript 194 | /******/ __webpack_require__.f.require = (chunkId, promises) => { 195 | /******/ // "1" is the signal for "already loaded" 196 | /******/ if(!installedChunks[chunkId]) { 197 | /******/ if("webpack-runtime" != chunkId) { 198 | /******/ installChunk(require("./" + __webpack_require__.u(chunkId))); 199 | /******/ } else installedChunks[chunkId] = 1; 200 | /******/ } 201 | /******/ }; 202 | /******/ 203 | /******/ module.exports = __webpack_require__; 204 | /******/ __webpack_require__.C = installChunk; 205 | /******/ 206 | /******/ // no HMR 207 | /******/ 208 | /******/ // no HMR manifest 209 | /******/ })(); 210 | /******/ 211 | /************************************************************************/ 212 | /******/ 213 | /******/ 214 | /******/ })() 215 | ; -------------------------------------------------------------------------------- /frontend/.next/static/media/26a46d62cd723877-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/26a46d62cd723877-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/55c55f0601d81cf3-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/55c55f0601d81cf3-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/581909926a08bbc8-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/581909926a08bbc8-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/6d93bde91c0c2823-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/6d93bde91c0c2823-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/97e0cb1ae144a2a9-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/97e0cb1ae144a2a9-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/a34f9d1faa5f3315-s.p.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/a34f9d1faa5f3315-s.p.woff2 -------------------------------------------------------------------------------- /frontend/.next/static/media/df0a9ae256c0569c-s.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/.next/static/media/df0a9ae256c0569c-s.woff2 -------------------------------------------------------------------------------- /frontend/.next/types/app/layout.ts: -------------------------------------------------------------------------------- 1 | // File: C:\_Code\blog-AI\frontend\app\layout.tsx 2 | import * as entry from '../../../app/layout.js' 3 | import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js' 4 | 5 | type TEntry = typeof import('../../../app/layout.js') 6 | 7 | // Check that the entry is a valid entry 8 | checkFields | false 13 | dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static' 14 | dynamicParams?: boolean 15 | fetchCache?: 'auto' | 'force-no-store' | 'only-no-store' | 'default-no-store' | 'default-cache' | 'only-cache' | 'force-cache' 16 | preferredRegion?: 'auto' | 'global' | 'home' | string | string[] 17 | runtime?: 'nodejs' | 'experimental-edge' | 'edge' 18 | maxDuration?: number 19 | 20 | metadata?: any 21 | generateMetadata?: Function 22 | viewport?: any 23 | generateViewport?: Function 24 | 25 | }, TEntry, ''>>() 26 | 27 | // Check the prop type of the entry function 28 | checkFields, 'default'>>() 29 | 30 | // Check the arguments and return type of the generateMetadata function 31 | if ('generateMetadata' in entry) { 32 | checkFields>, 'generateMetadata'>>() 33 | checkFields>, 'generateMetadata'>>() 34 | } 35 | 36 | // Check the arguments and return type of the generateViewport function 37 | if ('generateViewport' in entry) { 38 | checkFields>, 'generateViewport'>>() 39 | checkFields>, 'generateViewport'>>() 40 | } 41 | 42 | // Check the arguments and return type of the generateStaticParams function 43 | if ('generateStaticParams' in entry) { 44 | checkFields>, 'generateStaticParams'>>() 45 | checkFields }, { __tag__: 'generateStaticParams', __return_type__: ReturnType> }>>() 46 | } 47 | 48 | type PageParams = any 49 | export interface PageProps { 50 | params?: any 51 | searchParams?: any 52 | } 53 | export interface LayoutProps { 54 | children?: React.ReactNode 55 | 56 | params?: any 57 | } 58 | 59 | // ============= 60 | // Utility types 61 | type RevalidateRange = T extends { revalidate: any } ? NonNegative : never 62 | 63 | // If T is unknown or any, it will be an empty {} type. Otherwise, it will be the same as Omit. 64 | type OmitWithTag = Omit 65 | type Diff = 0 extends (1 & T) ? {} : OmitWithTag 66 | 67 | type FirstArg = T extends (...args: [infer T, any]) => any ? unknown extends T ? any : T : never 68 | type SecondArg = T extends (...args: [any, infer T]) => any ? unknown extends T ? any : T : never 69 | type MaybeField = T extends { [k in K]: infer G } ? G extends Function ? G : never : never 70 | 71 | 72 | 73 | function checkFields<_ extends { [k in keyof any]: never }>() {} 74 | 75 | // https://github.com/sindresorhus/type-fest 76 | type Numeric = number | bigint 77 | type Zero = 0 | 0n 78 | type Negative = T extends Zero ? never : `${T}` extends `-${string}` ? T : never 79 | type NonNegative = T extends Zero ? T : Negative extends never ? T : '__invalid_negative_number__' 80 | -------------------------------------------------------------------------------- /frontend/.next/types/app/page.ts: -------------------------------------------------------------------------------- 1 | // File: C:\_Code\blog-AI\frontend\app\page.tsx 2 | import * as entry from '../../../app/page.js' 3 | import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js' 4 | 5 | type TEntry = typeof import('../../../app/page.js') 6 | 7 | // Check that the entry is a valid entry 8 | checkFields | false 13 | dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static' 14 | dynamicParams?: boolean 15 | fetchCache?: 'auto' | 'force-no-store' | 'only-no-store' | 'default-no-store' | 'default-cache' | 'only-cache' | 'force-cache' 16 | preferredRegion?: 'auto' | 'global' | 'home' | string | string[] 17 | runtime?: 'nodejs' | 'experimental-edge' | 'edge' 18 | maxDuration?: number 19 | 20 | metadata?: any 21 | generateMetadata?: Function 22 | viewport?: any 23 | generateViewport?: Function 24 | 25 | }, TEntry, ''>>() 26 | 27 | // Check the prop type of the entry function 28 | checkFields, 'default'>>() 29 | 30 | // Check the arguments and return type of the generateMetadata function 31 | if ('generateMetadata' in entry) { 32 | checkFields>, 'generateMetadata'>>() 33 | checkFields>, 'generateMetadata'>>() 34 | } 35 | 36 | // Check the arguments and return type of the generateViewport function 37 | if ('generateViewport' in entry) { 38 | checkFields>, 'generateViewport'>>() 39 | checkFields>, 'generateViewport'>>() 40 | } 41 | 42 | // Check the arguments and return type of the generateStaticParams function 43 | if ('generateStaticParams' in entry) { 44 | checkFields>, 'generateStaticParams'>>() 45 | checkFields }, { __tag__: 'generateStaticParams', __return_type__: ReturnType> }>>() 46 | } 47 | 48 | type PageParams = any 49 | export interface PageProps { 50 | params?: any 51 | searchParams?: any 52 | } 53 | export interface LayoutProps { 54 | children?: React.ReactNode 55 | 56 | params?: any 57 | } 58 | 59 | // ============= 60 | // Utility types 61 | type RevalidateRange = T extends { revalidate: any } ? NonNegative : never 62 | 63 | // If T is unknown or any, it will be an empty {} type. Otherwise, it will be the same as Omit. 64 | type OmitWithTag = Omit 65 | type Diff = 0 extends (1 & T) ? {} : OmitWithTag 66 | 67 | type FirstArg = T extends (...args: [infer T, any]) => any ? unknown extends T ? any : T : never 68 | type SecondArg = T extends (...args: [any, infer T]) => any ? unknown extends T ? any : T : never 69 | type MaybeField = T extends { [k in K]: infer G } ? G extends Function ? G : never : never 70 | 71 | 72 | 73 | function checkFields<_ extends { [k in keyof any]: never }>() {} 74 | 75 | // https://github.com/sindresorhus/type-fest 76 | type Numeric = number | bigint 77 | type Zero = 0 | 0n 78 | type Negative = T extends Zero ? never : `${T}` extends `-${string}` ? T : never 79 | type NonNegative = T extends Zero ? T : Negative extends never ? T : '__invalid_negative_number__' 80 | -------------------------------------------------------------------------------- /frontend/.next/types/package.json: -------------------------------------------------------------------------------- 1 | {"type": "module"} -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Blog-AI Frontend 2 | 3 | This is the frontend for the Blog-AI application, which provides a user interface for generating and managing blog posts and books using AI. 4 | 5 | ## Features 6 | 7 | - **Blog Post Generation**: Create high-quality blog posts on any topic with customizable options 8 | - **Book Generation**: Generate complete books with chapters and topics 9 | - **Content Editing**: Edit generated content with an intuitive interface 10 | - **Conversation History**: Track your interactions with the AI 11 | - **Download Options**: Export your content in different formats 12 | 13 | ## Components 14 | 15 | ### Content Generation 16 | 17 | - **ContentGenerator**: UI for generating blog posts with options for tone, research, proofreading, and humanization 18 | - **BookGenerator**: UI for generating books with options for number of chapters, sections per chapter, and more 19 | 20 | ### Content Viewing and Editing 21 | 22 | - **ContentViewer**: Displays generated content based on its type (blog or book) 23 | - **BookViewer**: Specialized component for viewing books with chapter navigation 24 | - **BookEditor**: Full-featured editor for modifying book content, including chapter titles and topic content 25 | 26 | ## Type Definitions 27 | 28 | The application uses TypeScript for type safety. Key type definitions include: 29 | 30 | ### Blog Types 31 | 32 | - `Section`: Represents a section of a blog post with an ID and content 33 | - `BlogPost`: Represents a complete blog post with title, sections, tags, and date 34 | - `BlogGenerationOptions`: Options for generating a blog post 35 | 36 | ### Book Types 37 | 38 | - `Topic`: Represents a topic within a chapter with title and content 39 | - `Chapter`: Represents a chapter with number, title, and topics 40 | - `Book`: Represents a complete book with title, chapters, tags, and date 41 | - `BookGenerationOptions`: Options for generating a book 42 | 43 | ## Getting Started 44 | 45 | 1. Install dependencies: 46 | ``` 47 | npm install 48 | ``` 49 | 50 | 2. Run the development server: 51 | ``` 52 | npm run dev 53 | ``` 54 | 55 | 3. Open [http://localhost:3000](http://localhost:3000) in your browser 56 | 57 | ## API Integration 58 | 59 | The frontend communicates with the backend API to generate and manage content. Key endpoints include: 60 | 61 | - `/generate-blog`: Generate a blog post 62 | - `/generate-book`: Generate a book 63 | - `/edit-section`: Edit a section of content 64 | - `/save-book`: Save changes to a book 65 | - `/download-book`: Download a book in different formats 66 | 67 | ## Technologies Used 68 | 69 | - Next.js 70 | - React 71 | - TypeScript 72 | - Tailwind CSS 73 | - Headless UI 74 | -------------------------------------------------------------------------------- /frontend/app/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function Error({ 4 | error, 5 | reset, 6 | }: { 7 | error: Error & { digest?: string }; 8 | reset: () => void; 9 | }) { 10 | return ( 11 |
12 |
13 |

Something went wrong!

14 |

We apologize for the inconvenience. Please try again.

15 | 21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /frontend/app/global-error.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function GlobalError({ 4 | error, 5 | reset, 6 | }: { 7 | error: Error & { digest?: string }; 8 | reset: () => void; 9 | }) { 10 | return ( 11 | 12 | 13 |
14 |
15 |

Something went wrong!

16 |

We apologize for the inconvenience. Please try again.

17 | 23 |
24 |
25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /frontend/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | body { 12 | color: rgb(var(--foreground-rgb)); 13 | background: rgb(var(--background-end-rgb)); 14 | } 15 | -------------------------------------------------------------------------------- /frontend/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Blog AI Generator', 9 | description: 'AI-powered blog and book content generator', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | 20 | {children} 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/app/loading.tsx: -------------------------------------------------------------------------------- 1 | export default function Loading() { 2 | return ( 3 |
4 |
5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | export default function NotFound() { 4 | return ( 5 |
6 |
7 |

Page Not Found

8 |

Could not find requested resource

9 | 13 | Return Home 14 | 15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /frontend/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState, useEffect } from 'react'; 4 | import { v4 as uuidv4 } from 'uuid'; 5 | import { Tab } from '@headlessui/react'; 6 | import ContentGenerator from '../components/ContentGenerator'; 7 | import BookGenerator from '../components/BookGenerator'; 8 | import ConversationHistory from '../components/ConversationHistory'; 9 | import ContentViewer from '../components/ContentViewer'; 10 | 11 | function classNames(...classes) { 12 | return classes.filter(Boolean).join(' '); 13 | } 14 | 15 | export default function Home() { 16 | const [conversationId] = useState(uuidv4()); 17 | const [content, setContent] = useState(null); 18 | const [loading, setLoading] = useState(false); 19 | 20 | return ( 21 |
22 | {/* Left sidebar - Conversation History */} 23 |
24 | 25 |
26 | 27 | {/* Main content area */} 28 |
29 |
30 |
31 | 32 | 33 | 35 | classNames( 36 | 'w-full rounded-lg py-3 text-sm font-medium leading-5 transition-all', 37 | 'ring-white ring-opacity-60 ring-offset-2 ring-offset-indigo-400 focus:outline-none focus:ring-2', 38 | selected 39 | ? 'bg-white shadow-sm text-indigo-700' 40 | : 'text-indigo-500 hover:bg-white/[0.12] hover:text-indigo-600' 41 | ) 42 | } 43 | > 44 | Blog Post 45 | 46 | 48 | classNames( 49 | 'w-full rounded-lg py-3 text-sm font-medium leading-5 transition-all', 50 | 'ring-white ring-opacity-60 ring-offset-2 ring-offset-indigo-400 focus:outline-none focus:ring-2', 51 | selected 52 | ? 'bg-white shadow-sm text-indigo-700' 53 | : 'text-indigo-500 hover:bg-white/[0.12] hover:text-indigo-600' 54 | ) 55 | } 56 | > 57 | Book 58 | 59 | 60 | 61 | 62 | 67 | 68 | 69 | 74 | 75 | 76 | 77 |
78 | 79 | {loading && ( 80 |
81 |
82 |
83 |
84 |
85 |
86 |

Generating your content...

87 |

This may take a few moments

88 |
89 | )} 90 | 91 | {content && !loading && ( 92 |
93 | 94 |
95 | )} 96 |
97 |
98 |
99 | ); 100 | } 101 | -------------------------------------------------------------------------------- /frontend/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { ReactNode, createContext } from 'react'; 4 | 5 | // Create a context for HeadlessUI 6 | export const HeadlessUIContext = createContext({}); 7 | 8 | interface ProvidersProps { 9 | children: ReactNode; 10 | } 11 | 12 | export function Providers({ children }: ProvidersProps) { 13 | return ( 14 | 15 | {children} 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /frontend/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gr8monk3ys/blog-AI/f0ef6ba5d4ddd5d531c7b410fb855654f653c6d3/frontend/bun.lockb -------------------------------------------------------------------------------- /frontend/components/BookViewer.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Disclosure } from '@headlessui/react'; 3 | import { ChevronUpIcon } from '@heroicons/react/24/outline'; 4 | import { Book, BookDownloadOptions } from '../types/book'; 5 | 6 | interface BookViewerProps { 7 | book: Book; 8 | filePath: string; 9 | } 10 | 11 | export default function BookViewer({ book, filePath }: BookViewerProps) { 12 | const [downloadFormat, setDownloadFormat] = useState<'markdown' | 'json'>('markdown'); 13 | 14 | const handleDownload = async () => { 15 | try { 16 | const response = await fetch(`http://localhost:8000/download-book`, { 17 | method: 'POST', 18 | headers: { 19 | 'Content-Type': 'application/json', 20 | }, 21 | body: JSON.stringify({ 22 | file_path: filePath, 23 | format: downloadFormat, 24 | }), 25 | }); 26 | 27 | if (!response.ok) { 28 | throw new Error('Failed to download book'); 29 | } 30 | 31 | // Create a download link 32 | const blob = await response.blob(); 33 | const url = window.URL.createObjectURL(blob); 34 | const a = document.createElement('a'); 35 | a.href = url; 36 | a.download = `${book.title}.${downloadFormat === 'markdown' ? 'md' : 'json'}`; 37 | document.body.appendChild(a); 38 | a.click(); 39 | window.URL.revokeObjectURL(url); 40 | document.body.removeChild(a); 41 | } catch (error) { 42 | console.error('Error downloading book:', error); 43 | alert('Failed to download book. Please try again.'); 44 | } 45 | }; 46 | 47 | return ( 48 |
49 |
50 |

{book.title}

51 |
52 | 60 | 66 |
67 |
68 | 69 | {book.tags && book.tags.length > 0 && ( 70 |
71 | Tags: 72 | {book.tags.map((tag, index) => ( 73 | 74 | {tag} 75 | 76 | ))} 77 |
78 | )} 79 | 80 | {book.date && ( 81 |
82 | Date: {book.date} 83 |
84 | )} 85 | 86 |
87 | {book.chapters.map((chapter) => ( 88 | 89 | {({ open }) => ( 90 | <> 91 | 92 | {chapter.title} 93 | 98 | 99 | 100 | {chapter.topics.map((topic, topicIndex) => ( 101 |
102 |

{topic.title}

103 |
{topic.content}
104 |
105 | ))} 106 |
107 | 108 | )} 109 |
110 | ))} 111 |
112 | 113 |
114 |

115 | Your book has been generated and saved to:
116 | {filePath} 117 |

118 |
119 |
120 | ); 121 | } 122 | -------------------------------------------------------------------------------- /frontend/components/ContentViewer.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { Popover } from '@headlessui/react'; 3 | import BookViewer from './BookViewer'; 4 | import BookEditor from './BookEditor'; 5 | import { Book } from '../types/book'; 6 | import { Section, BlogPost, SectionEditOptions } from '../types/blog'; 7 | 8 | interface ContentViewerProps { 9 | content: { 10 | type: 'blog' | 'book'; 11 | content?: BlogPost | any; 12 | title?: string; 13 | file_path: string; 14 | }; 15 | } 16 | 17 | export default function ContentViewer({ content }: ContentViewerProps) { 18 | const [editingSectionId, setEditingSectionId] = useState(null); 19 | const [editInstructions, setEditInstructions] = useState(''); 20 | const [isEditingBook, setIsEditingBook] = useState(false); 21 | const [bookData, setBookData] = useState(content.content?.book || null); 22 | 23 | const handleSectionEdit = async (sectionId: string) => { 24 | try { 25 | const response = await fetch('http://localhost:8000/edit-section', { 26 | method: 'POST', 27 | headers: { 28 | 'Content-Type': 'application/json', 29 | }, 30 | body: JSON.stringify({ 31 | file_path: content.file_path, 32 | section_id: sectionId, 33 | instructions: editInstructions, 34 | }), 35 | }); 36 | 37 | const data = await response.json(); 38 | if (data.success) { 39 | // Refresh content or update locally 40 | setEditingSectionId(null); 41 | setEditInstructions(''); 42 | } else { 43 | throw new Error(data.detail || 'Failed to update section'); 44 | } 45 | } catch (error) { 46 | console.error('Error updating section:', error); 47 | alert('Failed to update section. Please try again.'); 48 | } 49 | }; 50 | 51 | const handleBookSave = (updatedBook: Book): void => { 52 | setBookData(updatedBook); 53 | setIsEditingBook(false); 54 | }; 55 | 56 | if (content.type === 'blog') { 57 | return ( 58 |
59 |

{content.content.title}

60 | {content.content.sections.map((section: Section) => ( 61 | 62 |
setEditingSectionId(section.id)} 65 | onMouseLeave={() => setEditingSectionId(null)} 66 | > 67 |
{section.content}
68 | 69 | {editingSectionId === section.id && ( 70 | 71 |
72 |
73 |