File size: 3,956 Bytes
e9ecc21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { useEffect, useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from './ui/Card';
import { Button } from './ui/Button';
import { Filter, Download } from 'lucide-react';

export default function KnowledgeBase() {
  const [techniques, setTechniques] = useState([]);
  const [competition, setCompetition] = useState('');
  const [loading, setLoading] = useState(false);

  const fetchTechniques = async () => {
    setLoading(true);
    try {
      const response = await fetch(`/api/database/techniques${competition ? `?competition=${competition}` : ''}`);
      const data = await response.json();
      setTechniques(data);
    } catch (error) {
      console.error('Failed to fetch techniques:', error);
    } finally {
      setLoading(false);
    }
  };

  const generateConfig = async () => {
    try {
      const response = await fetch('/api/config/generate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ competition, minConfidence: 0.8 }),
      });
      
      const blob = await response.blob();
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'harvested_config.yaml';
      a.click();
    } catch (error) {
      console.error('Failed to generate config:', error);
    }
  };

  useEffect(() => {
    fetchTechniques();
  }, []);

  return (
    <div className="space-y-6">
      <h2 className="text-3xl font-bold text-gray-800">Knowledge Base</h2>
      
      <Card>
        <CardHeader>
          <CardTitle>Extracted Techniques</CardTitle>
        </CardHeader>
        <CardContent>
          <div className="flex gap-4 mb-6">
            <input
              type="text"
              placeholder="Filter by competition"
              value={competition}
              onChange={(e) => setCompetition(e.target.value)}
              className="input-field flex-1"
            />
            <Button onClick={fetchTechniques}>
              <Filter className="w-4 h-4 mr-2" />
              Filter
            </Button>
            <Button onClick={generateConfig} variant="secondary">
              <Download className="w-4 h-4 mr-2" />
              Export Config
            </Button>
          </div>

          {loading ? (
            <div className="text-center py-8">Loading...</div>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full">
                <thead>
                  <tr className="border-b">
                    <th className="text-left py-2">Parameter</th>
                    <th className="text-left py-2">Value</th>
                    <th className="text-left py-2">Confidence</th>
                    <th className="text-left py-2">Source</th>
                  </tr>
                </thead>
                <tbody>
                  {techniques.map((technique) => (
                    <tr key={technique.id} className="border-b">
                      <td className="py-2 font-mono">{technique.name}</td>
                      <td className="py-2">{technique.value}</td>
                      <td className="py-2">
                        <div className="progress-container">
                          <div
                            className="progress-bar"
                            style={{ width: `${technique.confidence * 100}%` }}
                          />
                        </div>
                        <span className="text-sm">{(technique.confidence * 100).toFixed(1)}%</span>
                      </td>
                      <td className="py-2 text-sm text-gray-600">
                        {technique.rich_context ? 'AST' : 'Regex'}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
}