pradit/pages/Research.tsx
2025-11-20 17:04:57 +07:00

270 lines
12 KiB
TypeScript

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 (
<div className="bg-paper min-h-screen pt-24 pb-24">
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<header className="mb-12 pb-8 border-b border-gray-100">
<h1 className="font-serif text-4xl md:text-5xl text-ink leading-tight mb-6">
{t.title}
</h1>
<p className="font-serif text-xl text-subtle leading-relaxed max-w-3xl">
{t.subtitle}
</p>
</header>
{/* Controls: Search & Filter */}
<div className="flex flex-col md:flex-row gap-6 mb-16 items-start md:items-center justify-between">
{/* Categories */}
<div className="flex flex-wrap gap-2">
{t.categories.map((cat) => (
<button
key={cat}
onClick={() => setSelectedCategory(cat)}
className={`px-4 py-1.5 text-xs font-bold uppercase tracking-wider rounded-full transition-all border ${
selectedCategory === cat
? "bg-ink text-white border-ink"
: "bg-white text-subtle border-gray-200 hover:border-gray-400"
}`}
>
{cat}
</button>
))}
</div>
{/* Search Bar */}
<div className="relative w-full md:w-64 group">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<SearchIcon
size={14}
className="text-gray-400 group-focus-within:text-ink"
/>
</div>
<input
type="text"
value={searchQuery}
onChange={(e) => 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 && (
<button
onClick={() => setSearchQuery("")}
className="absolute inset-y-0 right-0 pr-2 flex items-center text-gray-400 hover:text-ink"
>
<X size={14} />
</button>
)}
</div>
</div>
{/* Results List */}
<div className="space-y-16">
{filteredArticles.length > 0 ? (
filteredArticles.map((article) => (
<article
key={article.id}
className="group relative grid grid-cols-1 md:grid-cols-12 gap-8 p-6 -mx-6 rounded-lg hover:bg-gray-50 transition-colors border border-transparent hover:border-gray-100"
>
{/* Metadata Column */}
<div className="md:col-span-3 flex flex-col gap-2">
<span className="font-mono text-xs font-bold text-subtle">
{article.date}
</span>
<span className="font-sans text-xs font-medium text-gray-400 uppercase tracking-wider">
{article.category}
</span>
<div className="flex flex-wrap gap-2 mt-2">
{article.tags.slice(0, 2).map((tag) => (
<span
key={tag}
className="inline-flex px-2 py-0.5 bg-gray-200/50 text-[10px] text-gray-600 rounded-sm font-mono"
>
#{tag}
</span>
))}
</div>
</div>
{/* Content Column */}
<div className="md:col-span-9">
<h2 className="font-serif text-2xl font-bold text-ink mb-3 group-hover:text-accent transition-colors">
<Link
to={
article.id === "lora-without-regret"
? "/research/lora-without-regret"
: "#"
}
>
{article.title}
</Link>
</h2>
<div className="mb-4 font-sans text-sm text-subtle italic">
{article.authors}
</div>
<p className="font-serif text-lg text-gray-600 leading-relaxed mb-6">
{article.abstract}
</p>
<Link
to={
article.id === "lora-without-regret"
? "/research/lora-without-regret"
: "#"
}
className="inline-flex items-center text-xs font-bold uppercase tracking-widest text-ink group-hover:text-accent transition-colors border-b border-transparent group-hover:border-accent pb-0.5"
>
{t.read_paper} <ArrowRight className="ml-2 w-3 h-3" />
</Link>
</div>
</article>
))
) : (
<div className="py-24 text-center border border-dashed border-gray-200 rounded-lg">
<Filter size={48} className="mx-auto text-gray-200 mb-4" />
<p className="font-serif text-subtle text-lg">{t.no_results}</p>
<button
onClick={() => {
setSearchQuery("");
setSelectedCategory(language === "en" ? "All" : "ทั้งหมด");
}}
className="mt-4 text-sm font-bold text-ink underline"
>
Clear filters
</button>
</div>
)}
</div>
</div>
</div>
);
};