diff --git a/web/app/docs/hardware/install-coral-tpu-host/page.tsx b/web/app/docs/hardware/install-coral-tpu-host/page.tsx index dc4be4c..a6990dd 100644 --- a/web/app/docs/hardware/install-coral-tpu-host/page.tsx +++ b/web/app/docs/hardware/install-coral-tpu-host/page.tsx @@ -10,58 +10,79 @@ export default function InstallCoralTPUHost() { return (

Install Coral TPU on the Host

- -

Before using Coral TPU inside an LXC container, the drivers must first be installed on the Proxmox VE host. This script automates that process, ensuring the necessary setup is completed.

- This guide explains how to install and configure Google Coral TPU drivers on a Proxmox VE host using ProxMenux. - This setup enables hardware acceleration for AI-based applications that leverage Coral TPU. + +

+ Before using Coral TPU inside an LXC container, the drivers must first be installed on the Proxmox VE host. This script automates that process, ensuring the necessary setup is completed. +

+ This guide explains how to install and configure Google Coral TPU drivers on a Proxmox VE host using ProxMenux. This setup enables hardware acceleration for AI-based applications that leverage Coral TPU.

- +

Overview

The script automates the following steps:

  1. Prompts for confirmation before proceeding with installation.
  2. Verifies and configures necessary repositories on the host.
  3. -
  4. Installs required dependencies for driver compilation.
  5. +
  6. Installs required build dependencies and kernel headers for driver compilation.
  7. Clones the Coral TPU driver repository and builds the drivers.
  8. Installs the compiled Coral TPU drivers.
  9. Prompts for a system restart to apply changes.
- +

Implementation Steps

The script prompts the user for confirmation before proceeding, as a system restart is required after installation.

+

The script verifies and configures required repositories:

  • Adds the pve-no-subscription repository if not present.
  • Adds non-free-firmware repositories for required packages.
  • -
  • Runs an update to fetch the latest package lists.
  • +
  • Runs apt-get update to fetch the latest package lists.
+ -

The script installs and compiles the required drivers:

+

The script installs and compiles the required Coral TPU drivers:

    -
  • Installs dependencies such as git, dkms, devscripts, and kernel headers.
  • -
  • Clones the gasket-driver repository from Google.
  • -
  • Builds the Coral TPU driver packages.
  • -
  • Installs the compiled drivers on the host.
  • +
  • Installs the following packages:
  • +
      +
    • git
    • +
    • devscripts
    • +
    • dh-dkms
    • +
    • dkms
    • +
    • pve-headers-$(uname -r) (Proxmox kernel headers)
    • +
    +
  • Clones the Coral TPU driver source from:
  • +
      +
    • https://github.com/google/gasket-driver
    • +
    +
  • Builds the driver using debuild and installs it using dpkg -i.
+ +
+

The script prompts the user to restart the server to apply the changes.

- +

Expected Results

- -
) } diff --git a/web/app/rss.xml/route.ts b/web/app/rss.xml/route.ts index 51f4501..6a0d54c 100644 --- a/web/app/rss.xml/route.ts +++ b/web/app/rss.xml/route.ts @@ -10,6 +10,31 @@ interface ChangelogEntry { title: string } +// Function to clean and format markdown content for RSS +function formatContentForRSS(content: string): string { + return ( + content + // Convert ### headers to bold text + .replace(/^### (.+)$/gm, "**$1**") + // Convert ** bold ** to simple bold + .replace(/\*\*(.*?)\*\*/g, "$1") + // Clean code blocks - remove ``` and format nicely + .replace(/```[\s\S]*?```/g, (match) => { + const code = match.replace(/```/g, "").trim() + return `\n${code}\n` + }) + // Convert - bullet points to • + .replace(/^- /gm, "• ") + // Clean up multiple newlines + .replace(/\n{3,}/g, "\n\n") + // Remove backslashes used for line breaks + .replace(/\\\s*$/gm, "") + // Clean up extra spaces + .replace(/\s+/g, " ") + .trim() + ) +} + async function parseChangelog(): Promise { try { const changelogPath = path.join(process.cwd(), "..", "CHANGELOG.md") @@ -21,45 +46,67 @@ async function parseChangelog(): Promise { const fileContents = fs.readFileSync(changelogPath, "utf8") const entries: ChangelogEntry[] = [] - // Split by any heading (## or ###) to catch all changes, not just versions - const sections = fileContents.split(/^(##\s+.*$)/gm).filter((section) => section.trim()) + // Split by ## headers (both versions and dates) + const lines = fileContents.split("\n") + let currentEntry: Partial | null = null + let contentLines: string[] = [] - for (let i = 0; i < sections.length - 1; i += 2) { - const headerLine = sections[i] - const content = sections[i + 1] || "" + for (const line of lines) { + // Check for version header: ## [1.1.1] - 2025-03-21 + const versionMatch = line.match(/^##\s+\[([^\]]+)\]\s*-\s*(\d{4}-\d{2}-\d{2})/) - // Check if it's a version header (## [version] - date) - const versionMatch = headerLine.match(/##\s+\[([^\]]+)\]\s*-\s*(\d{4}-\d{2}-\d{2})/) + // Check for date-only header: ## 2025-05-13 + const dateMatch = line.match(/^##\s+(\d{4}-\d{2}-\d{2})$/) - if (versionMatch) { - const version = versionMatch[1] - const date = versionMatch[2] + if (versionMatch || dateMatch) { + // Save previous entry if exists + if (currentEntry && contentLines.length > 0) { + const rawContent = contentLines.join("\n").trim() + currentEntry.content = formatContentForRSS(rawContent) + if (currentEntry.version && currentEntry.date && currentEntry.title) { + entries.push(currentEntry as ChangelogEntry) + } + } - entries.push({ - version, - date, - content: content.trim(), - url: `https://macrimi.github.io/ProxMenux/changelog#${version}`, - title: `ProxMenux ${version}`, - }) - } else { - // Check for date-only headers (## 2025-05-13) - const dateMatch = headerLine.match(/##\s+(\d{4}-\d{2}-\d{2})/) - if (dateMatch) { + // Start new entry + if (versionMatch) { + const version = versionMatch[1] + const date = versionMatch[2] + currentEntry = { + version, + date, + url: `https://macrimi.github.io/ProxMenux/changelog#${version}`, + title: `ProxMenux ${version}`, + } + } else if (dateMatch) { const date = dateMatch[1] - - entries.push({ + currentEntry = { version: date, date, - content: content.trim(), url: `https://macrimi.github.io/ProxMenux/changelog#${date}`, title: `ProxMenux Update ${date}`, - }) + } + } + + contentLines = [] + } else if (currentEntry && line.trim()) { + // Add content lines (skip empty lines at the beginning) + if (contentLines.length > 0 || line.trim() !== "") { + contentLines.push(line) } } } - return entries.slice(0, 15) // Latest 15 entries + // Don't forget the last entry + if (currentEntry && contentLines.length > 0) { + const rawContent = contentLines.join("\n").trim() + currentEntry.content = formatContentForRSS(rawContent) + if (currentEntry.version && currentEntry.date && currentEntry.title) { + entries.push(currentEntry as ChangelogEntry) + } + } + + return entries.slice(0, 20) // Latest 20 entries } catch (error) { console.error("Error parsing changelog:", error) return [] @@ -87,7 +134,7 @@ export async function GET() { (entry) => ` ${entry.title} - 500 ? "..." : ""}]]> + 1000 ? entry.content.substring(0, 1000) + "..." : entry.content}]]> ${entry.url} ${entry.url} ${new Date(entry.date).toUTCString()}