Full Code of Nutlope/smartpdfs for AI

main 5021dd353c33 cached
44 files
154.3 KB
61.2k tokens
44 symbols
1 requests
Download .txt
Repository: Nutlope/smartpdfs
Branch: main
Commit: 5021dd353c33
Files: 44
Total size: 154.3 KB

Directory structure:
gitextract_c9h6c21g/

├── .eslintrc.json
├── .example.env
├── .gitignore
├── .node-version
├── .prettierrc
├── LICENSE
├── README.md
├── components.json
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── prisma/
│   └── schema.prisma
├── src/
│   ├── app/
│   │   ├── actions.ts
│   │   ├── api/
│   │   │   ├── image/
│   │   │   │   └── route.ts
│   │   │   ├── s3-upload/
│   │   │   │   └── route.ts
│   │   │   └── summarize/
│   │   │       └── route.ts
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   ├── page.tsx
│   │   └── pdf/
│   │       └── [id]/
│   │           ├── page.tsx
│   │           └── smart-pdf-viewer.tsx
│   ├── components/
│   │   ├── HomeLandingDrop.tsx
│   │   ├── icons/
│   │   │   ├── github.tsx
│   │   │   ├── sparkles.tsx
│   │   │   └── x.tsx
│   │   ├── images/
│   │   │   ├── homepage-image-1.tsx
│   │   │   └── homepage-image-2.tsx
│   │   └── ui/
│   │       ├── action-button.tsx
│   │       ├── button.tsx
│   │       ├── logo.tsx
│   │       ├── select.tsx
│   │       ├── spinner.tsx
│   │       ├── summary-content.tsx
│   │       ├── table-of-contents.tsx
│   │       ├── toast.tsx
│   │       └── toaster.tsx
│   ├── hooks/
│   │   └── use-toast.ts
│   └── lib/
│       ├── ai.ts
│       ├── prisma.ts
│       ├── s3client.ts
│       ├── summarize.ts
│       └── utils.ts
├── tailwind.config.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.json
================================================
{
  "extends": ["next/core-web-vitals", "next/typescript"]
}


================================================
FILE: .example.env
================================================
TOGETHER_API_KEY=
DATABASE_URL=

S3_UPLOAD_KEY=
S3_UPLOAD_SECRET=
S3_UPLOAD_BUCKET=
S3_UPLOAD_REGION=


================================================
FILE: .gitignore
================================================
# 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*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
.env*.local


================================================
FILE: .node-version
================================================
20.12.1


================================================
FILE: .prettierrc
================================================
{
  "plugins": ["prettier-plugin-tailwindcss"]
}


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2025 Hassan El Mghari

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.

================================================
FILE: README.md
================================================
<a href="https://github.com/Nutlope/smartpdfs">
  <img alt="SmartPDF" src="./public/og.jpg">
  <h1 align="center">SmartPDF</h1>
</a>

<p align="center">
  Instantly summarize and section your PDFs with AI. Powered by Llama 3.3 on Together AI.
</p>

## Tech stack

- [Together AI](https://togetherai.link) for inference
- [Llama 3.3](https://togetherai.link/llama-3.3) for the LLM
- Next.js with Tailwind & TypeScript
- Prisma ORM with Neon (Postgres)
- Helicone for observability
- Plausible for analytics
- S3 for PDF storage

## Cloning & running

1. Clone the repo: `git clone https://github.com/Nutlope/smartpdfs`
2. Create a `.env` file and add your environment variables (see `.example.env`):
   - `TOGETHER_API_KEY=`
   - `DATABASE_URL=`
   - `S3_UPLOAD_KEY=`
   - `S3_UPLOAD_SECRET=`
   - `S3_UPLOAD_BUCKET=`
   - `S3_UPLOAD_REGION=us-east-1`
   - `HELICONE_API_KEY=` (optional, for observability)
3. Run `pnpm install` to install dependencies
4. Run `pnpm prisma generate` to generate the Prisma client
5. Run `pnpm dev` to start the development server

## Roadmap

- [ ] Add some rate limiting by IP address
- [ ] Integrate OCR for image parsing in PDFs
- [ ] Add a bit more polish (make the link icon nicer) & add a "powered by Together" sign
- [ ] Implement additional revision steps for improved summaries
- [ ] Add a demo PDF for new users to be able to see it in action
- [ ] Add feedback system with thumbs up/down feature


================================================
FILE: components.json
================================================
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "src/app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "iconLibrary": "lucide"
}

================================================
FILE: next.config.ts
================================================
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "napkinsdev.s3.us-east-1.amazonaws.com",
      },
      {
        protocol: "https",
        hostname: "api.together.ai",
      },
    ],
  },
};

export default nextConfig;


================================================
FILE: package.json
================================================
{
  "name": "pdf-summary",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "postinstall": "prisma generate",
    "start": "next start",
    "lint": "next lint",
    "update:all": "pnpm update --interactive --latest"
  },
  "dependencies": {
    "@ai-sdk/togetherai": "^2.0.37",
    "@aws-sdk/client-s3": "^3.797.0",
    "@neondatabase/serverless": "^1.0.0",
    "@prisma/adapter-neon": "^6.6.0",
    "@prisma/client": "^6.6.0",
    "@radix-ui/react-select": "^2.1.2",
    "@radix-ui/react-slot": "^1.1.0",
    "@radix-ui/react-toast": "^1.2.2",
    "@tailwindcss/typography": "^0.5.16",
    "ai": "^6.0.108",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.1",
    "dedent": "^1.5.3",
    "lucide-react": "^0.503.0",
    "nanoid": "^5.1.5",
    "next": "16.1.6",
    "next-plausible": "^3.12.5",
    "next-s3-upload": "^0.3.4",
    "pdfjs-dist": "^4.8.69",
    "react": "19.2.4",
    "react-dom": "19.2.4",
    "react-dropzone": "^14.3.5",
    "tailwind-merge": "^2.5.4",
    "tailwindcss-animate": "^1.0.7",
    "together-ai": "^0.37.0",
    "ws": "^8.18.0",
    "zod": "^4.3.6"
  },
  "devDependencies": {
    "@types/node": "^22.15.3",
    "@types/react": "^19.2.14",
    "@types/react-dom": "^19.2.3",
    "@types/ws": "^8.5.13",
    "eslint": "9.25.1",
    "eslint-config-next": "15.3.1",
    "postcss": "^8",
    "prettier": "^3.3.3",
    "prettier-plugin-tailwindcss": "^0.6.8",
    "prisma": "^6.6.0",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  },
  "engines": {
    "node": "22.x"
  },
  "pnpm": {
    "onlyBuiltDependencies": [
      "@prisma/client"
    ]
  }
}


================================================
FILE: postcss.config.mjs
================================================
/** @type {import('postcss-load-config').Config} */
const config = {
  plugins: {
    tailwindcss: {},
  },
};

export default config;


================================================
FILE: prisma/schema.prisma
================================================
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model SmartPDF {
  id        String   @id @default(nanoid(5))
  createdAt DateTime @default(now())
  imageUrl  String
  pdfUrl    String
  pdfName   String

  sections Section[]
}

model Section {
  id       String @id @default(nanoid(5))
  type     String
  title    String
  summary  String
  position Int

  SmartPDF   SmartPDF @relation(fields: [smartPDFId], references: [id])
  smartPDFId String
}


================================================
FILE: src/app/actions.ts
================================================
"use server";

import { nanoid } from "nanoid";
import client from "@/lib/prisma";
import { redirect } from "next/navigation";

const slugify = (text: string) => {
  return text
    .toLowerCase()
    .replace(/ /g, "-")
    .replace(/[^\w-]+/g, "")
    .replace(/--+/g, "-")
    .replace(/^-+/, "")
    .replace(/-+$/, "")
    .slice(0, 20);
};

export async function sharePdf({
  pdfName,
  pdfUrl,
  imageUrl,
  sections,
}: {
  pdfName: string;
  pdfUrl: string;
  imageUrl: string;
  sections: {
    type: string;
    title: string;
    summary: string;
    position: number;
  }[];
}) {
  const smartPdf = await client.smartPDF.create({
    data: {
      id: `${slugify(sections[0].title)}-${nanoid(4)}`,
      pdfName,
      pdfUrl,
      imageUrl,
      sections: {
        createMany: {
          data: sections,
        },
      },
    },
  });

  redirect(`/pdf/${smartPdf.id}`);
}


================================================
FILE: src/app/api/image/route.ts
================================================
import dedent from "dedent";
import { togetheraiBaseClient, togetheraiClient } from "@/lib/ai";
import { ImageGenerationResponse } from "@/lib/summarize";
import { awsS3Client } from "@/lib/s3client";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { generateText } from "ai";

export async function POST(req: Request) {
  const json = await req.json();
  const text = "text" in json ? json.text : "";

  const start = new Date();

  const truncatedText = text.slice(0, 2000);

  const { text: visualDescription } = await generateText({
    model: togetheraiClient(
      "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
    ),
    prompt: dedent`
      Based on the following content, describe a single visual scene that represents its essence. 
      The scene should be suitable for a painting or illustration.
      Do NOT include any text, words, or writing in your description.
      Just describe what you would see: objects, colors, atmosphere, lighting, mood.
      Keep it to 2-3 sentences.

      Content: ${truncatedText}

      Visual scene description:
    `,
  });

  const prompt = dedent`
    ${visualDescription}

    Oil painting, fine art, museum quality, artistic brushstrokes. 
    No text, no words, no letters, no writing, no documents, no signs.
    Pure visual illustration only.
  `;

  const generatedImage = await togetheraiBaseClient.images.generate({
    model: "black-forest-labs/FLUX.2-dev",
    width: 1280,
    height: 720,
    prompt: prompt,
  });

  const end = new Date();
  console.log(`Image generation took ${end.getTime() - start.getTime()}ms`);

  const imageData = generatedImage.data[0];
  if (!imageData) throw new Error("No image data generated");

  if (imageData.url === undefined)
    throw new Error("Expected URL response format");

  const imageUrl = imageData.url;

  if (!imageUrl) throw new Error("No image URL returned");

  const imageFetch = await fetch(imageUrl);
  const imageBlob = await imageFetch.blob();
  const imageBuffer = Buffer.from(await imageBlob.arrayBuffer());

  const coverImageKey = `pdf-cover-${generatedImage.id}.jpg`;

  const uploadedFile = await awsS3Client.send(
    new PutObjectCommand({
      Bucket: process.env.S3_UPLOAD_BUCKET || "",
      Key: coverImageKey,
      Body: imageBuffer,
      ContentType: "image/jpeg",
    }),
  );

  if (!uploadedFile) {
    throw new Error("Failed to upload enhanced image to S3");
  }

  return Response.json({
    url: `https://${process.env.S3_UPLOAD_BUCKET}.s3.${
      process.env.S3_UPLOAD_REGION || "us-east-1"
    }.amazonaws.com/${coverImageKey}`,
  } as ImageGenerationResponse);
}

export const runtime = "edge";


================================================
FILE: src/app/api/s3-upload/route.ts
================================================
export { POST } from "next-s3-upload/route";


================================================
FILE: src/app/api/summarize/route.ts
================================================
import { togetheraiBaseClient } from "@/lib/ai";
import assert from "assert";
import dedent from "dedent";
import { z } from "zod";

export async function POST(req: Request) {
  const { text, language } = await req.json();

  assert.ok(typeof text === "string");
  assert.ok(typeof language === "string");

  const systemPrompt = dedent`
    You are an expert at summarizing text.

    Your task:
    1. Read the document excerpt I will provide
    2. Create a concise summary in ${language}
    3. Generate a short, descriptive title in ${language}

    Guidelines for the summary:
    - Format the summary in HTML
    - Use <p> tags for paragraphs (2-3 sentences each)
    - Use <ul> and <li> tags for bullet points
    - Use <h3> tags for subheadings when needed but don't repeat the initial title in the first paragraph
    - Ensure proper spacing with appropriate HTML tags

    The summary should be well-structured and easy to scan, while maintaining accuracy and completeness.
    Please analyze the text thoroughly before starting the summary.

    IMPORTANT: Output ONLY valid JSON matching the schema. Output ONLY valid HTML without any markdown or plain text line breaks.
  `;

  const summarySchema = z.object({
    title: z.string().describe("A title for the summary"),
    summary: z
      .string()
      .describe(
        "The actual summary of the text containing new lines breaks between paragraphs or phrases for better readability.",
      ),
  });

  const jsonSchema = z.toJSONSchema(summarySchema, {
    target: "openapi-3.0",
    io: "output",
  });

  const summaryResponse = await togetheraiBaseClient.chat.completions.create({
    model: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
    messages: [
      {
        role: "system",
        content: systemPrompt,
      },
      {
        role: "user",
        content: text,
      },
    ],
    response_format: {
      type: "json_schema",
      json_schema: {
        name: "summary",
        schema: jsonSchema,
      },
    } as any,
  });

  const content = summaryResponse.choices[0]?.message?.content;

  if (!content) {
    console.log("Content was blank", JSON.stringify(summaryResponse, null, 2));
    return Response.json({ error: "No content generated" }, { status: 500 });
  }

  const parsed = summarySchema.parse(JSON.parse(content));

  return Response.json(parsed);
}

export const runtime = "edge";


================================================
FILE: src/app/globals.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  font-family: Arial, Helvetica, sans-serif;
}

@layer base {
  :root {
    --background: 37 27% 94%;
    --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 2.44% 24.12%;
    --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;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}


================================================
FILE: src/app/layout.tsx
================================================
import GithubIcon from "@/components/icons/github";
import XIcon from "@/components/icons/x";
import Logo from "@/components/ui/logo";
import type { Metadata } from "next";
import { Plus_Jakarta_Sans } from "next/font/google";
import "./globals.css";
import { Toaster } from "@/components/ui/toaster";
import Link from "next/link";
import PlausibleProvider from "next-plausible";

const font = Plus_Jakarta_Sans({
  subsets: ["latin"],
  display: "swap",
  variable: "--font-plus-jakarta-sans",
});

export const metadata: Metadata = {
  title: "Smart PDFs | Summarize PDFs in seconds",
  description:
    "Upload a PDF to get a quick, clear, and shareable summary with AI for free!",
  openGraph: {
    images: "https://smartpdfs.vercel.app/og.jpg",
  },
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" className="h-full">
      <head>
        <PlausibleProvider domain="smartpdfs.ai" />
      </head>
      <body
        className={`${font.variable} flex min-h-full flex-col bg-gray-100 font-[family-name:var(--font-plus-jakarta-sans)] text-gray-900 antialiased`}
      >
        <header className="py-6 text-center">
          <Link href="/" className="inline-flex justify-center">
            <Logo />
          </Link>
        </header>

        <main className="grow overflow-hidden">{children}</main>
        <Toaster />
        <footer className="mx-auto mt-14 flex w-full max-w-7xl items-center justify-between px-4 py-6 md:mt-0">
          <p className="text-xs text-gray-300 md:text-sm">
            Powered by Llama 3.3 on{" "}
            <a
              target="_blank"
              rel="noopener noreferrer"
              className="text-gray-400 underline transition hover:text-gray-900"
              href="https://togetherai.link/"
            >
              Together AI
            </a>
          </p>

          <div className="flex items-center gap-2 md:gap-3">
            <a
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-1 rounded-lg border border-gray-250 bg-white px-2 py-1.5 text-xs text-gray-300 shadow transition hover:bg-white/75 md:rounded-xl md:px-4 md:text-sm"
              href="https://github.com/nutlope/smartpdfs"
            >
              <GithubIcon className="size-4" />
              GitHub
            </a>
            <a
              href="https://x.com/nutlope"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-1 rounded-lg border border-gray-250 bg-white px-2 py-1.5 text-xs text-gray-300 shadow transition hover:bg-white/75 md:rounded-xl md:px-4 md:text-sm"
            >
              <XIcon className="size-3" />
              Twitter
            </a>
          </div>
        </footer>
      </body>
    </html>
  );
}


================================================
FILE: src/app/page.tsx
================================================
"use client";

import { useS3Upload } from "next-s3-upload";
import { Button } from "@/components/ui/button";
import {
  Chunk,
  chunkPdf,
  generateImage,
  generateQuickSummary,
  summarizeStream,
} from "@/lib/summarize";
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
import { FormEvent, useState } from "react";
import "pdfjs-dist/legacy/build/pdf.worker.mjs";
import { MenuIcon, SquareArrowOutUpRight } from "lucide-react";
import { sharePdf } from "@/app/actions";
import ActionButton from "@/components/ui/action-button";
import Link from "next/link";
import { useToast } from "@/hooks/use-toast";
import { HomeLandingDrop } from "@/components/HomeLandingDrop";
import SummaryContent from "@/components/ui/summary-content";
import TableOfContents from "@/components/ui/table-of-contents";

export type StatusApp = "idle" | "parsing" | "generating";

export default function Home() {
  const [status, setStatus] = useState<StatusApp>("idle");
  const [file, setFile] = useState<File>();
  const [fileUrl, setFileUrl] = useState("");
  const [chunks, setChunks] = useState<Chunk[]>([]);
  const [activeChunkIndex, setActiveChunkIndex] = useState<
    number | "quick-summary" | null
  >(null);
  const [quickSummary, setQuickSummary] = useState<{
    title: string;
    summary: string;
  }>();
  const [image, setImage] = useState<string>();
  const [showMobileContents, setShowMobileContents] = useState(true);
  const { uploadToS3 } = useS3Upload();

  const { toast } = useToast();

  async function handleSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const language = new FormData(e.currentTarget).get("language");

    if (!file || typeof language !== "string") return;

    setStatus("parsing");

    const uploadedPdfPromise = uploadToS3(file);

    const arrayBuffer = await file.arrayBuffer();
    const pdf = await getDocument({ data: arrayBuffer }).promise;
    if (pdf.numPages > 500) {
      toast({
        variant: "destructive",
        title: "PDF too large (500 pages max)",
        description: "That PDF has too many pages. Please use a smaller PDF.",
      });
      setStatus("idle");
      return;
    }

    const localChunks = await chunkPdf(pdf);
    const totalText = localChunks.reduce(
      (acc, chunk) => acc + chunk.text.length,
      0,
    );

    if (totalText < 500) {
      toast({
        variant: "destructive",
        title: "Unable to process PDF",
        description:
          "The PDF appears to be a scanned document or contains too little text to process. Please ensure the PDF contains searchable text.",
      });
      setFile(undefined);
      setStatus("idle");
      return;
    }

    setChunks(localChunks);
    setStatus("generating");

    const summarizedChunks: Chunk[] = [];

    const writeStream = new WritableStream({
      write(chunk) {
        summarizedChunks.push(chunk);
        setChunks((chunks) => {
          return chunks.map((c) =>
            c.text === chunk.text ? { ...c, ...chunk } : c,
          );
        });
      },
    });

    const streamPromise = summarizeStream(localChunks, language);
    const imagePromise = generateImage(localChunks[0]?.text ?? "");

    const [stream] = await Promise.all([streamPromise]);
    const controller = new AbortController();
    await stream.pipeTo(writeStream, { signal: controller.signal });

    const quickSummary = await generateQuickSummary(summarizedChunks, language);
    const imageUrl = await imagePromise;

    setQuickSummary(quickSummary);
    setImage(imageUrl);

    const uploadedPdf = await uploadedPdfPromise;
    setFileUrl(uploadedPdf.url);

    setActiveChunkIndex((activeChunkIndex) =>
      activeChunkIndex === null ? "quick-summary" : activeChunkIndex,
    );

    await sharePdf({
      pdfName: file.name,
      pdfUrl: uploadedPdf.url,
      imageUrl: imageUrl,
      sections: [
        {
          type: "quick-summary",
          title: quickSummary.title,
          summary: quickSummary.summary,
          position: 0,
        },
        ...summarizedChunks.map((chunk, index) => ({
          type: "summary",
          title: chunk?.title ?? "",
          summary: chunk?.summary ?? "",
          position: index + 1,
        })),
      ],
    });
  }

  return (
    <div>
      {status === "idle" || status === "parsing" ? (
        <HomeLandingDrop
          status={status}
          file={file}
          setFile={(file) => file && setFile(file)}
          handleSubmit={handleSubmit}
        />
      ) : (
        <div className="mt-6 px-4 md:mt-10">
          <div className="mx-auto max-w-3xl">
            <div className="flex items-center justify-between rounded-lg border border-gray-250 px-4 py-2 md:px-6 md:py-3">
              <div className="inline-flex items-center gap-4">
                <p className="md:text-lg">{file?.name}</p>
              </div>

              <div className="flex flex-row gap-2">
                {fileUrl && (
                  <Link href={fileUrl} target="_blank">
                    <ActionButton>
                      <SquareArrowOutUpRight size={14} />
                      <span>Original PDF</span>
                    </ActionButton>
                  </Link>
                )}
              </div>
            </div>

            <div className="mt-8 rounded-lg bg-gray-200 px-4 py-2 shadow md:hidden">
              <Button
                onClick={() => setShowMobileContents(!showMobileContents)}
                className="w-full text-gray-500 hover:bg-transparent"
                variant="ghost"
              >
                <MenuIcon />
                {showMobileContents ? "Hide" : "Show"} contents
              </Button>

              {showMobileContents && (
                <div className="mt-4">
                  <TableOfContents
                    activeChunkIndex={activeChunkIndex}
                    setActiveChunkIndex={setActiveChunkIndex}
                    quickSummary={quickSummary}
                    chunks={chunks}
                  />
                </div>
              )}
            </div>

            <div className="mt-4 flex gap-4">
              <div className="w-full grow rounded-lg bg-white p-5 text-gray-500 shadow">
                {activeChunkIndex === "quick-summary" ? (
                  <SummaryContent
                    title={quickSummary?.title}
                    summary={quickSummary?.summary}
                    imageUrl={image}
                  />
                ) : activeChunkIndex !== null ? (
                  <SummaryContent
                    title={chunks[activeChunkIndex].title}
                    summary={chunks[activeChunkIndex].summary}
                  />
                ) : (
                  <div className="flex animate-pulse items-center justify-center py-4 text-lg md:py-8">
                    Generating your Smart PDF&hellip;
                  </div>
                )}
              </div>

              <div className="hidden w-full max-w-60 shrink-0 md:flex">
                <TableOfContents
                  activeChunkIndex={activeChunkIndex}
                  setActiveChunkIndex={setActiveChunkIndex}
                  quickSummary={quickSummary}
                  chunks={chunks}
                />
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}


================================================
FILE: src/app/pdf/[id]/page.tsx
================================================
import SmartPDFViewer from "@/app/pdf/[id]/smart-pdf-viewer";
import client from "@/lib/prisma";
import { notFound } from "next/navigation";
import { unstable_cache } from "next/cache";
import { Metadata, ResolvingMetadata } from "next";

const getSmartPDF = unstable_cache(
  async (id: string) => {
    return client.smartPDF.findUnique({
      where: { id },
      include: { sections: true },
    });
  },
  ["smart-pdf-query"],
  { revalidate: false },
);

export async function generateMetadata(
  {
    params,
  }: {
    params: Promise<{ id: string }>;
  },
  parent: ResolvingMetadata,
): Promise<Metadata> {
  // read route params
  const { id } = await params;
  const parentData = await parent;

  // fetch data
  const smartPdf = await getSmartPDF(id);

  if (!smartPdf) notFound();

  return {
    title: `${smartPdf.sections[0].title.slice(0, 60)} | ${parentData.title?.absolute}`,
    description: `${smartPdf.sections[0].summary
      .replace(/<[^>]*>/g, "")
      .slice(0, 160)}...`,
    openGraph: {
      images: [smartPdf.imageUrl],
    },
  };
}

export default async function Home({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const id = (await params).id;
  const smartPdf = await getSmartPDF(id);

  if (!smartPdf) notFound();

  return <SmartPDFViewer smartPdf={smartPdf} />;
}


================================================
FILE: src/app/pdf/[id]/smart-pdf-viewer.tsx
================================================
"use client";

import { Button } from "@/components/ui/button";
import { Section, SmartPDF } from "@prisma/client";
import { LinkIcon, MenuIcon, SquareArrowOutUpRight } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import TableOfContents from "@/components/ui/table-of-contents";
import SummaryContent from "@/components/ui/summary-content";
import ActionButton from "@/components/ui/action-button";
import { useToast } from "@/hooks/use-toast";

export default function SmartPDFViewer({
  smartPdf,
}: {
  smartPdf: SmartPDF & { sections: Section[] };
}) {
  const { toast } = useToast();
  const [showMobileContents, setShowMobileContents] = useState(true);
  const [activeSection, setActiveSection] = useState<number | "quick-summary">(
    "quick-summary",
  );

  const handleShare = () => {
    toast({
      title: "Copied to Clipboard 📋",
      description:
        "Share link has been copied. Ready to share your PDF summary! 🔗",
    });
    navigator.clipboard.writeText(window.location.href);
  };

  const quickSummary = smartPdf.sections[0];
  const pdfSections = smartPdf.sections.slice(1);

  return (
    <div className="mt-6 px-4 md:mt-10">
      <div className="mx-auto max-w-3xl">
        <div className="flex flex-col items-center justify-between gap-4 rounded-lg border border-gray-250 px-4 py-2 text-center sm:flex-row md:px-6 md:py-3">
          <p className="w-[-webkit-fill-available] max-w-96 truncate md:text-lg md:leading-9">
            {smartPdf.pdfName}
          </p>
          <div className="flex flex-row gap-2">
            <Link href={smartPdf.pdfUrl} target="_blank">
              <ActionButton>
                <SquareArrowOutUpRight size={14} />
                <span>Original PDF</span>
              </ActionButton>
            </Link>
            <div className="md:hidden">
              <ActionButton onClick={handleShare} size="icon">
                <LinkIcon />
              </ActionButton>
            </div>
            <div className="hidden md:block" onClick={handleShare}>
              <ActionButton type="submit">
                <LinkIcon />
                <span>Share Summary</span>
              </ActionButton>
            </div>
          </div>
        </div>

        <div className="mt-8 rounded-lg bg-gray-200 px-4 py-2 shadow md:hidden">
          <Button
            onClick={() => setShowMobileContents(!showMobileContents)}
            className="w-full text-gray-500 hover:bg-transparent"
            variant="ghost"
          >
            <MenuIcon />
            {showMobileContents ? "Hide" : "Show"} contents
          </Button>

          {showMobileContents && (
            <div className="mt-4">
              <TableOfContents
                activeChunkIndex={activeSection}
                setActiveChunkIndex={(idx) =>
                  idx !== null && setActiveSection(idx)
                }
                quickSummary={smartPdf.sections[0]}
                chunks={smartPdf.sections.slice(1).map((section) => ({
                  ...section,
                  text: section.summary,
                }))}
              />
            </div>
          )}
        </div>

        <div className="mt-4 flex gap-4">
          <div className="w-full grow rounded-lg bg-white p-5 text-gray-500 shadow">
            {activeSection === "quick-summary" ? (
              <SummaryContent
                title={quickSummary.title}
                summary={quickSummary.summary}
                imageUrl={smartPdf.imageUrl}
              />
            ) : activeSection !== null ? (
              <SummaryContent
                title={pdfSections[activeSection].title}
                summary={pdfSections[activeSection].summary}
              />
            ) : (
              <div className="flex animate-pulse items-center justify-center py-4 text-lg md:py-8">
                Generating your Smart PDF&hellip;
              </div>
            )}
          </div>

          <div className="hidden w-full max-w-60 shrink-0 md:flex">
            <TableOfContents
              activeChunkIndex={activeSection}
              setActiveChunkIndex={(idx) =>
                idx !== null && setActiveSection(idx)
              }
              quickSummary={smartPdf.sections[0]}
              chunks={smartPdf.sections.slice(1).map((section) => ({
                ...section,
                text: section.summary,
              }))}
            />
          </div>
        </div>
      </div>
    </div>
  );
}


================================================
FILE: src/components/HomeLandingDrop.tsx
================================================
"use client";

import { SparklesIcon } from "lucide-react";
import { Button } from "./ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "./ui/select";
import Dropzone from "react-dropzone";
import HomepageImage1 from "./images/homepage-image-1";
import HomepageImage2 from "./images/homepage-image-2";
import { StatusApp } from "@/app/page";
import { useToast } from "@/hooks/use-toast";

export const HomeLandingDrop = ({
  status,
  file,
  setFile,
  handleSubmit,
}: {
  status: StatusApp;
  file?: File | null;
  setFile: (file: File | null) => void;
  handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
}) => {
  const { toast } = useToast();
  return (
    <div className="mx-auto mt-6 max-w-lg md:mt-10">
      <h1 className="text-center text-4xl font-bold md:text-5xl">
        Summarize PDFs
        <br /> in seconds
      </h1>
      <p className="mx-auto mt-6 max-w-md text-balance text-center leading-snug md:text-lg md:leading-snug">
        Upload a <strong>PDF</strong> to get a quick, clear, and shareable
        summary.
      </p>

      <form
        onSubmit={handleSubmit}
        className="relative mx-auto mt-20 max-w-md px-4 md:mt-16"
      >
        <div className="pointer-events-none absolute left-[-40px] top-[-185px] flex w-[200px] items-center md:-left-[calc(min(30vw,350px))] md:-top-20 md:w-[390px]">
          <HomepageImage1 />
        </div>
        <div className="pointer-events-none absolute right-[20px] top-[-110px] flex w-[70px] justify-center md:-right-[calc(min(30vw,350px))] md:-top-5 md:w-[390px]">
          <HomepageImage2 />
        </div>

        <div className="relative">
          <div className="flex flex-col rounded-xl bg-white px-6 py-6 shadow md:px-12 md:py-8">
            <label className="text-gray-500" htmlFor="file">
              Upload PDF
            </label>
            <Dropzone
              multiple={false}
              accept={{
                "application/pdf": [".pdf"],
              }}
              onDrop={(acceptedFiles) => {
                const file = acceptedFiles[0];
                if (file.size > 15 * 1024 * 1024) {
                  // 10MB in bytes
                  toast({
                    title: "📁 File Too Large",
                    description: "⚠️ File size must be less than 15MB",
                  });
                  return;
                }
                setFile(file);
              }}
            >
              {({ getRootProps, getInputProps, isDragAccept }) => (
                <div
                  className={`mt-2 flex aspect-video cursor-pointer items-center justify-center rounded-lg border border-dashed bg-gray-100 ${isDragAccept ? "border-blue-500" : "border-gray-250"}`}
                  {...getRootProps()}
                >
                  <input required={!file} {...getInputProps()} />
                  <div className="text-center">
                    {file ? (
                      <p>{file.name}</p>
                    ) : (
                      <Button type="button" className="md:text-base">
                        Select PDF
                      </Button>
                    )}
                  </div>
                </div>
              )}
            </Dropzone>
            <label className="mt-8 text-gray-500" htmlFor="language">
              Language
            </label>
            <Select defaultValue="english" name="language">
              <SelectTrigger className="mt-2 bg-gray-100" id="language">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {[
                  { label: "English", value: "english" },
                  { label: "German", value: "german" },
                  { label: "French", value: "french" },
                  { label: "Italian", value: "italian" },
                  { label: "Portuguese", value: "portuguese" },
                  { label: "Hindi", value: "hindi" },
                  { label: "Spanish", value: "spanish" },
                  { label: "Thai", value: "thai" },
                ].map((language) => (
                  <SelectItem key={language.value} value={language.value}>
                    {language.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="mt-8 text-center">
            <Button
              type="submit"
              variant="secondary"
              className="w-60 border bg-white/80 text-base font-semibold hover:bg-white md:w-auto"
              disabled={status === "parsing"}
            >
              <SparklesIcon />
              Generate
            </Button>
          </div>
        </div>
      </form>
    </div>
  );
};


================================================
FILE: src/components/icons/github.tsx
================================================
import { ComponentProps } from "react";

export default function GithubIcon(props: ComponentProps<"svg">) {
  return (
    <svg
      width={11}
      height={12}
      viewBox="0 0 11 12"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        fillRule="evenodd"
        clipRule="evenodd"
        d="M5.5.5C2.462.5 0 3.024 0 6.14c0 2.49 1.576 4.605 3.761 5.35.275.052.376-.122.376-.272 0-.133-.005-.489-.008-.959-1.53.34-1.853-.756-1.853-.756-.25-.652-.61-.825-.61-.825-.5-.35.038-.343.038-.343.552.04.842.581.842.581.49.862 1.288.613 1.6.469.051-.364.193-.613.35-.753-1.22-.143-2.505-.627-2.505-2.788 0-.615.214-1.119.566-1.513-.057-.143-.245-.716.054-1.492 0 0 .462-.152 1.512.578a5.147 5.147 0 011.377-.19 5.16 5.16 0 011.377.19c1.05-.73 1.511-.579 1.511-.579.3.777.111 1.35.055 1.493.352.394.565.898.565 1.513 0 2.167-1.286 2.644-2.51 2.783.197.174.372.518.372 1.044 0 .754-.007 1.362-.007 1.547 0 .15.1.327.379.271a5.522 5.522 0 002.722-2.055A5.731 5.731 0 0011 6.14C11 3.024 8.537.5 5.5.5z"
        fill="#B7B7B7"
      />
    </svg>
  );
}


================================================
FILE: src/components/icons/sparkles.tsx
================================================
import { ComponentProps } from "react";

export default function SparklesIcon(props: ComponentProps<"svg">) {
  return (
    <svg
      width={14}
      height={14}
      viewBox="0 0 14 14"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
      {...props}
    >
      <path
        opacity={0.8}
        fill="url(#pattern0_136_130632)"
        d="M0 -0.000244141H14V13.999755859H0z"
      />
      <defs>
        <pattern
          id="pattern0_136_130632"
          patternContentUnits="objectBoundingBox"
          width={1}
          height={1}
        >
          <use xlinkHref="#image0_136_130632" transform="scale(.00195)" />
        </pattern>
        <image
          id="image0_136_130632"
          width={512}
          height={512}
          xlinkHref="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IArs4c6QAAIABJREFUeAHt3QnYHVWd5/EfSSALkJUAAcK+SMIS2VEEkdioyKMO0IpiXIkwqIF2QbvphkFURluRpkdEZeyJtvpERxyBoYdNlM2whSXshJAAgeyBLCQkpOf9d1eRN/e9975V99Zylm89T54k73vvrXM+9T/n/KvuqVMSGwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIINBLYLKk30u6XtIpvX7OPxFAAAEEEEAgUIE9Ja2R9O/JnzckHRVoXakWAggggAACCCQCv+41+KdJwN2StkAIAQQQQAABBMIUOFzSxiYJgCUCHwyzytQKAQQQQAABBG5pMfhbAvCEpC0hQgABBBBAAIGwBE5uM/inXwWcHVaVqQ0CCCCAAAJxCwyUNDtDArBQ0vC4qag9AggggAAC4QicmWHwT68CXBROtakJAggggAAC8QoMlfR8jgRglaRx8XJRcwQQQAABBMIQuCDH4J9eBfhRGFWnFggggAACCMQpMFbSKx0kABskTYyTjFojgAACCCDgv8AVHQz+6VUAWyqYDQEEEEAAAQQ8E7Alf9d1kQBYInC8Z3WmuAgggAACCEQv8JsuB39LAGayRHD0cQQAAggggIBHAke0WfI3vcSf9e/TPKo3RUUAAQQQQCBqgdsLOPtPE4RnJQ2OWpPKI4AAAggg4IGAPdQnHbyL+vuLHtSbIiKAAAIIIBCtgC35+2gJCcBiSSOiVaXiCCCAAAIIOC5wVgmDf3oV4ZuO153iIYAAAgggEKXANpIWlJgArJE0PkpZKo0AAggggIDDAheWOPinVwGudrj+FA0BBBBAAIHoBLbvcMnfdGDP+vcbkiZFp0uFEUAAAQQQcFTghxWc/adJwvWOGlAsBBBAAAEEohLYV9Lr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"
        />
      </defs>
    </svg>
  );
}


================================================
FILE: src/components/icons/x.tsx
================================================
import { ComponentProps } from "react";

export default function XIcon(props: ComponentProps<"svg">) {
  return (
    <svg
      width={10}
      height={10}
      viewBox="0 0 10 10"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        fillRule="evenodd"
        clipRule="evenodd"
        d="M6.717 10L4.302 6.404 1.279 10H0l3.734-4.44L0 0h3.283L5.56 3.388 8.411 0H9.69L6.129 4.235 10 10H6.717zM8.14 8.986H7.28L1.83 1.013h.861l2.182 3.193.378.554L8.14 8.986z"
        fill="#B7B7B7"
      />
    </svg>
  );
}


================================================
FILE: src/components/images/homepage-image-1.tsx
================================================
import { ComponentProps } from "react";

export default function HomepageImage1(props: ComponentProps<"svg">) {
  return (
    <svg
      width={379}
      height={341}
      viewBox="0 0 379 341"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
      {...props}
    >
      <g clipPath="url(#clip0_136_130388)">
        <rect
          opacity={0.2}
          x={350.017}
          y={105.134}
          width={8.22857}
          height={1.37143}
          rx={0.685714}
          transform="rotate(-9.807 350.017 105.134)"
          fill="#E1E1E1"
        />
        <rect
          opacity={0.2}
          x={364.967}
          y={191.623}
          width={8.22857}
          height={1.37143}
          rx={0.685714}
          transform="rotate(-9.807 364.967 191.623)"
          fill="#E1E1E1"
        />
        <rect
          opacity={0.2}
          x={375.778}
          y={189.754}
          width={8.22857}
          height={1.37143}
          rx={0.685714}
          transform="rotate(-9.807 375.778 189.754)"
          fill="#E1E1E1"
        />
        <mask
          id="a"
          style={{
            maskType: "alpha",
          }}
          maskUnits="userSpaceOnUse"
          x={-19}
          y={24}
          width={417}
          height={285}
        >
          <path
            transform="rotate(-9.807 -18.712 89.538)"
            fill="url(#paint0_linear_136_130388)"
            d="M-18.7124 89.5377H365.2876V311.7087H-18.7124z"
          />
        </mask>
        <g mask="url(#a)">
          <rect
            x={123.228}
            y={126.749}
            width={104.6}
            height={370.657}
            rx={5.5}
            transform="rotate(-9.807 123.228 126.749)"
            fill="#fff"
            stroke="#B7B7B7"
          />
          <path
            transform="rotate(-9.807 136.031 139.338)"
            fill="#E1E1E1"
            d="M136.031 139.338H219.68810000000002V140.70943H136.031z"
          />
          <rect
            x={148.177}
            y={209.61}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 148.177 209.61)"
            fill="#E1E1E1"
          />
          <rect
            x={160.324}
            y={279.882}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 160.324 279.882)"
            fill="#E1E1E1"
          />
          <path
            transform="rotate(-9.807 136.965 144.743)"
            fill="#E1E1E1"
            d="M136.965 144.743H220.6221V146.11443H136.965z"
          />
          <rect
            x={149.112}
            y={215.015}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 149.112 215.015)"
            fill="#E1E1E1"
          />
          <rect
            x={161.258}
            y={285.288}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 161.258 285.288)"
            fill="#E1E1E1"
          />
          <path
            transform="rotate(-9.807 137.899 150.149)"
            fill="#E1E1E1"
            d="M137.899 150.149H221.55610000000001V151.52043H137.899z"
          />
          <rect
            x={150.046}
            y={220.421}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 150.046 220.421)"
            fill="#E1E1E1"
          />
          <rect
            x={162.192}
            y={290.693}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 162.192 290.693)"
            fill="#E1E1E1"
          />
          <path
            transform="rotate(-9.807 138.834 155.554)"
            fill="#E1E1E1"
            d="M138.834 155.554H222.49110000000002V156.92543H138.834z"
          />
          <rect
            x={150.98}
            y={225.826}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 150.98 225.826)"
            fill="#E1E1E1"
          />
          <rect
            x={163.127}
            y={296.099}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 163.127 296.099)"
            fill="#E1E1E1"
          />
          <rect
            x={139.768}
            y={160.96}
            width={60.3429}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 139.768 160.96)"
            fill="#E1E1E1"
          />
          <rect
            x={151.915}
            y={231.232}
            width={60.3429}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 151.915 231.232)"
            fill="#E1E1E1"
          />
          <rect
            x={164.061}
            y={301.504}
            width={60.3429}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 164.061 301.504)"
            fill="#E1E1E1"
          />
          <rect
            x={142.104}
            y={174.474}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 142.104 174.474)"
            fill="#E1E1E1"
          />
          <rect
            x={154.251}
            y={244.746}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 154.251 244.746)"
            fill="#E1E1E1"
          />
          <rect
            x={166.397}
            y={315.018}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 166.397 315.018)"
            fill="#E1E1E1"
          />
          <rect
            x={143.038}
            y={179.879}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 143.038 179.879)"
            fill="#E1E1E1"
          />
          <rect
            x={155.185}
            y={250.151}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 155.185 250.151)"
            fill="#E1E1E1"
          />
          <rect
            x={167.331}
            y={320.424}
            width={83.6571}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 167.331 320.424)"
            fill="#E1E1E1"
          />
          <rect
            x={143.973}
            y={185.285}
            width={75.4286}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 143.973 185.285)"
            fill="#E1E1E1"
          />
          <rect
            x={156.119}
            y={255.557}
            width={75.4286}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 156.119 255.557)"
            fill="#E1E1E1"
          />
          <rect
            x={144.907}
            y={190.69}
            width={67.2}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 144.907 190.69)"
            fill="#E1E1E1"
          />
          <rect
            x={157.054}
            y={260.963}
            width={67.2}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 157.054 260.963)"
            fill="#E1E1E1"
          />
          <rect
            x={145.841}
            y={196.096}
            width={39.7714}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 145.841 196.096)"
            fill="#E1E1E1"
          />
          <rect
            x={157.988}
            y={266.368}
            width={39.7714}
            height={1.37143}
            rx={0.685714}
            transform="rotate(-9.807 157.988 266.368)"
            fill="#E1E1E1"
          />
          <g opacity={0.2}>
            <rect
              x={220.961}
              y={31.9166}
              width={104.6}
              height={370.657}
              rx={5.5}
              transform="rotate(-9.807 220.961 31.917)"
              fill="#fff"
              stroke="#B7B7B7"
            />
            <rect
              x={233.764}
              y={44.5057}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 233.764 44.506)"
              fill="#E1E1E1"
            />
            <rect
              x={245.91}
              y={114.778}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 245.91 114.778)"
              fill="#E1E1E1"
            />
            <rect
              x={258.057}
              y={185.05}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 258.057 185.05)"
              fill="#E1E1E1"
            />
            <rect
              x={270.203}
              y={255.322}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 270.203 255.322)"
              fill="#E1E1E1"
            />
            <rect
              x={234.698}
              y={49.9113}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 234.698 49.911)"
              fill="#E1E1E1"
            />
            <rect
              x={246.845}
              y={120.184}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 246.845 120.184)"
              fill="#E1E1E1"
            />
            <rect
              x={258.991}
              y={190.456}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 258.991 190.456)"
              fill="#E1E1E1"
            />
            <rect
              x={271.138}
              y={260.728}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 271.138 260.728)"
              fill="#E1E1E1"
            />
            <rect
              x={235.633}
              y={55.3168}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 235.633 55.317)"
              fill="#E1E1E1"
            />
            <rect
              x={247.779}
              y={125.589}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 247.779 125.589)"
              fill="#E1E1E1"
            />
            <rect
              x={259.926}
              y={195.861}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 259.926 195.861)"
              fill="#E1E1E1"
            />
            <rect
              x={272.072}
              y={266.134}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 272.072 266.134)"
              fill="#E1E1E1"
            />
            <rect
              x={236.567}
              y={60.7224}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 236.567 60.722)"
              fill="#E1E1E1"
            />
            <rect
              x={248.713}
              y={130.995}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 248.713 130.995)"
              fill="#E1E1E1"
            />
            <rect
              x={260.86}
              y={201.267}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 260.86 201.267)"
              fill="#E1E1E1"
            />
            <rect
              x={273.006}
              y={271.539}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 273.006 271.539)"
              fill="#E1E1E1"
            />
            <rect
              x={237.501}
              y={66.1279}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 237.501 66.128)"
              fill="#E1E1E1"
            />
            <rect
              x={249.648}
              y={136.4}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 249.648 136.4)"
              fill="#E1E1E1"
            />
            <rect
              x={261.794}
              y={206.672}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 261.794 206.672)"
              fill="#E1E1E1"
            />
            <rect
              x={273.941}
              y={276.945}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 273.941 276.945)"
              fill="#E1E1E1"
            />
            <rect
              x={239.837}
              y={79.6418}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 239.837 79.642)"
              fill="#E1E1E1"
            />
            <rect
              x={251.984}
              y={149.914}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 251.984 149.914)"
              fill="#E1E1E1"
            />
            <rect
              x={264.13}
              y={220.186}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 264.13 220.186)"
              fill="#E1E1E1"
            />
            <rect
              x={276.277}
              y={290.459}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 276.277 290.459)"
              fill="#E1E1E1"
            />
            <rect
              x={240.771}
              y={85.0474}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 240.771 85.047)"
              fill="#E1E1E1"
            />
            <rect
              x={252.918}
              y={155.32}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 252.918 155.32)"
              fill="#E1E1E1"
            />
            <rect
              x={265.064}
              y={225.592}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 265.064 225.592)"
              fill="#E1E1E1"
            />
            <rect
              x={277.211}
              y={295.864}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 277.211 295.864)"
              fill="#E1E1E1"
            />
            <rect
              x={241.706}
              y={90.4529}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 241.706 90.453)"
              fill="#E1E1E1"
            />
            <rect
              x={253.852}
              y={160.725}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 253.852 160.725)"
              fill="#E1E1E1"
            />
            <rect
              x={265.999}
              y={230.997}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 265.999 230.997)"
              fill="#E1E1E1"
            />
            <rect
              x={278.145}
              y={301.27}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 278.145 301.27)"
              fill="#E1E1E1"
            />
            <rect
              x={242.64}
              y={95.8585}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 242.64 95.859)"
              fill="#E1E1E1"
            />
            <rect
              x={254.787}
              y={166.131}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 254.787 166.131)"
              fill="#E1E1E1"
            />
            <rect
              x={266.933}
              y={236.403}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 266.933 236.403)"
              fill="#E1E1E1"
            />
            <rect
              x={279.08}
              y={306.675}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 279.08 306.675)"
              fill="#E1E1E1"
            />
            <rect
              x={243.575}
              y={101.264}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 243.575 101.264)"
              fill="#E1E1E1"
            />
            <rect
              x={255.721}
              y={171.536}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 255.721 171.536)"
              fill="#E1E1E1"
            />
            <rect
              x={267.867}
              y={241.809}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 267.867 241.809)"
              fill="#E1E1E1"
            />
            <rect
              x={280.014}
              y={312.081}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 280.014 312.081)"
              fill="#E1E1E1"
            />
          </g>
          <g opacity={0.2}>
            <rect
              x={58.5247}
              y={-247.586}
              width={104.6}
              height={370.657}
              rx={5.5}
              transform="rotate(-9.807 58.525 -247.586)"
              fill="#fff"
              stroke="#B7B7B7"
            />
            <rect
              x={119.913}
              y={46.0917}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 119.913 46.092)"
              fill="#E1E1E1"
            />
            <rect
              x={120.848}
              y={51.4973}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 120.848 51.497)"
              fill="#E1E1E1"
            />
            <rect
              x={121.782}
              y={56.9028}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 121.782 56.903)"
              fill="#E1E1E1"
            />
            <rect
              x={122.716}
              y={62.3084}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 122.716 62.308)"
              fill="#E1E1E1"
            />
            <rect
              x={123.651}
              y={67.7139}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 123.651 67.714)"
              fill="#E1E1E1"
            />
            <rect
              x={125.987}
              y={81.2278}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 125.987 81.228)"
              fill="#E1E1E1"
            />
            <rect
              x={126.921}
              y={86.6334}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 126.921 86.633)"
              fill="#E1E1E1"
            />
            <rect
              x={127.855}
              y={92.0389}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 127.855 92.039)"
              fill="#E1E1E1"
            />
            <rect
              x={116.643}
              y={27.1722}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 116.643 27.172)"
              fill="#E1E1E1"
            />
            <rect
              x={128.79}
              y={97.4445}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 128.79 97.445)"
              fill="#E1E1E1"
            />
            <rect
              x={117.577}
              y={32.5778}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 117.577 32.578)"
              fill="#E1E1E1"
            />
            <path
              transform="rotate(-9.807 129.724 102.85)"
              fill="#E1E1E1"
              d="M129.724 102.85H169.4954V104.22143H129.724z"
            />
          </g>
          <g opacity={0.2}>
            <rect
              x={-8.37503}
              y={25.6289}
              width={104.6}
              height={370.657}
              rx={4.5}
              transform="rotate(-9.807 -8.375 25.629)"
              fill="#fff"
              stroke="#B7B7B7"
            />
            <rect
              x={4.42767}
              y={38.218}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 4.428 38.218)"
              fill="#E1E1E1"
            />
            <rect
              x={16.5742}
              y={108.49}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 16.574 108.49)"
              fill="#E1E1E1"
            />
            <rect
              x={28.7207}
              y={178.763}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 28.72 178.763)"
              fill="#E1E1E1"
            />
            <rect
              x={40.8672}
              y={249.035}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 40.867 249.035)"
              fill="#E1E1E1"
            />
            <rect
              x={53.0136}
              y={319.307}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 53.014 319.307)"
              fill="#E1E1E1"
            />
            <rect
              x={5.36206}
              y={43.6235}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 5.362 43.623)"
              fill="#E1E1E1"
            />
            <rect
              x={17.5085}
              y={113.896}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 17.509 113.896)"
              fill="#E1E1E1"
            />
            <rect
              x={29.655}
              y={184.168}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 29.655 184.168)"
              fill="#E1E1E1"
            />
            <rect
              x={41.8015}
              y={254.44}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 41.801 254.44)"
              fill="#E1E1E1"
            />
            <rect
              x={6.29639}
              y={49.0291}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 6.296 49.03)"
              fill="#E1E1E1"
            />
            <rect
              x={18.4429}
              y={119.301}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 18.443 119.301)"
              fill="#E1E1E1"
            />
            <rect
              x={30.5894}
              y={189.574}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 30.59 189.574)"
              fill="#E1E1E1"
            />
            <rect
              x={42.7358}
              y={259.846}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 42.736 259.846)"
              fill="#E1E1E1"
            />
            <rect
              x={7.23071}
              y={54.4346}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 7.23 54.435)"
              fill="#E1E1E1"
            />
            <rect
              x={19.3772}
              y={124.707}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 19.377 124.707)"
              fill="#E1E1E1"
            />
            <rect
              x={31.5237}
              y={194.979}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 31.524 194.979)"
              fill="#E1E1E1"
            />
            <rect
              x={43.6702}
              y={265.251}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 43.67 265.251)"
              fill="#E1E1E1"
            />
            <rect
              x={8.1651}
              y={59.8402}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 8.165 59.84)"
              fill="#E1E1E1"
            />
            <rect
              x={20.3116}
              y={130.112}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 20.312 130.112)"
              fill="#E1E1E1"
            />
            <rect
              x={32.458}
              y={200.385}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 32.458 200.385)"
              fill="#E1E1E1"
            />
            <rect
              x={44.6045}
              y={270.657}
              width={60.3429}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 44.605 270.657)"
              fill="#E1E1E1"
            />
            <rect
              x={10.5009}
              y={73.3541}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 10.5 73.354)"
              fill="#E1E1E1"
            />
            <rect
              x={22.6474}
              y={143.626}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 22.647 143.626)"
              fill="#E1E1E1"
            />
            <rect
              x={34.7939}
              y={213.899}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 34.794 213.899)"
              fill="#E1E1E1"
            />
            <rect
              x={46.9404}
              y={284.171}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 46.94 284.171)"
              fill="#E1E1E1"
            />
            <rect
              x={11.4353}
              y={78.7596}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 11.435 78.76)"
              fill="#E1E1E1"
            />
            <rect
              x={23.5818}
              y={149.032}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 23.582 149.032)"
              fill="#E1E1E1"
            />
            <rect
              x={35.7283}
              y={219.304}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 35.728 219.304)"
              fill="#E1E1E1"
            />
            <rect
              x={47.8748}
              y={289.576}
              width={83.6571}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 47.875 289.576)"
              fill="#E1E1E1"
            />
            <rect
              x={12.3696}
              y={84.1652}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 12.37 84.165)"
              fill="#E1E1E1"
            />
            <rect
              x={24.5161}
              y={154.438}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 24.516 154.438)"
              fill="#E1E1E1"
            />
            <rect
              x={36.6626}
              y={224.71}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 36.663 224.71)"
              fill="#E1E1E1"
            />
            <rect
              x={48.8091}
              y={294.982}
              width={75.4286}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 48.81 294.982)"
              fill="#E1E1E1"
            />
            <rect
              x={13.304}
              y={89.5708}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 13.304 89.57)"
              fill="#E1E1E1"
            />
            <rect
              x={25.4505}
              y={159.843}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 25.45 159.843)"
              fill="#E1E1E1"
            />
            <rect
              x={37.597}
              y={230.115}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 37.597 230.115)"
              fill="#E1E1E1"
            />
            <rect
              x={49.7434}
              y={300.388}
              width={67.2}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 49.743 300.388)"
              fill="#E1E1E1"
            />
            <rect
              x={14.2383}
              y={94.9763}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 14.238 94.976)"
              fill="#E1E1E1"
            />
            <rect
              x={26.3848}
              y={165.249}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 26.385 165.249)"
              fill="#E1E1E1"
            />
            <rect
              x={38.5313}
              y={235.521}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 38.531 235.521)"
              fill="#E1E1E1"
            />
            <rect
              x={50.6778}
              y={305.793}
              width={39.7714}
              height={1.37143}
              rx={0.685714}
              transform="rotate(-9.807 50.678 305.793)"
              fill="#E1E1E1"
            />
          </g>
        </g>
        <g
          style={{
            mixBlendMode: "color-burn",
          }}
          filter="url(#filter0_f_136_130388)"
        >
          <path
            transform="rotate(-9.807 141.637 171.771)"
            fill="#3F3C3C"
            d="M141.637 171.771H223.92270000000002V199.19959999999998H141.637z"
          />
        </g>
        <g filter="url(#filter1_f_136_130388)">
          <path
            transform="rotate(-9.807 129.641 126.524)"
            fill="#B7B7B7"
            d="M129.641 126.524H216.041V219.78109999999998H129.641z"
          />
        </g>
        <g
          style={{
            mixBlendMode: "color-burn",
          }}
          opacity={0.4}
          filter="url(#filter2_f_136_130388)"
        >
          <path
            transform="rotate(-9.807 145.841 196.096)"
            fill="#3F3C3C"
            fillOpacity={0.36}
            d="M145.841 196.096H228.12670000000003V223.5246H145.841z"
          />
        </g>
        <path
          transform="rotate(-9.807 130.575 131.93)"
          fill="url(#pattern0_136_130388)"
          d="M130.575 131.93H212.8607V214.21570000000003H130.575z"
        />
      </g>
      <defs>
        <filter
          id="filter0_f_136_130388"
          x={129.637}
          y={145.756}
          width={109.755}
          height={65.043}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feGaussianBlur
            stdDeviation={6}
            result="effect1_foregroundBlur_136_130388"
          />
        </filter>
        <filter
          id="filter1_f_136_130388"
          x={81.6407}
          y={63.8085}
          width={197.021}
          height={202.61}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feGaussianBlur
            stdDeviation={24}
            result="effect1_foregroundBlur_136_130388"
          />
        </filter>
        <filter
          id="filter2_f_136_130388"
          x={117.841}
          y={154.081}
          width={141.755}
          height={97.043}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feGaussianBlur
            stdDeviation={14}
            result="effect1_foregroundBlur_136_130388"
          />
        </filter>
        <pattern
          id="pattern0_136_130388"
          patternContentUnits="objectBoundingBox"
          width={1}
          height={1}
        >
          <use xlinkHref="#image0_136_130388" transform="scale(.00195)" />
        </pattern>
        <linearGradient
          id="paint0_linear_136_130388"
          x1={173.288}
          y1={66.9091}
          x2={173.288}
          y2={311.709}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#fff" stopOpacity={0} />
          <stop offset={0.44} stopColor="#F6F6F6" stopOpacity={0.935} />
          <stop offset={1} stopColor="#737373" stopOpacity={0} />
        </linearGradient>
        <clipPath id="clip0_136_130388">
          <path
            fill="#fff"
            transform="rotate(-9.807 331.558 28.444)"
            d="M0 0H334V288H0z"
          />
        </clipPath>
        <image
          id="image0_136_130388"
          width={512}
          height={512}
          xlinkHref="data:image/png;base64,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"
        />
      </defs>
    </svg>
  );
}


================================================
FILE: src/components/images/homepage-image-2.tsx
================================================
import { ComponentProps } from "react";

export default function HomepageImage2(props: ComponentProps<"svg">) {
  return (
    <svg
      width={130}
      height={190}
      viewBox="0 0 130 190"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <path
        d="M74.005 37.846l4.568 14.42 14.468 4.426-12.304 8.792.274 15.122-12.172-8.985-14.3 4.937 4.78-14.349-9.113-12.068 15.13.1 8.669-12.395z"
        fill="#3F3C3C"
      />
      <path
        d="M113.565 65.814l-8.567-1.31m-8.612 29.68l-5.132-6.983M36.461 54.023l-8.567-1.31m22.309-21.387l-5.131-6.984m30.898.653l1.31-8.567m21.386 22.31l6.984-5.131m-41.472 68.492l1.31-8.567M35.808 84.92l6.984-5.131m31.214-41.943l4.568 14.42 14.468 4.426-12.304 8.792.274 15.122-12.172-8.985-14.3 4.937 4.78-14.349-9.113-12.068 15.13.1 8.669-12.395z"
        stroke="#3F3C3C"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <g filter="url(#filter0_f_136_130610)">
        <rect
          x={26.2013}
          y={69.6304}
          width={83.8367}
          height={97.6327}
          rx={6}
          transform="rotate(8.695 26.201 69.63)"
          fill="#B7B7B7"
        />
      </g>
      <rect
        x={29.3711}
        y={62.5384}
        width={79.7143}
        height={95.6327}
        rx={5}
        transform="rotate(8.695 29.371 62.538)"
        fill="#fff"
        stroke="url(#paint0_linear_136_130610)"
        strokeWidth={2}
      />
      <rect
        x={35.1612}
        y={74.2214}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 35.161 74.221)"
        fill="url(#paint1_linear_136_130610)"
      />
      <rect
        x={34.5195}
        y={78.4175}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 34.52 78.418)"
        fill="url(#paint2_linear_136_130610)"
      />
      <rect
        x={33.8778}
        y={82.6136}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 33.878 82.614)"
        fill="url(#paint3_linear_136_130610)"
      />
      <rect
        x={33.236}
        y={86.8098}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 33.236 86.81)"
        fill="url(#paint4_linear_136_130610)"
      />
      <rect
        x={32.5943}
        y={91.0059}
        width={46.6939}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 32.594 91.006)"
        fill="url(#paint5_linear_136_130610)"
      />
      <rect
        x={30.9899}
        y={101.496}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 30.99 101.496)"
        fill="url(#paint6_linear_136_130610)"
      />
      <rect
        x={30.3482}
        y={105.692}
        width={64.7347}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 30.348 105.692)"
        fill="url(#paint7_linear_136_130610)"
      />
      <rect
        x={29.7064}
        y={109.888}
        width={58.3673}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 29.706 109.888)"
        fill="url(#paint8_linear_136_130610)"
      />
      <rect
        x={29.0647}
        y={114.084}
        width={52}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 29.065 114.084)"
        fill="url(#paint9_linear_136_130610)"
      />
      <rect
        x={28.423}
        y={118.281}
        width={30.7755}
        height={2.12245}
        rx={1.06122}
        transform="rotate(8.695 28.423 118.281)"
        fill="url(#paint10_linear_136_130610)"
      />
      <defs>
        <filter
          id="filter0_f_136_130610"
          x={0.278534}
          y={58.4677}
          width={119.959}
          height={131.51}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feGaussianBlur
            stdDeviation={6}
            result="effect1_foregroundBlur_136_130610"
          />
        </filter>
        <linearGradient
          id="paint0_linear_136_130610"
          x1={17.3909}
          y1={120.827}
          x2={112.371}
          y2={82.0926}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="silver" />
          <stop offset={1} />
        </linearGradient>
        <linearGradient
          id="paint1_linear_136_130610"
          x1={57.447}
          y1={74.2456}
          x2={57.6648}
          y2={78.1289}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint2_linear_136_130610"
          x1={56.8052}
          y1={78.4417}
          x2={57.0231}
          y2={82.325}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint3_linear_136_130610"
          x1={56.1635}
          y1={82.6378}
          x2={56.3814}
          y2={86.5211}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint4_linear_136_130610"
          x1={55.5217}
          y1={86.8339}
          x2={55.7396}
          y2={90.7172}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint5_linear_136_130610"
          x1={48.6692}
          y1={91.03}
          x2={48.9704}
          y2={94.9021}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint6_linear_136_130610"
          x1={53.2756}
          y1={101.52}
          x2={53.4935}
          y2={105.404}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint7_linear_136_130610"
          x1={52.6339}
          y1={105.716}
          x2={52.8518}
          y2={109.6}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint8_linear_136_130610"
          x1={49.8001}
          y1={109.912}
          x2={50.0416}
          y2={113.793}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint9_linear_136_130610"
          x1={46.9663}
          y1={114.109}
          x2={47.2371}
          y2={117.985}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
        <linearGradient
          id="paint10_linear_136_130610"
          x1={39.0178}
          y1={118.305}
          x2={39.4712}
          y2={122.147}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#1D1D1D" />
          <stop offset={1} stopColor="#838383" />
        </linearGradient>
      </defs>
    </svg>
  );
}


================================================
FILE: src/components/ui/action-button.tsx
================================================
"use client";

import { Button } from "@/components/ui/button";
import Spinner from "@/components/ui/spinner";
import { ComponentProps } from "react";
import { useFormStatus } from "react-dom";

export default function ActionButton({
  children,
  className,
  ...rest
}: ComponentProps<typeof Button>) {
  const { pending } = useFormStatus();

  return (
    <span className="relative">
      <Button
        className={`${className} ${pending ? "*:invisible" : ""}`}
        disabled={pending}
        {...rest}
      >
        {children}
      </Button>
      <div className="pointer-events-none absolute inset-0 flex items-center justify-center text-white">
        <Spinner loading={pending} className="size-4" />
      </div>
    </span>
  );
}


================================================
FILE: src/components/ui/button.tsx
================================================
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow hover:bg-primary/90",
        destructive:
          "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
        outline:
          "border text-base border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
        "outline-active":
          "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
        secondary:
          "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-9 px-4 py-2",
        sm: "h-8 rounded-md px-3 text-xs",
        lg: "h-10 rounded-md px-8",
        icon: "h-9 w-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  },
);

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button";
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    );
  },
);
Button.displayName = "Button";

export { Button, buttonVariants };


================================================
FILE: src/components/ui/logo.tsx
================================================
export default function Logo(props: React.ComponentProps<"svg">) {
  return (
    <svg
      width={165}
      height={30}
      viewBox="0 0 165 30"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      {...props}
    >
      <g filter="url(#filter0_f_136_195792)">
        <path
          d="M5.583 6.471c2.363 2.62 8.823 1.765 12.907.892 1.848-.395 3.711.853 3.875 2.736.514 5.932 1.273 16.838-.34 14.604-1.538-2.133-9.02-1.271-13.342-.568-1.694.275-3.324-.847-3.56-2.547-.831-5.96-2.255-18.127.46-15.117z"
          fill="#B7B7B7"
        />
      </g>
      <path
        d="M5.583 5.471c2.908 3.224 12.02 1.186 15.274.327.609-.16 1.227.247 1.287.874.425 4.452 1.756 19.63-.118 17.03-1.834-2.541-12.107-.83-15.416-.203a1.002 1.002 0 01-1.186-.829c-.652-4.329-2.937-20.632.16-17.199z"
        fill="url(#paint0_linear_136_195792)"
      />
      <path
        d="M18.245 14.756S12.985 10.208 14 14.5c1.015 4.291-4.244-.257-4.244-.257"
        stroke="#E1E1E1"
        strokeWidth={1.5}
        strokeLinecap="square"
      />
      <path
        d="M31.04 18.046h2.34c.182 2.444 2.08 4.056 4.862 4.056 2.444 0 4.186-1.118 4.186-3.094 0-2.262-2.236-2.73-4.992-3.198-2.938-.494-5.954-1.456-5.954-4.992 0-3.094 2.522-5.174 6.214-5.174 4.056 0 6.552 2.262 6.76 5.538h-2.34c-.26-2.106-1.95-3.484-4.42-3.484-2.366 0-3.952 1.04-3.952 2.99 0 2.184 2.21 2.626 4.94 3.094 2.964.494 6.006 1.482 6.006 5.018 0 3.146-2.652 5.356-6.474 5.356-4.446 0-7.046-2.522-7.176-6.11zm31.003-7.462c2.756 0 5.018 1.586 5.018 5.772V24h-2.132v-7.514c0-2.6-1.144-3.952-3.146-3.952-2.21 0-3.562 1.664-3.562 4.368V24h-2.132v-7.514c0-2.6-1.17-3.952-3.198-3.952-2.184 0-3.51 1.82-3.51 4.472V24h-2.132V10.74h1.846l.286 1.82c.702-.962 1.82-1.976 3.874-1.976 1.846 0 3.432.832 4.186 2.522.806-1.43 2.236-2.522 4.602-2.522zM81.522 22.05h.676V24h-1.17c-1.768 0-2.366-.754-2.392-2.054-.832 1.196-2.158 2.21-4.446 2.21-2.912 0-4.888-1.456-4.888-3.874 0-2.652 1.846-4.134 5.33-4.134h3.9v-.91c0-1.716-1.222-2.756-3.302-2.756-1.872 0-3.12.884-3.38 2.236h-2.132c.312-2.6 2.418-4.134 5.616-4.134 3.38 0 5.33 1.69 5.33 4.784v5.798c0 .702.26.884.858.884zm-2.99-3.458v-.65h-4.108c-1.898 0-2.964.702-2.964 2.21 0 1.3 1.118 2.184 2.886 2.184 2.652 0 4.186-1.534 4.186-3.744zm11.44-7.852h.599v2.08h-1.066c-2.782 0-3.536 2.314-3.536 4.42V24h-2.132V10.74h1.846l.286 2.002c.624-1.014 1.638-2.002 4.004-2.002zm3.867 9.802V12.69h-2.392v-1.95h2.391V7.022h2.133v3.718h3.431v1.95h-3.431v7.826c0 1.118.39 1.534 1.533 1.534h2.106V24h-2.314c-2.547 0-3.458-1.118-3.458-3.458z"
        fill="#3F3C3C"
      />
      <path
        d="M104.364 24l3.224-18.2h6.682c3.9 0 6.188 2.34 6.188 5.356 0 4.342-3.172 6.734-7.566 6.734h-3.536L108.264 24h-3.9zm9.516-14.95h-2.99l-.962 5.59h3.016c2.132 0 3.562-1.118 3.562-3.172 0-1.586-.988-2.418-2.626-2.418zM127.195 24h-6.708l3.224-18.2h5.538c5.486 0 8.684 3.146 8.684 7.852 0 6.318-4.004 10.348-10.738 10.348zm-.182-14.95l-2.054 11.7h2.678c4.082 0 6.37-2.99 6.37-6.916 0-3.042-1.872-4.784-4.992-4.784h-2.002zM138.667 24l3.224-18.2h11.882l-.598 3.354h-7.982l-.754 4.264h6.526l-.572 3.198h-6.526l-1.3 7.384h-3.9zm19.69-13.546c3.224 0 5.746 1.482 5.746 4.368h-3.458c0-1.144-.858-1.768-2.314-1.768-1.56 0-2.496.546-2.496 1.404 0 .78.936 1.066 2.262 1.248 2.522.338 5.356.988 5.356 3.848 0 3.224-2.938 4.602-6.422 4.602-3.406 0-5.824-1.534-5.824-4.654h3.406c.052 1.404 1.118 2.028 2.522 2.028 1.69 0 2.704-.494 2.704-1.534 0-.832-.91-1.118-2.496-1.378-2.496-.416-5.07-1.04-5.07-3.718 0-2.86 2.496-4.446 6.084-4.446z"
        fill="url(#paint1_linear_136_195792)"
      />
      <defs>
        <filter
          id="filter0_f_136_195792"
          x={0}
          y={2}
          width={27}
          height={27}
          filterUnits="userSpaceOnUse"
          colorInterpolationFilters="sRGB"
        >
          <feFlood floodOpacity={0} result="BackgroundImageFix" />
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
          <feGaussianBlur
            stdDeviation={2}
            result="effect1_foregroundBlur_136_195792"
          />
        </filter>
        <linearGradient
          id="paint0_linear_136_195792"
          x1={13.8044}
          y1={5.47122}
          x2={13.8044}
          y2={23.7029}
          gradientUnits="userSpaceOnUse"
        >
          <stop stopColor="#3F3C3C" />
          <stop offset={1} />
        </linearGradient>
        <linearGradient
          id="paint1_linear_136_195792"
          x1={110.952}
          y1={10.8909}
          x2={170.317}
          y2={28.5703}
          gradientUnits="userSpaceOnUse"
        >
          <stop />
          <stop offset={1} stopColor="#3F3C3C" />
        </linearGradient>
      </defs>
    </svg>
  );
}


================================================
FILE: src/components/ui/select.tsx
================================================
"use client"

import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"

import { cn } from "@/lib/utils"

const Select = SelectPrimitive.Root

const SelectGroup = SelectPrimitive.Group

const SelectValue = SelectPrimitive.Value

const SelectTrigger = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <SelectPrimitive.Trigger
    ref={ref}
    className={cn(
      "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
      className
    )}
    {...props}
  >
    {children}
    <SelectPrimitive.Icon asChild>
      <ChevronDown className="h-4 w-4 opacity-50" />
    </SelectPrimitive.Icon>
  </SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName

const SelectScrollUpButton = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.ScrollUpButton
    ref={ref}
    className={cn(
      "flex cursor-default items-center justify-center py-1",
      className
    )}
    {...props}
  >
    <ChevronUp className="h-4 w-4" />
  </SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName

const SelectScrollDownButton = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.ScrollDownButton
    ref={ref}
    className={cn(
      "flex cursor-default items-center justify-center py-1",
      className
    )}
    {...props}
  >
    <ChevronDown className="h-4 w-4" />
  </SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
  SelectPrimitive.ScrollDownButton.displayName

const SelectContent = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
  <SelectPrimitive.Portal>
    <SelectPrimitive.Content
      ref={ref}
      className={cn(
        "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
        position === "popper" &&
          "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
        className
      )}
      position={position}
      {...props}
    >
      <SelectScrollUpButton />
      <SelectPrimitive.Viewport
        className={cn(
          "p-1",
          position === "popper" &&
            "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
        )}
      >
        {children}
      </SelectPrimitive.Viewport>
      <SelectScrollDownButton />
    </SelectPrimitive.Content>
  </SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName

const SelectLabel = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.Label
    ref={ref}
    className={cn("px-2 py-1.5 text-sm font-semibold", className)}
    {...props}
  />
))
SelectLabel.displayName = SelectPrimitive.Label.displayName

const SelectItem = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
  <SelectPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      className
    )}
    {...props}
  >
    <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
      <SelectPrimitive.ItemIndicator>
        <Check className="h-4 w-4" />
      </SelectPrimitive.ItemIndicator>
    </span>
    <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
  </SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName

const SelectSeparator = React.forwardRef<
  React.ElementRef<typeof SelectPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <SelectPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 my-1 h-px bg-muted", className)}
    {...props}
  />
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName

export {
  Select,
  SelectGroup,
  SelectValue,
  SelectTrigger,
  SelectContent,
  SelectLabel,
  SelectItem,
  SelectSeparator,
  SelectScrollUpButton,
  SelectScrollDownButton,
}


================================================
FILE: src/components/ui/spinner.tsx
================================================
import { ReactNode } from "react";

export default function Spinner({
  loading = true,
  children,
  className = "",
}: {
  loading?: boolean;
  children?: ReactNode;
  className?: string;
}) {
  if (!loading) return children;

  const spinner = (
    <>
      <style jsx>
        {`
          @keyframes spinner {
            from {
              opacity: 1;
            }
            to {
              opacity: 0.25;
            }
          }
        `}
      </style>
      <span className={`relative inline-flex size-4 ${className}`}>
        {Array.from(Array(8).keys()).map((i) => (
          <span
            key={i}
            className="absolute left-[calc(50%-12.5%/2)] top-0 h-[100%] w-[12.5%] animate-[spinner_800ms_linear_infinite] before:block before:h-[30%] before:w-[100%] before:rounded-full before:bg-current"
            style={{
              transform: `rotate(${45 * i}deg)`,
              animationDelay: `calc(-${8 - i} / 8 * 800ms)`,
            }}
          />
        ))}
      </span>
    </>
  );

  if (!children) return spinner;

  return (
    <span className="relative flex h-full items-center justify-center">
      <span className="invisible flex">{children}</span>

      <span className="absolute inset-0 flex items-center justify-center">
        {spinner}
      </span>
    </span>
  );
}


================================================
FILE: src/components/ui/summary-content.tsx
================================================
"use client";

import Image from "next/image";

interface SummaryContentProps {
  title?: string;
  summary?: string;
  imageUrl?: string;
}

export default function SummaryContent({
  title,
  summary,
  imageUrl,
}: SummaryContentProps) {
  return (
    <div>
      {imageUrl && (
        <>
          <Image
            className="rounded-md"
            src={imageUrl}
            width={1280}
            height={720}
            alt=""
          />
          <hr className="-mx-5 my-8" />
        </>
      )}
      <h2 className="text-xl font-semibold text-gray-900">{title}</h2>
      <div
        className="prose mt-4 text-sm"
        dangerouslySetInnerHTML={{
          __html: summary || "",
        }}
      />
    </div>
  );
}


================================================
FILE: src/components/ui/table-of-contents.tsx
================================================
"use client";

import { Button } from "@/components/ui/button";
import Spinner from "@/components/ui/spinner";
import { Chunk } from "@/lib/summarize";

interface TableOfContentsProps {
  activeChunkIndex: number | "quick-summary" | null;
  setActiveChunkIndex: (index: number | "quick-summary" | null) => void;
  quickSummary: { title: string; summary: string } | undefined;
  chunks: Chunk[];
}

export default function TableOfContents({
  activeChunkIndex,
  setActiveChunkIndex,
  quickSummary,
  chunks,
}: TableOfContentsProps) {
  return (
    <div className="flex w-full min-w-0 flex-col gap-4">
      <Button
        variant="outline"
        className={`${activeChunkIndex === "quick-summary" ? "bg-white hover:bg-white" : "hover:bg-gray-200"} inline-flex w-full justify-between border-gray-250 px-4 py-6 text-base font-semibold shadow-sm`}
        onClick={() => setActiveChunkIndex("quick-summary")}
        disabled={!quickSummary}
      >
        Quick summary
        <Spinner loading={!quickSummary} />
      </Button>
      <hr />
      <div className="flex flex-col gap-2">
        {chunks.map((chunk, i) => (
          <Button
            key={i}
            variant="outline"
            className={`${activeChunkIndex === i ? "bg-white hover:bg-white" : "hover:bg-gray-200"} inline-flex h-auto w-full justify-between border-gray-250 px-4 py-3 text-base shadow-sm transition disabled:cursor-not-allowed`}
            disabled={!chunk.summary}
            onClick={() => setActiveChunkIndex(i)}
          >
            <span className="flex h-full min-w-0 flex-col justify-start text-left">
              <span className="text-xs font-medium uppercase text-gray-500">
                Section {i + 1}
              </span>
              <span className="truncate text-sm">
                {chunk.title ?? <>&hellip;</>}
              </span>
            </span>
            <Spinner loading={!chunk.summary} />
          </Button>
        ))}
      </div>
    </div>
  );
}


================================================
FILE: src/components/ui/toast.tsx
================================================
"use client"

import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const ToastProvider = ToastPrimitives.Provider

const ToastViewport = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Viewport>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Viewport
    ref={ref}
    className={cn(
      "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
      className
    )}
    {...props}
  />
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName

const toastVariants = cva(
  "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
  {
    variants: {
      variant: {
        default: "border bg-background text-foreground",
        destructive:
          "destructive group border-destructive bg-destructive text-destructive-foreground",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

const Toast = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Root>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
    VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
  return (
    <ToastPrimitives.Root
      ref={ref}
      className={cn(toastVariants({ variant }), className)}
      {...props}
    />
  )
})
Toast.displayName = ToastPrimitives.Root.displayName

const ToastAction = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Action>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Action
    ref={ref}
    className={cn(
      "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
      className
    )}
    {...props}
  />
))
ToastAction.displayName = ToastPrimitives.Action.displayName

const ToastClose = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Close>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Close
    ref={ref}
    className={cn(
      "absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
      className
    )}
    toast-close=""
    {...props}
  >
    <X className="h-4 w-4" />
  </ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName

const ToastTitle = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Title>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Title
    ref={ref}
    className={cn("text-sm font-semibold [&+div]:text-xs", className)}
    {...props}
  />
))
ToastTitle.displayName = ToastPrimitives.Title.displayName

const ToastDescription = React.forwardRef<
  React.ElementRef<typeof ToastPrimitives.Description>,
  React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
  <ToastPrimitives.Description
    ref={ref}
    className={cn("text-sm opacity-90", className)}
    {...props}
  />
))
ToastDescription.displayName = ToastPrimitives.Description.displayName

type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>

type ToastActionElement = React.ReactElement<typeof ToastAction>

export {
  type ToastProps,
  type ToastActionElement,
  ToastProvider,
  ToastViewport,
  Toast,
  ToastTitle,
  ToastDescription,
  ToastClose,
  ToastAction,
}


================================================
FILE: src/components/ui/toaster.tsx
================================================
"use client"

import { useToast } from "@/hooks/use-toast"
import {
  Toast,
  ToastClose,
  ToastDescription,
  ToastProvider,
  ToastTitle,
  ToastViewport,
} from "@/components/ui/toast"

export function Toaster() {
  const { toasts } = useToast()

  return (
    <ToastProvider>
      {toasts.map(function ({ id, title, description, action, ...props }) {
        return (
          <Toast key={id} {...props}>
            <div className="grid gap-1">
              {title && <ToastTitle>{title}</ToastTitle>}
              {description && (
                <ToastDescription>{description}</ToastDescription>
              )}
            </div>
            {action}
            <ToastClose />
          </Toast>
        )
      })}
      <ToastViewport />
    </ToastProvider>
  )
}


================================================
FILE: src/hooks/use-toast.ts
================================================
"use client";

// Inspired by react-hot-toast library
import * as React from "react";

import type { ToastActionElement, ToastProps } from "@/components/ui/toast";

const TOAST_LIMIT = 1;
const TOAST_REMOVE_DELAY = 1000000;

type ToasterToast = ToastProps & {
  id: string;
  title?: React.ReactNode;
  description?: React.ReactNode;
  action?: ToastActionElement;
};

type ActionTypes = {
  ADD_TOAST: "ADD_TOAST";
  UPDATE_TOAST: "UPDATE_TOAST";
  DISMISS_TOAST: "DISMISS_TOAST";
  REMOVE_TOAST: "REMOVE_TOAST";
};

let count = 0;

function genId() {
  count = (count + 1) % Number.MAX_SAFE_INTEGER;
  return count.toString();
}

type Action =
  | {
      type: ActionTypes["ADD_TOAST"];
      toast: ToasterToast;
    }
  | {
      type: ActionTypes["UPDATE_TOAST"];
      toast: Partial<ToasterToast>;
    }
  | {
      type: ActionTypes["DISMISS_TOAST"];
      toastId?: ToasterToast["id"];
    }
  | {
      type: ActionTypes["REMOVE_TOAST"];
      toastId?: ToasterToast["id"];
    };

interface State {
  toasts: ToasterToast[];
}

const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();

const addToRemoveQueue = (toastId: string) => {
  if (toastTimeouts.has(toastId)) {
    return;
  }

  const timeout = setTimeout(() => {
    toastTimeouts.delete(toastId);
    dispatch({
      type: "REMOVE_TOAST",
      toastId: toastId,
    });
  }, TOAST_REMOVE_DELAY);

  toastTimeouts.set(toastId, timeout);
};

export const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case "ADD_TOAST":
      return {
        ...state,
        toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
      };

    case "UPDATE_TOAST":
      return {
        ...state,
        toasts: state.toasts.map((t) =>
          t.id === action.toast.id ? { ...t, ...action.toast } : t,
        ),
      };

    case "DISMISS_TOAST": {
      const { toastId } = action;

      // ! Side effects ! - This could be extracted into a dismissToast() action,
      // but I'll keep it here for simplicity
      if (toastId) {
        addToRemoveQueue(toastId);
      } else {
        state.toasts.forEach((toast) => {
          addToRemoveQueue(toast.id);
        });
      }

      return {
        ...state,
        toasts: state.toasts.map((t) =>
          t.id === toastId || toastId === undefined
            ? {
                ...t,
                open: false,
              }
            : t,
        ),
      };
    }
    case "REMOVE_TOAST":
      if (action.toastId === undefined) {
        return {
          ...state,
          toasts: [],
        };
      }
      return {
        ...state,
        toasts: state.toasts.filter((t) => t.id !== action.toastId),
      };
  }
};

const listeners: Array<(state: State) => void> = [];

let memoryState: State = { toasts: [] };

function dispatch(action: Action) {
  memoryState = reducer(memoryState, action);
  listeners.forEach((listener) => {
    listener(memoryState);
  });
}

type Toast = Omit<ToasterToast, "id">;

function toast({ ...props }: Toast) {
  const id = genId();

  const update = (props: ToasterToast) =>
    dispatch({
      type: "UPDATE_TOAST",
      toast: { ...props, id },
    });
  const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });

  dispatch({
    type: "ADD_TOAST",
    toast: {
      ...props,
      id,
      open: true,
      onOpenChange: (open) => {
        if (!open) dismiss();
      },
    },
  });

  return {
    id: id,
    dismiss,
    update,
  };
}

function useToast() {
  const [state, setState] = React.useState<State>(memoryState);

  React.useEffect(() => {
    listeners.push(setState);
    return () => {
      const index = listeners.indexOf(setState);
      if (index > -1) {
        listeners.splice(index, 1);
      }
    };
  }, [state]);

  return {
    ...state,
    toast,
    dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
  };
}

export { useToast, toast };


================================================
FILE: src/lib/ai.ts
================================================
import { createTogetherAI } from "@ai-sdk/togetherai";
import Together from "together-ai";

export const togetheraiClient = createTogetherAI({
  apiKey: process.env.TOGETHER_API_KEY ?? "",
  baseURL: "https://together.helicone.ai/v1",
  headers: {
    "Helicone-Auth": `Bearer ${process.env.HELICONE_API_KEY}`,
    "Helicone-Property-AppName": "SmartPDF",
  },
});

export const togetheraiBaseClient = new Together({
  apiKey: process.env.TOGETHER_API_KEY ?? "",
});


================================================
FILE: src/lib/prisma.ts
================================================
import { PrismaClient } from "@prisma/client";

declare global {
  // eslint-disable-next-line no-var
  var prisma: PrismaClient | undefined;
}

const client = globalThis.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalThis.prisma = client;

export default client;


================================================
FILE: src/lib/s3client.ts
================================================
import { S3Client } from "@aws-sdk/client-s3";

export const awsS3Client = new S3Client({
  region: process.env.S3_UPLOAD_REGION || "us-east-1",
  credentials: {
    accessKeyId: process.env.S3_UPLOAD_KEY || "",
    secretAccessKey: process.env.S3_UPLOAD_SECRET || "",
  },
});


================================================
FILE: src/lib/summarize.ts
================================================
import { PDFDocumentProxy } from "pdfjs-dist";
import assert from "assert";

export type Chunk = {
  text: string;
  summary?: string;
  title?: string;
};

export async function getPdfText(pdf: PDFDocumentProxy) {
  const numPages = pdf.numPages;
  let fullText = "";

  for (let pageNum = 1; pageNum <= numPages; pageNum++) {
    const page = await pdf.getPage(pageNum);
    const textContent = await page.getTextContent();

    let lastY = null;
    let pageText = "";

    // Process each text item
    for (const item of textContent.items) {
      if ("str" in item) {
        // Check for new line based on Y position
        if (lastY !== null && lastY !== item.transform[5]) {
          pageText += "\n";

          // Add extra line break if there's significant vertical space
          if (lastY - item.transform[5] > 12) {
            // Adjust this threshold as needed
            pageText += "\n";
          }
        }

        pageText += item.str;
        lastY = item.transform[5];
      }
    }

    fullText += pageText + "\n\n"; // Add double newline between pages
  }

  return fullText;
}

export async function chunkPdf(pdf: PDFDocumentProxy) {
  // const chunkCharSize = 6000; // 100k
  // const chunkCharSize = 100_000;
  const maxChunkSize = 50_000;
  // ideally have at least 4 chunks
  // chunk size = total chars / 4 OR 100k, whichever is smaller

  const fullText = await getPdfText(pdf);

  const chunks: Chunk[] = [];
  const chunkCharSize = Math.min(maxChunkSize, Math.ceil(fullText.length / 4));

  for (let i = 0; i < fullText.length; i += chunkCharSize) {
    const text = fullText.slice(i, i + chunkCharSize);
    chunks.push({ text });
  }

  return chunks;
}

export async function summarizeStream(chunks: Chunk[], language: string) {
  let reading = true;
  const stream = new ReadableStream({
    async start(controller) {
      const promises = chunks.map(async (chunk) => {
        const text = chunk.text;
        const response = await fetch("/api/summarize", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ text, language }),
        });
        let data;
        try {
          data = await response.json();
          if (reading) {
            controller.enqueue({
              ...chunk,
              summary: data.summary,
              title: data.title,
            });
          }
        } catch (e) {
          console.log(e);
        }
      });

      await Promise.all(promises);
      controller.close();
    },

    cancel() {
      console.log("read stream canceled");
      reading = false;
    },
  });

  return stream;
}

export async function generateQuickSummary(chunks: Chunk[], language: string) {
  const allSummaries = chunks.map((chunk) => chunk.summary).join("\n\n");

  const response = await fetch("/api/summarize", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ text: allSummaries, language }),
  });

  const { title, summary } = await response.json();

  console.log("title", title);
  assert.ok(typeof title === "string");
  assert.ok(typeof summary === "string");

  return { title, summary };
}

export type ImageGenerationResponse = {
  url: string;
};

export async function generateImage(text: string) {
  const response = await fetch("/api/image", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ text }),
  });

  const data: ImageGenerationResponse = await response.json();

  return data.url;
}


================================================
FILE: src/lib/utils.ts
================================================
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}


================================================
FILE: tailwind.config.ts
================================================
import type { Config } from "tailwindcss";
import tailwindcssAnimate from "tailwindcss-animate";

export default {
  darkMode: ["class"],
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      borderRadius: {
        lg: "var(--radius)",
        md: "calc(var(--radius) - 2px)",
        sm: "calc(var(--radius) - 4px)",
      },
      colors: {
        gray: {
          "100": "#F4F1EC",
          "200": "#FAF8F5",
          "250": "#E1E1E1",
          "300": "#B7B7B7",
          "500": "#9A9A9A",
          "900": "#3F3C3C",
        },
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        chart: {
          "1": "hsl(var(--chart-1))",
          "2": "hsl(var(--chart-2))",
          "3": "hsl(var(--chart-3))",
          "4": "hsl(var(--chart-4))",
          "5": "hsl(var(--chart-5))",
        },
      },
    },
  },
  plugins: [tailwindcssAnimate, require("@tailwindcss/typography")],
} satisfies Config;


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}
Download .txt
gitextract_c9h6c21g/

├── .eslintrc.json
├── .example.env
├── .gitignore
├── .node-version
├── .prettierrc
├── LICENSE
├── README.md
├── components.json
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── prisma/
│   └── schema.prisma
├── src/
│   ├── app/
│   │   ├── actions.ts
│   │   ├── api/
│   │   │   ├── image/
│   │   │   │   └── route.ts
│   │   │   ├── s3-upload/
│   │   │   │   └── route.ts
│   │   │   └── summarize/
│   │   │       └── route.ts
│   │   ├── globals.css
│   │   ├── layout.tsx
│   │   ├── page.tsx
│   │   └── pdf/
│   │       └── [id]/
│   │           ├── page.tsx
│   │           └── smart-pdf-viewer.tsx
│   ├── components/
│   │   ├── HomeLandingDrop.tsx
│   │   ├── icons/
│   │   │   ├── github.tsx
│   │   │   ├── sparkles.tsx
│   │   │   └── x.tsx
│   │   ├── images/
│   │   │   ├── homepage-image-1.tsx
│   │   │   └── homepage-image-2.tsx
│   │   └── ui/
│   │       ├── action-button.tsx
│   │       ├── button.tsx
│   │       ├── logo.tsx
│   │       ├── select.tsx
│   │       ├── spinner.tsx
│   │       ├── summary-content.tsx
│   │       ├── table-of-contents.tsx
│   │       ├── toast.tsx
│   │       └── toaster.tsx
│   ├── hooks/
│   │   └── use-toast.ts
│   └── lib/
│       ├── ai.ts
│       ├── prisma.ts
│       ├── s3client.ts
│       ├── summarize.ts
│       └── utils.ts
├── tailwind.config.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (44 symbols across 23 files)

FILE: src/app/actions.ts
  function sharePdf (line 18) | async function sharePdf({

FILE: src/app/api/image/route.ts
  function POST (line 8) | async function POST(req: Request) {

FILE: src/app/api/summarize/route.ts
  function POST (line 6) | async function POST(req: Request) {

FILE: src/app/layout.tsx
  function RootLayout (line 26) | function RootLayout({

FILE: src/app/page.tsx
  type StatusApp (line 24) | type StatusApp = "idle" | "parsing" | "generating";
  function Home (line 26) | function Home() {

FILE: src/app/pdf/[id]/page.tsx
  function generateMetadata (line 18) | async function generateMetadata(
  function Home (line 46) | async function Home({

FILE: src/app/pdf/[id]/smart-pdf-viewer.tsx
  function SmartPDFViewer (line 13) | function SmartPDFViewer({

FILE: src/components/icons/github.tsx
  function GithubIcon (line 3) | function GithubIcon(props: ComponentProps<"svg">) {

FILE: src/components/icons/sparkles.tsx
  function SparklesIcon (line 3) | function SparklesIcon(props: ComponentProps<"svg">) {

FILE: src/components/icons/x.tsx
  function XIcon (line 3) | function XIcon(props: ComponentProps<"svg">) {

FILE: src/components/images/homepage-image-1.tsx
  function HomepageImage1 (line 3) | function HomepageImage1(props: ComponentProps<"svg">) {

FILE: src/components/images/homepage-image-2.tsx
  function HomepageImage2 (line 3) | function HomepageImage2(props: ComponentProps<"svg">) {

FILE: src/components/ui/action-button.tsx
  function ActionButton (line 8) | function ActionButton({

FILE: src/components/ui/button.tsx
  type ButtonProps (line 39) | interface ButtonProps

FILE: src/components/ui/logo.tsx
  function Logo (line 1) | function Logo(props: React.ComponentProps<"svg">) {

FILE: src/components/ui/spinner.tsx
  function Spinner (line 3) | function Spinner({

FILE: src/components/ui/summary-content.tsx
  type SummaryContentProps (line 5) | interface SummaryContentProps {
  function SummaryContent (line 11) | function SummaryContent({

FILE: src/components/ui/table-of-contents.tsx
  type TableOfContentsProps (line 7) | interface TableOfContentsProps {
  function TableOfContents (line 14) | function TableOfContents({

FILE: src/components/ui/toast.tsx
  type ToastProps (line 115) | type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
  type ToastActionElement (line 117) | type ToastActionElement = React.ReactElement<typeof ToastAction>

FILE: src/components/ui/toaster.tsx
  function Toaster (line 13) | function Toaster() {

FILE: src/hooks/use-toast.ts
  constant TOAST_LIMIT (line 8) | const TOAST_LIMIT = 1;
  constant TOAST_REMOVE_DELAY (line 9) | const TOAST_REMOVE_DELAY = 1000000;
  type ToasterToast (line 11) | type ToasterToast = ToastProps & {
  type ActionTypes (line 18) | type ActionTypes = {
  function genId (line 27) | function genId() {
  type Action (line 32) | type Action =
  type State (line 50) | interface State {
  function dispatch (line 131) | function dispatch(action: Action) {
  type Toast (line 138) | type Toast = Omit<ToasterToast, "id">;
  function toast (line 140) | function toast({ ...props }: Toast) {
  function useToast (line 169) | function useToast() {

FILE: src/lib/summarize.ts
  type Chunk (line 4) | type Chunk = {
  function getPdfText (line 10) | async function getPdfText(pdf: PDFDocumentProxy) {
  function chunkPdf (line 46) | async function chunkPdf(pdf: PDFDocumentProxy) {
  function summarizeStream (line 66) | async function summarizeStream(chunks: Chunk[], language: string) {
  function generateQuickSummary (line 107) | async function generateQuickSummary(chunks: Chunk[], language: string) {
  type ImageGenerationResponse (line 127) | type ImageGenerationResponse = {
  function generateImage (line 131) | async function generateImage(text: string) {

FILE: src/lib/utils.ts
  function cn (line 4) | function cn(...inputs: ClassValue[]) {
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (167K chars).
[
  {
    "path": ".eslintrc.json",
    "chars": 61,
    "preview": "{\n  \"extends\": [\"next/core-web-vitals\", \"next/typescript\"]\n}\n"
  },
  {
    "path": ".example.env",
    "chars": 102,
    "preview": "TOGETHER_API_KEY=\nDATABASE_URL=\n\nS3_UPLOAD_KEY=\nS3_UPLOAD_SECRET=\nS3_UPLOAD_BUCKET=\nS3_UPLOAD_REGION=\n"
  },
  {
    "path": ".gitignore",
    "chars": 475,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": ".node-version",
    "chars": 8,
    "preview": "20.12.1\n"
  },
  {
    "path": ".prettierrc",
    "chars": 49,
    "preview": "{\n  \"plugins\": [\"prettier-plugin-tailwindcss\"]\n}\n"
  },
  {
    "path": "LICENSE",
    "chars": 1072,
    "preview": "MIT License\n\nCopyright (c) 2025 Hassan El Mghari\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 1439,
    "preview": "<a href=\"https://github.com/Nutlope/smartpdfs\">\n  <img alt=\"SmartPDF\" src=\"./public/og.jpg\">\n  <h1 align=\"center\">SmartP"
  },
  {
    "path": "components.json",
    "chars": 448,
    "preview": "{\n  \"$schema\": \"https://ui.shadcn.com/schema.json\",\n  \"style\": \"new-york\",\n  \"rsc\": true,\n  \"tsx\": true,\n  \"tailwind\": {"
  },
  {
    "path": "next.config.ts",
    "chars": 335,
    "preview": "import type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n  images: {\n    remotePatterns: [\n      {\n    "
  },
  {
    "path": "package.json",
    "chars": 1658,
    "preview": "{\n  \"name\": \"pdf-summary\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \""
  },
  {
    "path": "postcss.config.mjs",
    "chars": 135,
    "preview": "/** @type {import('postcss-load-config').Config} */\nconst config = {\n  plugins: {\n    tailwindcss: {},\n  },\n};\n\nexport d"
  },
  {
    "path": "prisma/schema.prisma",
    "chars": 805,
    "preview": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for "
  },
  {
    "path": "src/app/actions.ts",
    "chars": 893,
    "preview": "\"use server\";\n\nimport { nanoid } from \"nanoid\";\nimport client from \"@/lib/prisma\";\nimport { redirect } from \"next/naviga"
  },
  {
    "path": "src/app/api/image/route.ts",
    "chars": 2667,
    "preview": "import dedent from \"dedent\";\nimport { togetheraiBaseClient, togetheraiClient } from \"@/lib/ai\";\nimport { ImageGeneration"
  },
  {
    "path": "src/app/api/s3-upload/route.ts",
    "chars": 45,
    "preview": "export { POST } from \"next-s3-upload/route\";\n"
  },
  {
    "path": "src/app/api/summarize/route.ts",
    "chars": 2393,
    "preview": "import { togetheraiBaseClient } from \"@/lib/ai\";\nimport assert from \"assert\";\nimport dedent from \"dedent\";\nimport { z } "
  },
  {
    "path": "src/app/globals.css",
    "chars": 993,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nbody {\n  font-family: Arial, Helvetica, sans-serif;\n}\n\n@laye"
  },
  {
    "path": "src/app/layout.tsx",
    "chars": 2912,
    "preview": "import GithubIcon from \"@/components/icons/github\";\nimport XIcon from \"@/components/icons/x\";\nimport Logo from \"@/compon"
  },
  {
    "path": "src/app/page.tsx",
    "chars": 7367,
    "preview": "\"use client\";\n\nimport { useS3Upload } from \"next-s3-upload\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n "
  },
  {
    "path": "src/app/pdf/[id]/page.tsx",
    "chars": 1320,
    "preview": "import SmartPDFViewer from \"@/app/pdf/[id]/smart-pdf-viewer\";\nimport client from \"@/lib/prisma\";\nimport { notFound } fro"
  },
  {
    "path": "src/app/pdf/[id]/smart-pdf-viewer.tsx",
    "chars": 4528,
    "preview": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Section, SmartPDF } from \"@prisma/client\";\nimpo"
  },
  {
    "path": "src/components/HomeLandingDrop.tsx",
    "chars": 4798,
    "preview": "\"use client\";\n\nimport { SparklesIcon } from \"lucide-react\";\nimport { Button } from \"./ui/button\";\nimport {\n  Select,\n  S"
  },
  {
    "path": "src/components/icons/github.tsx",
    "chars": 1095,
    "preview": "import { ComponentProps } from \"react\";\n\nexport default function GithubIcon(props: ComponentProps<\"svg\">) {\n  return (\n "
  },
  {
    "path": "src/components/icons/sparkles.tsx",
    "chars": 20913,
    "preview": "import { ComponentProps } from \"react\";\n\nexport default function SparklesIcon(props: ComponentProps<\"svg\">) {\n  return ("
  },
  {
    "path": "src/components/icons/x.tsx",
    "chars": 561,
    "preview": "import { ComponentProps } from \"react\";\n\nexport default function XIcon(props: ComponentProps<\"svg\">) {\n  return (\n    <s"
  },
  {
    "path": "src/components/images/homepage-image-1.tsx",
    "chars": 58735,
    "preview": "import { ComponentProps } from \"react\";\n\nexport default function HomepageImage1(props: ComponentProps<\"svg\">) {\n  return"
  },
  {
    "path": "src/components/images/homepage-image-2.tsx",
    "chars": 7799,
    "preview": "import { ComponentProps } from \"react\";\n\nexport default function HomepageImage2(props: ComponentProps<\"svg\">) {\n  return"
  },
  {
    "path": "src/components/ui/action-button.tsx",
    "chars": 751,
    "preview": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport Spinner from \"@/components/ui/spinner\";\nimport { "
  },
  {
    "path": "src/components/ui/button.tsx",
    "chars": 2053,
    "preview": "import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"cla"
  },
  {
    "path": "src/components/ui/logo.tsx",
    "chars": 4714,
    "preview": "export default function Logo(props: React.ComponentProps<\"svg\">) {\n  return (\n    <svg\n      width={165}\n      height={3"
  },
  {
    "path": "src/components/ui/select.tsx",
    "chars": 5632,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SelectPrimitive from \"@radix-ui/react-select\"\nimport { Check, C"
  },
  {
    "path": "src/components/ui/spinner.tsx",
    "chars": 1332,
    "preview": "import { ReactNode } from \"react\";\n\nexport default function Spinner({\n  loading = true,\n  children,\n  className = \"\",\n}:"
  },
  {
    "path": "src/components/ui/summary-content.tsx",
    "chars": 743,
    "preview": "\"use client\";\n\nimport Image from \"next/image\";\n\ninterface SummaryContentProps {\n  title?: string;\n  summary?: string;\n  "
  },
  {
    "path": "src/components/ui/table-of-contents.tsx",
    "chars": 1992,
    "preview": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport Spinner from \"@/components/ui/spinner\";\nimport { "
  },
  {
    "path": "src/components/ui/toast.tsx",
    "chars": 4832,
    "preview": "\"use client\"\n\nimport * as React from \"react\"\nimport * as ToastPrimitives from \"@radix-ui/react-toast\"\nimport { cva, type"
  },
  {
    "path": "src/components/ui/toaster.tsx",
    "chars": 786,
    "preview": "\"use client\"\n\nimport { useToast } from \"@/hooks/use-toast\"\nimport {\n  Toast,\n  ToastClose,\n  ToastDescription,\n  ToastPr"
  },
  {
    "path": "src/hooks/use-toast.ts",
    "chars": 3962,
    "preview": "\"use client\";\n\n// Inspired by react-hot-toast library\nimport * as React from \"react\";\n\nimport type { ToastActionElement,"
  },
  {
    "path": "src/lib/ai.ts",
    "chars": 467,
    "preview": "import { createTogetherAI } from \"@ai-sdk/togetherai\";\nimport Together from \"together-ai\";\n\nexport const togetheraiClien"
  },
  {
    "path": "src/lib/prisma.ts",
    "chars": 296,
    "preview": "import { PrismaClient } from \"@prisma/client\";\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var prisma: Pris"
  },
  {
    "path": "src/lib/s3client.ts",
    "chars": 278,
    "preview": "import { S3Client } from \"@aws-sdk/client-s3\";\n\nexport const awsS3Client = new S3Client({\n  region: process.env.S3_UPLOA"
  },
  {
    "path": "src/lib/summarize.ts",
    "chars": 3610,
    "preview": "import { PDFDocumentProxy } from \"pdfjs-dist\";\nimport assert from \"assert\";\n\nexport type Chunk = {\n  text: string;\n  sum"
  },
  {
    "path": "src/lib/utils.ts",
    "chars": 166,
    "preview": "import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: Cla"
  },
  {
    "path": "tailwind.config.ts",
    "chars": 2093,
    "preview": "import type { Config } from \"tailwindcss\";\nimport tailwindcssAnimate from \"tailwindcss-animate\";\n\nexport default {\n  dar"
  },
  {
    "path": "tsconfig.json",
    "chars": 702,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2017\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n "
  }
]

About this extraction

This page contains the full source code of the Nutlope/smartpdfs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (154.3 KB), approximately 61.2k tokens, and a symbol index with 44 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!