From 6f9defe29a02ecacd65ed38afcde7b14edad2053 Mon Sep 17 00:00:00 2001 From: "sirin.ph" Date: Thu, 20 Nov 2025 17:04:57 +0700 Subject: [PATCH] initial commit --- .gitignore | 24 + App.tsx | 267 ++++++++ README.md | 20 + STYLE_GUIDE.md | 79 +++ components/ChatWidget.tsx | 110 ++++ components/MatrixViz.tsx | 164 +++++ components/TerminalBlock.tsx | 94 +++ index.html | 66 ++ index.tsx | 15 + metadata.json | 5 + package.json | 23 + pages/BlogPost.tsx | 444 +++++++++++++ pages/HireUs.tsx | 104 ++++ pages/Home.tsx | 699 +++++++++++++++++++++ pages/Playground.tsx | 329 ++++++++++ pages/Research.tsx | 269 ++++++++ pages/Services.tsx | 198 ++++++ pnpm-lock.yaml | 1138 ++++++++++++++++++++++++++++++++++ tsconfig.json | 29 + vite.config.ts | 23 + 20 files changed, 4100 insertions(+) create mode 100644 .gitignore create mode 100644 App.tsx create mode 100644 README.md create mode 100644 STYLE_GUIDE.md create mode 100644 components/ChatWidget.tsx create mode 100644 components/MatrixViz.tsx create mode 100644 components/TerminalBlock.tsx create mode 100644 index.html create mode 100644 index.tsx create mode 100644 metadata.json create mode 100644 package.json create mode 100644 pages/BlogPost.tsx create mode 100644 pages/HireUs.tsx create mode 100644 pages/Home.tsx create mode 100644 pages/Playground.tsx create mode 100644 pages/Research.tsx create mode 100644 pages/Services.tsx create mode 100644 pnpm-lock.yaml create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/App.tsx b/App.tsx new file mode 100644 index 0000000..00e6ab8 --- /dev/null +++ b/App.tsx @@ -0,0 +1,267 @@ +import React, { useContext, useState } from "react"; +import { HashRouter, Routes, Route, Link, useLocation } from "react-router-dom"; +import { Home } from "./pages/Home"; +import { BlogPost } from "./pages/BlogPost"; +import { Research } from "./pages/Research"; +import { Services } from "./pages/Services"; +import { HireUs } from "./pages/HireUs"; +import { Playground } from "./pages/Playground"; +import { ChatWidget } from "./components/ChatWidget"; +import { Cpu, Menu, X, Globe, Terminal } from "lucide-react"; + +// --- Language Context --- +type Language = "en" | "th"; + +interface LanguageContextType { + language: Language; + toggleLanguage: () => void; +} + +export const LanguageContext = React.createContext({ + language: "en", + toggleLanguage: () => {}, +}); + +export const useLanguage = () => useContext(LanguageContext); + +// --- Navigation --- +const Navigation: React.FC = () => { + const [isOpen, setIsOpen] = useState(false); + const location = useLocation(); + const { language, toggleLanguage } = useLanguage(); + + const isActive = (path: string) => { + if (path === "/research" && location.pathname.startsWith("/research")) { + return "text-ink font-semibold"; + } + return location.pathname === path + ? "text-ink font-semibold" + : "text-subtle hover:text-ink transition-colors"; + }; + + return ( + + ); +}; + +const Footer: React.FC = () => { + const { language } = useLanguage(); + return ( +
+
+
+ + Pradit + +

+ {language === "en" + ? "We build production-grade AI systems. No hype, just engineering. Specializing in LLM integration, custom evaluations, and scalable architecture." + : "เราสร้างระบบ AI ระดับใช้งานจริง เน้นวิศวกรรมไม่เน้นโฆษณา เชี่ยวชาญด้านการรวมระบบ LLM, การประเมินผล และสถาปัตยกรรมที่ปรับขนาดได้"} +

+
+
+

+ Offerings +

+
    +
  • + + MVP Development + +
  • +
  • + + System Audits + +
  • +
  • + + Custom Integration + +
  • +
+
+
+

+ Connect +

+ +
+
+
+ ); +}; + +export default function App() { + const [language, setLanguage] = useState("en"); + + const toggleLanguage = () => { + setLanguage((prev) => (prev === "en" ? "th" : "en")); + }; + + return ( + + +
+ +
+ + } /> + } /> + } + /> + } /> + } /> + } /> + +
+
+ +
+
+
+ ); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..4450ca2 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +
+GHBanner +
+ +# Run and deploy your AI Studio app + +This contains everything you need to run your app locally. + +View your app in AI Studio: https://ai.studio/apps/drive/1lSdt9DucwKsU3WO83AD5ieLoPx_QLmVF + +## Run Locally + +**Prerequisites:** Node.js + + +1. Install dependencies: + `npm install` +2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key +3. Run the app: + `npm run dev` diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md new file mode 100644 index 0000000..f210dce --- /dev/null +++ b/STYLE_GUIDE.md @@ -0,0 +1,79 @@ +# Pradit (ประดิษฐ์) Design System + +**Philosophy:** "Engineer First, Sales Second." +The aesthetic of Pradit is minimal, precise, and reminiscent of technical documentation or a high-end code editor. It avoids gradients, heavy drop shadows, and stock photography in favor of clean typography, terminal-inspired visual elements, and high information density. + +--- + +## 1. Color Palette + +We use a strict semantic color system. + +| Token | Hex | Usage | +| :---------- | :-------- | :------------------------------------------------------------------------------- | +| **Paper** | `#fdfdfd` | Main background. Slightly off-white to reduce eye strain. | +| **Ink** | `#111111` | Primary text, strong headers, active states. | +| **Subtle** | `#666666` | Secondary text, metadata, descriptions. | +| **Accent** | `#2563eb` | Primary action color (Blue-600). Used sparingly for links and active indicators. | +| **Code Bg** | `#1e1e1e` | Dark background for terminal blocks and code snippets (VS Code Dark default). | + +--- + +## 2. Typography + +We use a tri-font stack to separate functional UI from reading content. + +### Serif: Merriweather + +_Usage:_ Long-form text, blog posts, titles, quotes. +_Why:_ Establishes authority and academic rigor. + +### Sans-Serif: Inter + +_Usage:_ UI labels, navigation, buttons, short descriptions. +_Why:_ Clean, legible, and modern. + +### Monospace: Fira Code + +_Usage:_ Code snippets, terminal inputs, tags, dates, metadata. +_Why:_ Signals technical precision. + +--- + +## 3. UI Patterns & Components + +### The "Terminal" Aesthetic + +Elements that represent "work" (code, search, inputs) should mimic terminal interfaces. + +- **Inputs:** No rounded corners (or very slight `rounded-sm`). Bottom borders or dark backgrounds. +- **Prompt:** Use `>` or `$` prefixes for input labels. + +### Borders over Shadows + +Use 1px borders (`border-gray-200`) to define hierarchy. Shadows should be subtle and used only for floating elements (modals, sticky headers). + +### Buttons + +- **Primary:** `bg-ink` text-white, `rounded-sm`. Uppercase text, tracking-widest. +- **Secondary:** `border border-gray-200` text-ink. +- **Tags/Pills:** `rounded-full`, `uppercase`, `text-xs`, `font-bold`. + +### Interactive Visualizations + +Do not use static images for technical concepts. Use code blocks (`TerminalBlock`) or interactive React components (`MatrixViz`) that allow the user to manipulate variables. + +--- + +## 4. Layout Grid + +- **Container:** Max-width 7xl (`max-w-7xl`) centered. +- **Spacing:** Generous vertical whitespace (`py-24`). +- **Columns:** 12-column grid for complex layouts (Sidebar takes 3, Content takes 6-9). + +--- + +## 5. Voice & Tone + +- **English:** Professional, concise, jargon-correct. No marketing fluff. +- **Thai:** Formal but accessible. Use English terms for specific technical concepts (e.g., "Fine-tuning", "Latency") where a Thai translation would be ambiguous. diff --git a/components/ChatWidget.tsx b/components/ChatWidget.tsx new file mode 100644 index 0000000..517b83f --- /dev/null +++ b/components/ChatWidget.tsx @@ -0,0 +1,110 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { MessageSquare, X, Send, Terminal } from 'lucide-react'; + +interface Message { + id: string; + text: string; + sender: 'user' | 'bot'; + timestamp: Date; +} + +export const ChatWidget: React.FC = () => { + const [isOpen, setIsOpen] = useState(false); + const [messages, setMessages] = useState([ + { id: '1', text: "System online. I am Pradit's automated assistant. How can I help you engineer your next AI system?", sender: 'bot', timestamp: new Date() } + ]); + const [input, setInput] = useState(""); + const bottomRef = useRef(null); + + useEffect(() => { + if (isOpen) { + bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); + } + }, [messages, isOpen]); + + const handleSend = async (e: React.FormEvent) => { + e.preventDefault(); + if (!input.trim()) return; + + const userMsg: Message = { id: Date.now().toString(), text: input, sender: 'user', timestamp: new Date() }; + setMessages(prev => [...prev, userMsg]); + setInput(""); + + // Mock response + setTimeout(() => { + const botMsg: Message = { + id: (Date.now() + 1).toString(), + text: "ACK. Request received. Our engineers are currently optimizing a training run. Please visit 'Hire Us' to schedule a deep dive consultation.", + sender: 'bot', + timestamp: new Date() + }; + setMessages(prev => [...prev, botMsg]); + }, 800); + }; + + return ( +
+ {/* Chat Window */} + {isOpen && ( +
+ {/* Header */} +
+
+
+ +
+ Pradit/Assistant +
+ +
+ + {/* Messages */} +
+ {messages.map((msg) => ( +
+
+ {msg.text} +
+
+ ))} +
+
+ + {/* Input */} +
+
+ {">"} + setInput(e.target.value)} + placeholder="Type your query..." + className="flex-grow bg-transparent text-sm outline-none text-ink placeholder:text-gray-400 font-sans" + /> +
+ +
+
+ )} + + {/* Toggle Button */} + {!isOpen && ( + + )} +
+ ); +}; \ No newline at end of file diff --git a/components/MatrixViz.tsx b/components/MatrixViz.tsx new file mode 100644 index 0000000..59eff53 --- /dev/null +++ b/components/MatrixViz.tsx @@ -0,0 +1,164 @@ +import React, { useState } from "react"; +import { Sliders } from "lucide-react"; + +export const MatrixViz: React.FC = () => { + const [rank, setRank] = useState(4); + + // Constants for visualization scaling + const d = 16; // Hidden dimension simulation + const k = 16; // Output dimension simulation + + // Calculate imaginary parameters based on user slider + // Assuming a real model like Llama-7B, d_model might be 4096. + // We scale the display numbers to look realistic. + const realD = 4096; + const realK = 4096; + + const paramsFull = realD * realK; + const paramsLoRA = realD * rank + rank * realK; + const reduction = ((1 - paramsLoRA / paramsFull) * 100).toFixed(2); + + // Helper to generate random opacity blue blocks + const renderGrid = ( + rows: number, + cols: number, + colorBase: string, + label: string, + ) => { + return ( +
+ {Array.from({ length: rows * cols }).map((_, i) => ( +
+ ))} + + {/* Matrix Label Overlay */} +
+ {label} +
+
+ ); + }; + + return ( +
+
+
+

+ + Interactive Decomposition +

+

+ Adjust the Rank (r) to see how LoRA decomposes the weight update + matrix into two smaller dense matrices. +

+
+ +
+ + setRank(parseInt(e.target.value))} + className="w-32 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-accent" + /> +
+
+ +
+ {/* Matrix B (d x r) */} +
+
+ B +
+ {renderGrid(16, rank, "#93c5fd", `${realD} × ${rank}`)} +
+ +
×
+ + {/* Matrix A (r x k) */} +
+
+ A +
+ {renderGrid(rank, 16, "#2563eb", `${rank} × ${realK}`)} +
+ + {/* Arrow */} +
+ + {/* Matrix Delta W */} +
+
+ ΔW +
+ {renderGrid(16, 16, "#4ade80", `${realD} × ${realK}`)} +
+
+ + {/* Math Dashboard */} +
+
+
+ Trainable Params (LoRA) +
+
+ {paramsLoRA.toLocaleString()} +
+
+ ({realD}×{rank}) + ({rank}×{realK}) +
+
+ +
+
+ Trainable Params (Full) +
+
+ {paramsFull.toLocaleString()} +
+
+ {realD} × {realK} +
+
+ +
+
+ Memory Reduction +
+
+ {reduction}% +
+
+ More VRAM for batch size +
+
+
+
+ ); +}; diff --git a/components/TerminalBlock.tsx b/components/TerminalBlock.tsx new file mode 100644 index 0000000..654fe1f --- /dev/null +++ b/components/TerminalBlock.tsx @@ -0,0 +1,94 @@ +import React, { useState, useEffect } from "react"; + +interface TerminalBlockProps { + title?: string; + lines: string[]; + className?: string; + typingEffect?: boolean; +} + +export const TerminalBlock: React.FC = ({ + title = "bash", + lines, + className, + typingEffect = false, +}) => { + const [displayedLines, setDisplayedLines] = useState( + typingEffect ? [] : lines, + ); + const [currentLineIndex, setCurrentLineIndex] = useState(0); + const [currentCharIndex, setCurrentCharIndex] = useState(0); + + useEffect(() => { + if (!typingEffect) return; + + if (currentLineIndex < lines.length) { + const currentLineFull = lines[currentLineIndex]; + + if (currentCharIndex < currentLineFull.length) { + const timeout = setTimeout( + () => { + setDisplayedLines((prev) => { + const newLines = [...prev]; + if (newLines[currentLineIndex] === undefined) { + newLines[currentLineIndex] = currentLineFull[currentCharIndex]; + } else { + newLines[currentLineIndex] += currentLineFull[currentCharIndex]; + } + return newLines; + }); + setCurrentCharIndex((prev) => prev + 1); + }, + 15 + Math.random() * 20, + ); // Random variance for realism + + return () => clearTimeout(timeout); + } else { + // Line finished, wait a bit then move to next + const timeout = setTimeout(() => { + setCurrentLineIndex((prev) => prev + 1); + setCurrentCharIndex(0); + }, 300); + return () => clearTimeout(timeout); + } + } + }, [typingEffect, lines, currentLineIndex, currentCharIndex]); + + return ( +
+
+
+
+
+
+
+
{title}
+
+
+ {displayedLines.map((line, idx) => ( +
+ {line.startsWith("$") ? ( + {line} + ) : line.startsWith(">") ? ( + {line} + ) : line.startsWith("#") ? ( + {line} + ) : ( + {line} + )} +
+ ))} + {/* Cursor */} + {typingEffect && currentLineIndex < lines.length && ( +
+ )} + {/* Static Cursor when done */} + {(!typingEffect || currentLineIndex >= lines.length) && ( +
+ )} +
+
+ ); +}; diff --git a/index.html b/index.html new file mode 100644 index 0000000..3c3116e --- /dev/null +++ b/index.html @@ -0,0 +1,66 @@ + + + + + + Pradit | AI Consultancy + + + + + + + + +
+ + + diff --git a/index.tsx b/index.tsx new file mode 100644 index 0000000..6ca5361 --- /dev/null +++ b/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const rootElement = document.getElementById('root'); +if (!rootElement) { + throw new Error("Could not find root element to mount to"); +} + +const root = ReactDOM.createRoot(rootElement); +root.render( + + + +); \ No newline at end of file diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..67ba22f --- /dev/null +++ b/metadata.json @@ -0,0 +1,5 @@ +{ + "name": "Pradit", + "description": "A high-end, academic-style technical consultancy website featuring technical deep dives and clear service offerings.", + "requestFramePermissions": [] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0bcb8c8 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "pradit", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.9.6", + "lucide-react": "^0.554.0" + }, + "devDependencies": { + "@types/node": "^22.14.0", + "@vitejs/plugin-react": "^5.0.0", + "typescript": "~5.8.2", + "vite": "^6.2.0" + } +} diff --git a/pages/BlogPost.tsx b/pages/BlogPost.tsx new file mode 100644 index 0000000..d678af9 --- /dev/null +++ b/pages/BlogPost.tsx @@ -0,0 +1,444 @@ +import React, { useState, useEffect } from "react"; +import { MatrixViz } from "../components/MatrixViz"; +import { useLanguage } from "../App"; +import { + Play, + Pause, + FileText, + Headphones, + Zap, + Volume2, + X, +} from "lucide-react"; + +export const BlogPost: React.FC = () => { + const { language } = useLanguage(); + const [activeSection, setActiveSection] = useState("intro"); + const [activeTab, setActiveTab] = useState<"read" | "listen">("read"); + const [isPlaying, setIsPlaying] = useState(false); + const [showMiniPlayer, setShowMiniPlayer] = useState(false); + + // Simple scroll spy logic + useEffect(() => { + const handleScroll = () => { + const sections = ["intro", "methods", "results", "discussion"]; + for (const section of sections) { + const element = document.getElementById(section); + if (element) { + const rect = element.getBoundingClientRect(); + if (rect.top >= 0 && rect.top <= 300) { + setActiveSection(section); + break; + } + } + } + }; + window.addEventListener("scroll", handleScroll); + return () => window.removeEventListener("scroll", handleScroll); + }, []); + + const handleMainPlayPause = () => { + const newState = !isPlaying; + setIsPlaying(newState); + if (newState) { + setShowMiniPlayer(true); + } + }; + + const content = { + en: { + title: "LoRA Without Regret", + subtitle: "John Schulman in collaboration with Pradit", + date: "Sep 29, 2025", + tldr_title: "Executive Summary (TL;DR)", + tldr_text: + "Low-Rank Adaptation (LoRA) is a technique to fine-tune large models efficiently. Our research confirms that while LoRA saves 90% of memory, it can match full fine-tuning performance only if the rank (r) is sufficiently high and alpha scaling is tuned correctly. Ideal for post-training but not pre-training.", + tabs: { read: "Read Article", listen: "Listen (TTS)" }, + intro_1: + "Today’s leading language models contain upwards of a trillion parameters, pretrained on tens of trillions of tokens. Base model performance keeps improving with scale, as these trillions are necessary for learning and representing all the patterns in written-down human knowledge.", + intro_2: + "In contrast, post-training involves smaller datasets and generally focuses on narrower domains of knowledge and ranges of behavior. It seems wasteful to use a terabit of weights to represent updates from a gigabit or megabit of training data. This intuition has motivated parameter efficient fine-tuning (PEFT), which adjusts a large network by updating a much smaller set of parameters.", + method_title: "The Method", + method_1: + "The leading PEFT method is low-rank adaptation, or LoRA. LoRA replaces each weight matrix W from the original model with a modified version W' = W + γBA, where B and A are matrices that together have far fewer parameters than W, and γ is a constant scaling factor.", + method_2: + "In effect, LoRA creates a low-dimensional representation of the updates imparted by fine-tuning. LoRA may offer advantages in the cost and speed of post-training, and there are also a few operational reasons to prefer it to full fine-tuning.", + results_title: "Operational Advantages", + results_list: [ + { + title: "Multi-tenant serving", + text: "Since LoRA trains an adapter (i.e., the A and B matrices) while keeping the original weights unchanged, a single inference server can keep many adapters in memory.", + }, + { + title: "Layout size for training", + text: "FullFT usually requires an order of magnitude more accelerators than sampling from the same model does.", + }, + { + title: "Ease of loading", + text: "With fewer weights to store, LoRA adapters are fast and easy to set up or transfer between machines.", + }, + ], + conclusion_title: "Conclusion", + conclusion_text: + "The question remains: can LoRA match the performance of full fine-tuning? Our internal benchmarks suggest yes, provided rank scaling is carefully managed.", + nav: { + intro: "Introduction", + methods: "Methods", + results: "Results", + discussion: "Conclusion", + }, + now_playing: "Now Playing", + paused: "Paused", + transcript_title: "Transcript", + }, + th: { + title: "LoRA โดยไม่เสียใจ", + subtitle: "John Schulman ร่วมกับ Pradit (ประดิษฐ์)", + date: "29 กันยายน 2025", + tldr_title: "บทสรุปผู้บริหาร (TL;DR)", + tldr_text: + "Low-Rank Adaptation (LoRA) เป็นเทคนิคการปรับแต่งโมเดลขนาดใหญ่ที่มีประสิทธิภาพ งานวิจัยของเรายืนยันว่าแม้ LoRA จะประหยัดหน่วยความจำได้ถึง 90% แต่จะให้ผลลัพธ์เทียบเท่าการ Fine-tune แบบเต็มรูปแบบได้ก็ต่อเมื่อค่า Rank (r) สูงเพียงพอและมีการปรับค่า Alpha อย่างถูกต้อง เหมาะสำหรับขั้นตอน Post-training แต่ไม่เหมาะกับ Pre-training", + tabs: { read: "อ่านบทความ", listen: "ฟังเสียงบรรยาย" }, + intro_1: + "โมเดลภาษาชั้นนำในปัจจุบันมีพารามิเตอร์มากกว่าล้านล้านตัว ผ่านการฝึกฝนบนข้อมูลมหาศาล ประสิทธิภาพของโมเดลพื้นฐานดีขึ้นเรื่อยๆ ตามขนาด ซึ่งจำเป็นสำหรับการเรียนรู้รูปแบบความรู้ทั้งหมดของมนุษย์", + intro_2: + "ในทางตรงกันข้าม การฝึกฝนหลังเสร็จสิ้น (Post-training) มักใช้ชุดข้อมูลขนาดเล็กและเน้นขอบเขตความรู้ที่แคบกว่า ดูเหมือนจะสิ้นเปลืองที่จะใช้น้ำหนักระดับเทราบิตเพื่อแทนการอัปเดตจากข้อมูลเพียงกิกะบิต แนวคิดนี้จึงนำไปสู่การปรับแต่งแบบประหยัดพารามิเตอร์ (PEFT)", + method_title: "วิธีการ", + method_1: + "วิธี PEFT ชั้นนำคือ Low-rank adaptation หรือ LoRA ซึ่งแทนที่เมทริกซ์น้ำหนัก W แต่ละตัวด้วยเวอร์ชันแก้ไข W' = W + γBA โดยที่ B และ A เป็นเมทริกซ์ที่มีพารามิเตอร์น้อยกว่า W มาก", + method_2: + "โดยสรุป LoRA สร้างตัวแทนมิติที่ต่ำกว่าของการอัปเดตที่เกิดจากการ Fine-tuning LoRA อาจมีข้อได้เปรียบในด้านต้นทุนและความเร็ว และยังมีเหตุผลด้านการปฏิบัติงานที่ทำให้เป็นที่นิยมมากกว่า Full Fine-tuning", + results_title: "ข้อได้เปรียบด้านการปฏิบัติงาน", + results_list: [ + { + title: "การให้บริการแบบ Multi-tenant", + text: "เนื่องจาก LoRA ฝึกฝน Adapter (เมทริกซ์ A และ B) โดยไม่เปลี่ยนน้ำหนักเดิม เซิร์ฟเวอร์เดียวจึงสามารถเก็บ Adapter หลายตัวในหน่วยความจำได้", + }, + { + title: "ขนาด Layout สำหรับการฝึก", + text: "FullFT มักต้องการตัวเร่งความเร็ว (GPU/TPU) มากกว่าการสุ่มตัวอย่างจากโมเดลเดียวกันถึงหนึ่งระดับ (Order of magnitude)", + }, + { + title: "ความง่ายในการโหลด", + text: "ด้วยน้ำหนักที่ต้องเก็บน้อยกว่า LoRA adapters จึงตั้งค่าและโอนย้ายระหว่างเครื่องได้รวดเร็ว", + }, + ], + conclusion_title: "บทสรุป", + conclusion_text: + "คำถามยังคงอยู่: LoRA สามารถทำงานได้เทียบเท่ากับ Full Fine-tuning หรือไม่? การทดสอบภายในของเราชี้ว่า 'ได้' หากมีการจัดการ Rank scaling อย่างระมัดระวัง", + nav: { + intro: "บทนำ", + methods: "วิธีการ", + results: "ผลลัพธ์", + discussion: "บทสรุป", + }, + now_playing: "กำลังเล่น", + paused: "หยุดชั่วคราว", + transcript_title: "คำบรรยาย", + }, + }; + + const t = content[language]; + + return ( +
+ {/* Article Header */} +
+

+ {t.title} +

+
+ {t.subtitle} +
+ + + {/* View Tabs */} +
+
+ + +
+
+
+ + {/* TL;DR Section */} +
+
+
+
+
+ +
+
+

+ {t.tldr_title} +

+

+ {t.tldr_text} +

+
+
+
+
+ + {activeTab === "listen" ? ( + /* Voice Interface */ +
+
+ {/* Left: Sticky Player */} +
+
+
+ {isPlaying && ( + + )} + +
+ +

+ {t.title} +

+

+ Voice: Gemini 2.5 Flash TTS +

+ + {/* Fake Waveform */} +
+ {[...Array(30)].map((_, i) => ( +
+ ))} +
+ +
+ + + +
+
+
+ + {/* Right: Scrollable Transcript */} +
+
+ {t.transcript_title} +
+
+

{t.intro_1}

+

{t.intro_2}

+
+

+ {t.method_title} +

+

{t.method_1}

+

{t.method_2}

+
+

+ {t.results_title} +

+ {t.results_list.map((item, idx) => ( +

+ {item.title}:{" "} + {item.text} +

+ ))} +
+

{t.conclusion_text}

+
+
+
+
+ ) : ( + /* Read Interface */ +
+ {/* Left Sidebar - TOC */} + + + {/* Main Content */} +
+ + +
+

+ {t.intro_1} +

+

{t.intro_2}

+
+ +
+

+ {t.method_title} +

+

{t.method_1}

+

{t.method_2}

+
+ +
+

+ {t.results_title} +

+
    + {t.results_list.map((item, idx) => ( +
  • + {item.title}.{" "} + {item.text} +
  • + ))} +
+
+ +
+

+ {t.conclusion_title} +

+

{t.conclusion_text}

+
+
+ + {/* Right Sidebar - Footnotes */} + +
+ )} + + {/* Mini Player Overlay - Persistent if showMiniPlayer is true */} + {showMiniPlayer && activeTab === "read" && ( +
+
+
+
+ {isPlaying && ( + + )} + +
+
+ + {isPlaying ? t.now_playing : t.paused} + + + {t.title} + +
+
+ +
+ + + + +
+ + +
+
+
+ )} +
+ ); +}; diff --git a/pages/HireUs.tsx b/pages/HireUs.tsx new file mode 100644 index 0000000..8e6c833 --- /dev/null +++ b/pages/HireUs.tsx @@ -0,0 +1,104 @@ + +import React from 'react'; +import { TerminalBlock } from '../components/TerminalBlock'; +import { Mail, MessageSquare, Code } from 'lucide-react'; + +export const HireUs: React.FC = () => { + return ( +
+
+ + {/* Left Column: Context */} +
+

+ Work With Us +

+

+ We are currently accepting new engagements for Q4 2025. We look for partners who have clear technical hurdles in their AI roadmap, rather than open-ended exploration. +

+ +
+
+

Engagement Models

+
    +
  • +

    Strategic Sprint (4-6 Weeks)

    +

    Best for MVPs, Feasibility Studies, and Architecture Audits. We ship a working artifact and a technical roadmap.

    +
  • +
  • +

    Quarterly Retainer

    +

    For teams needing ongoing specialized ML expertise to augment their core engineering staff. Includes weekly syncs and code review.

    +
  • +
+
+ +
+

What we need from you

+
+

+ To ensure we are a good fit, please provide technical details in your inquiry. + Mention your current stack (e.g., AWS, Python, Vercel), specific model constraints, and the primary metric you are trying to improve (latency, accuracy, cost). +

+
+
+
+
+ + {/* Right Column: Form */} +
+
e.preventDefault()}> +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+
+ ); +}; \ No newline at end of file diff --git a/pages/Home.tsx b/pages/Home.tsx new file mode 100644 index 0000000..11b0076 --- /dev/null +++ b/pages/Home.tsx @@ -0,0 +1,699 @@ +import React, { useState } from "react"; +import { TerminalBlock } from "../components/TerminalBlock"; +import { + ArrowRight, + Activity, + Search, + Database, + ChevronRight, + GitCommit, + BarChart, + Server, + Shield, + Box, + Cloud, + Layers, + Cpu, + Lock, + X, + Zap, + Globe, +} from "lucide-react"; +import { Link } from "react-router-dom"; +import { useLanguage } from "../App"; + +// Type definition for Projects +interface ProjectData { + id: string; + category: string; + title: string; + shortDesc: string; + fullDesc: string; + metrics: { label: string; value: string }[]; + stack: string[]; + architecture: string; + challenge: string; +} + +export const Home: React.FC = () => { + const { language } = useLanguage(); + const [selectedProject, setSelectedProject] = useState( + null, + ); + + const content = { + en: { + new_research: "New Research: LoRA Without Regret", + hero_title: "Engineering Intelligence.", + hero_subtitle: + "We bridge the gap between research papers and production environments. Specialized consulting for LLM infrastructure, evaluation pipelines, and custom model adaptation.", + btn_services: "View Services", + btn_research: "Read Research", + latest_thinking: "Latest Thinking", + view_archive: "View Archive", + lora_desc: + "Fine-tuning large models is expensive. Low-rank adaptation (LoRA) promises efficiency, but does it sacrifice performance? Our deep dive into rank scaling and matrix initialization.", + technical_deep_dive: "Technical Deep Dive", + expertise_title: "Our Expertise", + process_title: "The Pipeline", + process_desc: + "We don't just write code; we engineer systems. Our engagement process is designed for transparency and velocity.", + projects_title: "Selected Deployments", + projects_desc: + "We don't sell hours. We sell shipped, production-grade systems. Click on a project to view the architecture.", + trusted_stack: "Built with Production Standards", + modal_stack: "Tech Stack", + modal_impact: "Business Impact", + modal_arch: "Architecture Highlight", + modal_challenge: "The Challenge", + close: "Close", + services: { + mvp: { + title: "MVP & Prototyping", + desc: "From concept to deployed model in weeks. We build robust POCs using the latest foundation models (Gemini, Claude, OpenAI) to validate business value before heavy investment.", + }, + audit: { + title: "System Audit", + desc: "Why is your RAG pipeline hallucinating? We perform deep architectural audits, evaluating retrieval quality, prompt efficacy, and security vulnerabilities.", + }, + integration: { + title: "Custom Integration", + desc: "Fine-tuning and integrating open-weights models into your secure infrastructure. We handle the MLOps so you own your weights and your data.", + }, + }, + learn_more: "Learn more", + process_steps: [ + { + step: "01", + title: "Discovery & Audit", + desc: "We define the metric that matters. Is it latency? Accuracy? Cost?", + }, + { + step: "02", + title: "Prototyping", + desc: "Rapid iteration using state-of-the-art models to validate feasibility.", + }, + { + step: "03", + title: "Evaluation (Evals)", + desc: "We build a custom test suite (Pass@k, RAGAS) before we ship.", + }, + { + step: "04", + title: "Production", + desc: "Containerization, CI/CD pipelines, and observability setup.", + }, + ], + stack: { + infra: "Infrastructure", + orchestration: "Orchestration", + inference: "Inference & Serving", + data: "Data & Vector Ops", + }, + projects: [ + { + id: "compliance", + category: "FinTech / Legal", + title: "ComplianceGuard AI", + shortDesc: + "Automated regulatory compliance checking for a Tier-1 bank. Reduced manual review time by 85% using a secure RAG pipeline.", + fullDesc: + "We architected a secure, on-premise Retrieval Augmented Generation (RAG) system that ingests thousands of changing regulatory documents (PDFs) and cross-references them with loan applications in real-time.", + challenge: + "The client was spending 2000+ man-hours monthly manually checking loan applications against constantly updating Bank of Thailand regulations. Privacy requirements prevented using public APIs.", + architecture: + 'Hybrid-cloud setup. Sensitive data stays on-prem (OpenShift) using a fine-tuned Llama-3-70B for inference. Regulatory documents are indexed in Weaviate. LangChain orchestrates the "Reasoning" step to cite specific regulatory clauses.', + metrics: [ + { label: "Review Time", value: "-85%" }, + { label: "False Positives", value: "< 2%" }, + { label: "Cost Saving", value: "$45k/mo" }, + ], + stack: [ + "Llama 3 70B", + "Weaviate", + "OpenShift", + "LangChain", + "Python", + ], + }, + { + id: "retail", + category: "E-Commerce", + title: "OmniFlow Agentic Router", + shortDesc: + "High-throughput customer support agent handling 50k+ daily tickets. Deflects 92% of queries with sub-2s latency.", + fullDesc: + "A sophisticated multi-agent system that acts as the first line of defense for a major e-commerce platform. It uses tool-calling to actually perform actions (check status, process refund) rather than just chatting.", + challenge: + 'During "11.11" sales events, support volume spikes 10x. Traditional chatbots were too rigid, and human agents were overwhelmed. The system needed to be autonomous but safe.', + architecture: + 'We built a Router Agent using GPT-4o-mini for speed. It classifies intent and routes to specialized Sub-Agents (Refund Agent, Logistics Agent). We implemented a "Human-in-the-loop" handover protocol for low-confidence scores.', + metrics: [ + { label: "Deflection Rate", value: "92%" }, + { label: "Avg Response", value: "1.2s" }, + { label: "CSAT Score", value: "4.8/5" }, + ], + stack: ["GPT-4o", "Redis", "FastAPI", "Kubernetes", "Postgres"], + }, + ], + }, + th: { + new_research: "งานวิจัยใหม่: LoRA โดยไม่เสียใจ", + hero_title: "วิศวกรรมแห่งปัญญาประดิษฐ์", + hero_subtitle: + "เราเชื่อมช่องว่างระหว่างงานวิจัยทางวิชาการและการใช้งานจริง เชี่ยวชาญด้านโครงสร้างพื้นฐาน LLM, การประเมินผล และการปรับแต่งโมเดลตามความต้องการ", + btn_services: "ดูบริการของเรา", + btn_research: "อ่านงานวิจัย", + latest_thinking: "แนวคิดล่าสุด", + view_archive: "ดูบทความทั้งหมด", + lora_desc: + "การ Fine-tune โมเดลขนาดใหญ่มีค่าใช้จ่ายสูง LoRA สัญญาว่าจะเพิ่มประสิทธิภาพ แต่จะลดคุณภาพหรือไม่? เจาะลึกเรื่อง Rank scaling และการเริ่มต้น Matrix", + technical_deep_dive: "เจาะลึกทางเทคนิค", + expertise_title: "ความเชี่ยวชาญของเรา", + process_title: "กระบวนการทำงาน", + process_desc: + "เราไม่ได้แค่เขียนโค้ด แต่เราออกแบบระบบ กระบวนการของเราเน้นความโปร่งใสและความรวดเร็ว", + projects_title: "ผลงานที่ผ่านมา", + projects_desc: + "เราไม่ได้ขายชั่วโมงการทำงาน แต่เราส่งมอบระบบที่ใช้งานได้จริง คลิกที่โปรเจกต์เพื่อดูสถาปัตยกรรม", + trusted_stack: "สร้างด้วยมาตรฐานระดับ Production", + modal_stack: "Tech Stack", + modal_impact: "ผลลัพธ์ทางธุรกิจ", + modal_arch: "จุดเด่นของสถาปัตยกรรม", + modal_challenge: "ความท้าทาย", + close: "ปิด", + services: { + mvp: { + title: "MVP และต้นแบบ", + desc: "จากแนวคิดสู่โมเดลที่ใช้งานได้จริงในไม่กี่สัปดาห์ เราสร้าง POC ที่แข็งแกร่งด้วยโมเดลล่าสุด (Gemini, Claude, OpenAI) เพื่อตรวจสอบความคุ้มค่าก่อนการลงทุนจริง", + }, + audit: { + title: "ตรวจสอบระบบ", + desc: "ทำไมระบบ RAG ของคุณถึงให้ข้อมูลผิด? เราตรวจสอบสถาปัตยกรรมอย่างละเอียด ประเมินคุณภาพการสืบค้น และช่องโหว่ด้านความปลอดภัย", + }, + integration: { + title: "การรวมระบบตามสั่ง", + desc: "ปรับแต่ง (Fine-tune) และรวมโมเดล Open-weights เข้ากับโครงสร้างพื้นฐานที่ปลอดภัยของคุณ เราดูแล MLOps เพื่อให้คุณเป็นเจ้าของข้อมูลและโมเดลอย่างแท้จริง", + }, + }, + learn_more: "เรียนรู้เพิ่มเติม", + process_steps: [ + { + step: "01", + title: "ค้นหา & ตรวจสอบ", + desc: "เรากำหนดตัวชี้วัดที่สำคัญที่สุด ไม่ว่าจะเป็น ความหน่วง ความแม่นยำ หรือต้นทุน", + }, + { + step: "02", + title: "สร้างต้นแบบ", + desc: "ทำซ้ำอย่างรวดเร็วโดยใช้โมเดลล่าสุดเพื่อตรวจสอบความเป็นไปได้", + }, + { + step: "03", + title: "การประเมินผล (Evals)", + desc: "เราสร้างชุดทดสอบเฉพาะ (Pass@k, RAGAS) ก่อนส่งมอบงาน", + }, + { + step: "04", + title: "Production", + desc: "การทำ Containerization, ระบบ CI/CD และการติดตั้งระบบสังเกตการณ์", + }, + ], + stack: { + infra: "Infrastructure", + orchestration: "Orchestration", + inference: "Inference & Serving", + data: "Data & Vector Ops", + }, + projects: [ + { + id: "compliance", + category: "FinTech / Legal", + title: "ComplianceGuard AI", + shortDesc: + "ระบบตรวจสอบการปฏิบัติตามกฎระเบียบอัตโนมัติสำหรับธนาคารชั้นนำ ลดเวลาการตรวจสอบด้วยคนลง 85% โดยใช้ RAG pipeline ที่ปลอดภัย", + fullDesc: + "เราออกแบบระบบ Retrieval Augmented Generation (RAG) ภายในองค์กรที่ปลอดภัย ซึ่งนำเข้าเอกสารกฎระเบียบหลายพันฉบับที่เปลี่ยนแปลงตลอดเวลา และตรวจสอบเทียบกับคำขอสินเชื่อแบบเรียลไทม์", + challenge: + "ลูกค้าใช้เวลาคนทำงานกว่า 2,000 ชั่วโมงต่อเดือนในการตรวจสอบคำขอสินเชื่อด้วยตนเองเทียบกับกฎระเบียบธนาคารแห่งประเทศไทย ข้อกำหนดด้านความเป็นส่วนตัวไม่อนุญาตให้ใช้ Public API", + architecture: + 'ระบบ Hybrid-cloud ข้อมูลสำคัญอยู่ภายในองค์กร (OpenShift) โดยใช้ Llama-3-70B ที่ปรับแต่งแล้ว เอกสารกฎระเบียบถูกจัดทำดัชนีใน Weaviate LangChain ควบคุมขั้นตอน "การให้เหตุผล" เพื่ออ้างอิงข้อกฎหมายเฉพาะ', + metrics: [ + { label: "เวลาตรวจสอบ", value: "-85%" }, + { label: "False Positives", value: "< 2%" }, + { label: "ประหยัดต้นทุน", value: "$45k/เดือน" }, + ], + stack: [ + "Llama 3 70B", + "Weaviate", + "OpenShift", + "LangChain", + "Python", + ], + }, + { + id: "retail", + category: "E-Commerce", + title: "OmniFlow Agentic Router", + shortDesc: + "ระบบตอบรับลูกค้าความเร็วสูง รองรับ 50,000+ ตั๋วต่อวัน แก้ไขปัญหาอัตโนมัติได้ 92% ด้วยความเร็วต่ำกว่า 2 วินาที", + fullDesc: + "ระบบ Multi-agent อัจฉริยะที่ทำหน้าที่เป็นด่านหน้าสำหรับแพลตฟอร์มอีคอมเมิร์ซขนาดใหญ่ ใช้การเรียกใช้เครื่องมือ (Tool-calling) เพื่อดำเนินการจริง (ตรวจสอบสถานะ, คืนเงิน) แทนที่จะเป็นแค่การแชท", + challenge: + 'ในช่วงเทศกาล "11.11" ปริมาณการติดต่อเพิ่มขึ้น 10 เท่า Chatbot แบบเดิมแข็งทื่อเกินไป และพนักงานรับมือไม่ไหว ระบบต้องทำงานอัตโนมัติแต่ปลอดภัย', + architecture: + 'เราสร้าง Router Agent โดยใช้ GPT-4o-mini เพื่อความเร็ว โดยจำแนกเจตนาและส่งต่อไปยัง Agent เฉพาะทาง (Refund Agent, Logistics Agent) เราใช้โปรโตคอล "Human-in-the-loop" สำหรับเคสที่มีความมั่นใจต่ำ', + metrics: [ + { label: "อัตราการตอบกลับ", value: "92%" }, + { label: "ความเร็วเฉลี่ย", value: "1.2s" }, + { label: "คะแนน CSAT", value: "4.8/5" }, + ], + stack: ["GPT-4o", "Redis", "FastAPI", "Kubernetes", "Postgres"], + }, + ], + }, + }; + + const t = content[language]; + + return ( +
+ {/* Hero Section */} +
+
+
+
+ + + {t.new_research} + +

+ {t.hero_title} +

+

+ {t.hero_subtitle} +

+
+ + {t.btn_services} + + + {t.btn_research} + +
+
+ + {/* Technical Trust Signal with Typing Effect */} +
+ Running 164 test cases...", + "> Pass@1: 92.4% [OK]", + "> Latency (p99): 450ms [WARN]", + "# Optimization suggestion:", + "# Switch to batch inference or semantic caching.", + "$ _", + ]} + className="transform lg:rotate-1 hover:rotate-0 transition-transform duration-500" + /> +
+
+
+
+ + {/* Trusted Stack / Logos (Revamped) */} +
+
+
+ {/* Infrastructure */} +
+
+ +
+

+ {t.stack.infra} +

+

+ AWS, GCP, Azure, Terraform +

+
+ + {/* Orchestration */} +
+
+ +
+

+ {t.stack.orchestration} +

+

+ Kubernetes, Docker, Ray, Airflow +

+
+ + {/* Inference */} +
+
+ +
+

+ {t.stack.inference} +

+

+ vLLM, TorchServe, ONNX Runtime +

+
+ + {/* Data */} +
+
+ +
+

+ {t.stack.data} +

+

+ Pinecone, Weaviate, Postgres, Redis +

+
+
+
+
+ + {/* Featured Research Snippet */} +
+
+
+

+ {t.latest_thinking} +

+ + {t.view_archive}{" "} + + +
+ + +
+
+

+ LoRA Without Regret +

+

+ {t.lora_desc} +

+ + {t.technical_deep_dive} + +
+
+ {/* Mini visualization for the teaser */} +
+ {[...Array(48)].map((_, i) => ( +
+ ))} +
+
+
+ +
+
+ + {/* Services Preview */} +
+
+

+ {t.expertise_title} +

+ +
+ {/* Service 1 */} +
+
+ +
+

+ {t.services.mvp.title} +

+

+ {t.services.mvp.desc} +

+ + {t.learn_more} + +
+ + {/* Service 2 */} +
+
+ +
+

+ {t.services.audit.title} +

+

+ {t.services.audit.desc} +

+ + {t.learn_more} + +
+ + {/* Service 3 */} +
+
+ +
+

+ {t.services.integration.title} +

+

+ {t.services.integration.desc} +

+ + {t.learn_more} + +
+
+
+
+ + {/* Process Pipeline Section */} +
+
+
+

+ {t.process_title} +

+

+ {t.process_desc} +

+
+ +
+ {t.process_steps.map((step, idx) => ( +
+
+ {step.step} +
+

{step.title}

+

+ {step.desc} +

+ {/* Connecting Line */} + {idx < 3 && ( +
+ )} +
+ ))} +
+
+
+ + {/* Featured Projects (Improved Enterprise) */} +
+
+
+

+ {t.projects_title} +

+

{t.projects_desc}

+
+ +
+ {t.projects.map((project) => ( +
setSelectedProject(project)} + className="border border-gray-200 rounded-sm hover:shadow-xl transition-all duration-300 p-8 bg-white flex flex-col cursor-pointer group hover:-translate-y-1" + > +
+
+
+ {project.id === "compliance" ? ( + + ) : ( + + )} +
+ + {project.category} + +
+
+ +
+
+ +

+ {project.title} +

+

+ {project.shortDesc} +

+ +
+ {project.metrics.map((metric, idx) => ( +
+
+ {metric.value} +
+
+ {metric.label} +
+
+ ))} +
+
+ ))} +
+
+
+ + {/* Project Modal */} + {selectedProject && ( +
+
setSelectedProject(null)} + >
+
+ {/* Modal Left: Overview */} +
+

+ {selectedProject.title} +

+ + {selectedProject.category} + + +
+
+

+ {t.modal_challenge} +

+

+ {selectedProject.challenge} +

+
+
+

+ {t.modal_arch} +

+

+ {selectedProject.architecture} +

+
+
+

+ {t.modal_impact} +

+
+ {selectedProject.metrics.map((metric, idx) => ( +
+
+ {metric.value} +
+
+ {metric.label} +
+
+ ))} +
+
+
+
+ + {/* Modal Right: Stack */} +
+ + +

+ {t.modal_stack} +

+
+ {selectedProject.stack.map((tech, i) => ( +
+
+ {tech} +
+ ))} +
+ +
+ +

+ "Pradit delivered this system 2 weeks ahead of schedule. The + documentation was better than our internal standard." +

+
+ - CTO, Client Partner +
+
+
+
+
+ )} +
+ ); +}; diff --git a/pages/Playground.tsx b/pages/Playground.tsx new file mode 100644 index 0000000..c57d744 --- /dev/null +++ b/pages/Playground.tsx @@ -0,0 +1,329 @@ +import React, { useState, useEffect } from "react"; +import { + UploadCloud, + FileText, + Database, + Search, + CheckCircle2, + ArrowRight, + Loader2, + Lock, + Cpu, + File, + Terminal, +} from "lucide-react"; +import { useLanguage } from "../App"; +import { TerminalBlock } from "../components/TerminalBlock"; + +export const Playground: React.FC = () => { + const { language } = useLanguage(); + const [step, setStep] = useState<"upload" | "processing" | "ready">("upload"); + const [processingStage, setProcessingStage] = useState(0); // 0: Parsing, 1: Chunking, 2: Embedding, 3: Indexing + const [query, setQuery] = useState(""); + const [showResult, setShowResult] = useState(false); + + const content = { + en: { + title: "Enterprise Knowledge Engine", + subtitle: + "Experience our secure RAG pipeline architecture. Turn unstructured documents into queryable intelligence.", + upload_title: "Data Ingestion", + upload_desc: + "Drag and drop your internal PDFs, DOCX, or Wiki dumps here. We simulate the ingestion process secure enterprises use.", + drop_label: "Drop corporate assets here", + processing_title: "Processing Pipeline", + stages: [ + "Optical Character Recognition (OCR)", + "Semantic Chunking", + "Vector Embedding (text-embedding-3-large)", + "Pinecone Indexing", + ], + query_placeholder: "Ask a question about the uploaded documents...", + query_btn: "Retrieve Insight", + result_title: "Synthesized Answer", + source_title: "Source Attribution", + value_prop: + "Why this matters: Most enterprise knowledge is trapped in PDFs. We build pipelines that unlock this data while respecting RBAC (Role-Based Access Control).", + }, + th: { + title: "เครื่องยนต์ความรู้องค์กร", + subtitle: + "สัมผัสสถาปัตยกรรม RAG ที่ปลอดภัยของเรา เปลี่ยนเอกสารที่ไม่มีโครงสร้างให้เป็นข้อมูลอัจฉริยะที่ค้นหาได้", + upload_title: "การนำเข้าข้อมูล", + upload_desc: + "ลากและวาง PDF, DOCX หรือ Wiki ภายในองค์กรที่นี่ เราจำลองกระบวนการนำเข้าข้อมูลที่องค์กรระดับสูงใช้", + drop_label: "วางไฟล์ข้อมูลองค์กรที่นี่", + processing_title: "ท่อประมวลผลข้อมูล", + stages: [ + "การแปลงภาพเป็นข้อความ (OCR)", + "การแบ่งส่วนความหมาย (Semantic Chunking)", + "การสร้าง Vector (text-embedding-3-large)", + "การจัดทำดัชนี Pinecone", + ], + query_placeholder: "ถามคำถามเกี่ยวกับเอกสารที่อัปโหลด...", + query_btn: "ค้นหาข้อมูลเชิงลึก", + result_title: "คำตอบที่สังเคราะห์แล้ว", + source_title: "การอ้างอิงแหล่งที่มา", + value_prop: + "ทำไมสิ่งนี้ถึงสำคัญ: ความรู้องค์กรส่วนใหญ่ติดอยู่ใน PDF เราสร้างระบบที่ปลดล็อกข้อมูลนี้โดยยังคงรักษาความปลอดภัยตามสิทธิ์การเข้าถึง (RBAC)", + }, + }; + + const t = content[language]; + + const handleSimulateUpload = () => { + setStep("processing"); + setProcessingStage(0); + + // Simulate pipeline stages + const interval = setInterval(() => { + setProcessingStage((prev) => { + if (prev >= 3) { + clearInterval(interval); + setTimeout(() => setStep("ready"), 800); + return 3; + } + return prev + 1; + }); + }, 1500); + }; + + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + if (!query) return; + setShowResult(true); + }; + + return ( +
+
+
+

+ {t.title} +

+

+ {t.subtitle} +

+
+ +
+ {/* Left: Demo Interface */} +
+ {/* Step 1: Upload */} +
+
+
+ +
+

+ {t.upload_title} +

+ {step === "upload" && ( + <> +

+ {t.upload_desc} +

+ +
+ + policy_v2.pdf + + + technical_specs.docx + +
+ + )} +
+
+ + {/* Step 2: Processing Pipeline */} + {(step === "processing" || step === "ready") && ( +
+

+ {t.processing_title} +

+
+ {t.stages.map((stage, index) => ( +
+
index + ? "bg-green-500 border-green-500" + : processingStage === index + ? "bg-white border-accent animate-pulse" + : "bg-white border-gray-200" + }`} + >
+ +
= index ? "opacity-100" : "opacity-30"}`} + > +

+ {stage} +

+ {processingStage === index && ( +

+ Processing... +

+ )} +
+
+ ))} +
+
+ )} + + {/* Step 3: Query Interface */} + {step === "ready" && ( +
+
+
+ Secure Context +
+
+ +
+ setQuery(e.target.value)} + className="w-full bg-gray-50 border border-gray-200 p-4 pr-12 rounded-sm text-ink focus:outline-none focus:border-ink focus:ring-1 focus:ring-ink font-serif placeholder:text-gray-400" + placeholder={t.query_placeholder} + /> + +
+ + {showResult && ( +
+
+

+ {t.result_title} +

+

+ Based on the{" "} + + technical_specs.docx + + , the maximum concurrent connection limit for the + websocket gateway is{" "} + 10,000 users per + shard. To increase this, you must scale the Redis + cluster horizontally. +

+
+ +
+

+ {t.source_title} +

+
+ "...gateway.max_connections = 10000 # Hard limit per + shard. See Redis scaling section..." +
+ Score: 0.89 +
+
+
+
+ )} +
+ )} +
+ + {/* Right: Architecture Context */} +
+
+
+
+ + pipeline_logs.txt +
+
+
+ $ init_ingestion_job --secure +
+ {step === "processing" && ( + <> +
+ [INFO] File uploaded: technical_specs.docx (2.4MB) +
+
+ [INFO] Parsing PDF structure... +
+ {processingStage >= 1 && ( +
+ [PROC] Chunking strategy: RecursiveCharacter (512tk) +
+ )} + {processingStage >= 2 && ( +
+ [EMBD] Batch embedding 142 chunks... +
+ )} + {processingStage >= 3 && ( +
+ [INDX] Upserting to namespace 'corp-knowledge'... +
+ )} + + )} + {step === "ready" && ( + <> +
+ [DONE] Indexing complete. Latency: 4.2s +
+
+ ---------------------------------------- +
+
+ $ waiting_for_query... +
+ {showResult && ( + <> +
$ query_received
+
+ [RETR] Semantic search k=3 +
+
+ [GEN] LLM Context window filled (1200 tokens) +
+ + )} + + )} +
+
+ +
+

+ Business Value +

+

+ {t.value_prop} +

+
+
+
+
+
+
+ ); +}; diff --git a/pages/Research.tsx b/pages/Research.tsx new file mode 100644 index 0000000..6c5d434 --- /dev/null +++ b/pages/Research.tsx @@ -0,0 +1,269 @@ +import React, { useState, useMemo } from "react"; +import { Link } from "react-router-dom"; +import { ArrowRight, Search as SearchIcon, Filter, X } from "lucide-react"; +import { useLanguage } from "../App"; + +export const Research: React.FC = () => { + const { language } = useLanguage(); + const [searchQuery, setSearchQuery] = useState(""); + const [selectedCategory, setSelectedCategory] = useState("All"); + + const content = { + en: { + title: "Research Archive", + subtitle: + "Our collection of white papers, technical deep dives, and engineering retrospectives. We believe in open-sourcing our learnings from the frontier of applied AI.", + read_paper: "Read Paper", + search_placeholder: "grep search-query...", + no_results: "No research found matching criteria.", + categories: [ + "All", + "Fine-tuning", + "Systems", + "Architecture", + "Small Models", + ], + articles: [ + { + id: "lora-without-regret", + title: "LoRA Without Regret", + date: "Sep 29, 2025", + authors: "John Schulman, Pradit", + abstract: + "Fine-tuning large models is expensive. We investigate whether Low-Rank Adaptation (LoRA) can truly match full fine-tuning performance across various downstream tasks, analyzing rank scaling and matrix initialization.", + tags: ["Fine-tuning", "Optimization", "Deep Learning"], + category: "Fine-tuning", + }, + { + id: "rag-latency-optimization", + title: "Optimizing RAG Latency: A Systems Approach", + date: "Aug 14, 2025", + authors: "Pradit Engineering", + abstract: + "Retrieval-Augmented Generation often suffers from p99 latency spikes. We break down the contribution of embedding generation, vector search, and reranking, proposing a caching layer that reduces latency by 40%.", + tags: ["RAG", "Systems", "Latency"], + category: "Architecture", + }, + { + id: "small-models-reasoning", + title: "The Unreasonable Effectiveness of Small Models", + date: "July 02, 2025", + authors: "Pradit Research", + abstract: + "Can a 7B parameter model reason as well as a 70B model? With specific chain-of-thought fine-tuning on high-quality synthetic data, we demonstrate parity on GSM8K benchmarks.", + tags: ["Small Models", "Reasoning", "Data Efficiency"], + category: "Small Models", + }, + ], + }, + th: { + title: "คลังงานวิจัย", + subtitle: + "คลังเอกสารทางเทคนิคและการถอดบทเรียนทางวิศวกรรม เราเชื่อในการเปิดเผยสิ่งที่เราเรียนรู้จากพรมแดนแห่ง AI ประยุกต์สู่สาธารณะ", + read_paper: "อ่านบทความ", + search_placeholder: "ค้นหาบทความ...", + no_results: "ไม่พบงานวิจัยที่ตรงกับเงื่อนไข", + categories: [ + "ทั้งหมด", + "Fine-tuning", + "Systems", + "Architecture", + "Small Models", + ], + articles: [ + { + id: "lora-without-regret", + title: "LoRA โดยไม่เสียใจ", + date: "29 ก.ย. 2025", + authors: "John Schulman, Pradit (ประดิษฐ์)", + abstract: + "การ Fine-tune โมเดลขนาดใหญ่มีค่าใช้จ่ายสูง เราตรวจสอบว่า Low-Rank Adaptation (LoRA) สามารถให้ประสิทธิภาพเทียบเท่าการ Fine-tune เต็มรูปแบบได้หรือไม่ โดยวิเคราะห์การปรับขนาด Rank และการเริ่มต้น Matrix", + tags: ["Fine-tuning", "Optimization", "Deep Learning"], + category: "Fine-tuning", + }, + { + id: "rag-latency-optimization", + title: "การปรับปรุงความหน่วง RAG: แนวทางเชิงระบบ", + date: "14 ส.ค. 2025", + authors: "Pradit Engineering", + abstract: + "ระบบ RAG มักประสบปัญหาค่าความหน่วง p99 สูง เราจำแนกส่วนประกอบของการสร้าง Embedding, Vector Search และ Reranking พร้อมเสนอชั้น Caching ที่ลดความหน่วงได้ถึง 40%", + tags: ["RAG", "Systems", "Latency"], + category: "Architecture", + }, + { + id: "small-models-reasoning", + title: "ประสิทธิภาพที่น่าทึ่งของโมเดลขนาดเล็ก", + date: "02 ก.ค. 2025", + authors: "Pradit Research", + abstract: + "โมเดล 7B สามารถให้เหตุผลได้ดีเท่ากับ 70B หรือไม่? ด้วยการ Fine-tune แบบ Chain-of-thought บนข้อมูลสังเคราะห์คุณภาพสูง เราแสดงให้เห็นถึงความสามารถที่เทียบเท่ากันบน GSM8K", + tags: ["Small Models", "Reasoning", "Data Efficiency"], + category: "Small Models", + }, + ], + }, + }; + + const t = content[language]; + + // Filtering Logic + const filteredArticles = useMemo(() => { + return t.articles.filter((article) => { + const matchesSearch = + article.title.toLowerCase().includes(searchQuery.toLowerCase()) || + article.abstract.toLowerCase().includes(searchQuery.toLowerCase()); + + // Map 'All' or 'ทั้งหมด' to show everything + const isAll = + selectedCategory === "All" || selectedCategory === "ทั้งหมด"; + const matchesCategory = + isAll || + article.category === selectedCategory || + article.tags.includes(selectedCategory); + + return matchesSearch && matchesCategory; + }); + }, [searchQuery, selectedCategory, t.articles]); + + return ( +
+
+ {/* Header */} +
+

+ {t.title} +

+

+ {t.subtitle} +

+
+ + {/* Controls: Search & Filter */} +
+ {/* Categories */} +
+ {t.categories.map((cat) => ( + + ))} +
+ + {/* Search Bar */} +
+
+ +
+ setSearchQuery(e.target.value)} + className="block w-full pl-9 pr-3 py-2 border-b-2 border-gray-200 bg-transparent text-sm font-mono text-ink focus:outline-none focus:border-ink transition-colors placeholder:text-gray-400" + placeholder={t.search_placeholder} + /> + {searchQuery && ( + + )} +
+
+ + {/* Results List */} +
+ {filteredArticles.length > 0 ? ( + filteredArticles.map((article) => ( +
+ {/* Metadata Column */} +
+ + {article.date} + + + {article.category} + +
+ {article.tags.slice(0, 2).map((tag) => ( + + #{tag} + + ))} +
+
+ + {/* Content Column */} +
+

+ + {article.title} + +

+ +
+ {article.authors} +
+ +

+ {article.abstract} +

+ + + {t.read_paper} + +
+
+ )) + ) : ( +
+ +

{t.no_results}

+ +
+ )} +
+
+
+ ); +}; diff --git a/pages/Services.tsx b/pages/Services.tsx new file mode 100644 index 0000000..dab29ee --- /dev/null +++ b/pages/Services.tsx @@ -0,0 +1,198 @@ + +import React from 'react'; +import { TerminalBlock } from '../components/TerminalBlock'; +import { Check, ArrowRight } from 'lucide-react'; +import { Link } from 'react-router-dom'; + +export const Services: React.FC = () => { + return ( +
+
+ +
+

+ Services +

+

+ We operate at the intersection of software engineering and machine learning research. Our engagements are typically project-based or retainer-style for high-growth technical teams who need to ship, not just explore. +

+
+ +
+ {/* Service Block 1: MVP */} +
+
+
+ 01 — Prototyping +
+
+ +

Accelerated MVP

+

+ We help founders and technical leads validate AI hypotheses quickly. Instead of spending months hiring a full ML team, we deliver a production-ready prototype in 4-6 weeks. +

+ +
    + {[ + "Full stack implementation (React + Python/Node)", + "Model selection (Gemini, Claude, OpenAI) & prompt engineering", + "Basic evaluation pipeline setup", + "Deployment to your cloud (AWS/GCP)" + ].map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+
+ +
+
+ + {/* Service Block 2: Audit */} +
+
+
+ 02 — Architecture +
+
+ +

RAG & System Audit

+

+ Your retrieval system is likely the bottleneck. We perform a rigorous audit of your embedding strategies, chunking logic, and reranking stages to improve context relevance and reduce hallucinations. +

+ +
    + {[ + "Vector Database Indexing Strategy Review", + "Embedding Latency & Cost Analysis", + "Context Window Optimization", + "Security & Prompt Injection Vulnerability Scan" + ].map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+
+ +
+
+ + {/* Service Block 3: Integration */} +
+
+
+ 03 — Fine-tuning +
+
+

Custom Model Integration

+

+ When prompt engineering hits a wall, we fine-tune open weights (Llama 3, Mistral, Gemma) on your proprietary data. We handle the data cleaning, training runs (LoRA/QLoRA), and deployment optimization. +

+
    + {[ + "Dataset curation and cleaning pipelines", + "Parameter-Efficient Fine-Tuning (LoRA)", + "Evaluation against base model benchmarks", + "Private cloud deployment (AWS/GCP/Azure)" + ].map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ +
+
+ +
+
+ +
+
+

Ready to build?

+

+ We take on a limited number of clients per quarter to ensure deep technical focus on every project. +

+ + Schedule Consultation + +
+ {/* Background decoration */} +
+
+ {[...Array(12)].map((_, i) => ( +
+ ))} +
+
+
+
+
+
+ ); +}; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..ee1d838 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1138 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + lucide-react: + specifier: ^0.554.0 + version: 0.554.0(react@19.2.0) + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + react-router-dom: + specifier: ^7.9.6 + version: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + devDependencies: + '@types/node': + specifier: ^22.14.0 + version: 22.19.1 + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.1.1(vite@6.4.1(@types/node@22.19.1)) + typescript: + specifier: ~5.8.2 + version: 5.8.3 + vite: + specifier: ^6.2.0 + version: 6.4.1(@types/node@22.19.1) + +packages: + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@rolldown/pluginutils@1.0.0-beta.47': + resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@22.19.1': + resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} + + '@vitejs/plugin-react@5.1.1': + resolution: {integrity: sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + baseline-browser-mapping@2.8.29: + resolution: {integrity: sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==} + hasBin: true + + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001756: + resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + electron-to-chromium@1.5.258: + resolution: {integrity: sha512-rHUggNV5jKQ0sSdWwlaRDkFc3/rRJIVnOSe9yR4zrR07m3ZxhP4N27Hlg8VeJGGYgFTxK5NqDmWI4DSH72vIJg==} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.554.0: + resolution: {integrity: sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react-router-dom@7.9.6: + resolution: {integrity: sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.9.6: + resolution: {integrity: sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + vite@6.4.1: + resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + +snapshots: + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@rolldown/pluginutils@1.0.0-beta.47': {} + + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + + '@rollup/rollup-android-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/estree@1.0.8': {} + + '@types/node@22.19.1': + dependencies: + undici-types: 6.21.0 + + '@vitejs/plugin-react@5.1.1(vite@6.4.1(@types/node@22.19.1))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.47 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 6.4.1(@types/node@22.19.1) + transitivePeerDependencies: + - supports-color + + baseline-browser-mapping@2.8.29: {} + + browserslist@4.28.0: + dependencies: + baseline-browser-mapping: 2.8.29 + caniuse-lite: 1.0.30001756 + electron-to-chromium: 1.5.258 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.28.0) + + caniuse-lite@1.0.30001756: {} + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + electron-to-chromium@1.5.258: {} + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.554.0(react@19.2.0): + dependencies: + react: 19.2.0 + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + node-releases@2.0.27: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react-router-dom@7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + + react-router@7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + cookie: 1.0.2 + react: 19.2.0 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.0(react@19.2.0) + + react@19.2.0: {} + + rollup@4.53.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + set-cookie-parser@2.7.2: {} + + source-map-js@1.2.1: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + typescript@5.8.3: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.1.4(browserslist@4.28.0): + dependencies: + browserslist: 4.28.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + vite@6.4.1(@types/node@22.19.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.19.1 + fsevents: 2.3.3 + + yallist@3.1.1: {} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2c6eed5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "types": [ + "node" + ], + "moduleResolution": "bundler", + "isolatedModules": true, + "moduleDetection": "force", + "allowJs": true, + "jsx": "react-jsx", + "paths": { + "@/*": [ + "./*" + ] + }, + "allowImportingTsExtensions": true, + "noEmit": true + } +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..ee5fb8d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,23 @@ +import path from 'path'; +import { defineConfig, loadEnv } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, '.', ''); + return { + server: { + port: 3000, + host: '0.0.0.0', + }, + plugins: [react()], + define: { + 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY), + 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY) + }, + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + } + } + }; +});