gijl commited on
Commit
cabe16f
·
verified ·
1 Parent(s): 19d2701

Create frontend/src/App.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/App.jsx +115 -0
frontend/src/App.jsx ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from 'react'
2
+
3
+ const MAX_TOKENS_LIMIT = 60
4
+
5
+ const EXAMPLES = [
6
+ 'العلم نور و',
7
+ 'أفضل طريقة لتعلم البرمجة هي',
8
+ 'في يوم من الأيام كان هناك',
9
+ 'الطقس اليوم',
10
+ ]
11
+
12
+ function App() {
13
+ const [prompt, setPrompt] = useState('')
14
+ const [maxTokens, setMaxTokens] = useState(20)
15
+ const [output, setOutput] = useState('')
16
+ const [loading, setLoading] = useState(false)
17
+ const [error, setError] = useState('')
18
+
19
+ async function handleGenerate() {
20
+ if (!prompt.trim()) {
21
+ setError('اكتب نصاً أولاً')
22
+ return
23
+ }
24
+ setLoading(true)
25
+ setError('')
26
+ setOutput('')
27
+ try {
28
+ const res = await fetch('/api/generate', {
29
+ method: 'POST',
30
+ headers: { 'Content-Type': 'application/json' },
31
+ body: JSON.stringify({ prompt, max_new_tokens: maxTokens }),
32
+ })
33
+ const data = await res.json()
34
+ if (!res.ok) {
35
+ throw new Error(data.detail || 'حدث خطأ غير متوقَّع')
36
+ }
37
+ setOutput(data.output)
38
+ } catch (err) {
39
+ setError(err.message)
40
+ } finally {
41
+ setLoading(false)
42
+ }
43
+ }
44
+
45
+ function handleKeyDown(e) {
46
+ if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
47
+ handleGenerate()
48
+ }
49
+ }
50
+
51
+ return (
52
+ <div className="page">
53
+ <div className="card">
54
+ <header>
55
+ <h1>HTDN</h1>
56
+ <p className="subtitle">نموذج لغوي عربي تجريبي (~350M معامل)</p>
57
+ </header>
58
+
59
+ <label className="field-label" htmlFor="prompt">
60
+ النص المبدئي — اكتب أي جملة تريد
61
+ </label>
62
+ <textarea
63
+ id="prompt"
64
+ value={prompt}
65
+ onChange={(e) => setPrompt(e.target.value)}
66
+ onKeyDown={handleKeyDown}
67
+ placeholder="اكتب جملة ليكملها النموذج... (Ctrl/Cmd + Enter للتوليد)"
68
+ rows={4}
69
+ />
70
+
71
+ <div className="examples">
72
+ {EXAMPLES.map((ex) => (
73
+ <button key={ex} className="example-chip" onClick={() => setPrompt(ex)}>
74
+ {ex}
75
+ </button>
76
+ ))}
77
+ </div>
78
+
79
+ <div className="controls">
80
+ <label htmlFor="tokens">
81
+ عدد التوكِنات الجديدة: <strong>{maxTokens}</strong>
82
+ </label>
83
+ <input
84
+ id="tokens"
85
+ type="range"
86
+ min={1}
87
+ max={MAX_TOKENS_LIMIT}
88
+ value={maxTokens}
89
+ onChange={(e) => setMaxTokens(Number(e.target.value))}
90
+ />
91
+ </div>
92
+
93
+ <button className="generate-btn" onClick={handleGenerate} disabled={loading}>
94
+ {loading ? 'جارٍ التوليد...' : 'ولّد النص'}
95
+ </button>
96
+
97
+ {error && <div className="error">{error}</div>}
98
+
99
+ {output && (
100
+ <div className="output">
101
+ <h2>الناتج</h2>
102
+ <p>{output}</p>
103
+ </div>
104
+ )}
105
+
106
+ <p className="note">
107
+ توليد greedy بسيط بلا KV-cache — قد يستغرق ثوانٍ، والنتائج أولية بحكم قصر
108
+ التدريب.
109
+ </p>
110
+ </div>
111
+ </div>
112
+ )
113
+ }
114
+
115
+ export default App