Move pipeline components to dedicated folder
Browse files- src/App.tsx +4 -4
- src/components/Sidebar.tsx +3 -3
- src/components/{FeatureExtraction.tsx → pipelines/FeatureExtraction.tsx} +3 -3
- src/components/{FeatureExtractionConfig.tsx → pipelines/FeatureExtractionConfig.tsx} +17 -11
- src/components/{TextClassification.tsx → pipelines/TextClassification.tsx} +2 -2
- src/components/{TextGeneration.tsx → pipelines/TextGeneration.tsx} +7 -3
- src/components/{TextGenerationConfig.tsx → pipelines/TextGenerationConfig.tsx} +2 -2
- src/components/{ZeroShotClassification.tsx → pipelines/ZeroShotClassification.tsx} +7 -7
- src/components/{ZeroShotClassificationConfig.tsx → pipelines/ZeroShotClassificationConfig.tsx} +20 -12
- src/lib/huggingface.ts +6 -1
src/App.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
| 1 |
import { useEffect, useState } from 'react'
|
| 2 |
import { Settings } from 'lucide-react'
|
| 3 |
-
import ZeroShotClassification from './components/ZeroShotClassification'
|
| 4 |
-
import TextClassification from './components/TextClassification'
|
| 5 |
import Header from './Header'
|
| 6 |
import { useModel } from './contexts/ModelContext'
|
| 7 |
import { getModelsByPipeline } from './lib/huggingface'
|
| 8 |
-
import TextGeneration from './components/TextGeneration'
|
| 9 |
-
import FeatureExtraction from './components/FeatureExtraction'
|
| 10 |
import Sidebar from './components/Sidebar'
|
| 11 |
import ModelReadme from './components/ModelReadme'
|
| 12 |
import { PipelineLayout } from './components/PipelineLayout'
|
|
|
|
| 1 |
import { useEffect, useState } from 'react'
|
| 2 |
import { Settings } from 'lucide-react'
|
| 3 |
+
import ZeroShotClassification from './components/pipelines/ZeroShotClassification'
|
| 4 |
+
import TextClassification from './components/pipelines/TextClassification'
|
| 5 |
import Header from './Header'
|
| 6 |
import { useModel } from './contexts/ModelContext'
|
| 7 |
import { getModelsByPipeline } from './lib/huggingface'
|
| 8 |
+
import TextGeneration from './components/pipelines/TextGeneration'
|
| 9 |
+
import FeatureExtraction from './components/pipelines/FeatureExtraction'
|
| 10 |
import Sidebar from './components/Sidebar'
|
| 11 |
import ModelReadme from './components/ModelReadme'
|
| 12 |
import { PipelineLayout } from './components/PipelineLayout'
|
src/components/Sidebar.tsx
CHANGED
|
@@ -3,9 +3,9 @@ import PipelineSelector from './PipelineSelector'
|
|
| 3 |
import ModelSelector from './ModelSelector'
|
| 4 |
import ModelInfo from './ModelInfo'
|
| 5 |
import { useModel } from '../contexts/ModelContext'
|
| 6 |
-
import TextGenerationConfig from './TextGenerationConfig'
|
| 7 |
-
import FeatureExtractionConfig from './FeatureExtractionConfig'
|
| 8 |
-
import ZeroShotClassificationConfig from './ZeroShotClassificationConfig'
|
| 9 |
|
| 10 |
interface SidebarProps {
|
| 11 |
isOpen: boolean
|
|
|
|
| 3 |
import ModelSelector from './ModelSelector'
|
| 4 |
import ModelInfo from './ModelInfo'
|
| 5 |
import { useModel } from '../contexts/ModelContext'
|
| 6 |
+
import TextGenerationConfig from './pipelines/TextGenerationConfig'
|
| 7 |
+
import FeatureExtractionConfig from './pipelines/FeatureExtractionConfig'
|
| 8 |
+
import ZeroShotClassificationConfig from './pipelines/ZeroShotClassificationConfig'
|
| 9 |
|
| 10 |
interface SidebarProps {
|
| 11 |
isOpen: boolean
|
src/components/{FeatureExtraction.tsx → pipelines/FeatureExtraction.tsx}
RENAMED
|
@@ -4,9 +4,9 @@ import {
|
|
| 4 |
EmbeddingExample,
|
| 5 |
FeatureExtractionWorkerInput,
|
| 6 |
WorkerMessage
|
| 7 |
-
} from '
|
| 8 |
-
import { useModel } from '
|
| 9 |
-
import { useFeatureExtraction } from '
|
| 10 |
|
| 11 |
interface Point2D {
|
| 12 |
x: number
|
|
|
|
| 4 |
EmbeddingExample,
|
| 5 |
FeatureExtractionWorkerInput,
|
| 6 |
WorkerMessage
|
| 7 |
+
} from '../../types'
|
| 8 |
+
import { useModel } from '../../contexts/ModelContext'
|
| 9 |
+
import { useFeatureExtraction } from '../../contexts/FeatureExtractionContext'
|
| 10 |
|
| 11 |
interface Point2D {
|
| 12 |
x: number
|
src/components/{FeatureExtractionConfig.tsx → pipelines/FeatureExtractionConfig.tsx}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import React from 'react'
|
| 2 |
-
import { useFeatureExtraction } from '
|
| 3 |
|
| 4 |
const FeatureExtractionConfig = () => {
|
| 5 |
const { config, setConfig } = useFeatureExtraction()
|
|
@@ -17,10 +17,12 @@ const FeatureExtractionConfig = () => {
|
|
| 17 |
</label>
|
| 18 |
<select
|
| 19 |
value={config.pooling}
|
| 20 |
-
onChange={(e) =>
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
| 24 |
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
| 25 |
>
|
| 26 |
<option value="mean">Mean Pooling</option>
|
|
@@ -37,10 +39,12 @@ const FeatureExtractionConfig = () => {
|
|
| 37 |
<input
|
| 38 |
type="checkbox"
|
| 39 |
checked={config.normalize}
|
| 40 |
-
onChange={(e) =>
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
| 44 |
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
| 45 |
/>
|
| 46 |
<span className="text-sm font-medium text-gray-700">
|
|
@@ -59,10 +63,12 @@ const FeatureExtractionConfig = () => {
|
|
| 59 |
<strong>Mean Pooling:</strong> Average all token embeddings
|
| 60 |
</p>
|
| 61 |
<p className="mb-1">
|
| 62 |
-
<strong>CLS Token:</strong> Use the [CLS] token embedding (if
|
|
|
|
| 63 |
</p>
|
| 64 |
<p>
|
| 65 |
-
<strong>Max Pooling:</strong> Take element-wise maximum across
|
|
|
|
| 66 |
</p>
|
| 67 |
</div>
|
| 68 |
</div>
|
|
|
|
| 1 |
import React from 'react'
|
| 2 |
+
import { useFeatureExtraction } from '../../contexts/FeatureExtractionContext'
|
| 3 |
|
| 4 |
const FeatureExtractionConfig = () => {
|
| 5 |
const { config, setConfig } = useFeatureExtraction()
|
|
|
|
| 17 |
</label>
|
| 18 |
<select
|
| 19 |
value={config.pooling}
|
| 20 |
+
onChange={(e) =>
|
| 21 |
+
setConfig((prev) => ({
|
| 22 |
+
...prev,
|
| 23 |
+
pooling: e.target.value as 'mean' | 'cls' | 'max'
|
| 24 |
+
}))
|
| 25 |
+
}
|
| 26 |
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
|
| 27 |
>
|
| 28 |
<option value="mean">Mean Pooling</option>
|
|
|
|
| 39 |
<input
|
| 40 |
type="checkbox"
|
| 41 |
checked={config.normalize}
|
| 42 |
+
onChange={(e) =>
|
| 43 |
+
setConfig((prev) => ({
|
| 44 |
+
...prev,
|
| 45 |
+
normalize: e.target.checked
|
| 46 |
+
}))
|
| 47 |
+
}
|
| 48 |
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
| 49 |
/>
|
| 50 |
<span className="text-sm font-medium text-gray-700">
|
|
|
|
| 63 |
<strong>Mean Pooling:</strong> Average all token embeddings
|
| 64 |
</p>
|
| 65 |
<p className="mb-1">
|
| 66 |
+
<strong>CLS Token:</strong> Use the [CLS] token embedding (if
|
| 67 |
+
available)
|
| 68 |
</p>
|
| 69 |
<p>
|
| 70 |
+
<strong>Max Pooling:</strong> Take element-wise maximum across
|
| 71 |
+
tokens
|
| 72 |
</p>
|
| 73 |
</div>
|
| 74 |
</div>
|
src/components/{TextClassification.tsx → pipelines/TextClassification.tsx}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import { useState, useCallback, useEffect } from 'react'
|
| 2 |
-
import { TextClassificationWorkerInput, WorkerMessage } from '
|
| 3 |
-
import { useModel } from '
|
| 4 |
|
| 5 |
const PLACEHOLDER_TEXTS: string[] = [
|
| 6 |
'I absolutely love this product! It exceeded all my expectations.',
|
|
|
|
| 1 |
import { useState, useCallback, useEffect } from 'react'
|
| 2 |
+
import { TextClassificationWorkerInput, WorkerMessage } from '../../types'
|
| 3 |
+
import { useModel } from '../../contexts/ModelContext'
|
| 4 |
|
| 5 |
const PLACEHOLDER_TEXTS: string[] = [
|
| 6 |
'I absolutely love this product! It exceeded all my expectations.',
|
src/components/{TextGeneration.tsx → pipelines/TextGeneration.tsx}
RENAMED
|
@@ -1,8 +1,12 @@
|
|
| 1 |
import { useState, useRef, useEffect, useCallback } from 'react'
|
| 2 |
import { Send, Trash2, Loader2, X } from 'lucide-react'
|
| 3 |
-
import {
|
| 4 |
-
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
function TextGeneration() {
|
| 8 |
const { config, messages, setMessages } = useTextGeneration()
|
|
|
|
| 1 |
import { useState, useRef, useEffect, useCallback } from 'react'
|
| 2 |
import { Send, Trash2, Loader2, X } from 'lucide-react'
|
| 3 |
+
import {
|
| 4 |
+
ChatMessage,
|
| 5 |
+
TextGenerationWorkerInput,
|
| 6 |
+
WorkerMessage
|
| 7 |
+
} from '../../types'
|
| 8 |
+
import { useModel } from '../../contexts/ModelContext'
|
| 9 |
+
import { useTextGeneration } from '../../contexts/TextGenerationContext'
|
| 10 |
|
| 11 |
function TextGeneration() {
|
| 12 |
const { config, messages, setMessages } = useTextGeneration()
|
src/components/{TextGenerationConfig.tsx → pipelines/TextGenerationConfig.tsx}
RENAMED
|
@@ -2,8 +2,8 @@ import { Switch } from '@headlessui/react'
|
|
| 2 |
import {
|
| 3 |
useTextGeneration,
|
| 4 |
GenerationConfigState
|
| 5 |
-
} from '
|
| 6 |
-
import { useModel } from '
|
| 7 |
|
| 8 |
function TextGenerationConfig() {
|
| 9 |
const { config, setConfig, messages, updateSystemMessage } =
|
|
|
|
| 2 |
import {
|
| 3 |
useTextGeneration,
|
| 4 |
GenerationConfigState
|
| 5 |
+
} from '../../contexts/TextGenerationContext'
|
| 6 |
+
import { useModel } from '../../contexts/ModelContext'
|
| 7 |
|
| 8 |
function TextGenerationConfig() {
|
| 9 |
const { config, setConfig, messages, updateSystemMessage } =
|
src/components/{ZeroShotClassification.tsx → pipelines/ZeroShotClassification.tsx}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import { useEffect, useCallback } from 'react'
|
| 2 |
-
import { WorkerMessage, ZeroShotWorkerInput } from '
|
| 3 |
-
import { useModel } from '
|
| 4 |
-
import { useZeroShotClassification } from '
|
| 5 |
import { Send, Loader2 } from 'lucide-react'
|
| 6 |
|
| 7 |
function ZeroShotClassification() {
|
|
@@ -81,7 +81,7 @@ function ZeroShotClassification() {
|
|
| 81 |
const busy: boolean = status !== 'ready'
|
| 82 |
|
| 83 |
return (
|
| 84 |
-
<div className="flex flex-col h-
|
| 85 |
<div className="flex items-center justify-between mb-4">
|
| 86 |
<h1 className="text-2xl font-bold">Zero-Shot Classification</h1>
|
| 87 |
</div>
|
|
@@ -96,7 +96,7 @@ function ZeroShotClassification() {
|
|
| 96 |
onChange={(e) => setText(e.target.value)}
|
| 97 |
placeholder="Enter text items to classify, one per line..."
|
| 98 |
className="w-full p-3 border border-gray-300 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:bg-gray-100 disabled:cursor-not-allowed"
|
| 99 |
-
rows={
|
| 100 |
disabled={!hasBeenLoaded || busy}
|
| 101 |
/>
|
| 102 |
</div>
|
|
@@ -126,11 +126,11 @@ function ZeroShotClassification() {
|
|
| 126 |
|
| 127 |
{/* Results Grid */}
|
| 128 |
<div className="flex-1 overflow-hidden">
|
| 129 |
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-
|
| 130 |
{sections.map((section, index) => (
|
| 131 |
<div
|
| 132 |
key={index}
|
| 133 |
-
className="flex flex-col bg-white border border-gray-200 rounded-lg
|
| 134 |
>
|
| 135 |
<div className="px-3 py-2 bg-gray-50 border-b border-gray-200">
|
| 136 |
<h3
|
|
|
|
| 1 |
import { useEffect, useCallback } from 'react'
|
| 2 |
+
import { WorkerMessage, ZeroShotWorkerInput } from '../../types'
|
| 3 |
+
import { useModel } from '../../contexts/ModelContext'
|
| 4 |
+
import { useZeroShotClassification } from '../../contexts/ZeroShotClassificationContext'
|
| 5 |
import { Send, Loader2 } from 'lucide-react'
|
| 6 |
|
| 7 |
function ZeroShotClassification() {
|
|
|
|
| 81 |
const busy: boolean = status !== 'ready'
|
| 82 |
|
| 83 |
return (
|
| 84 |
+
<div className="flex flex-col h-full max-h-[100vh] w-full p-4">
|
| 85 |
<div className="flex items-center justify-between mb-4">
|
| 86 |
<h1 className="text-2xl font-bold">Zero-Shot Classification</h1>
|
| 87 |
</div>
|
|
|
|
| 96 |
onChange={(e) => setText(e.target.value)}
|
| 97 |
placeholder="Enter text items to classify, one per line..."
|
| 98 |
className="w-full p-3 border border-gray-300 rounded-lg resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:bg-gray-100 disabled:cursor-not-allowed"
|
| 99 |
+
rows={12}
|
| 100 |
disabled={!hasBeenLoaded || busy}
|
| 101 |
/>
|
| 102 |
</div>
|
|
|
|
| 126 |
|
| 127 |
{/* Results Grid */}
|
| 128 |
<div className="flex-1 overflow-hidden">
|
| 129 |
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-4 h-full">
|
| 130 |
{sections.map((section, index) => (
|
| 131 |
<div
|
| 132 |
key={index}
|
| 133 |
+
className="flex flex-col bg-white border border-gray-200 rounded-lg max-h-96"
|
| 134 |
>
|
| 135 |
<div className="px-3 py-2 bg-gray-50 border-b border-gray-200">
|
| 136 |
<h3
|
src/components/{ZeroShotClassificationConfig.tsx → pipelines/ZeroShotClassificationConfig.tsx}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
import React from 'react'
|
| 2 |
import { Plus, Minus, Trash2 } from 'lucide-react'
|
| 3 |
-
import { useZeroShotClassification } from '
|
| 4 |
|
| 5 |
const ZeroShotClassificationConfig = () => {
|
| 6 |
const {
|
|
@@ -27,22 +27,27 @@ const ZeroShotClassificationConfig = () => {
|
|
| 27 |
<input
|
| 28 |
type="range"
|
| 29 |
min="0.1"
|
| 30 |
-
max="0.
|
| 31 |
-
step="0.
|
| 32 |
value={config.threshold}
|
| 33 |
-
onChange={(e) =>
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
| 37 |
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
| 38 |
/>
|
| 39 |
<p className="text-xs text-gray-500 mt-1">
|
| 40 |
-
Minimum confidence score required for classification (lower values
|
|
|
|
| 41 |
</p>
|
| 42 |
</div>
|
| 43 |
|
| 44 |
<div className="pt-2 border-t border-gray-200">
|
| 45 |
-
<h4 className="text-sm font-semibold text-gray-800 mb-3">
|
|
|
|
|
|
|
| 46 |
|
| 47 |
<div className="space-y-2 max-h-40 overflow-y-auto">
|
| 48 |
{sections.map((section, index) => (
|
|
@@ -94,13 +99,16 @@ const ZeroShotClassificationConfig = () => {
|
|
| 94 |
<div className="pt-2 border-t border-gray-200">
|
| 95 |
<div className="text-xs text-gray-500">
|
| 96 |
<p className="mb-1">
|
| 97 |
-
<strong>Threshold:</strong> Items with confidence scores below this
|
|
|
|
| 98 |
</p>
|
| 99 |
<p className="mb-1">
|
| 100 |
-
<strong>Categories:</strong> Edit category names to customize
|
|
|
|
| 101 |
</p>
|
| 102 |
<p>
|
| 103 |
-
<strong>Other:</strong> Fallback category for items that don't meet
|
|
|
|
| 104 |
</p>
|
| 105 |
</div>
|
| 106 |
</div>
|
|
|
|
| 1 |
import React from 'react'
|
| 2 |
import { Plus, Minus, Trash2 } from 'lucide-react'
|
| 3 |
+
import { useZeroShotClassification } from '../../contexts/ZeroShotClassificationContext'
|
| 4 |
|
| 5 |
const ZeroShotClassificationConfig = () => {
|
| 6 |
const {
|
|
|
|
| 27 |
<input
|
| 28 |
type="range"
|
| 29 |
min="0.1"
|
| 30 |
+
max="0.95"
|
| 31 |
+
step="0.01"
|
| 32 |
value={config.threshold}
|
| 33 |
+
onChange={(e) =>
|
| 34 |
+
setConfig((prev) => ({
|
| 35 |
+
...prev,
|
| 36 |
+
threshold: parseFloat(e.target.value)
|
| 37 |
+
}))
|
| 38 |
+
}
|
| 39 |
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
| 40 |
/>
|
| 41 |
<p className="text-xs text-gray-500 mt-1">
|
| 42 |
+
Minimum confidence score required for classification (lower values
|
| 43 |
+
classify more items)
|
| 44 |
</p>
|
| 45 |
</div>
|
| 46 |
|
| 47 |
<div className="pt-2 border-t border-gray-200">
|
| 48 |
+
<h4 className="text-sm font-semibold text-gray-800 mb-3">
|
| 49 |
+
Categories
|
| 50 |
+
</h4>
|
| 51 |
|
| 52 |
<div className="space-y-2 max-h-40 overflow-y-auto">
|
| 53 |
{sections.map((section, index) => (
|
|
|
|
| 99 |
<div className="pt-2 border-t border-gray-200">
|
| 100 |
<div className="text-xs text-gray-500">
|
| 101 |
<p className="mb-1">
|
| 102 |
+
<strong>Threshold:</strong> Items with confidence scores below this
|
| 103 |
+
threshold will be classified as "Other"
|
| 104 |
</p>
|
| 105 |
<p className="mb-1">
|
| 106 |
+
<strong>Categories:</strong> Edit category names to customize
|
| 107 |
+
classification labels
|
| 108 |
</p>
|
| 109 |
<p>
|
| 110 |
+
<strong>Other:</strong> Fallback category for items that don't meet
|
| 111 |
+
the threshold for any specific category
|
| 112 |
</p>
|
| 113 |
</div>
|
| 114 |
</div>
|
src/lib/huggingface.ts
CHANGED
|
@@ -153,8 +153,13 @@ const getModelsByPipeline = async (
|
|
| 153 |
// }
|
| 154 |
|
| 155 |
// First search with filter=onnx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
const response1 = await fetch(
|
| 157 |
-
`https://huggingface.co/api/models?filter=${pipelineTag}&filter=onnx&sort=downloads&limit=50`,
|
| 158 |
{
|
| 159 |
method: 'GET'
|
| 160 |
// headers: {
|
|
|
|
| 153 |
// }
|
| 154 |
|
| 155 |
// First search with filter=onnx
|
| 156 |
+
console.log(
|
| 157 |
+
pipelineTag === 'feature-extraction'
|
| 158 |
+
? '&search=sentence-transformers'
|
| 159 |
+
: '&filter=onnx'
|
| 160 |
+
)
|
| 161 |
const response1 = await fetch(
|
| 162 |
+
`https://huggingface.co/api/models?filter=${pipelineTag}${pipelineTag === 'feature-extraction' ? '&library=sentence-transformers' : '&filter=onnx'}&sort=downloads&limit=50`,
|
| 163 |
{
|
| 164 |
method: 'GET'
|
| 165 |
// headers: {
|