NAKSTStudio commited on
Commit
30bea28
·
verified ·
1 Parent(s): f1d2299

Chess Gemma 3 fine-tuned model with commentary generation

Browse files
Files changed (5) hide show
  1. README.md +302 -135
  2. config.json +2 -2
  3. generation_config.json +13 -0
  4. model.safetensors +2 -2
  5. tokenizer_config.json +2 -3
README.md CHANGED
@@ -9,14 +9,43 @@ tags:
9
  - game-analysis
10
  - flutter
11
  - mobile
 
12
  language:
13
  - en
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  ---
15
 
16
  # Chess Gemma Commentary 🎯♟️
17
  ### By NAKST Studio
18
  <br>
19
- Fine-tuned **Gemma 3 270M** model for generating chess move commentary, ELO predictions, and move classifications.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  ## Model Details
22
 
@@ -27,103 +56,183 @@ Fine-tuned **Gemma 3 270M** model for generating chess move commentary, ELO pred
27
  - **Training Framework:** Unsloth + Hugging Face Transformers
28
  - **Hardware:** Google Colab T4 GPU
29
  - **Model Size:** 500MB (full) / 150MB (quantized q4_k_m)
 
30
 
31
  ## Capabilities
32
 
33
  ✅ **Chess Move Commentary** - Detailed analysis of chess positions and moves
34
  ✅ **ELO Prediction** - Estimates player skill rating (1000-2800)
35
  ✅ **Move Classification** - Labels moves as Best Move, Good Move, Blunder, etc.
 
36
  ✅ **Mobile Ready** - Works on Android with flutter_gemma or Ollama
37
  ✅ **Offline** - No internet required for inference
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  ## Input Format
40
 
41
- The model expects chess position data formatted EXACTLY as follows:
42
 
 
 
 
 
 
 
43
  ```
44
- Analyze this chess move:
45
- FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1,
46
- SAN: Nf6,
47
- Player Color: Black,
48
- Move Classification: Book Move,
49
- Best Alternative Move: g8f6,
50
- CP Before: 27,
51
- CP After: 21,
52
- Opening: Queen's Pawn Game,
53
- Name: Player_123,
54
- is Player Or Bot: Player
55
- Provide Commentary, predicted elo, classification.
 
 
 
 
 
 
56
  ```
57
 
58
- ### Field Descriptions (In Order)
59
-
60
- | Field | Type | Required | Example | Explanation |
61
- |-------|------|----------|--------------------------------------------------------------------------------------------------------------|-------------|
62
- | **FEN** | string | ✅ REQUIRED | `rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1` | Forsyth-Edwards Notation - exact chess position before the move. This is the standard notation that describes where every piece is on the board. |
63
- | **SAN** | string | ✅ REQUIRED | `Nf6` | Standard Algebraic Notation - the move that was played. Examples: e4, Nxf6, O-O (castling), Qh5+, exd5 |
64
- | **Player Color** | string | ✅ REQUIRED | `Black` or `White` | Which side played the move. Must be exactly "White" or "Black" |
65
- | **Move Classification** | string | ✅ REQUIRED | `Book Move`, `Best Move`, `Good Move`, `Inaccuracy`, `Blunder`, `Brilliant`, `Great`, `Inaccuracy`, `Mistake` | Category of the move. Common values: "Book Move", "Best Move", "Good Move", "Inaccuracy", "Blunder", "Forced Move" |
66
- | **Best Alternative Move** | string | ✅ REQUIRED | `g8f6` | What the engine recommends instead (in coordinate notation). Example: if move is Nf6, alternative might be d6, e6, etc. |
67
- | **CP Before** | integer | ✅ REQUIRED | `27` | Centipawn evaluation BEFORE the move. Positive = White better, Negative = Black better. 100 cp ≈ 1 pawn |
68
- | **CP After** | integer | ✅ REQUIRED | `21` | Centipawn evaluation AFTER the move. Shows the impact of the move on the position |
69
- | **Opening** | string | OPTIONAL | `Queen's Pawn Game` | Opening name from opening database. Can be "None" if unknown |
70
- | **Name** | string | OPTIONAL | `Player_123` | Player name or ID. Can be "Unknown" or "..." if not applicable |
71
- | **is Player Or Bot** | string | ✅ REQUIRED | `Player`, `Bot`, `Not Sure` | Whether the move was made by a human player or chess engine. Must be one of these three exact values |
 
 
72
 
73
  ## Sample Input & Output
74
 
75
- ### Example 1: Strong Opening
76
 
77
  **Input:**
78
- ```
79
- Analyze this chess move:
80
- FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1,
81
- SAN: Nf6,
82
- Player Color: Black,
83
- Move Classification: Book Move,
84
- Best Alternative Move: g8f6,
85
- CP Before: 27,
86
- CP After: 21,
87
- Opening: Queen's Pawn Game,
88
- Name: Player_8007,
89
- is Player Or Bot: Player
90
- Provide Commentary, predicted elo, classification.
 
 
 
 
 
 
 
 
91
  ```
92
 
93
  **Output:**
94
  ```
95
  Commentary: Excellent opening response! Nf6 is the classical development move against d4. It immediately challenges the center and prepares flexible piece development. This maintains the tension and gives Black excellent counterplay.
96
-
97
  Predicted ELO: 1850
98
-
99
- Classification: Book Move
100
  ```
101
 
102
- ### Example 2: Middlegame Move
103
 
104
  **Input:**
105
- ```
106
- Analyze this chess move:
107
- FEN: r1bqkb1r/pppp1ppp/2n2n2/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq e6 0 4,
108
- SAN: Nc3,
109
- Player Color: White,
110
- Move Classification: Best Move,
111
- Best Alternative Move: b1c3,
112
- CP Before: 42,
113
- CP After: 38,
114
- Opening: Nimzo-Indian Defense,
115
- Name: GrandMaster_Smith,
116
- is Player Or Bot: Player
117
- Provide Commentary, predicted elo, classification.
 
 
 
 
 
 
 
 
118
  ```
119
 
120
  **Output:**
121
  ```
122
- Commentary: Strong centralization! Nc3 develops with pressure on e4 and controls key central squares. This move prepares to complete development while maintaining the center tension. A solid, principled continuation in this dynamic position.
123
-
124
  Predicted ELO: 2400
 
 
125
 
126
- Classification: Best Move
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  ```
128
 
129
  ## Usage Examples
@@ -132,25 +241,36 @@ Classification: Best Move
132
  ```python
133
  from transformers import AutoModelForCausalLM, AutoTokenizer
134
 
135
- model = AutoModelForCausalLM.from_pretrained("your-username/chess-gemma-commentary")
136
- tokenizer = AutoTokenizer.from_pretrained("your-username/chess-gemma-commentary")
137
-
138
- prompt = """Analyze this chess move:
139
- FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1,
140
- SAN: Nf6,
141
- Player Color: Black,
142
- Move Classification: Book Move,
143
- Best Alternative Move: g8f6,
144
- CP Before: 27,
145
- CP After: 21,
146
- Opening: Queen's Pawn Game,
147
- Name: Player_123,
148
- is Player Or Bot: Player
149
- Provide Commentary, predicted elo, classification."""
150
-
151
- inputs = tokenizer(prompt, return_tensors="pt")
152
- outputs = model.generate(**inputs, max_new_tokens=256, temperature=0.7)
153
- print(tokenizer.decode(outputs[0], skip_special_tokens=True))
 
 
 
 
 
 
 
 
 
 
 
154
  ```
155
 
156
  ### Flutter (flutter_gemma)
@@ -158,81 +278,122 @@ print(tokenizer.decode(outputs[0], skip_special_tokens=True))
158
  import 'package:flutter_gemma/flutter_gemma.dart';
159
 
160
  class ChessAnalyzer {
161
- late GemmaModel model;
162
-
163
  Future<void> initModel() async {
164
- model = await GemmaModel.load(
165
- modelPath: 'assets/model.safetensors',
166
- tokenizerPath: 'assets/tokenizer.model',
167
- configPath: 'assets/config.json',
 
 
 
 
 
 
 
 
 
168
  );
169
  }
170
 
171
  Future<String> analyzeMove({
 
 
 
172
  required String fen,
173
- required String san,
174
- required String playerColor,
175
- required String moveClassification,
176
- required String bestAltMove,
177
- required int cpBefore,
178
- required int cpAfter,
179
- String opening = 'None',
180
- String name = 'Unknown',
181
- required String isPlayerOrBot,
182
  }) async {
183
- final prompt = """Analyze this chess move:
184
- FEN: $fen,
185
- SAN: $san,
186
- Player Color: $playerColor,
187
- Move Classification: $moveClassification,
188
- Best Alternative Move: $bestAltMove,
189
- CP Before: $cpBefore,
190
- CP After: $cpAfter,
191
- Opening: $opening,
192
- Name: $name,
193
- is Player Or Bot: $isPlayerOrBot
194
- Provide Commentary, predicted elo, classification.""";
195
-
196
- return await model.generate(prompt: prompt, maxTokens: 256);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
  }
199
 
200
  // Usage
201
  final analyzer = ChessAnalyzer();
 
 
202
  await analyzer.initModel();
203
 
 
204
  final result = await analyzer.analyzeMove(
 
 
 
205
  fen: 'rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1',
206
- san: 'Nf6',
207
- playerColor: 'Black',
208
- moveClassification: 'Book Move',
209
- bestAltMove: 'g8f6',
210
- cpBefore: 27,
211
- cpAfter: 21,
212
- opening: 'Queen\'s Pawn Game',
213
- name: 'Player_123',
214
- isPlayerOrBot: 'Player',
215
  );
216
 
217
  print(result);
 
 
 
218
  ```
219
 
220
  ## Output Format
221
 
222
  The model generates three key components:
223
 
224
- 1. **Commentary:** Multi-sentence chess analysis (5-50 words typically)
225
  2. **Predicted ELO:** Integer rating (1000-2800 typically)
226
- 3. **Classification:** Single label describing the move
227
 
228
  ## Performance Metrics
229
 
230
- - ⚡ **Inference Speed:** 10-20 tokens/second on mid-range Android phones
231
  - 💾 **Memory Required:** 4GB minimum RAM for on-device inference
232
  - 📱 **Model Sizes:**
233
- - Full precision: 500MB
234
- - Quantized (q4_k_m): 150MB
235
- - 🎯 **Pattern Accuracy:** ~92% consistency with training data
236
 
237
  ## Training Configuration
238
 
@@ -243,8 +404,8 @@ The model generates three key components:
243
  - **Learning Rate:** 2e-4
244
  - **Batch Size:** 8 (effective; per device: 1, gradient accumulation: 8)
245
  - **Optimizer:** AdamW 8-bit
246
- - **Warmup Steps:** 50
247
- - **Training Time:** ~40 minutes (3 epochs on Colab T4)
248
 
249
  ## Model Files
250
 
@@ -262,15 +423,19 @@ chess-gemma-commentary/
262
 
263
  ## Important Notes
264
 
265
- ⚠️ **Format Sensitivity:** This model is trained on the EXACT format shown above. Follow field order, spacing, and punctuation precisely for best results.
 
 
266
 
267
- ⚠️ **Commas Matter:** Notice commas after each field (except the last one). Don't remove them.
 
 
268
 
269
- ✅ **Optional Fields:** Only "Opening" and "Name" are optional - all others are required.
270
 
271
- ✅ **Flexible Values:** You can change the values, but keep the field labels and format identical.
272
 
273
- ✅ **Multi-position:** Works well for opening, middlegame, and endgame positions.
274
 
275
  ## Known Limitations
276
 
@@ -278,6 +443,8 @@ chess-gemma-commentary/
278
  - ❌ Requires 4GB+ RAM for mobile inference (quantization helps)
279
  - ❌ Temperature affects output randomness (0.7 recommended for chess)
280
  - ❌ Cannot analyze positions with invalid FEN notation
 
 
281
 
282
  ## License
283
 
@@ -287,8 +454,8 @@ This model is distributed under the **Gemma Community License**. See: https://ai
287
 
288
  ```bibtex
289
  @model{chess_gemma_commentary_2025,
290
- title={Chess Gemma Commentary},
291
- author={Your Name},
292
  year={2025},
293
  howpublished={Hugging Face Hub}
294
  }
@@ -312,4 +479,4 @@ This model is distributed under the **Gemma Community License**. See: https://ai
312
 
313
  **Made with ❤️ by NAKST Studio**
314
 
315
- *Last Updated: November 3, 2025*
 
9
  - game-analysis
10
  - flutter
11
  - mobile
12
+ - multilingual
13
  language:
14
  - en
15
+ - hi
16
+ - es
17
+ - zh
18
+ - fr
19
+ - de
20
+ - pt
21
+ - ru
22
+ - ja
23
+ - ar
24
+ - ko
25
+ - tr
26
+ - id
27
+ - bn
28
  ---
29
 
30
  # Chess Gemma Commentary 🎯♟️
31
  ### By NAKST Studio
32
  <br>
33
+ Fine-tuned <strong>Gemma 3 270M</strong> model for generating chess move commentary, ELO predictions, and move classifications in <strong>14 languages</strong>.
34
+
35
+ ---
36
+
37
+ <div align="center">
38
+
39
+ ### 💙 Support & Shape NAKST Studio
40
+
41
+ [![Donate](https://img.shields.io/badge/💙_Donate-Support_Free_Development-0080FF?style=for-the-badge)](https://nakststudio.com/donate)
42
+ [![Vote Next App](https://img.shields.io/badge/🗳️_Vote-Choose_Our_Next_App-FF6B6B?style=for-the-badge)](https://nakststudio.com/vote-next-app-beta)
43
+
44
+ **Help us keep building free, privacy-focused chess tools!** Support teen developers creating amazing apps without ads or data collection. Vote for what we build next!
45
+
46
+ </div>
47
+
48
+ ---
49
 
50
  ## Model Details
51
 
 
56
  - **Training Framework:** Unsloth + Hugging Face Transformers
57
  - **Hardware:** Google Colab T4 GPU
58
  - **Model Size:** 500MB (full) / 150MB (quantized q4_k_m)
59
+ - **Languages Supported:** 14 (English, Hindi, Spanish, Mandarin Chinese, French, German, Portuguese, Russian, Japanese, Arabic, Korean, Turkish, Indonesian, Bengali)
60
 
61
  ## Capabilities
62
 
63
  ✅ **Chess Move Commentary** - Detailed analysis of chess positions and moves
64
  ✅ **ELO Prediction** - Estimates player skill rating (1000-2800)
65
  ✅ **Move Classification** - Labels moves as Best Move, Good Move, Blunder, etc.
66
+ ✅ **Multilingual Support** - Generate commentary in 14 different languages
67
  ✅ **Mobile Ready** - Works on Android with flutter_gemma or Ollama
68
  ✅ **Offline** - No internet required for inference
69
 
70
+ ## Supported Languages
71
+
72
+ | Language Code | Language Name | Native Name |
73
+ |---------------|---------------|-------------|
74
+ | `en` | English | English |
75
+ | `hi` | Hindi | हिन्दी |
76
+ | `es` | Spanish | Español |
77
+ | `zh` | Mandarin Chinese | 中文 |
78
+ | `fr` | French | Français |
79
+ | `de` | German | Deutsch |
80
+ | `pt` | Portuguese | Português |
81
+ | `ru` | Russian | Русский |
82
+ | `ja` | Japanese | 日本語 |
83
+ | `ar` | Arabic | العربية |
84
+ | `ko` | Korean | 한국어 |
85
+ | `tr` | Turkish | Türkçe |
86
+ | `id` | Indonesian | Bahasa Indonesia |
87
+ | `bn` | Bengali | বাংলা |
88
+
89
  ## Input Format
90
 
91
+ The model uses a **conversational format** with system and user messages. The input expects a JSON-like structure with role-based messages.
92
 
93
+ ### System Message (Required)
94
+ ```python
95
+ {
96
+ 'role': 'system',
97
+ 'content': 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.'
98
+ }
99
  ```
100
+
101
+ ### User Message Format
102
+ ```python
103
+ {
104
+ 'role': 'user',
105
+ 'content': '''LanguageL: English
106
+ LangCode: en
107
+ Type: standard
108
+ FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1
109
+ MoveSAN: Nf6
110
+ Side: Black
111
+ Actor: human
112
+ Name: John
113
+ Gender: male
114
+ Tag: Book
115
+ BestAlt: g8f6
116
+ CP: 27->21 (Δ=6)'''
117
+ }
118
  ```
119
 
120
+ ### Field Descriptions
121
+
122
+ | Field | Type | Required | Example | Explanation |
123
+ |---------------|------|------------|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
124
+ | **LanguageL** | string | ✅ REQUIRED | `English`, `Hindi`, `Spanish` | Full language name for commentary generation |
125
+ | **LangCode** | string | ✅ REQUIRED | `en`, `hi`, `es` | ISO 639-1 language code (see table above) |
126
+ | **Type** | string | ✅ REQUIRED | `standard`, `explanation` | Commentary type: `standard` (30-40 words) or `explanation` (explain best move, ≤50 words) |
127
+ | **FEN** | string | ✅ REQUIRED | `rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1` | Forsyth-Edwards Notation - exact chess position before the move |
128
+ | **MoveSAN** | string | ✅ REQUIRED | `Nf6`, `e4`, `O-O` | Standard Algebraic Notation - the move that was played |
129
+ | **Side** | string | ✅ REQUIRED | `White`, `Black` | Which side played the move |
130
+ | **Actor** | string | ✅ REQUIRED | `human`, `bot` | Whether move was made by human or engine |
131
+ | **NAME** | string | OPTIONAL | `Name of human or bot` | Human or bot gender who played the move for personalized commentary |
132
+ | **Gender** | string | OPTIONAL | `male`, `female`, `neutral` | Player or bot gender for personalized commentary |
133
+ | **Tag** | string | ✅ REQUIRED | `Book`, `Best`, `Good`, `Inaccuracy`, `Mistake`, `Blunder`, `Brilliant` | Move classification tag |
134
+ | **BestAlt** | string | ✅ REQUIRED | `g8f6`, `e2e4` | Best alternative move in coordinate notation |
135
+ | **CP** | string | ✅ REQUIRED | `27->21 (Δ=6)` | Centipawn evaluation: before->after (Delta=change). Format: `CPBefore->CPAfter (Δ=change)` |
136
 
137
  ## Sample Input & Output
138
 
139
+ ### Example 1: English Commentary (Standard)
140
 
141
  **Input:**
142
+ ```python
143
+ [
144
+ {
145
+ 'role': 'system',
146
+ 'content': 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.'
147
+ },
148
+ {
149
+ 'role': 'user',
150
+ 'content': '''LanguageL: English
151
+ LangCode: en
152
+ Type: standard
153
+ FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1
154
+ MoveSAN: Nf6
155
+ Side: Black
156
+ Actor: human
157
+ Gender: male
158
+ Tag: Book
159
+ BestAlt: g8f6
160
+ CP: 27->21 (Δ=6)'''
161
+ }
162
+ ]
163
  ```
164
 
165
  **Output:**
166
  ```
167
  Commentary: Excellent opening response! Nf6 is the classical development move against d4. It immediately challenges the center and prepares flexible piece development. This maintains the tension and gives Black excellent counterplay.
 
168
  Predicted ELO: 1850
169
+ Verified Classification: Book Move
 
170
  ```
171
 
172
+ ### Example 2: Hindi Commentary (Standard)
173
 
174
  **Input:**
175
+ ```python
176
+ [
177
+ {
178
+ 'role': 'system',
179
+ 'content': 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.'
180
+ },
181
+ {
182
+ 'role': 'user',
183
+ 'content': '''LanguageL: Hindi
184
+ LangCode: hi
185
+ Type: standard
186
+ FEN: r1bqkb1r/pppp1ppp/2n2n2/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq e6 0 4
187
+ MoveSAN: Nc3
188
+ Side: White
189
+ Actor: human
190
+ Gender: female
191
+ Tag: Best
192
+ BestAlt: b1c3
193
+ CP: 42->38 (Δ=4)'''
194
+ }
195
+ ]
196
  ```
197
 
198
  **Output:**
199
  ```
200
+ Commentary: शानदार केंद्रीकरण! Nc3 e4 पर दबाव के साथ विकसित होता है और प्रमुख केंद्रीय वर्गों को नियंत्रित करता है। यह चाल विकास को पूरा करने की तैयारी करती है जबकि केंद्र तनाव बनाए रखती है।
 
201
  Predicted ELO: 2400
202
+ Verified Classification: Best Move
203
+ ```
204
 
205
+ ### Example 3: Explanation Type (Spanish)
206
+
207
+ **Input:**
208
+ ```python
209
+ [
210
+ {
211
+ 'role': 'system',
212
+ 'content': 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.'
213
+ },
214
+ {
215
+ 'role': 'user',
216
+ 'content': '''LanguageL: Spanish
217
+ LangCode: es
218
+ Type: explanation
219
+ FEN: 2rq1rk1/pb1nb1pp/1p6/3p1p2/3Pn3/P1N5/1PQNBPPP/R1B1R1K1 w - - 0 16
220
+ MoveSAN: f3
221
+ Side: White
222
+ Actor: human
223
+ Gender: male
224
+ Tag: Mistake
225
+ BestAlt: d2e4
226
+ CP: 23->59 (Δ=36)'''
227
+ }
228
+ ]
229
+ ```
230
+
231
+ **Output:**
232
+ ```
233
+ Commentary: El movimiento f3 debilita el rey y permite contraataques tácticos. La mejor alternativa Ne4 centralizaría el caballo con amenazas activas mientras mantiene la seguridad del rey. Este error costó aproximadamente un tercio de peón en ventaja posicional.
234
+ Predicted ELO: 1650
235
+ Verified Classification: Mistake
236
  ```
237
 
238
  ## Usage Examples
 
241
  ```python
242
  from transformers import AutoModelForCausalLM, AutoTokenizer
243
 
244
+ model = AutoModelForCausalLM.from_pretrained("NAKSTStudio/chess-gemma-commentary")
245
+ tokenizer = AutoTokenizer.from_pretrained("NAKSTStudio/chess-gemma-commentary")
246
+
247
+ # Prepare messages
248
+ messages = [
249
+ {
250
+ 'role': 'system',
251
+ 'content': 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.'
252
+ },
253
+ {
254
+ 'role': 'user',
255
+ 'content': '''LanguageL: English
256
+ LangCode: en
257
+ Type: standard
258
+ FEN: rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1
259
+ MoveSAN: Nf6
260
+ Side: Black
261
+ Actor: human
262
+ Gender: male
263
+ Tag: Book
264
+ BestAlt: g8f6
265
+ CP: 27->21 (Δ=6)'''
266
+ }
267
+ ]
268
+
269
+ # Generate response
270
+ inputs = tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True)
271
+ outputs = model.generate(inputs, max_new_tokens=256, temperature=0.7)
272
+ response = tokenizer.decode(outputs[0], skip_special_tokens=True)
273
+ print(response)
274
  ```
275
 
276
  ### Flutter (flutter_gemma)
 
278
  import 'package:flutter_gemma/flutter_gemma.dart';
279
 
280
  class ChessAnalyzer {
281
+ late InferenceModel model;
282
+
283
  Future<void> initModel() async {
284
+ // Install model from Hugging Face (one-time operation)
285
+ await FlutterGemma.installModel(
286
+ modelType: ModelType.gemmaIt,
287
+ ).fromNetwork(
288
+ 'https://huggingface.co/NAKSTStudio/chess-gemma-commentary/resolve/main/model.safetensors',
289
+ ).withProgress((progress) {
290
+ print('Downloading model: ${progress.percentage}%');
291
+ }).install();
292
+
293
+ // Create model instance for inference
294
+ model = await FlutterGemma.getActiveModel(
295
+ maxTokens: 256,
296
+ preferredBackend: PreferredBackend.gpu,
297
  );
298
  }
299
 
300
  Future<String> analyzeMove({
301
+ required String language,
302
+ required String langCode,
303
+ required String type,
304
  required String fen,
305
+ required String moveSAN,
306
+ required String side,
307
+ required String actor,
308
+ required String gender,
309
+ required String tag,
310
+ required String bestAlt,
311
+ required String cp,
 
 
312
  }) async {
313
+ final chat = await model.createChat(temperature: 0.7);
314
+
315
+ // Add system message
316
+ await chat.addQueryChunk(Message.text(
317
+ text: 'Generate professional chess commentary in the specified language. For Type=standard use 30–40 words. For Type=explanation, explain the best move briefly (≤50 words). Return exactly: Commentary, Predicted ELO, Verified Classification.',
318
+ isUser: false,
319
+ ));
320
+
321
+ // Add user message with chess position data
322
+ await chat.addQueryChunk(Message.text(
323
+ text: '''LanguageL: $language
324
+ LangCode: $langCode
325
+ Type: $type
326
+ FEN: $fen
327
+ MoveSAN: $moveSAN
328
+ Side: $side
329
+ Actor: $actor
330
+ Gender: $gender
331
+ Tag: $tag
332
+ BestAlt: $bestAlt
333
+ CP: $cp''',
334
+ isUser: true,
335
+ ));
336
+
337
+ // Generate response
338
+ final response = await chat.generateChatResponse();
339
+
340
+ await chat.close();
341
+
342
+ if (response is TextResponse) {
343
+ return response.token;
344
+ }
345
+
346
+ return 'Error generating response';
347
+ }
348
+
349
+ Future<void> dispose() async {
350
+ await model.close();
351
  }
352
  }
353
 
354
  // Usage
355
  final analyzer = ChessAnalyzer();
356
+
357
+ // Initialize once (downloads model if not present)
358
  await analyzer.initModel();
359
 
360
+ // Use multiple times
361
  final result = await analyzer.analyzeMove(
362
+ language: 'English',
363
+ langCode: 'en',
364
+ type: 'standard',
365
  fen: 'rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b KQkq - 0 1',
366
+ moveSAN: 'Nf6',
367
+ side: 'Black',
368
+ actor: 'human',
369
+ gender: 'male',
370
+ tag: 'Book',
371
+ bestAlt: 'g8f6',
372
+ cp: '27->21 (Δ=6)',
 
 
373
  );
374
 
375
  print(result);
376
+
377
+ // Clean up when done
378
+ await analyzer.dispose();
379
  ```
380
 
381
  ## Output Format
382
 
383
  The model generates three key components:
384
 
385
+ 1. **Commentary:** Multi-sentence chess analysis in the specified language (30-50 words typically)
386
  2. **Predicted ELO:** Integer rating (1000-2800 typically)
387
+ 3. **Verified Classification:** Single label describing the move (Book Move, Best Move, Good Move, Inaccuracy, Mistake, Blunder, Brilliant)
388
 
389
  ## Performance Metrics
390
 
391
+ - ⚡ **Inference Speed:** 15-30 tokens/second on mid-range Android phones
392
  - 💾 **Memory Required:** 4GB minimum RAM for on-device inference
393
  - 📱 **Model Sizes:**
394
+ - TASK File(int 8 dynamic): ~250 mb
395
+ - TASK File: ~500 mb
396
+ - 🌍 **Language Coverage:** 14 languages spanning 5+ billion speakers
397
 
398
  ## Training Configuration
399
 
 
404
  - **Learning Rate:** 2e-4
405
  - **Batch Size:** 8 (effective; per device: 1, gradient accumulation: 8)
406
  - **Optimizer:** AdamW 8-bit
407
+ - **Warmup Steps:** 5
408
+ - **Training Time:** ~100 minutes (4 epochs on Colab T4)
409
 
410
  ## Model Files
411
 
 
423
 
424
  ## Important Notes
425
 
426
+ ⚠️ **Format Sensitivity:** This model is trained on the EXACT format shown above. Follow field order, spacing, and field names precisely for best results.
427
+
428
+ ⚠️ **Language Codes:** Use the correct ISO 639-1 language code from the supported languages table. Incorrect codes may produce unexpected results.
429
 
430
+ ⚠️ **Commentary Types:**
431
+ - `Type=standard`: Generates 30-40 word general commentary
432
+ - `Type=explanation`: Generates ≤50 word explanation focusing on why the best alternative move is superior
433
 
434
+ ✅ **Conversational Format:** The model uses a message-based format with system and user roles for better context understanding.
435
 
436
+ ✅ **Gender-Aware:** Optionally customize commentary style based on player gender (male/female/neutral).
437
 
438
+ ✅ **Delta Information:** The CP field format `CPBefore->CPAfter (Δ=change)` helps the model understand move impact.
439
 
440
  ## Known Limitations
441
 
 
443
  - ❌ Requires 4GB+ RAM for mobile inference (quantization helps)
444
  - ❌ Temperature affects output randomness (0.7 recommended for chess)
445
  - ❌ Cannot analyze positions with invalid FEN notation
446
+ - ❌ Language quality may vary - English has most training data coverage
447
+ - ❌ Some languages may require native speaker validation for natural phrasing
448
 
449
  ## License
450
 
 
454
 
455
  ```bibtex
456
  @model{chess_gemma_commentary_2025,
457
+ title={Chess Gemma Commentary: Multilingual Chess Analysis},
458
+ author={NAKST Studio},
459
  year={2025},
460
  howpublished={Hugging Face Hub}
461
  }
 
479
 
480
  **Made with ❤️ by NAKST Studio**
481
 
482
+ *Last Updated: November 7, 2025*
config.json CHANGED
@@ -7,7 +7,7 @@
7
  "attention_dropout": 0.0,
8
  "attn_logit_softcapping": null,
9
  "bos_token_id": 2,
10
- "torch_dtype": "float16",
11
  "eos_token_id": 106,
12
  "final_logit_softcapping": null,
13
  "head_dim": 256,
@@ -49,7 +49,7 @@
49
  "sliding_window": 512,
50
  "transformers_version": "4.56.2",
51
  "unsloth_fixed": true,
52
- "unsloth_version": "2025.10.12",
53
  "use_bidirectional_attention": false,
54
  "use_cache": true,
55
  "vocab_size": 262144
 
7
  "attention_dropout": 0.0,
8
  "attn_logit_softcapping": null,
9
  "bos_token_id": 2,
10
+ "dtype": "float16",
11
  "eos_token_id": 106,
12
  "final_logit_softcapping": null,
13
  "head_dim": 256,
 
49
  "sliding_window": 512,
50
  "transformers_version": "4.56.2",
51
  "unsloth_fixed": true,
52
+ "unsloth_version": "2025.11.1",
53
  "use_bidirectional_attention": false,
54
  "use_cache": true,
55
  "vocab_size": 262144
generation_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 2,
3
+ "do_sample": true,
4
+ "eos_token_id": [
5
+ 1,
6
+ 106
7
+ ],
8
+ "max_length": 32768,
9
+ "pad_token_id": 0,
10
+ "top_k": 64,
11
+ "top_p": 0.95,
12
+ "transformers_version": "4.56.2"
13
+ }
model.safetensors CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:5b1e395af93ce68b0734b58e44d704a2114f5bca9545db153146f4c61c143ed8
3
- size 536223056
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:accd9b8709ec7ac61d0a7edff2eb50b8d15943259da36524c3565e2a60ce2a22
3
+ size 536333936
tokenizer_config.json CHANGED
@@ -51341,6 +51341,5 @@
51341
  "spaces_between_special_tokens": false,
51342
  "tokenizer_class": "GemmaTokenizer",
51343
  "unk_token": "<unk>",
51344
- "use_default_system_prompt": false,
51345
- "chat_template": "{{ bos_token }}\n{%- if messages[0]['role'] == 'system' -%}\n {%- if messages[0]['content'] is string -%}\n {%- set first_user_prefix = messages[0]['content'] + '\n\n' -%}\n {%- else -%}\n {%- set first_user_prefix = messages[0]['content'][0]['text'] + '\n\n' -%}\n {%- endif -%}\n {%- set loop_messages = messages[1:] -%}\n{%- else -%}\n {%- set first_user_prefix = \"\" -%}\n {%- set loop_messages = messages -%}\n{%- endif -%}\n{%- for message in loop_messages -%}\n {%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) -%}\n {{ raise_exception(\"Conversation roles must alternate user/assistant/user/assistant/...\") }}\n {%- endif -%}\n {%- if (message['role'] == 'assistant') -%}\n {%- set role = \"model\" -%}\n {%- else -%}\n {%- set role = message['role'] -%}\n {%- endif -%}\n {{ '<start_of_turn>' + role + '\n' + (first_user_prefix if loop.first else \"\") }}\n {%- if message['content'] is string -%}\n {{ message['content'] | trim }}\n {%- elif message['content'] is iterable -%}\n {%- for item in message['content'] -%}\n {%- if item['type'] == 'image' -%}\n {{ '<start_of_image>' }}\n {%- elif item['type'] == 'text' -%}\n {{ item['text'] | trim }}\n {%- endif -%}\n {%- endfor -%}\n {%- else -%}\n {{ raise_exception(\"Invalid content type\") }}\n {%- endif -%}\n {{ '<end_of_turn>\n' }}\n{%- endfor -%}\n{%- if add_generation_prompt -%}\n {{ '<start_of_turn>model\n' }}\n{%- endif -%}\n"
51346
- }
 
51341
  "spaces_between_special_tokens": false,
51342
  "tokenizer_class": "GemmaTokenizer",
51343
  "unk_token": "<unk>",
51344
+ "use_default_system_prompt": false
51345
+ }