[
  {
    "path": ".env-example",
    "content": "GITHUB_APP_ID=app_id\nGITHUB_APP_PRIVATE_KEY=\"-----Base64 encoded GitHub App private key-----\""
  },
  {
    "path": ".gitignore",
    "content": "# deps\n/node_modules\n\n# generated content\n.contentlayer\n.content-collections\n.source\n\n# test & build\n/coverage\n/.next/\n/out/\n/build\n*.tsbuildinfo\n\n# misc\n.DS_Store\n*.pem\n/.pnp\n.pnp.js\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# others\n.env*.local\n.vercel\nnext-env.d.ts"
  },
  {
    "path": "CITATION.cff",
    "content": "cff-version: 1.2.0\ntitle: AIcademy\nmessage: >-\n  If you use this software, please cite it using the\n  metadata from this file.\ntype: software\nauthors:\n  - given-names: Epsilon\nrepository-code: \"https://github.com/aicademyorg/AIcademy\"\nurl: \"https://theaicademy.org\"\nabstract: A friendly community offering free AI education.\nlicense: MIT\ndate-released: \"2023-03-25\"\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nAIcademy is a friendly place to learn about AI. We’re committed to keeping it that way.\n\nBy using AIcademy, you agree to follow this Code of Conduct.\n\nIn short: **Be kind**. **No harassment**, **trolling**, or **spamming**.\n\n- **Harassment**: We don’t allow behavior that targets or demeans individuals or groups. This includes offensive comments, unwanted attention, doxxing, stalking, slurs, or anything that makes others feel unsafe — regardless of gender, background, identity, ability, or beliefs.\n\n- **Trolling**: Provoking arguments, derailing discussions, or posting deliberately disruptive messages wastes everyone's time. Stay constructive and kind, even when disagreeing.\n\n- **Spamming**: Posting irrelevant links, excessive self-promotion, or repeatedly sharing off-topic content disrupts the learning experience. Keep the space clean and focused.\n\nIf you see someone harassing, trolling, or spamming in any part of the AIcademy community (website, GitHub, discussions, discord etc.), please email us at [`hiaicademy@gmail.com`](mailto:hiaicademy@gmail.com) — ideally with a screenshot or link to the incident.\n\nThe moderator team will take any action we believe necessary to keep AIcademy a safe, respectful space — including content removal or account bans."
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to AIcademy\n\nThank you for your interest in contributing to AIcademy.\n\nWhether you're fixing a typo, improving content, or adding new features, your contributions are appreciated.\n\n## How to Contribute\n\n1. Fork this repository\n2. Create a new branch\n3. Make your changes\n4. Open a pull request with a clear description\n\nPlease keep changes focused and respectful. For questions or suggestions, feel free to open an issue or email us at `hiaicademy@gmail.com`.\n\nBy contributing, you agree to follow our [Code of Conduct](https://github.com/aicademyorg/AIcademy/blob/main/CODE_OF_CONDUCT.md).\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright © 2025 AIcademy\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# AIcademy\n\nAIcademy is a friendly community offering free AI education.\n\n## Installation\n\nEnsure [pnpm](https://pnpm.io) is installed on your system.\n\n```\n# install the dependencies.\npnpm install\n\n# start the development server\npnpm dev\n```\n\nThe server will be running at [http://localhost:3000](http://localhost:3000).\n\n## Contributing\n\nContributions are welcome! Whether you're improving content, fixing bugs, or adding new features, your help makes AIcademy better for everyone.\n\n> [Please follow these steps to contribute](/CONTRIBUTING.md).\n\nRecent Contributions:\n\n![Alt](https://repobeats.axiom.co/api/embed/d4bca36f7e3aef4a00b262ce58cfba3d4d59575d.svg \"Repobeats analytics image\")\n\n## License\n\nCopyright © 2025 AIcademy\n\nAIcademy is open-source and released under the MIT License.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nAt AIcademy, we take platform security seriously. \n\nWhile we don’t collect personal data or require sign-ups, we’re committed to keeping our open-source learning environment safe and trustworthy for everyone.\n\n### Reporting a Vulnerability\n\nIf you discover a security issue in our website or codebase, please report it privately by emailing:\n\n📧 **hiaicademy@gmail.com**\n\nWe appreciate responsible disclosures and will review all reports promptly. Please avoid public disclosure until we’ve had a chance to investigate and address the issue.\n\nThank you for helping keep AIcademy safe.\n"
  },
  {
    "path": "app/[lang]/(home)/layout.tsx",
    "content": "import type { ReactNode } from \"react\";\nimport { HomeLayout } from \"fumadocs-ui/layouts/home\";\nimport { baseOptions, linkItems } from \"@/app/layout.config\";\nimport {\n  NavbarMenu,\n  NavbarMenuContent,\n  NavbarMenuLink,\n  NavbarMenuTrigger,\n} from \"fumadocs-ui/layouts/home/navbar\";\nimport { Footer } from \"@/components/footer\";\nimport Link from \"fumadocs-core/link\";\nimport Image from \"next/image\";\nimport Preview from \"@/public/learn/python/banner.png\";\nimport { Code } from \"lucide-react\";\n\nexport default async function Layout({\n  params,\n  children,\n}: {\n  params: Promise<{ lang: string }>;\n  children: ReactNode;\n}) {\n  const { lang } = await params;\n  return (\n    <HomeLayout\n      {...baseOptions(lang)}\n      links={[\n        {\n          type: \"custom\",\n          on: \"nav\",\n          children: (\n            <NavbarMenu>\n              <NavbarMenuTrigger>\n                <Link href=\"/docs/python\">Learn</Link>\n              </NavbarMenuTrigger>\n              <NavbarMenuContent className=\"text-[15px]\">\n                <NavbarMenuLink href=\"/docs/python\" className=\"md:row-span-2\">\n                  <div className=\"-mx-3 -mt-3\">\n                    <Image\n                      src={Preview}\n                      alt=\"Perview\"\n                      className=\"rounded-t-lg object-cover\"\n                      style={{\n                        maskImage:\n                          \"linear-gradient(to bottom,white 60%,transparent)\",\n                      }}\n                    />\n                  </div>\n                  <p className=\"font-medium\">Python</p>\n                  <p className=\"text-fd-muted-foreground text-sm\">\n                    Learn Python for Data Science\n                  </p>\n                </NavbarMenuLink>\n\n                <NavbarMenuLink href=\"/docs/pytorch\" className=\"lg:col-start-2\">\n                  <Code className=\"bg-fd-primary text-fd-primary-foreground p-1 mb-2 rounded-md\" />\n                  <p className=\"font-medium\">Pytorch</p>\n                  <p className=\"text-fd-muted-foreground text-sm\">\n                    Learn Pytorch\n                  </p>\n                </NavbarMenuLink>\n\n                <NavbarMenuLink\n                  href=\"/docs/deeplearning\"\n                  className=\"lg:col-start-2\"\n                >\n                  <Code className=\"bg-fd-primary text-fd-primary-foreground p-1 mb-2 rounded-md\" />\n                  <p className=\"font-medium\">Deep Learning</p>\n                  <p className=\"text-fd-muted-foreground text-sm\">\n                    Learn Deep Learning\n                  </p>\n                </NavbarMenuLink>\n\n                <NavbarMenuLink\n                  href=\"/docs/ml\"\n                  className=\"lg:col-start-3 lg:row-start-1\"\n                >\n                  <Code className=\"bg-fd-primary text-fd-primary-foreground p-1 mb-2 rounded-md\" />\n                  <p className=\"font-medium\">Machine Learning</p>\n                  <p className=\"text-fd-muted-foreground text-sm\">\n                    Learn machine learning\n                  </p>\n                </NavbarMenuLink>\n              </NavbarMenuContent>\n            </NavbarMenu>\n          ),\n        },\n        {\n          icon: <Code />,\n          text: \"Blog\",\n          url: \"/blog\",\n          active: \"nested-url\",\n        },\n        {\n          icon: <Code />,\n          text: \"About\",\n          url: \"/about\",\n        },\n        ...linkItems,\n      ]}\n      className=\"dark:bg-neutral-950 dark:[--color-fd-background:var(--color-neutral-950)]\"\n    >\n      {children}\n      <Footer />\n    </HomeLayout>\n  );\n}\n"
  },
  {
    "path": "app/[lang]/(home)/page.tsx",
    "content": "import Link from 'next/link';\n\nexport default function HomePage() {\n  return (\n    <main\n      style={{\n        flex: 1,\n        display: 'flex',\n        flexDirection: 'column',\n        textAlign: 'center',\n        justifyContent: 'center',\n      }}\n    >\n      <h1\n        style={{\n          fontSize: '2rem',\n          fontWeight: 'bold',\n          marginBottom: '1rem',\n        }}\n      >\n        Hello World\n      </h1>\n      <p>\n        You can open{' '}\n        <Link\n          href=\"/docs\"\n          style={{\n            fontWeight: '600',\n            textDecoration: 'underline',\n          }}\n        >\n          /docs\n        </Link>{' '}\n        and see the documentation.\n      </p>\n    </main>\n  );\n}\n"
  },
  {
    "path": "app/[lang]/api/search/route.ts",
    "content": "import { source } from '@/lib/source';\nimport { createFromSource } from 'fumadocs-core/search/server';\n\nexport const { GET } = createFromSource(source);\n"
  },
  {
    "path": "app/[lang]/docs/[[...slug]]/page.tsx",
    "content": "import { source } from \"@/lib/source\";\nimport {\n  DocsPage,\n  DocsBody,\n  DocsDescription,\n  DocsTitle,\n  PageLastUpdate,\n} from \"fumadocs-ui/layouts/docs/page\";\nimport { notFound } from \"next/navigation\";\nimport { createRelativeLink } from \"fumadocs-ui/mdx\";\nimport { getMDXComponents } from \"@/mdx-components\";\nimport { getGithubLastEdit } from \"fumadocs-core/content/github\";\nimport { getPageTreePeers } from \"fumadocs-core/page-tree\";\nimport { Feedback } from \"@/components/feedback\";\nimport { onRateAction } from \"@/lib/github\";\nimport { i18n } from \"@/lib/i18n\";\nimport { Card, Cards } from \"fumadocs-ui/components/card\";\nimport { LLMCopyButtonWithDropdown } from \"@/components/ai/page-actions\";\nimport { SquarePen } from \"lucide-react\";\n\nfunction DocsCategory({ url, lang }: { url: string; lang: string }) {\n  return (\n    <Cards>\n      {getPageTreePeers(source.pageTree[lang], url).map((peer) => (\n        <Card key={peer.url} title={peer.name} href={peer.url}>\n          {peer.description}\n        </Card>\n      ))}\n    </Cards>\n  );\n}\n\nexport default async function Page(props: {\n  params: Promise<{ lang: string; slug?: string[] }>;\n}) {\n  const { slug, lang } = await props.params;\n  const page = source.getPage(slug, lang);\n  if (!page) notFound();\n\n  const MDXContent = page.data.body;\n\n  let githubPath: string;\n\n  if (lang === i18n.defaultLanguage) {\n    githubPath = `content/docs/${page.path}`;\n  } else {\n    githubPath = `content/docs/${page.path.replace(/\\.mdx$/, `.${lang}.mdx`)}`;\n  }\n\n  const lastModifiedTime = await getGithubLastEdit({\n    owner: \"aicademyorg\",\n    repo: \"aicademy\",\n    path: githubPath,\n    token: process.env.GITHUB_TOKEN,\n  });\n\n  const githubUrl = `https://github.com/aicademyorg/aicademy/blob/main/${githubPath}`;\n\n  return (\n    <DocsPage\n      toc={page.data.toc}\n      full={page.data.full}\n      tableOfContent={{\n        style: \"clerk\",\n        single: false,\n      }}\n    >\n      <div className=\"flex flex-col sm:flex-row sm:justify-between sm:items-start\">\n        <div className=\"flex-1\">\n          <DocsTitle>{page.data.title}</DocsTitle>\n          <div className=\"mt-4\">\n            <DocsDescription>{page.data.description}</DocsDescription>\n          </div>\n        </div>\n        <div className=\"flex-shrink-0 sm:ml-4 pb-4 sm:pb-0\">\n          <LLMCopyButtonWithDropdown\n            markdownUrl={`${page.url}.mdx`}\n            githubUrl={githubUrl}\n            colab={page.data.colab}\n          />\n        </div>\n      </div>\n      <DocsBody className=\"max-sm:pb-16\">\n        <MDXContent\n          components={getMDXComponents({\n            a: createRelativeLink(source, page),\n            DocsCategory: ({ url }) => {\n              return <DocsCategory url={url ?? page.url} lang={lang} />;\n            },\n          })}\n        />\n        {page.data.index && <DocsCategory url={page.url} lang={lang} />}\n      </DocsBody>\n      <Feedback onRateAction={onRateAction} lang={lang} />\n      <div className=\"flex items-center justify-between\">\n        <a\n          href={githubUrl}\n          rel=\"noreferrer noopener\"\n          target=\"_blank\"\n          className=\"w-fit border rounded-lg py-1.5 px-2 font-medium text-xs text-fd-secondary-foreground bg-fd-secondary transition-colors hover:text-fd-accent-foreground hover:bg-fd-accent inline-flex items-center gap-1.5\"\n        >\n          <SquarePen className=\"size-3.5\" />\n          Edit on GitHub\n        </a>\n        {lastModifiedTime && <PageLastUpdate date={lastModifiedTime} />}\n      </div>\n    </DocsPage>\n  );\n}\n\nexport async function generateStaticParams() {\n  return source.generateParams(\"slug\", \"lang\");\n}\n\nexport async function generateMetadata(props: {\n  params: Promise<{ lang: string; slug?: string[] }>;\n}) {\n  const { slug, lang } = await props.params;\n  const page = source.getPage(slug, lang);\n  if (!page) notFound();\n\n  return {\n    title: page.data.title,\n    description: page.data.description,\n  };\n}\n"
  },
  {
    "path": "app/[lang]/docs/layout.tsx",
    "content": "import { DocsLayout, type DocsLayoutProps } from \"fumadocs-ui/layouts/docs\";\nimport type { ReactNode } from \"react\";\nimport { baseOptions, linkItems } from \"@/app/layout.config\";\nimport { source } from \"@/lib/source\";\n// import { Footer } from \"@/components/footer\";\n\nconst docsOptions: DocsLayoutProps = {\n  ...baseOptions,\n  tree: source.pageTree as any,\n  links: linkItems,\n  sidebar: {\n    tabs: {\n      transform(option, node) {\n        const meta = source.getNodeMeta(node);\n        if (!meta || !node.icon) return option;\n\n        const color = `var(--ui-color)`;\n\n        return {\n          ...option,\n          icon: (\n            <div\n              className=\"[&_svg]:size-11/12 rounded-lg size-full max-md:bg-(--tab-color)/10 max-md:border max-md:p-1.5\"\n              style={\n                {\n                  color,\n                  \"--tab-color\": color,\n                } as object\n              }\n            >\n              {node.icon}\n            </div>\n          ),\n        };\n      },\n    },\n  },\n};\n\nexport default async function Layout({\n  params,\n  children,\n}: {\n  params: Promise<{ lang: string }>;\n  children: ReactNode;\n}) {\n  const { lang } = await params;\n  return (\n    <DocsLayout\n      {...baseOptions(lang)}\n      {...docsOptions}\n      tree={source.pageTree[lang]}\n    >\n      {children}\n      {/* <Footer /> */}\n    </DocsLayout>\n  );\n}\n"
  },
  {
    "path": "app/[lang]/docs/raw/[...slug]/route.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { type NextRequest, NextResponse } from 'next/server';\n\nasync function findFileWithParentheses(\n  basePath: string,\n  segments: string[],\n): Promise<string | null> {\n  if (segments.length === 0) return null;\n\n  const [current, ...rest] = segments;\n  const currentPath = join(basePath, current);\n\n  if (rest.length === 0) {\n    if (existsSync(currentPath)) {\n      return currentPath;\n    }\n  } else if (existsSync(currentPath)) {\n    const found = await findFileWithParentheses(currentPath, rest);\n    if (found) return found;\n  }\n\n  try {\n    const entries = await readdir(basePath, { withFileTypes: true });\n    for (const entry of entries) {\n      if (entry.isDirectory() && entry.name.startsWith('(') && entry.name.endsWith(')')) {\n        const parenthesesPath = join(basePath, entry.name);\n\n        if (rest.length === 0) {\n          const filePath = join(parenthesesPath, current);\n          if (existsSync(filePath)) {\n            return filePath;\n          }\n        } else {\n          const found = await findFileWithParentheses(parenthesesPath, [current, ...rest]);\n          if (found) return found;\n        }\n      }\n    }\n  } catch (error) {\n    console.error(error);\n  }\n\n  return null;\n}\n\nexport async function GET(\n  _request: NextRequest,\n  { params }: { params: Promise<{ slug: string[] }> },\n) {\n  try {\n    const { slug = [] } = await params;\n    const basePath = join(process.cwd(), 'content/docs');\n\n    const directPath = join(basePath, ...slug);\n    if (existsSync(directPath)) {\n      const content = await readFile(directPath, 'utf-8');\n      return new NextResponse(content, {\n        headers: {\n          'Content-Type': 'text/markdown; charset=utf-8',\n        },\n      });\n    }\n\n    const foundPath = await findFileWithParentheses(basePath, slug);\n    if (foundPath) {\n      const content = await readFile(foundPath, 'utf-8');\n      return new NextResponse(content, {\n        headers: {\n          'Content-Type': 'text/markdown; charset=utf-8',\n        },\n      });\n    }\n\n    return new NextResponse('File not found', { status: 404 });\n  } catch (error) {\n    return new NextResponse('File not found', { status: 404 });\n  }\n}\n"
  },
  {
    "path": "app/[lang]/global.css",
    "content": "@import \"tailwindcss\";\n@import \"fumadocs-ui/css/neutral.css\";\n@import \"fumadocs-ui/css/preset.css\";\n\n:root {\n  --purple-color: #2563eb;\n  --ui-color: #2563eb;\n  --color-fd-primary: var(--ui-color);\n}\n\nbody {\n  overscroll-behavior-y: none;\n  background-color: var(--color-fd-background);\n}\n\n.dark {\n  --purple-color: #818cf8;\n  --ui-color: #60a5fa;\n  --color-fd-primary: var(--ui-color);\n}\n"
  },
  {
    "path": "app/[lang]/layout.tsx",
    "content": "import \"./global.css\";\nimport \"katex/dist/katex.css\";\nimport { RootProvider } from 'fumadocs-ui/provider/next';\nimport { defineI18nUI } from \"fumadocs-ui/i18n\";\nimport type { ReactNode } from \"react\";\nimport { Inter, Geist, Geist_Mono } from \"next/font/google\";\nimport { baseUrl, createMetadata } from \"@/lib/metadata\";\nimport { i18n, uiDictionary } from \"@/lib/i18n\";\nimport { Metadata } from \"next\";\n\nconst { provider } = defineI18nUI(i18n, {\n  translations: {\n    en: {\n      displayName: \"English\",\n    },\n    // Add other languages\n    // cn: {\n    //   displayName: 'Chinese',\n    //   search: '搜尋文檔',\n    // },\n  },\n});\n\nexport async function generateMetadata({\n  params,\n}: {\n  params: Promise<{ lang: string }>;\n}): Promise<Metadata> {\n  const lang = (await params).lang;\n  const t =\n    uiDictionary[lang as keyof typeof uiDictionary]?.metadata ||\n    uiDictionary.en.metadata;\n\n  return createMetadata({\n    title: {\n      template: t.titleTemplate,\n      default: t.defaultTitle,\n    },\n    description: t.description,\n    metadataBase: baseUrl,\n  });\n}\n\nconst geist = Geist({\n  variable: \"--font-sans\",\n  subsets: [\"latin\"],\n});\n\nconst mono = Geist_Mono({\n  variable: \"--font-mono\",\n  subsets: [\"latin\"],\n});\n\nexport const inter = Inter({\n  subsets: ['latin'],\n  variable: '--font-inter',\n})\n\nexport default async function RootLayout({\n  params,\n  children,\n}: {\n  params: Promise<{ lang: string }>;\n  children: ReactNode;\n}) {\n  const lang = (await params).lang;\n  return (\n    <html\n      lang={lang}\n      className={`${inter.className} ${mono.variable}`}\n      suppressHydrationWarning\n    >\n      <body\n        className=\"bg-neutral-100 dark:bg-neutral-900\"\n        style={{\n          display: \"flex\",\n          flexDirection: \"column\",\n          minHeight: \"100vh\",\n        }}\n      >\n        <RootProvider i18n={provider(lang)}>{children}</RootProvider>\n      </body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "app/[lang]/llms.mdx/[[...slug]]/route.ts",
    "content": "import { type NextRequest, NextResponse } from \"next/server\";\nimport { getLLMText } from \"@/lib/get-llm-text\";\nimport { source } from \"@/lib/source\";\nimport { notFound } from \"next/navigation\";\n\nexport const revalidate = false;\n\nexport async function GET(\n  _req: NextRequest,\n  { params }: { params: Promise<{ lang: string; slug?: string[] }> }\n) {\n  const { slug, lang } = await params;\n  const page = source.getPage(slug, lang);\n  if (!page) notFound();\n\n  return new NextResponse(await getLLMText(page));\n}\n\nexport function generateStaticParams() {\n  return source.generateParams();\n}\n\n"
  },
  {
    "path": "app/layout.config.tsx",
    "content": "import type { LinkItemType } from \"fumadocs-ui/layouts/shared\";\nimport type { BaseLayoutProps } from \"fumadocs-ui/layouts/shared\";\nimport { i18n, uiDictionary } from \"@/lib/i18n\";\nimport { SiDiscord, SiGithub } from \"react-icons/si\";\n\nexport const linkItems: LinkItemType[] = [\n  {\n    type: \"icon\",\n    icon: <SiGithub />,\n    text: \"Github\",\n    url: \"https://github.com/aicademyorg/AIcademy\",\n  },\n  {\n    type: \"icon\",\n    icon: <SiDiscord />,\n    text: \"Discord\",\n    url: \"https://discord.com/invite/bxnwugmNZg\",\n  },\n];\n\nexport const logo = (\n  <>\n    <svg\n      className=\"dark:hidden w-5 md:w-5 text-[color:var(--ui-color)]\"\n      role=\"img\"\n      aria-label=\"AIcademy Logo\"\n      viewBox=\"0 0 500 500\"\n      fill=\"currentColor\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        fill-rule=\"evenodd\"\n        clip-rule=\"evenodd\"\n        d=\"M228.5 0.981853C153.412 5.91485 79.941 49.8029 39.811 113.693C0.252014 176.676 -8.69499 254.291 15.048 328.504C18.912 340.58 26.616 358.778 32.192 369C34.442 373.125 37.864 379.425 39.796 383C52.807 407.077 79.559 438.119 101.687 454.816C124.459 471.999 152.044 485.119 180.936 492.508C195.886 496.331 206.088 497.862 225.238 499.158C281.901 502.99 339.138 488.09 385.929 457.325C441.019 421.104 479.598 364.441 492.911 300.196C500.335 264.368 499.452 223.317 490.498 187.991C471.541 113.207 418.007 50.6099 346.961 20.1519C310.593 4.55985 271.158 -1.82115 228.5 0.981853ZM231.5 76.6679C177.356 83.3199 133.235 109.92 105.127 152.859C101.757 158.007 99 162.582 99 163.026C99 163.469 104.514 161.057 111.253 157.666C134.392 146.021 153.558 141.155 179.665 140.296C206.546 139.412 227.571 143.077 250.054 152.567C323.985 183.773 364.869 262.271 347.936 340.5C342.801 364.225 333.213 384.653 316.28 407.949C314.841 409.928 317.028 409.084 327.71 403.534C376.693 378.088 409.271 333.885 419.688 278.736C422.427 264.236 422.158 232.102 419.173 217.166C407.241 157.465 366.457 108.691 310.623 87.3509C290.861 79.7969 269.155 75.9519 247.5 76.1689C240.35 76.2409 233.15 76.4659 231.5 76.6679ZM168 217.373C149.565 221.641 135.627 229.236 122.932 241.932C93.858 271.005 88.206 315.596 109.087 351.171C121.665 372.601 137.318 386.073 156.445 391.929C176.253 397.994 202.672 396.021 222.676 386.983C271.44 364.951 290.377 305.477 263.206 259.694C251.597 240.133 230.633 224.188 209 218.466C200.559 216.233 175.778 215.573 168 217.373Z\"\n      />\n    </svg>\n    <svg\n      className=\"hidden dark:flex w-5 md:w-5 text-[color:var(--ui-color)]\"\n      role=\"img\"\n      aria-label=\"AIcademy Logo\"\n      viewBox=\"0 0 500 500\"\n      fill=\"currentColor\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        fill-rule=\"evenodd\"\n        clip-rule=\"evenodd\"\n        d=\"M228.5 0.981853C153.412 5.91485 79.941 49.8029 39.811 113.693C0.252014 176.676 -8.69499 254.291 15.048 328.504C18.912 340.58 26.616 358.778 32.192 369C34.442 373.125 37.864 379.425 39.796 383C52.807 407.077 79.559 438.119 101.687 454.816C124.459 471.999 152.044 485.119 180.936 492.508C195.886 496.331 206.088 497.862 225.238 499.158C281.901 502.99 339.138 488.09 385.929 457.325C441.019 421.104 479.598 364.441 492.911 300.196C500.335 264.368 499.452 223.317 490.498 187.991C471.541 113.207 418.007 50.6099 346.961 20.1519C310.593 4.55985 271.158 -1.82115 228.5 0.981853ZM231.5 76.6679C177.356 83.3199 133.235 109.92 105.127 152.859C101.757 158.007 99 162.582 99 163.026C99 163.469 104.514 161.057 111.253 157.666C134.392 146.021 153.558 141.155 179.665 140.296C206.546 139.412 227.571 143.077 250.054 152.567C323.985 183.773 364.869 262.271 347.936 340.5C342.801 364.225 333.213 384.653 316.28 407.949C314.841 409.928 317.028 409.084 327.71 403.534C376.693 378.088 409.271 333.885 419.688 278.736C422.427 264.236 422.158 232.102 419.173 217.166C407.241 157.465 366.457 108.691 310.623 87.3509C290.861 79.7969 269.155 75.9519 247.5 76.1689C240.35 76.2409 233.15 76.4659 231.5 76.6679ZM168 217.373C149.565 221.641 135.627 229.236 122.932 241.932C93.858 271.005 88.206 315.596 109.087 351.171C121.665 372.601 137.318 386.073 156.445 391.929C176.253 397.994 202.672 396.021 222.676 386.983C271.44 364.951 290.377 305.477 263.206 259.694C251.597 240.133 230.633 224.188 209 218.466C200.559 216.233 175.778 215.573 168 217.373Z\"\n      />\n    </svg>\n  </>\n);\n\nexport function baseOptions(locale: string): BaseLayoutProps {\n  const navLinks =\n    uiDictionary[locale as keyof typeof uiDictionary]?.nav?.navigation ||\n    uiDictionary.en.nav.navigation;\n  return {\n    i18n,\n    nav: {\n      title: (\n        <>\n          {logo}\n          <span className=\"text-[15px] font-medium\">\n            <span>AIcademy</span>\n          </span>\n        </>\n      ),\n      url: locale === i18n.defaultLanguage ? \"/\" : `/${locale}`,\n      transparentMode: \"top\",\n    },\n    links: [\n      ...navLinks.map((link) => ({\n        text: link.name,\n        url: link.href,\n      })),\n    ],\n  };\n}\n"
  },
  {
    "path": "app/llms-full.txt/route.ts",
    "content": "import { source } from \"@/lib/source\";\nimport { getLLMText } from \"@/lib/get-llm-text\";\n\n// cached forever\nexport const revalidate = false;\n\nexport async function GET() {\n  const scan = source.getPages().map(getLLMText);\n  const scanned = await Promise.all(scan);\n\n  return new Response(scanned.join(\"\\n\\n\"));\n}\n\n"
  },
  {
    "path": "components/ai/page-actions.tsx",
    "content": "\"use client\";\nimport { useMemo, useState } from \"react\";\nimport { Check, ChevronDown, Copy, ExternalLinkIcon } from \"lucide-react\";\nimport { usePathname } from \"next/navigation\";\nimport { cn } from \"../../lib/cn\";\nimport { useCopyButton } from \"fumadocs-ui/utils/use-copy-button\";\nimport { buttonVariants } from \"fumadocs-ui/components/ui/button\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"fumadocs-ui/components/ui/popover\";\nimport { cva } from \"class-variance-authority\";\n\nconst cache = new Map<string, string>();\n\nexport function LLMCopyButton({ markdownUrl }: { markdownUrl: string }) {\n  const [isLoading, setLoading] = useState(false);\n  const [checked, onClick] = useCopyButton(async () => {\n    const cached = cache.get(markdownUrl);\n    if (cached) return navigator.clipboard.writeText(cached);\n\n    setLoading(true);\n\n    try {\n      await navigator.clipboard.write([\n        new ClipboardItem({\n          \"text/plain\": fetch(markdownUrl).then(async (res) => {\n            const content = await res.text();\n            cache.set(markdownUrl, content);\n\n            return content;\n          }),\n        }),\n      ]);\n    } finally {\n      setLoading(false);\n    }\n  });\n\n  return (\n    <button\n      disabled={isLoading}\n      className={cn(\n        buttonVariants({\n          color: \"secondary\",\n          size: \"sm\",\n          className: \"gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground\",\n        })\n      )}\n      onClick={onClick}\n    >\n      {checked ? <Check /> : <Copy />}\n      Copy Markdown\n    </button>\n  );\n}\n\nexport function LLMCopyButtonWithDropdown({\n  markdownUrl,\n  githubUrl,\n  colab,\n}: {\n  markdownUrl: string;\n  githubUrl: string;\n  colab?: string;\n}) {\n  const [isLoading, setLoading] = useState(false);\n  const [isOpen, setIsOpen] = useState(false);\n  const pathname = usePathname();\n  const [checked, onClick] = useCopyButton(async () => {\n    const cached = cache.get(markdownUrl);\n    if (cached) return navigator.clipboard.writeText(cached);\n\n    setLoading(true);\n\n    try {\n      await navigator.clipboard.write([\n        new ClipboardItem({\n          \"text/plain\": fetch(markdownUrl).then(async (res) => {\n            const content = await res.text();\n            cache.set(markdownUrl, content);\n\n            return content;\n          }),\n        }),\n      ]);\n    } finally {\n      setLoading(false);\n    }\n  });\n\n  const handleViewMarkdown = () => {\n    if (!pathname) return;\n\n    // Open the current path with .md extension in a new window\n    window.open(`${pathname}.md`, \"_blank\");\n  };\n\n  const items = useMemo(() => {\n    const fullMarkdownUrl =\n      typeof window !== \"undefined\"\n        ? new URL(markdownUrl, window.location.origin)\n        : \"loading\";\n    const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;\n\n    const items = [\n      {\n        title: \"View as Markdown\",\n        onClick: handleViewMarkdown,\n        icon: (\n          <svg strokeLinejoin=\"round\" viewBox=\"0 0 22 16\">\n            <path\n              fillRule=\"evenodd\"\n              clipRule=\"evenodd\"\n              d=\"M19.5 2.25H2.5C1.80964 2.25 1.25 2.80964 1.25 3.5V12.5C1.25 13.1904 1.80964 13.75 2.5 13.75H19.5C20.1904 13.75 20.75 13.1904 20.75 12.5V3.5C20.75 2.80964 20.1904 2.25 19.5 2.25ZM2.5 1C1.11929 1 0 2.11929 0 3.5V12.5C0 13.8807 1.11929 15 2.5 15H19.5C20.8807 15 22 13.8807 22 12.5V3.5C22 2.11929 20.8807 1 19.5 1H2.5ZM3 4.5H4H4.25H4.6899L4.98715 4.82428L7 7.02011L9.01285 4.82428L9.3101 4.5H9.75H10H11V5.5V11.5H9V7.79807L7.73715 9.17572L7 9.97989L6.26285 9.17572L5 7.79807V11.5H3V5.5V4.5ZM15 8V4.5H17V8H19.5L17 10.5L16 11.5L15 10.5L12.5 8H15Z\"\n              fill=\"currentColor\"\n            />\n          </svg>\n        ),\n      },\n      ...(colab\n        ? [\n            {\n              title: \"Open in Colab\",\n              href: colab,\n              icon: (\n                <svg fill=\"currentColor\" role=\"img\" viewBox=\"0 0 24 24\">\n                  <title>Google Colab</title>\n                  <path d=\"M16.9414 4.9757a7.033 7.033 0 0 0-4.9308 2.0646 7.033 7.033 0 0 0-.1232 9.8068l2.395-2.395a3.6455 3.6455 0 0 1 5.1497-5.1478l2.397-2.3989a7.033 7.033 0 0 0-4.8877-1.9297zM7.07 4.9855a7.033 7.033 0 0 0-4.8878 1.9316l2.3911 2.3911a3.6434 3.6434 0 0 1 5.0227.1271l1.7341-2.9737-.0997-.0802A7.033 7.033 0 0 0 7.07 4.9855zm15.0093 2.1721l-2.3892 2.3911a3.6455 3.6455 0 0 1-5.1497 5.1497l-2.4067 2.4068a7.0362 7.0362 0 0 0 9.9456-9.9476zM1.932 7.1674a7.033 7.033 0 0 0-.002 9.6816l2.397-2.397a3.6434 3.6434 0 0 1-.004-4.8916zm7.664 7.4235c-1.38 1.3816-3.5863 1.411-5.0168.1134l-2.397 2.395c2.4693 2.3328 6.263 2.5753 9.0072.5455l.1368-.1115z\" />\n                </svg>\n              ),\n            },\n          ]\n        : []),\n\n      {\n        title: \"Open in ChatGPT\",\n        href: `https://chatgpt.com/?${new URLSearchParams({\n          hints: \"search\",\n          q,\n        })}`,\n        icon: (\n          <svg\n            role=\"img\"\n            viewBox=\"0 0 24 24\"\n            fill=\"currentColor\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <title>OpenAI</title>\n            <path d=\"M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z\" />\n          </svg>\n        ),\n      },\n      {\n        title: \"Open in Claude\",\n        href: `https://claude.ai/new?${new URLSearchParams({\n          q,\n        })}`,\n        icon: (\n          <svg\n            fill=\"currentColor\"\n            role=\"img\"\n            viewBox=\"0 0 24 24\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <title>Anthropic</title>\n            <path d=\"m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z\" />\n          </svg>\n        ),\n      },\n    ];\n\n    return items;\n  }, [githubUrl, markdownUrl, colab]);\n\n  return (\n    <div className=\"flex\">\n      <button\n        disabled={isLoading}\n        onClick={onClick}\n        className={cn(\n          buttonVariants({\n            color: \"secondary\",\n            size: \"sm\",\n            className:\n              \"gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground rounded-r-none border-r-0 cursor-pointer\",\n          })\n        )}\n      >\n        {checked ? <Check /> : <Copy />}\n        Copy page\n      </button>\n      <Popover open={isOpen} onOpenChange={setIsOpen}>\n        <PopoverTrigger\n          className={cn(\n            buttonVariants({\n              color: \"secondary\",\n              size: \"sm\",\n              className:\n                \"gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground rounded-l-none border-l cursor-pointer\",\n            })\n          )}\n        >\n          <ChevronDown\n            className={cn(\n              \"size-3.5 text-fd-muted-foreground transition-transform duration-200\",\n              isOpen && \"rotate-180\"\n            )}\n          />\n        </PopoverTrigger>\n        <PopoverContent\n          className=\"flex flex-col overflow-auto w-auto min-w-44\"\n          align=\"end\"\n        >\n          {items.map((item, index) => {\n            if (item.onClick) {\n              return (\n                <button\n                  key={index}\n                  onClick={item.onClick}\n                  className={cn(\n                    optionVariants(),\n                    \"w-full text-left justify-start\"\n                  )}\n                >\n                  {item.icon}\n                  <span className=\"font-normal mr-4\">{item.title}</span>\n                  <ExternalLinkIcon className=\"text-fd-muted-foreground size-3.5 ms-auto\" />\n                </button>\n              );\n            }\n            return (\n              <a\n                key={index}\n                href={item.href}\n                rel=\"noreferrer noopener\"\n                target=\"_blank\"\n                className={cn(\n                  optionVariants(),\n                  \"w-full text-left justify-start\"\n                )}\n              >\n                {item.icon}\n                <span className=\"font-normal mr-4\">{item.title}</span>\n                <ExternalLinkIcon className=\"text-fd-muted-foreground size-3.5 ms-auto\" />\n              </a>\n            );\n          })}\n        </PopoverContent>\n      </Popover>\n    </div>\n  );\n}\n\nconst optionVariants = cva(\n  \"text-sm p-2 rounded-lg inline-flex items-center gap-2 hover:text-fd-accent-foreground hover:bg-fd-accent [&_svg]:size-4 cursor-pointer\"\n);\n"
  },
  {
    "path": "components/banner.tsx",
    "content": "import { Banner } from \"fumadocs-ui/components/banner\";\nimport Link from \"next/link\";\n\nexport function SiteBanner() {\n  return (\n    <Banner id=\"close\">\n      <Link\n        href=\"https://github.com/aicademyorg/AIcademy\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        className=\"flex items-center\"\n      >\n        Give AIcademy a star on GitHub!\n      </Link>\n    </Banner>\n  );\n}\n"
  },
  {
    "path": "components/feedback.tsx",
    "content": "\"use client\";\nimport { cn } from \"@/lib/cn\";\nimport { buttonVariants } from \"fumadocs-ui/components/ui/button\";\nimport { ThumbsDown, ThumbsUp } from \"lucide-react\";\nimport { type SyntheticEvent, useEffect, useState, useTransition } from \"react\";\nimport {\n  Collapsible,\n  CollapsibleContent,\n} from \"fumadocs-ui/components/ui/collapsible\";\nimport { cva } from \"class-variance-authority\";\nimport { usePathname } from \"next/navigation\";\nimport { uiDictionary } from \"@/lib/i18n\";\n\nconst rateButtonVariants = cva(\n  \"inline-flex cursor-pointer items-center gap-2 px-3 py-2 rounded-full font-medium border text-sm [&_svg]:size-4 disabled:cursor-not-allowed\",\n  {\n    variants: {\n      active: {\n        true: \"bg-fd-accent text-fd-accent-foreground [&_svg]:fill-current\",\n        false: \"text-fd-muted-foreground\",\n      },\n    },\n  }\n);\n\nexport interface Feedback {\n  opinion: \"good\" | \"bad\";\n  url?: string;\n  message: string;\n}\n\nexport interface ActionResponse {\n  githubUrl: string;\n}\n\ninterface Result extends Feedback {\n  response?: ActionResponse;\n}\n\nexport function Feedback({\n  onRateAction,\n  lang = \"en\",\n}: {\n  onRateAction: (url: string, feedback: Feedback) => Promise<ActionResponse>;\n  lang?: string;\n}) {\n  const url = usePathname();\n  const [previous, setPrevious] = useState<Result | null>(null);\n  const [opinion, setOpinion] = useState<\"good\" | \"bad\" | null>(null);\n  const [message, setMessage] = useState(\"\");\n  const [isPending, startTransition] = useTransition();\n  const t =\n    uiDictionary[lang as keyof typeof uiDictionary]?.feedback ||\n    uiDictionary.en.feedback;\n\n  useEffect(() => {\n    const item = localStorage.getItem(`docs-feedback-${url}`);\n    if (item === null) return;\n    setPrevious(JSON.parse(item) as Result);\n  }, [url]);\n\n  useEffect(() => {\n    const key = `docs-feedback-${url}`;\n    if (previous) localStorage.setItem(key, JSON.stringify(previous));\n    else localStorage.removeItem(key);\n  }, [previous, url]);\n\n  function submit(e?: SyntheticEvent) {\n    if (opinion == null) return;\n\n    startTransition(async () => {\n      const feedback: Feedback = {\n        opinion,\n        message,\n      };\n\n      void onRateAction(url, feedback).then((response) => {\n        setPrevious({\n          response,\n          ...feedback,\n        });\n        setMessage(\"\");\n        setOpinion(null);\n      });\n    });\n\n    e?.preventDefault();\n  }\n\n  const activeOpinion = previous?.opinion ?? opinion;\n\n  return (\n    <Collapsible\n      open={opinion !== null || previous !== null}\n      onOpenChange={(v) => {\n        if (!v) setOpinion(null);\n      }}\n      className=\"border-y py-3\"\n    >\n      <div className=\"flex flex-row items-center gap-2\">\n        <p className=\"text-sm font-medium pe-2\">{t.wasHelpful}</p>\n\n        <button\n          disabled={previous !== null}\n          className={cn(\n            rateButtonVariants({\n              active: activeOpinion === \"good\",\n            })\n          )}\n          onClick={() => setOpinion(\"good\")}\n        >\n          <ThumbsUp />\n          {t.good}\n        </button>\n\n        <button\n          disabled={previous !== null}\n          className={cn(\n            rateButtonVariants({\n              active: activeOpinion === \"bad\",\n            })\n          )}\n          onClick={() => setOpinion(\"bad\")}\n        >\n          <ThumbsDown />\n          {t.bad}\n        </button>\n      </div>\n\n      <CollapsibleContent className=\"mt-3\">\n        {previous ? (\n          <div className=\"px-3 py-6 flex flex-col items-center gap-3 bg-fd-card text-fd-card-foreground text-sm text-center rounded-xl text-fd-muted-foreground\">\n            <p>{t.thankYou}</p>\n\n            <div className=\"flex flex-row items-center gap-2\">\n              <a\n                href={previous.response?.githubUrl}\n                rel=\"noreferrer noopener\"\n                target=\"_blank\"\n                className={cn(\n                  buttonVariants({ color: \"primary\" }),\n                  \"text-xs cursor-pointer\"\n                )}\n              >\n                {t.viewOnGitHub}\n              </a>\n\n              <button\n                className={cn(\n                  buttonVariants({ color: \"secondary\" }),\n                  \"text-xs cursor-pointer\"\n                )}\n                onClick={() => {\n                  setOpinion(previous.opinion);\n                  setPrevious(null);\n                }}\n              >\n                {t.submitAgain}\n              </button>\n            </div>\n          </div>\n        ) : (\n          <form className=\"flex flex-col gap-3\" onSubmit={submit}>\n            <textarea\n              autoFocus\n              required\n              value={message}\n              onChange={(e) => setMessage(e.target.value)}\n              className=\"border rounded-lg bg-fd-secondary text-fd-secondary-foreground p-3 resize-none focus-visible:outline-none placeholder:text-fd-muted-foreground\"\n              placeholder={t.placeholder}\n              onKeyDown={(e) => {\n                if (!e.shiftKey && e.key === \"Enter\") {\n                  submit(e);\n                }\n              }}\n            />\n\n            <button\n              type=\"submit\"\n              disabled={isPending}\n              className={cn(\n                buttonVariants({ color: \"outline\" }),\n                \"w-fit px-3 cursor-pointer disabled:cursor-not-allowed\"\n              )}\n            >\n              {t.submit}\n            </button>\n          </form>\n        )}\n      </CollapsibleContent>\n    </Collapsible>\n  );\n}\n"
  },
  {
    "path": "components/footer.tsx",
    "content": "import Image from \"next/image\";\nimport {\n  SiDiscord,\n  SiGithub,\n  SiX,\n  SiYoutube,\n  SiInstagram,\n  SiLinkedin,\n  // SiDiscourse,\n} from \"react-icons/si\";\nimport DarkLogo from \"@/public/logo-dark.png\";\nimport LightLogo from \"@/public/logo-light.png\";\n\nconst YEAR = new Date().getFullYear();\n\nexport const Footer = (): React.ReactElement => {\n  const socialLinks = [\n    { href: \"https://twitter.com/aicademyorg\", icon: SiX, label: \"Twitter\" },\n    {\n      href: \"https://www.youtube.com/@aicademyorg\",\n      icon: SiYoutube,\n      label: \"YouTube\",\n    },\n    { href: \"https://github.com/aicademyorg\", icon: SiGithub, label: \"GitHub\" },\n    {\n      href: \"https://discord.com/invite/bxnwugmNZg\",\n      icon: SiDiscord,\n      label: \"Discord\",\n    },\n    {\n      href: \"https://www.instagram.com/aicademyorg\",\n      icon: SiInstagram,\n      label: \"Instagram\",\n    },\n    {\n      href: \"https://www.linkedin.com/company/aicademyorg\",\n      icon: SiLinkedin,\n      label: \"LinkedIn\",\n    },\n    // { href: \"#\", icon: SiDiscourse, label: \"Discourse\" },\n  ];\n\n  return (\n    <footer className=\"mt-auto border-t bg-fd-card py-16 text-fd-secondary-foreground\">\n      <div className=\"flex flex-col items-center gap-5 sm:flex-row sm:items-center sm:justify-between md:px-13\">\n        <div className=\"flex items-center gap-2\">\n          <Image\n            src={LightLogo}\n            className=\"dark:hidden w-5 md:w-5\"\n            alt=\"AIcademy Logo\"\n          />\n          <Image\n            src={DarkLogo}\n            className=\"hidden dark:flex w-5 md:w-5\"\n            alt=\"AIcademy Logo\"\n          />\n          <p className=\"text-[15px] font-medium\">\n            AIcademy{\" \"}\n            <span className=\"text-[13px] font-normal text-[#757575] dark:text-[#989898] pl-[3px]\">\n              &copy; {YEAR}\n            </span>\n          </p>\n        </div>\n        <div className=\"flex items-center gap-4.5\">\n          {socialLinks.map(({ href, icon: Icon, label }) => (\n            <a\n              key={label}\n              href={href}\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              aria-label={label}\n              className=\"text-[#757575] dark:text-[#989898] hover:text-gray-900 dark:hover:text-white transition-colors\"\n            >\n              <Icon className=\"size-4.25\" />\n            </a>\n          ))}\n        </div>\n      </div>\n    </footer>\n  );\n};\n"
  },
  {
    "path": "components/mdx/mermaid.tsx",
    "content": "'use client';\n\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { useTheme } from 'next-themes';\n\nexport function Mermaid({ chart }: { chart: string }) {\n  const id = useId();\n  const [svg, setSvg] = useState('');\n  const containerRef = useRef<HTMLDivElement>(null);\n  const currentChartRef = useRef<string>(null);\n  const { resolvedTheme } = useTheme();\n\n  useEffect(() => {\n    const container = containerRef.current;\n    if (currentChartRef.current === chart || !container) return;\n    currentChartRef.current = chart;\n\n    async function renderChart() {\n      const { default: mermaid } = await import('mermaid');\n\n      try {\n        mermaid.initialize({\n          startOnLoad: false,\n          securityLevel: 'loose',\n          fontFamily: 'inherit',\n          themeCSS: 'margin: 1.5rem auto 0;',\n          theme: resolvedTheme === 'dark' ? 'dark' : 'default',\n        });\n        const { svg, bindFunctions } = await mermaid.render(\n          id,\n          chart.replaceAll('\\\\n', '\\n'),\n        );\n\n        bindFunctions?.(container!);\n        setSvg(svg);\n      } catch (error) {\n        console.error('Error while rendering mermaid', error);\n      }\n    }\n\n    void renderChart();\n  }, [chart, id, resolvedTheme]);\n\n  return <div ref={containerRef} dangerouslySetInnerHTML={{ __html: svg }} />;\n}"
  },
  {
    "path": "content/docs/math/index.mdx",
    "content": "---\ntitle: Mathematics\ndescription: Mathematics for Machine Learning\nicon: Code \n---\n\n"
  },
  {
    "path": "content/docs/math/meta.json",
    "content": "{\n  \"title\": \"Mathematics\",\n  \"description\": \"Maths for Machine Learning\",\n  \"root\": true,\n  \"icon\": \"Sigma\"\n}\n"
  },
  {
    "path": "content/docs/meta.json",
    "content": "{\n  \"pages\": [\"python\", \"math\"],\n  \"description\": \"Welcome to the AIcademy documentation!\"\n}\n"
  },
  {
    "path": "content/docs/python/index.mdx",
    "content": "---\ntitle: Welcome\ndescription: Learn Python for Data Science\nicon: Album\n---\n\nimport { Accordion, Accordions } from \"fumadocs-ui/components/accordion\";\nimport { SiNumpy, SiPandas, SiPython, SiScikitlearn } from \"react-icons/si\";\n\nWelcome to the **Python for Data Science** course!\nThis course will teach you Python and key libraries for data science, from basics to advanced.\n\nThis is a hands-on course where you'll learn by solving Python problems. At the end of each module, you'll find exercises to help reinforce and apply what you've learned.\n\n## What you'll learn\n\nYou’ll begin with Python basics and then learn key libraries for data science.\n\n<Cards>\n\n<Card icon={<SiPython className=\"text-purple-300\" />} title='Python' href=\"/docs/python/python\">\n\nA powerful and versatile programming language widely used in machine learning.\n\n</Card>\n\n<Card icon={<SiNumpy className=\"text-blue-300\" />} title='NumPy' href=\"/docs/python/numpy\">\n\nA library for fast numerical computations and working with arrays.\n\n</Card>\n\n<Card icon={<SiPandas />} title='Pandas'  href=\"/docs/python/pandas\">\n\nA tool for data manipulation and analysis using DataFrames.\n\n</Card>\n\n<Card icon={<SiPandas />} title='Matplotlib'  href=\"/docs/python/matplotlib\">\n\nA library for creating static, interactive, and animated visualizations.\n\n</Card>\n\n<Card icon={<SiScikitlearn />} title='Scikit Learn'  href=\"/docs/python/scikit-learn\">\n\nA library for building and evaluating machine learning models.\n\n</Card>\n\n</Cards>\n\nBy the end, you’ll have a solid foundation to explore, analyze, and work with data.\n\n## Getting Help\n\nIf you need help or have questions, feel free to ask on our [Discord](https://discord.com/invite/bxnwugmNZg) server. \n\n## FAQ\n\nSome answers to frequently asked questions.\n\n<Accordions>\n  <Accordion title=\"Who is this course for?\">\n    This course is for anyone curious about AI and programming with Python, from\n    complete beginners to professionals seeking to boost productivity.\n  </Accordion>\n  <Accordion title=\"Do I need prior coding experience?\">\n    No prior coding experience is required. This course is designed to be\n    accessible to complete beginners while also providing valuable insights for\n    those with some coding background.\n  </Accordion>\n  <Accordion title=\"Do I need to take the courses in a specific order?\">\n    We recommend taking the courses in the prescribed order for a logical and\n    consistent learning experience.\n  </Accordion>\n  <Accordion title=\"What kind of support will I have during the course?\">\n    You will have access to a community of learners and professionals, as well\n    as continuous guidance and feedback from your AI companions.\n  </Accordion>\n</Accordions>\n\n## Let’s go\n\nLet's get started by [setting up](/docs/python/setup) your Python environment.\n"
  },
  {
    "path": "content/docs/python/matplotlib/index.mdx",
    "content": "---\ntitle: Matplotlib\ndescription: Getting started with Python\nicon: Terminal\nindex: true\n---\n\n## Matplotlib"
  },
  {
    "path": "content/docs/python/meta.json",
    "content": "{\n  \"title\": \"Python\",\n  \"description\": \"Python for Data Science\",\n  \"icon\": \"SiPython\",\n  \"root\": true,\n  \"pages\": [\n    \"---Introduction---\",\n    \"index\",\n    \"setup\",\n    \"---Modules---\",\n    \"python\",\n    \"numpy\",\n    \"pandas\",\n    \"matplotlib\",\n    \"---Optional---\",\n    \"scikit-learn\"\n  ]\n}\n"
  },
  {
    "path": "content/docs/python/numpy/index.mdx",
    "content": "---\ntitle: NumPy\ndescription: Getting started with Python\nicon: SiNumpy\nindex: true\n---\n\n## NumPy"
  },
  {
    "path": "content/docs/python/pandas/index.mdx",
    "content": "---\ntitle: Pandas\ndescription: Getting started with Python\nicon: SiPandas\nindex: true\n---\n\n## Pandas"
  },
  {
    "path": "content/docs/python/python/control-flow.mdx",
    "content": "---\ntitle: Control Flow\ndescription: Direct the logic of your program with conditions and loops.\n---\n\n5.1 Conditional Statements\n\n- if, else, elif\n\nNested if\n\n- 5.2 Loops\n- for and while Loops\n- range() and enumerate()\n- Loop Control: break, continue\n- Nested Loops"
  },
  {
    "path": "content/docs/python/python/data-structures.mdx",
    "content": "---\ntitle: Data Structures\ndescription: Store and organize data with Python's built-in collections.\n---\n\n6.1 Lists\n\n- Creation, Indexing, Slicing\n- List Methods\n\n6.2 Tuples\n\n6.3 Sets\n\n6.4 Dictionaries\n\n- Creating and Accessing Elements\n- Dictionary Methods\n\n"
  },
  {
    "path": "content/docs/python/python/data-types.mdx",
    "content": "---\ntitle: Data Types\ndescription: Work with and manipulate different types of data.\n---\n\nIn Python, data types classify the types of values a variable can hold. Every value in Python has a data type. Python is a dynamically typed language, so you don’t need to explicitly declare the type of a variable.\n\nSince everything in Python is an object, data types are actually classes, and the variables are instances (objects) of these classes.\n\n<Mermaid\n  chart={`\n    graph TD\n    A[Python Data Types] --> B[Numeric]\n    A --> C[Dictionary]\n    A --> D[Boolean]\n    A --> E[Set]\n    A --> F[Sequence Type]\n\n    B --> B1[Integer]\n    B --> B2[Float]\n    B --> B3[Complex Number]\n\n    F --> F1[Strings]\n    F --> F2[List]\n    F --> F3[Tuple]\n\n`}\n/>\n\n## Numeric\n\nThe numeric data type in Python represents the data that has a numeric value.\n\n### Integer (`int`)\n\nWhole numbers, positive or negative, without decimal points.\n\n```py\nx = 10\nprint(type(x))  # <class 'int'>\n```\n\nPython integers can be arbitrarily large (limited by memory).\n\n### Float (`float`)\n\nReal numbers with decimal points. Also supports scientific notation.\n\n```py\nx = 10.5\ny = 1.5e2\nprint(type(x), type(y))  # <class 'float'> <class 'float'>\n```\n\n### Complex (`complex`)\n\nUsed to represent complex numbers (real + imaginary). Suffix `j` is used for the imaginary part\n\n```py\nx = 2 + 3j\nprint(type(x))  # <class 'complex'>\n```\n\n## Sequence Type\n\nThe sequence Data Type in Python is the ordered collection of similar or different Python data types. \n\n### String (`str`)\n\nA string is a collection of one or more characters put in a single quote, double-quote or triple quote. In python there is no character data type, a character is a string of length one. \n\nExample:\n\n```py\n# String with single quotes\nprint('Welcome to the Geeks World')\n\n# String with double quotes\nprint(\"I'm a Geek\")\n\n# String with triple quotes\nprint('''I'm a Geek and I live in a world of \"Geeks\"''')\n```\n\nOutput:\n\n```sh\nWelcome to the Geeks World\nI'm a Geek\nI'm a Geek and I live in a world of \"Geeks\"\n```\n\n#### Accessing elements of string:\n\n| Character          | A   | I   | c   | a   | d   | e   | m   | y   |\n| ------------------ | --- | --- | --- | --- | --- | --- | --- | --- |\n| **Positive Index** | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   |\n| **Negative Index** | -8  | -7  | -6  | -5  | -4  | -3  | -2  | -1  |\n\n```py\nString1 = \"AIcademy\"\n\n# Printing First character\nprint(String1[0])\n\n# Printing Last character\nprint(String1[-1])\n```\n\noutput:\n\n```sh\nA\ny\n```\n\n#### Deleting/Updating from a String:\n\nIn Python, Updation or deletion of characters from a String is not allowed because Strings are immutable. Only new strings can be reassigned to the same name.\n\n### List\n\nLists are just like arrays, declared in other languages which is an ordered collection of data. It is very flexible as the items in a list do not need to be of the same type.\n\nLists in Python can be created by just placing the sequence inside the square brackets[].\n\n```py\n# Empty list\na = []\n\n# list with int values\na = [1, 2, 3]\nprint(a)\n\n# list with mixed int and string\nb = [\"Geeks\", \"For\", \"Geeks\", 4, 5]\nprint(b)\n```\n\noutput:\n\n```sh\n[1, 2, 3]\n['Geeks', 'For', 'Geeks', 4, 5]\n```\n\n#### Access List Items\n\nUse the index operator [ ] to access an item in a list. In Python, negative sequence indexes represent positions from the end of the array. Instead of having to compute the offset as in List[len(List)-3], it is enough to just write List[-3].\n\n```py\nList = [1, 2, 3, 4, 5, 6]\n\n# accessing a element\nprint(List[0])\nprint(List[2])\n\n# Negative indexing\n# print the last element of list\nprint(List[-1])\n# print the third last element of list\nprint(List[-3])\n```\n\noutput:\n\n```sh\n1\n3\n6\n4\n```\n\nAdding Elements to a List: Using append(), insert() and extend()\n\n```py\n# Creating a List\nList = []\n\n# Using append()\nList.append(1)\nList.append(2)\nprint(List)\n\n# Using insert()\nList.insert(3, 12)\nList.insert(0, 'Geeks')\nprint(List)\n\n# Using extend()\nList.extend([8, 'Geeks', 'Always'])\nprint(List)\n```\n\noutuput:\n\n```sh\n[1, 2]\n['Geeks', 1, 2, 12]\n['Geeks', 1, 2, 12, 8, 'Geeks', 'Always']\n```\n\nRemoving Elements from the List: Using remove() and pop()\n\n```py\n# Creating a List\nList = [1, 2, 3, 4, 5, 6,\n        7, 8, 9, 10, 11, 12]\n\n# using Remove() method\nList.remove(5)\nList.remove(6)\nprint(List)\n\n# using pop()\nList.pop()\nprint(List)\n```\n\noutput:\n\n```sh\n[1, 2, 3, 4, 7, 8, 9, 10, 11, 12]\n[1, 2, 3, 4, 7, 8, 9, 10, 11]\n```\n\n### Tuple\n\nJust like a list, a tuple is also an ordered collection of Python objects. The only difference between a tuple and a list is that tuples are immutable. Tuples cannot be modified after it is created.\n\n```py\nTuple1 = ()\nprint (Tuple1)\n\n# Creating a tuple of strings\nprint(('Geeks', 'For'))\n\n# Creating a Tuple of list\nprint(tuple([1, 2, 4, 5, 6]))\n\n# Creating a nested Tuple\nTuple1 = (0, 1, 2, 3)\nTuple2 = ('python', 'geek')\nTuple3 = (Tuple1, Tuple2)\nprint(Tuple3)\n```\n\noutput:\n\n```sh\n()\n('Geeks', 'For')\n(1, 2, 4, 5, 6)\n((0, 1, 2, 3), ('python', 'geek'))\n```\n\n#### Accessing element of a tuple\n\nUse the index operator [ ] to access an item in a tuple.\n\n```py\ntuple1 = tuple([1, 2, 3, 4, 5])\n\n# Accessing element using indexing\nprint(tuple1[0])\n\n# Accessing element using Negative\n# Indexing\nprint(tuple1[-1])\n```\n\noutput:\n\n```sh\n1\n5\n```\n\n### Deleting/updating elements of tuple\n\nItems of a tuple cannot be deleted as tuples are immutable in Python. Only new tuples can be reassigned to the same name.\n\n```py\ntuple1 = tuple([1, 2, 3, 4, 5])\n\n# Updating an element\ntuple1[0] = -1\n\n# Deleting an element\ndel tuple1[2]\n```\n\n## Boolean\n\nOnly two values: `True` and `False`.\n\n```py\nx = True\ny = False\nprint(type(x))  # <class 'bool'>\n```\n\nBooleans are often returned from comparison or logical operations.\n\n```py\nprint(1 == 1)     # True\nprint(1 < 2 and 3 > 1)  # True\n```\n\n## Set (`set`)\n\nUnordered collection of unique, immutable elements.\n\n```py\ns = {1, 2, 3, 2}\nprint(s)  # {1, 2, 3}\n```\n\n#### Adding elements: Using add() and update()\n\n```py\nset1 = set()\n\n# Adding to the Set using add()\nset1.add(8)\nset1.add((6, 7))\nprint(set1)\n\n# Additio to the Set using Update()\nset1.update([10, 11])\nprint(set1)\n```\n\noutput:\n\n```sh\n{8, (6, 7)}\n{8, 10, 11, (6, 7)}\n```\n\n#### Accessing a Set\n\n```py\n# Creating a set\nset1 = set([\"Geeks\", \"For\", \"Geeks\"])\n\n# Accessing using for loop\nfor i in set1:\n    print(i, end =\" \")\n```\n\noutput:\n\n```sh\nGeeks For\n```\n\n#### Removing elements from a set: Using remove(), discard(), pop() and clear()\n\n```py\n\nset1 = set([1, 2, 3, 4, 5, 6,\n            7, 8, 9, 10, 11, 12])\n\n# using Remove() method\nset1.remove(5)\nset1.remove(6)\nprint(set1)\n\n# using Discard() method\nset1.discard(8)\nset1.discard(9)\nprint(set1)\n\n# Set using the pop() method\nset1.pop()\nprint(set1)\n\n# Set using clear() method\nset1.clear()\nprint(set1)\n```\n\noutput:\n\n```sh\n{1, 2, 3, 4, 7, 8, 9, 10, 11, 12}\n{1, 2, 3, 4, 7, 10, 11, 12}\n{2, 3, 4, 7, 10, 11, 12}\nset()\n```\n\n## Dictionary (`dict`)\n\nUnordered collection of key-value pairs. Keys must be unique and immutable.\n\n```py\nperson = {\n    \"name\": \"Alice\",\n    \"age\": 30\n}\nprint(person[\"name\"])  # Alice\n```\n\noutput:\n\n```sh\n{}\n{1: 'Geeks', 2: 'For', 3: 'Geeks'}\n{1: [1, 2, 3, 4], 'Name': 'Geeks'}\n```\n\n#### Nested Dictionary\n\n<Mermaid\n  chart={`\n graph TD\n  %% Main keys\n  K1[\"1\"] --> V1[\"Geeks\"]\n  K2[\"2\"] --> V2[\"For\"]\n  K3[\"3\"] --> NK[\"Nested Keys\"]\n\n%% Nested keys and their values\nNK --> NA[\"A\"] --> VA[\"Welcome\"]\nNK --> NB[\"B\"] --> VB[\"To\"]\nNK --> NC[\"C\"] --> VC[\"Geeks\"]\n\n%% Grouping (optional visual clarity)\nsubgraph Keys\nK1\nK2\nK3\nend\n\nsubgraph Value Set 1\nV1\nV2\nend\n\nsubgraph Value Set 2\nVA\nVB\nVC\nend\n\n`}\n/>\n\n```py\n# Creating a Nested Dictionary\n# as shown in the below image\nDict = {1: 'Geeks', 2: 'For',\n        3:{'A' : 'Welcome', 'B' : 'To', 'C' : 'Geeks'}}\n\nprint(Dict)\n```\n\noutput:\n\n```sh\n{1: 'Geeks', 2: 'For', 3: {'A': 'Welcome', 'B': 'To', 'C': 'Geeks'}}\n```\n\n#### Adding elements to a Dictionary\n\nOne value at a time can be added to a Dictionary by defining value along with the key e.g. Dict[Key] = ‘Value’.\n\n```py\n# Creating an empty Dictionary\nDict = {}\n\n# Adding elements one at a time\nDict[0] = 'Geeks'\nDict[2] = 'For'\nDict[3] = 1\nprint(Dict)\n\n\n# Updating existing Key's Value\nDict[2] = 'Welcome'\nprint(Dict)\n```\n\noutput:\n\n```sh\n{0: 'Geeks', 2: 'For', 3: 1}\n{0: 'Geeks', 2: 'Welcome', 3: 1}\n```\n\n#### Accessing elements from a Dictionary\n\nIn order to access the items of a dictionary refer to its key name or use get() method.\n\n```py\n# Creating a Dictionary\nDict = {1: 'Geeks', 'name': 'For', 3: 'Geeks'}\n\n# accessing a element using key\nprint(Dict['name'])\n\n# accessing a element using get()\nprint(Dict.get(3))\n```\n\nOutput:\n\n```sh\nFor\nGeeks\n```\n\n#### Removing Elements from Dictionary\n\nUsing pop() and popitem()\n\n```py\n# Initial Dictionary\nDict = { 5 : 'Welcome', 6 : 'To', 7 : 'Geeks',\n        'A' : {1 : 'Geeks', 2 : 'For', 3 : 'Geeks'},\n       }\n\n# using pop()\nDict.pop(5)\nprint(Dict)\n\n# using popitem()\nDict.popitem()\nprint(Dict)\n```\n\noutput:\n\n```sh\n{'A': {1: 'Geeks', 2: 'For', 3: 'Geeks'}, 6: 'To', 7: 'Geeks'}\n{6: 'To', 7: 'Geeks'}\n```\n"
  },
  {
    "path": "content/docs/python/python/error-handling.mdx",
    "content": "---\ntitle: Error Handling\ndescription: Handle errors gracefully and write reliable code.\n---\n\n10.1 Types of Exceptions\n\n10.2 try, except, finally\n\n10.3 Handling Multiple Exceptions\n\n10.4 Raising Custom Exceptions\n\n10.5 Debugging Tips"
  },
  {
    "path": "content/docs/python/python/file-handling.mdx",
    "content": "---\ntitle: File Handling\ndescription: Reading and writing files with Python\n---\n\n7.1 Opening Files with open()\n\n7.2 Reading Text Files\n\n7.3 Writing Text Files\n\n7.4 Using with for File Handling\n\n7.5 Working with JSON\n\n- Reading JSON Files\n- Writing JSON Files"
  },
  {
    "path": "content/docs/python/python/functions.mdx",
    "content": "---\ntitle: Functions\ndescription: Write modular, reusable code.\n---\n\n8.1 Defining Functions with def\n\n8.2 Arguments and Return Values\n\n8.3 Default Arguments, *args, **kwargs\n\n8.4 Built-in vs User-defined Functions\n\n8.5 Lambda (Anonymous) Functions\n\n8.6 Functional Tools: map(), filter(), zip(), sorted()\n\n"
  },
  {
    "path": "content/docs/python/python/hello-world.mdx",
    "content": "---\ntitle: Hello, World!\ndescription: Understand the building blocks of a Python program.\n---\n\nHello, World! in python is the first python program which we learn when we start learning any program. It’s a simple program that displays the message “Hello, World!” on the screen."
  },
  {
    "path": "content/docs/python/python/index.mdx",
    "content": "---\ntitle: Python\ndescription: Getting started with Python\nicon: SiPython\nindex: true\n---\n\nPython is a high-level programming language known for its simplicity and flexibility. It supports structured, object-oriented, and functional programming, with syntax inspired by elements of C.\n\nCreated in the late 1980s by Guido van Rossum, it was designed to be both powerful and easy to use.\n\n## Why Python\n\nPython is the most popular language for data science because:\n\n- **Easy to learn**: Python’s simple, readable syntax is great for beginners and efficient for experienced developers.\n- **Free and open source**: Completely free to use, with a rich ecosystem of libraries at no cost.\n- **Powerful libraries**: Libraries like **NumPy**, **pandas**, and **matplotlib** make data analysis and visualization simple. Frameworks like **scikit-learn**, **TensorFlow**, and **PyTorch** let you build and train machine learning models with minimal code.\n- **Vast ecosystem**: From web scraping to automation, Python offers libraries for nearly every task.\n- **Scalable and versatile**: Python runs on all major platforms and scales from small scripts to large systems.\n- **Strong community**: A large and active user base ensures plenty of tutorials, documentation, and support.\n\nPython is also chosen for data science and machine learning for its object-oriented design, clear syntax, and dynamic memory management, making it ideal for a wide range of applications.\n\n## Modules\n"
  },
  {
    "path": "content/docs/python/python/meta.json",
    "content": "{\n  \"pages\": [\n    \"hello-world\",\n    \"operators\",\n    \"data-types\",\n    \"control-flow\",\n    \"data-structures\",\n    \"file-handling\",\n    \"functions\",\n    \"oop\",\n    \"error-handling\"\n  ]\n}\n"
  },
  {
    "path": "content/docs/python/python/oop.mdx",
    "content": "---\ntitle: Object Oriented \ndescription: Model real-world systems using classes and objects.\n---\n\n9.1 What is OOP?\n\n9.2 Creating Classes and Objects\n\n9.3 Instance vs Class Attributes\n\n9.4 Encapsulation and Access Modifiers\n\n9.5 self and Class Members\n\n9.6 Static Methods vs Class Methods\n\n9.7 Inheritance\n\n- Single and Multiple Inheritance\n- super() and issubclass()\n\n9.8 Polymorphism\n\n9.9 Abstract Classes"
  },
  {
    "path": "content/docs/python/python/operators.mdx",
    "content": "---\ntitle: Operators\ndescription: Calculations and comparisons using operators.\n---\n\nOperators are symbols used to perform operations on variables and values, such as arithmetic calculations, comparisons, or logical checks.\n\nLet's explore the most commonly used operators in Python:\n\n## Arithmetic Operators\n\nThese are used to do basic math operations like addition, subtraction, multiplication and division.\n\n| Operator | Description                  | Syntax   |\n| -------- | ---------------------------- | -------- |\n| `+`      | Addition                     | `x + y`  |\n| `-`      | Subtraction                  | `x - y`  |\n| `*`      | Multiplication               | `x * y`  |\n| `/`      | Division (decimal)           | `x / y`  |\n| `//`     | Floor Division (rounds down) | `x // y` |\n| `%`      | Modulus (remainder)          | `x % y`  |\n| `**`     | Power (exponent)             | `x ** y` |\n\nExample:\n\n```py\na = 7\nb = 2\n\nprint(a + b)   # Addition\nprint(a - b)   # Subtraction\nprint(a * b)   # Multiplication\nprint(a / b)   # Division\nprint(a // b)  # Floor Division\nprint(a % b)   # Modulus\nprint(a ** b)  # Exponent\n```\n\nOutput:\n\n```sh\n9\n5\n14\n3.5\n3\n1\n49\n```\n\n## Comparison Operators\n\nThese are used to compare two values. The result is either `True` or `False`.\n\n| Operator | Description              | Syntax   |\n| -------- | ------------------------ | -------- |\n| `>`      | Greater than             | `x > y`  |\n| `<`      | Less than                | `x < y`  |\n| `==`     | Equal to                 | `x == y` |\n| `!=`     | Not equal to             | `x != y` |\n| `>=`     | Greater than or equal to | `x >= y` |\n| `<=`     | Less than or equal to    | `x <= y` |\n\nExample:\n\n```py\nx = 8\ny = 10\n\nprint(x > y)   # Greater than\nprint(x < y)   # Less than\nprint(x == y)  # Equal to\nprint(x != y)  # Not equal to\nprint(x >= y)  # Greater than or equal to\nprint(x <= y)  # Less than or equal to\n```\n\nOutput:\n\n```sh\nFalse\nTrue\nFalse\nTrue\nFalse\nTrue\n```\n\n## Logical Operators\n\nThese are used to combine multiple conditions.\n\n| Operator | Description                      | Syntax    | Example            |\n| -------- | -------------------------------- | --------- | ------------------ |\n| `and`    | True if both conditions are true | `x and y` | `x > 5 and x < 10` |\n| `or`     | True if at least one is true     | `x or y`  | `x < 5 or x > 15`  |\n| `not`    | Reverses the condition           | `not x`   | `not(x > 5)`       |\n\nExample:\n\n```py\nx = 7\nprint(x > 5 and x < 10)  # True\nprint(x < 5 or x > 10)   # False\nprint(not(x > 5))        # False\n```\n\nOutput:\n\n```sh\nTrue\nFalse\nFalse\n```\n\n## Bitwise Operators\n\nBitwise operators work with binary (0s and 1s). These are advanced but useful for certain tasks.\n\n| Operator | Description         | Syntax   |\n| -------- | ------------------- | -------- |\n| `&`      | Bitwise AND         | `x & y`  |\n| `~`      | Bitwise NOT         | `~x`     |\n| `^`      | Bitwise XOR         | `x ^ y`  |\n| `>>`     | Bitwise right shift | `x >> y` |\n| `<<`     | Bitwise left shift  | `x << y` |\n\nExample:\n\n```py\na = 6\nb = 3\n\nprint(a & b)    # AND\nprint(~a)       # NOT\nprint(a ^ b)    # XOR\nprint(a >> 1)   # Right shift\nprint(a << 1)   # Left shift\n```\n\nOutput:\n\n```sh\n2\n-7\n5\n3\n12\n```\n\n## Assignment Operators\n\nThese are used to assign values to variables, sometimes after performing a calculation.\n\n| Operator | Meaning                       | Example   |\n| -------- | ----------------------------- | --------- |\n| `=`      | Assign value                  | `x = 5`   |\n| `+=`     | Add and assign                | `x += 2`  |\n| `-=`     | Subtract and assign           | `x -= 2`  |\n| `*=`     | Multiply and assign           | `x *= 2`  |\n| `/=`     | Divide and assign             | `x /= 2`  |\n| `//=`    | Floor divide and assign       | `x //= 2` |\n| `%=`     | Modulus and assign            | `x %= 2`  |\n| `**=`    | Power and assign              | `x **= 2` |\n| `:=`     | Assign in expression (Walrus) | `x := 5`  |\n\nExample:\n\n```py\n# = : Assign value\nx = 5\nprint(x)  # 5\n\n# += : Add and assign\nx += 3    # x = x + 3\nprint(x)  # 8\n\n# -= : Subtract and assign\nx -= 2    # x = x - 2\nprint(x)  # 6\n\n# *= : Multiply and assign\nx *= 4    # x = x * 4\nprint(x)  # 24\n\n# /= : Divide and assign\nx /= 6    # x = x / 6\nprint(x)  # 4.0\n\n# //= : Floor divide and assign\nx //= 3   # x = x // 3\nprint(x)  # 1.0\n\n# %= : Modulus and assign\nx = 10\nx %= 4    # x = x % 4\nprint(x)  # 2\n\n# **= : Power and assign\nx **= 3   # x = x ** 3\nprint(x)  # 8\n\n# := : Walrus operator (Python 3.8+)\nitems = [1, 2, 3, 4]\nwhile (length := len(items)) > 2:\n    print(length)\n    items.pop()\n```\n\n## Identity Operators\n\nThese check whether two variables refer to the same object in memory.\n\n| Operator | Meaning                      | Example      |\n| -------- | ---------------------------- | ------------ |\n| `is`     | True if same memory location | `a is b`     |\n| `is not` | True if different location   | `a is not b` |\n\nExample\n\n```py\na = 10\nb = 20\nc = a\n\nprint(a is not b)\nprint(a is c)\n```\n\nOutput:\n\n```\nTrue\nTrue\n```\n\n## Membership Operators\n\nThese check whether a value exists in a list, string, or other sequence.\n\n| Operator | Meaning                      | Example         |\n| -------- | ---------------------------- | --------------- |\n| `in`     | True if value is present     | `x in list`     |\n| `not in` | True if value is not present | `x not in list` |\n\nExample:\n\n```py\nfruits = [\"apple\", \"banana\", \"cherry\"]\n\nprint(\"apple\" in fruits)      # True\nprint(\"mango\" not in fruits)  # True\n```\n\nOutput:\n\n```sh\nTrue\nTrue\n```\n"
  },
  {
    "path": "content/docs/python/scikit-learn/index.mdx",
    "content": "---\ntitle: Scikit Learn\ndescription: Getting started with Python\nicon: SiScikitlearn\nindex: true\n---\n\n## Scikit Learn"
  },
  {
    "path": "content/docs/python/setup.mdx",
    "content": "---\ntitle: Setup\ndescription: Setting up your Python environment\nicon: Settings2\ncolab: https://colab.research.google.com/drive/1example\n---\n\nLet’s set up the tools you’ll use to write and execute your code. There are two main environments for working with Python: **Shell** and **Notebook**. Let’s explore both.\n\n<Callout>\n  Make sure [Python](https://www.python.org/downloads/) and\n  [IPython](https://ipython.org/install.html) are installed on your system.\n</Callout>\n\n## Shell\n\nThe Shell lets you run Python commands interactively in your terminal, line by line.\n\nStart the Python shell by running `python3` in your terminal (`python` on Windows).\n\n```sh title=\"Python shell\"\n(base) ➜  ~ python3   # [!code highlight]\nPython 3.11.4 (main, Jul  5 2023, 08:54:11) [Clang 14.0.6 ] on darwin\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n>>> print(\"Hello, World!\")  # print hello world\nHello, World!\n>>> 4 + 9  # add numbers\n13\n```\n\n### IPython\n\n[IPython](https://ipython.org/) is an enhanced shell with features like syntax highlighting, auto-completion, and better debugging.\n\nTo start IPython, run `ipython` in your terminal.\n\n```sh title=\"IPython shell\"\n(base) ➜  ~ ipython  # [!code highlight]\nPython 3.11.4 (main, Jul  5 2023, 08:54:11) [Clang 14.0.6 ]\nType 'copyright', 'credits' or 'license' for more information\nIPython 8.12.0 -- An enhanced Interactive Python. Type '?' for help.\n\nIn [1]: print(\"Hello, IPython!\")\nHello, IPython!\n\nIn [2]: 3 + 39\nOut[2]: 42\n```\n\nShells are great for quick tests but not ideal for complex projects. That’s where **Notebooks** come in.\n\n## Notebooks\n\nA notebook is a web-based interactive environment built on top of IPython. While working in the shell can be limiting, notebooks simplify the process by bringing code, visualizations, and explanations together in one place.\n\n### Jupyter Notebook\n\n[Jupyter Notebook](https://jupyter.org/) is a local web-based notebook, ideal for development, collaboration, and sharing.\n\nInstall it with the command `pip install notebook`, then launch it using `jupyter notebook`.\n\nThis will start a local web server, show the server log in your terminal, and automatically open the notebook in your browser at [localhost:8888](http://localhost:8888).\n\n![Jupyter Notebook](/learn/python/setup/jupyter.gif)\n\nThere is also an enhanced version of Jupyter Notebook called [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/), which provides a more flexible and powerful environment.\n\nInstall it with the command `pip install jupyterlab`, then launch it using `jupyter lab`.\n\n![JupyterLab](/learn/python/setup/jupyterlab.gif)\n\nLearn more about JupyterLab in this [tutorial](https://youtu.be/A5YyoCKxEOU?si=vQJXKYTakXIe-DJC) by the Jupyter team.\n\n### Google Colab\n\n[Google Colab](https://colab.research.google.com/) is a cloud-based notebook that runs in your browser. It comes with machine learning libraries pre-installed and offers free compute resources, such as GPUs and TPUs, for smaller workloads.\n\nDue to its ease of use, flexibility, and access to more compute, most people now prefer Colab over Jupyter.\n\n![Google Colab](/learn/python/setup/colab.gif)\n\nLearn more about Colab in this [tutorial](https://colab.research.google.com/notebooks/intro.ipynb) by the Colab team.\n\n### Kaggle Notebook\n\n[Kaggle Notebook](https://www.kaggle.com/code) is like Colab but fully connected to Kaggle’s datasets and competitions, making it easy to access data and join competitions right from the notebook.\n\n![Kaggle Notebook](/learn/python/setup/kaggle.gif)\n\nLearn more about Kaggle Notebooks in this [tutorial](https://www.kaggle.com/docs/notebooks) by the Kaggle team.\n\n## Which one to use?\n\nIf you’re unsure which environment to choose, [Colab](#google-colab) is a great option. It’s user-friendly, provides free access to more compute power, and comes with pre-installed machine learning libraries.\n\nFor this course, we’ll be using Colab as our primary environment.\n\nYou’re all set and ready to get started!\n"
  },
  {
    "path": "lib/cn.ts",
    "content": "export { twMerge as cn } from 'tailwind-merge';\n"
  },
  {
    "path": "lib/get-llm-text.ts",
    "content": "import { source } from \"@/lib/source\";\nimport type { InferPageType } from \"fumadocs-core/source\";\n\nexport async function getLLMText(page: InferPageType<typeof source>) {\n  const processed = await page.data.getText(\"processed\");\n\n  return `# ${page.data.title} \nURL: ${page.url}\nSource: https://raw.githubusercontent.com/aicademyorg/AIcademy/refs/heads/main/content/docs/${page.path}\n\n${page.data.description ?? ''}\n${processed}`;\n}\n\n"
  },
  {
    "path": "lib/github.ts",
    "content": "import { App, Octokit } from \"octokit\";\nimport type { Feedback } from \"@/components/feedback\";\n\nexport const repo = \"AIcademy\";\nexport const owner = \"aicademyorg\";\nexport const DocsCategory = \"Feedback\";\n\nlet instance: Octokit | undefined;\n\nasync function getOctokit(): Promise<Octokit> {\n  if (instance) return instance;\n  const appId = process.env.GITHUB_APP_ID;\n  const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;\n\n  if (!appId || !privateKey) {\n    throw new Error(\n      \"No GitHub keys provided for Github app, docs feedback feature will not work.\"\n    );\n  }\n\n  const app = new App({\n    appId,\n    privateKey,\n  });\n\n  const { data } = await app.octokit.request(\n    \"GET /repos/{owner}/{repo}/installation\",\n    {\n      owner,\n      repo,\n      headers: {\n        \"X-GitHub-Api-Version\": \"2022-11-28\",\n      },\n    }\n  );\n\n  instance = await app.getInstallationOctokit(data.id);\n  return instance;\n}\n\ninterface RepositoryInfo {\n  id: string;\n  discussionCategories: {\n    nodes: {\n      id: string;\n      name: string;\n    }[];\n  };\n}\n\nlet cachedDestination: RepositoryInfo | undefined;\nasync function getFeedbackDestination() {\n  if (cachedDestination) return cachedDestination;\n  const octokit = await getOctokit();\n\n  const {\n    repository,\n  }: {\n    repository: RepositoryInfo;\n  } = await octokit.graphql(`\n    query {\n      repository(owner: \"${owner}\", name: \"${repo}\") {\n        id\n        discussionCategories(first: 25) {\n          nodes { id name }\n        }\n      }\n    }\n  `);\n\n  return (cachedDestination = repository);\n}\n\nexport interface ActionResponse {\n  githubUrl: string;\n}\n\nexport async function onRateAction(\n  url: string,\n  feedback: Feedback\n): Promise<ActionResponse> {\n  \"use server\";\n  const octokit = await getOctokit();\n  const destination = await getFeedbackDestination();\n  if (!octokit || !destination)\n    throw new Error(\"GitHub comment integration is not configured.\");\n\n  const category = destination.discussionCategories.nodes.find(\n    (category) => category.name === DocsCategory\n  );\n\n  if (!category)\n    throw new Error(\n      `Please create a \"${DocsCategory}\" category in GitHub Discussion`\n    );\n\n  const title = `Feedback for ${url}`;\n  const body = `[${feedback.opinion}] ${feedback.message}\\n\\n> Forwarded from user feedback.`;\n\n  let discussion: { id: string; url: string } | undefined;\n  const searchResult = await octokit.graphql<any>(`\n    query {\n      search(type: DISCUSSION, query: ${JSON.stringify(\n        `${title} in:title repo:${owner}/${repo} author:@me`\n      )}, first: 1) {\n        nodes {\n          ... on Discussion { id, url }\n        }\n      }\n    }\n  `);\n\n  const nodes: { id: string; url: string }[] = searchResult.search.nodes;\n  if (nodes && nodes.length > 0 && nodes[0]) {\n    discussion = nodes[0];\n    try {\n      await octokit.graphql(`\n        mutation {\n          addDiscussionComment(input: { body: ${JSON.stringify(\n            body\n          )}, discussionId: \"${discussion.id}\" }) {\n            comment { id }\n          }\n        }\n      `);\n    } catch (err) {\n      console.error(\n        \"[onRateAction] Failed to add comment to existing discussion\",\n        {\n          url,\n          feedback,\n          discussionId: discussion.id,\n          error: err,\n        }\n      );\n      throw new Error(\"Failed to add comment to existing discussion.\");\n    }\n  } else {\n    let result;\n    try {\n      result = await octokit.graphql<any>(`\n        mutation {\n          createDiscussion(input: { repositoryId: \"${\n            destination.id\n          }\", categoryId: \"${category.id}\", body: ${JSON.stringify(\n        body\n      )}, title: ${JSON.stringify(title)} }) {\n            discussion { id, url }\n          }\n        }\n      `);\n      discussion = result?.createDiscussion?.discussion || result?.discussion;\n    } catch (err) {\n      console.error(\"[onRateAction] Error creating discussion\", {\n        url,\n        feedback,\n        error: err,\n      });\n    }\n    if (!discussion) {\n      try {\n        const retrySearch = await octokit.graphql<any>(`\n          query {\n            search(type: DISCUSSION, query: ${JSON.stringify(\n              `${title} in:title repo:${owner}/${repo} author:@me`\n            )}, first: 1) {\n              nodes {\n                ... on Discussion { id, url }\n              }\n            }\n          }\n        `);\n        const retryNodes: { id: string; url: string }[] =\n          retrySearch.search.nodes;\n        if (retryNodes && retryNodes.length > 0 && retryNodes[0]) {\n          discussion = retryNodes[0];\n        }\n      } catch (err) {\n        console.error(\n          \"[onRateAction] Error retrying discussion search after creation failure\",\n          {\n            url,\n            feedback,\n            error: err,\n          }\n        );\n      }\n    }\n  }\n\n  if (!discussion) {\n    console.error(\n      \"[onRateAction] Final failure: could not find or create discussion\",\n      {\n        url,\n        feedback,\n        title,\n      }\n    );\n    throw new Error(\n      \"Failed to create or find a discussion for feedback. Please ensure the 'Feedback' category exists in your GitHub Discussions and your GitHub App has the correct permissions.\"\n    );\n  }\n\n  return {\n    githubUrl: discussion.url,\n  };\n}\n"
  },
  {
    "path": "lib/i18n.ts",
    "content": "import { defineI18n } from \"fumadocs-core/i18n\";\n\nexport const i18n = defineI18n({\n  defaultLanguage: \"en\",\n  languages: [\"en\" /*, \"cn\", \"zh\", \"ja\", \"ru\", \"fr\"*/],\n  hideLocale: \"default-locale\",\n});\n\nexport type Language = (typeof i18n.languages)[number];\n\nexport function localizeUrl(url: string, lang: Language): string {\n  return lang === i18n.defaultLanguage ? url : `/${lang}${url}`;\n}\n\ninterface FeedbackTranslations {\n  wasHelpful: string;\n  good: string;\n  bad: string;\n  thankYou: string;\n  submitAgain: string;\n  placeholder: string;\n  submit: string;\n  viewOnGitHub: string;\n}\n\ninterface UIDictionary {\n  metadata: {\n    titleTemplate: string;\n    defaultTitle: string;\n    description: string;\n  };\n  nav: {\n    navigation: Array<{\n      name: string;\n      href: string;\n    }>;\n  };\n  feedback: FeedbackTranslations;\n}\n\nexport const uiDictionary: Record<Language, UIDictionary> = {\n  en: {\n    metadata: {\n      titleTemplate: \"%s | AIcademy\",\n      defaultTitle: \"AIcademy - Free AI Education for All\",\n      description: \"A friendly community offering free AI education\",\n    },\n    nav: {\n      navigation: [\n        { name: \"Courses\", href: \"/courses\" },\n        { name: \"Blog\", href: \"/blog\" },\n        { name: \"About\", href: \"/about\" },\n      ],\n    },\n    feedback: {\n      wasHelpful: \"Was this page helpful?\",\n      good: \"Yes\",\n      bad: \"No\",\n      thankYou: \"Thank you for your feedback!\",\n      submitAgain: \"Submit Again?\",\n      placeholder: \"Leave your feedback...\",\n      submit: \"Submit\",\n      viewOnGitHub: \"View on GitHub\",\n    },\n  },\n  /*\n  zh: {\n    metadata: {\n      titleTemplate: \"%s | AIcademy\",\n      defaultTitle: \"AIcademy - 免费AI教育平台\",\n      description: \"一个提供免费AI教育的友好社区\",\n    },\n    nav: {\n      navigation: [\n        { name: \"课程\", href: \"/cn/courses\" },\n        { name: \"博客\", href: \"/cn/blog\" },\n        { name: \"关于我们\", href: \"/cn/about\" },\n      ],\n    },\n    feedback: {\n      wasHelpful: \"这个页面对您有帮助吗？\",\n      good: \"有帮助\",\n      bad: \"没帮助\",\n      thankYou: \"感谢您的反馈！\",\n      submitAgain: \"要再次提交吗？\",\n      placeholder: \"欢迎留下您的反馈……\",\n      submit: \"提交\",\n      viewOnGitHub: \"在 GitHub 查看\",\n    },\n  },\n\n  ja: {\n    metadata: {\n      titleTemplate: \"%s | AIcademy\",\n      defaultTitle: \"AIcademy - 無料で学べるAI教育\",\n      description: \"誰でも無料で学べる、フレンドリーなAI教育コミュニティ\",\n    },\n    nav: {\n      navigation: [\n        { name: \"コース\", href: \"/ja/courses\" },\n        { name: \"ブログ\", href: \"/ja/blog\" },\n        { name: \"概要\", href: \"/ja/about\" },\n      ],\n    },\n    feedback: {\n      wasHelpful: \"このページは役に立ちましたか？\",\n      good: \"はい\",\n      bad: \"いいえ\",\n      thankYou: \"ご意見ありがとうございます！\",\n      submitAgain: \"もう一度送信しますか？\",\n      placeholder: \"ご意見・ご感想をご記入ください…\",\n      submit: \"送信する\",\n      viewOnGitHub: \"GitHub で見る\",\n    },\n  },\n  ru: {\n    metadata: {\n      titleTemplate: \"%s | AIcademy\",\n      defaultTitle: \"AIcademy — бесплатное образование в сфере ИИ\",\n      description:\n        \"Дружелюбное сообщество, предлагающее бесплатное обучение ИИ\",\n    },\n    nav: {\n      navigation: [\n        { name: \"Курсы\", href: \"/ru/courses\" },\n        { name: \"Блог\", href: \"/ru/blog\" },\n        { name: \"О проекте\", href: \"/ru/about\" },\n      ],\n    },\n    feedback: {\n      wasHelpful: \"Эта страница была полезной?\",\n      good: \"Да\",\n      bad: \"Нет\",\n      thankYou: \"Спасибо за отзыв!\",\n      submitAgain: \"Отправить снова?\",\n      placeholder: \"Оставьте свой отзыв...\",\n      submit: \"Отправить\",\n      viewOnGitHub: \"Посмотреть на GitHub\",\n    },\n  },\n  fr: {\n    metadata: {\n      titleTemplate: \"%s | AIcademy\",\n      defaultTitle: \"AIcademy - Éducation gratuite à l'IA\",\n      description:\n        \"Une communauté bienveillante proposant une éducation gratuite à l'IA\",\n    },\n    nav: {\n      navigation: [\n        { name: \"Cours\", href: \"/fr/courses\" },\n        { name: \"Blog\", href: \"/fr/blog\" },\n        { name: \"À propos\", href: \"/fr/about\" },\n      ],\n    },\n    feedback: {\n      wasHelpful: \"Cette page vous a-t-elle été utile ?\",\n      good: \"Oui\",\n      bad: \"Non\",\n      thankYou: \"Merci pour votre retour !\",\n      submitAgain: \"Envoyer un autre retour ?\",\n      placeholder: \"Laissez-nous votre avis...\",\n      submit: \"Envoyer\",\n      viewOnGitHub: \"Voir sur GitHub\",\n    },\n  },\n  */\n};\n"
  },
  {
    "path": "lib/metadata.ts",
    "content": "import type { Metadata } from \"next/types\";\n\nexport function createMetadata(override: Metadata): Metadata {\n  return {\n    ...override,\n    openGraph: {\n      title: override.title ?? undefined,\n      description: override.description ?? undefined,\n      url: \"https://aicademyorg.netlify.app\",\n      images: \"/banner.png\",\n      siteName: \"AIcademy\",\n      ...override.openGraph,\n    },\n    twitter: {\n      card: \"summary_large_image\",\n      creator: \"@aicademyorg\",\n      title: override.title ?? undefined,\n      description: override.description ?? undefined,\n      images: \"/banner.png\",\n      ...override.twitter,\n    },\n    icons: {\n      icon: \"/favicon.ico\",\n    },\n  };\n}\n\nexport const baseUrl =\n  process.env.NODE_ENV === \"development\" || !process.env.VERCEL_URL\n    ? new URL(\"http://localhost:3000\")\n    : new URL(`https://${process.env.VERCEL_URL}`);\n"
  },
  {
    "path": "lib/source.ts",
    "content": "import { docs } from \"@/.source/server\";\nimport { loader } from \"fumadocs-core/source\";\nimport { i18n } from \"@/lib/i18n\";\nimport { icons } from \"lucide-react\";\nimport { createElement } from \"react\";\nimport * as SiIcons from \"react-icons/si\";\n\n// See https://fumadocs.vercel.app/docs/headless/source-api for more info\nexport const source = loader({\n  // it assigns a URL to your pages\n  i18n,\n  baseUrl: \"/docs\",\n  icon(icon) {\n    if (icon && icon in icons)\n      return createElement(icons[icon as keyof typeof icons]);\n    if (icon && icon in SiIcons)\n      return createElement(SiIcons[icon as keyof typeof SiIcons]);\n  },\n  source: docs.toFumadocsSource(),\n});\n"
  },
  {
    "path": "mdx-components.tsx",
    "content": "import defaultMdxComponents from \"fumadocs-ui/mdx\";\nimport * as FilesComponents from \"fumadocs-ui/components/files\";\nimport * as TabsComponents from \"fumadocs-ui/components/tabs\";\nimport type { MDXComponents } from \"mdx/types\";\nimport { Accordion, Accordions } from \"fumadocs-ui/components/accordion\";\nimport * as icons from \"lucide-react\";\nimport { ImageZoom } from \"fumadocs-ui/components/image-zoom\";\nimport { Mermaid } from \"@/components/mdx/mermaid\";\n\nexport function getMDXComponents(components?: MDXComponents): MDXComponents {\n  return {\n    ...(icons as unknown as MDXComponents),\n    ...defaultMdxComponents,\n    ...TabsComponents,\n    ...FilesComponents,\n    img: (props) => <ImageZoom {...(props as any)} />,\n    Accordion,\n    Accordions,\n    Mermaid,\n    ...components,\n  };\n}\n"
  },
  {
    "path": "next.config.mjs",
    "content": "import { createMDX } from \"fumadocs-mdx/next\";\n\nconst withMDX = createMDX();\n\n/** @type {import('next').NextConfig} */\nconst config = {\n  reactStrictMode: true,\n  async rewrites() {\n    return [\n      {\n        source: \"/:lang/docs/:path*.mdx\",\n        destination: \"/:lang/llms.mdx/:path*\",\n      },\n    ];\n  },\n};\n\nexport default withMDX(config);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"aicademy\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build\",\n    \"dev\": \"next dev --turbo\",\n    \"start\": \"next start\",\n    \"postinstall\": \"fumadocs-mdx\"\n  },\n  \"dependencies\": {\n    \"@tailwindcss/postcss\": \"^4.1.18\",\n    \"class-variance-authority\": \"^0.7.1\",\n    \"clsx\": \"^2.1.1\",\n    \"fumadocs-core\": \"16.6.3\",\n    \"fumadocs-mdx\": \"14.2.7\",\n    \"fumadocs-ui\": \"16.6.3\",\n    \"katex\": \"^0.16.28\",\n    \"lucide-react\": \"^0.574.0\",\n    \"mermaid\": \"^11.12.3\",\n    \"next\": \"16.1.6\",\n    \"next-themes\": \"^0.4.6\",\n    \"octokit\": \"^5.0.5\",\n    \"postcss\": \"^8.5.6\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"react-icons\": \"^5.5.0\",\n    \"rehype-katex\": \"^7.0.1\",\n    \"remark\": \"^15.0.1\",\n    \"remark-gfm\": \"^4.0.1\",\n    \"remark-math\": \"^6.0.0\",\n    \"remark-mdx\": \"^3.1.1\",\n    \"shiki\": \"^3.22.0\",\n    \"tailwind-merge\": \"^3.4.1\",\n    \"tailwindcss\": \"^4.1.18\",\n    \"zod\": \"^4.3.6\"\n  },\n  \"devDependencies\": {\n    \"@types/mdx\": \"^2.0.13\",\n    \"@types/node\": \"25.2.3\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"typescript\": \"^5.9.3\"\n  }\n}"
  },
  {
    "path": "postcss.config.mjs",
    "content": "const config = {\n  plugins: {\n    \"@tailwindcss/postcss\": {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "proxy.ts",
    "content": "import type { NextRequest, NextFetchEvent } from \"next/server\";\nimport { NextResponse } from \"next/server\";\nimport { createI18nMiddleware } from \"fumadocs-core/i18n/middleware\";\nimport { i18n } from \"@/lib/i18n\";\n\nconst i18nMiddleware = createI18nMiddleware(i18n);\n\nexport function proxy(request: NextRequest, event: NextFetchEvent) {\n  const { pathname } = request.nextUrl;\n\n  // Handle .md requests\n  if (pathname.endsWith(\".md\")) {\n    const pathWithoutMd = pathname.slice(0, -3);\n\n    const langMatch = pathWithoutMd.match(/^\\/([a-z]{2})(\\/.*)?$/);\n    let lang = i18n.defaultLanguage; \n    let docPath = pathWithoutMd;\n\n    if (langMatch && i18n.languages.includes(langMatch[1] as any)) {\n      lang = langMatch[1] as any;\n      docPath = langMatch[2] || \"\";\n    } else {\n      docPath = pathWithoutMd;\n    }\n\n    // Remove leading slash from docPath if present\n    if (docPath.startsWith(\"/\")) {\n      docPath = docPath.slice(1);\n    }\n\n    // Handle root/index case\n    if (!docPath || docPath === \"\") {\n      docPath = \"index\";\n    }\n\n    // Remove 'docs' prefix if present (since the source system handles docs structure)\n    if (docPath.startsWith(\"docs/\")) {\n      docPath = docPath.slice(5); // Remove 'docs/'\n    } else if (docPath === \"docs\") {\n      docPath = \"index\";\n    }\n\n    // Construct the llms.mdx route with language and slug\n    const slugParts = docPath.split(\"/\").filter(Boolean);\n    const llmsRoute =\n      slugParts.length > 0\n        ? `/${lang}/llms.mdx/${slugParts.join(\"/\")}`\n        : `/${lang}/llms.mdx`;\n\n    return NextResponse.rewrite(new URL(llmsRoute, request.url));\n  }\n\n  // Continue with i18n middleware for non-.md requests\n  return i18nMiddleware(request, event);\n}\n\nexport const config = {\n  // Matcher ignoring `/_next/` and `/api/` but including .md files\n  matcher: [\"/((?!api|_next/static|_next/image|favicon.ico).*)\"],\n};\n"
  },
  {
    "path": "source.config.ts",
    "content": "import {\n  defineConfig,\n  defineDocs,\n  frontmatterSchema,\n  metaSchema,\n} from \"fumadocs-mdx/config\";\nimport rehypeKatex from \"rehype-katex\";\nimport remarkMath from \"remark-math\";\nimport { z } from \"zod\";\n\nexport const docs = defineDocs({\n  dir: \"./content/docs\",\n  docs: {\n    schema: frontmatterSchema.extend({\n      index: z.boolean().default(false),\n      colab: z.string().optional(),\n    }),\n    postprocess: {\n      includeProcessedMarkdown: true,\n    },\n  },\n  meta: {\n    schema: metaSchema,\n  },\n});\n\nexport default defineConfig({\n  mdxOptions: {\n    remarkPlugins: [remarkMath],\n    rehypePlugins: (v) => [rehypeKatex, ...v],\n  },\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"target\": \"ESNext\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"react-jsx\",\n    \"incremental\": true,\n    \"paths\": {\n      \"@/.source\": [\n        \"./.source/server.ts\"\n      ],\n      \"@/*\": [\n        \"./*\"\n      ]\n    },\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ]\n  },\n  \"include\": [\n    \"next-env.d.ts\",\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/types/**/*.ts\",\n    \"tailwind.config.js\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "utils/process-markdown-links.ts",
    "content": "/**\n * Processes markdown content to convert relative links to absolute URLs with .md extension\n * This is used when copying markdown content for LLMs\n */\nexport function processMarkdownLinks(\n    content: string,\n    baseUrl: string = 'https://aicademyorg.netlify.app/',\n  ): string {\n    // Process standard markdown links: [text](/path)\n    content = content.replace(/\\[([^\\]]+)\\]\\(\\/([^)]+)\\)/g, (match, text, path) => {\n      // Skip if it's already an absolute URL\n      if (path.startsWith('http://') || path.startsWith('https://')) {\n        return match;\n      }\n  \n      // Remove any trailing slashes\n      const cleanPath = path.replace(/\\/$/, '');\n  \n      // Don't add .md if it already has an extension or is an anchor\n      if (cleanPath.includes('.') || cleanPath.includes('#')) {\n        return `[${text}](${baseUrl}/${cleanPath})`;\n      }\n  \n      // Add .md extension for documentation links\n      return `[${text}](${baseUrl}/${cleanPath}.md)`;\n    });\n  \n    // Process HTML links: <a href=\"/path\">\n    content = content.replace(/href=\"\\/([^\"]+)\"/g, (match, path) => {\n      // Skip if it's already an absolute URL\n      if (path.startsWith('http://') || path.startsWith('https://')) {\n        return match;\n      }\n  \n      // Remove any trailing slashes\n      const cleanPath = path.replace(/\\/$/, '');\n  \n      // Don't add .md if it already has an extension or is an anchor\n      if (cleanPath.includes('.') || cleanPath.includes('#')) {\n        return `href=\"${baseUrl}/${cleanPath}\"`;\n      }\n  \n      // Add .md extension for documentation links\n      return `href=\"${baseUrl}/${cleanPath}.md\"`;\n    });\n  \n    // Process reference-style links: [text]: /path\n    content = content.replace(/^\\[([^\\]]+)\\]:\\s*\\/(.+)$/gm, (match, ref, path) => {\n      // Skip if it's already an absolute URL\n      if (path.startsWith('http://') || path.startsWith('https://')) {\n        return match;\n      }\n  \n      // Remove any trailing slashes\n      const cleanPath = path.replace(/\\/$/, '');\n  \n      // Don't add .md if it already has an extension\n      if (cleanPath.includes('.') || cleanPath.includes('#')) {\n        return `[${ref}]: ${baseUrl}/${cleanPath}`;\n      }\n  \n      // Add .md extension for documentation links\n      return `[${ref}]: ${baseUrl}/${cleanPath}.md`;\n    });\n  \n    return content;\n  }\n  "
  }
]