MrSimple07 commited on
Commit
80e55f8
Β·
1 Parent(s): bdd9340

new structure for the overall part

Browse files
Files changed (4) hide show
  1. ai_integration.py +78 -0
  2. app.py +45 -279
  3. chess_api.py +117 -0
  4. core.py +71 -0
ai_integration.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import datetime
3
+ import google.generativeai as genai
4
+ import os
5
+
6
+
7
+ genai.configure(api_key=os.environ.get('GOOGLE_API_KEY'))
8
+ model = genai.GenerativeModel('gemini-2.5-flash')
9
+
10
+ def get_counter_debuts(opponent_debuts, user_color, user_repertoire):
11
+ if not opponent_debuts or not opponent_debuts.strip():
12
+ return "❌ Iltimos, kamida bitta debyt kiriting!"
13
+
14
+ color_context = "Siz oq rangli o'ynaysiz." if user_color == "Oq" else "Siz qora rangli o'ynaysiz."
15
+
16
+ repertoire_context = ""
17
+ if user_repertoire and user_repertoire.strip():
18
+ repertoire_context = f"\n\nFOYDALANUVCHI REPERTUARI:\n{user_repertoire}\n\nIltimos, bu repertuarni hisobga olib tavsiyalar bering."
19
+
20
+ prompt = f"""
21
+ Siz professional shaxmat murabbiyisiz. {color_context}
22
+
23
+ Raqib quyidagi debyutlarni o'ynaydi:
24
+ {opponent_debuts}
25
+ {repertoire_context}
26
+
27
+ Har bir raqib debyuti uchun quyidagilarni bering:
28
+
29
+ ## DEBYT NOMI
30
+
31
+ **Qarshi Debyt:** [Eng yaxshi qarshi debyt]
32
+
33
+ **Asosiy G'oya:**
34
+ [2-3 jumlada tushuntirish]
35
+
36
+ **Strategik Rejalar:**
37
+ - [Reja 1]
38
+ - [Reja 2]
39
+ - [Reja 3]
40
+
41
+ **Muhim Yurishlar:**
42
+ [Boshlanish yurishlari ketma-ketligi]
43
+
44
+ **Tuzoqlar va Ehtiyot Choralari:**
45
+ [Diqqat qilish kerak bo'lgan narsalar]
46
+
47
+ ---
48
+
49
+ Javobni o'zbek tilida, toza markdown formatida bering.
50
+ """
51
+
52
+ try:
53
+ response = model.generate_content(prompt)
54
+ fixed_response = response.text.strip()
55
+
56
+ result = f"""# πŸ† SHAXMAT TAHLILI NATIJALARI
57
+
58
+ **Sana:** {datetime.now().strftime("%Y-%m-%d %H:%M")}
59
+ **Sizning Rangingiz:** {user_color}
60
+ ---
61
+
62
+ {fixed_response}
63
+
64
+ ---
65
+
66
+ ## πŸ’‘ QO'SHIMCHA MASLAHATLAR
67
+
68
+ 1. **O'rganish:** Har bir debyutni lichess.org/learn yoki chess.com da mashq qiling
69
+ 2. **Tahlil:** O'yinlaringizni tahlil qiling va xatolarni toping
70
+ 3. **Mashq:** Turli holatlarni mashq qiling
71
+ 4. **Vaqt:** Har bir debyutga kamida 30 daqiqa ajrating
72
+
73
+ βœ… **Omad tilaymiz! Yaxshi o'ynang!** β™ŸοΈ
74
+ """
75
+ return result
76
+
77
+ except Exception as e:
78
+ return f"❌ Xatolik yuz berdi: {str(e)}\n\nIltimos, GOOGLE_API_KEY to'g'ri o'rnatilganligini tekshiring."
app.py CHANGED
@@ -1,256 +1,15 @@
1
- import google.generativeai as genai
2
- import os
3
  import gradio as gr
4
- from datetime import datetime
5
  import logging
6
- import requests
7
- import time
8
- import pandas as pd
9
- import re
10
- from collections import Counter
11
 
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
  logger = logging.getLogger(__name__)
14
 
15
- genai.configure(api_key=os.environ.get('GOOGLE_API_KEY'))
16
- model = genai.GenerativeModel('gemini-2.5-flash')
17
-
18
- eco_data = None
19
-
20
- def load_eco_data():
21
- global eco_data
22
- try:
23
- eco_data = pd.read_csv('data/Chess Opening Reference - Sheet1.csv')
24
- logger.info(f"Loaded {len(eco_data)} ECO codes")
25
- return True
26
- except Exception as e:
27
- logger.error(f"Error loading ECO data: {str(e)}")
28
- return False
29
-
30
- def get_user_games_from_chess_com(username):
31
- try:
32
- logger.info(f"Fetching games for: {username}")
33
- username = username.strip().lower()
34
-
35
- user_url = f"https://api.chess.com/pub/player/{username}"
36
- response = requests.get(user_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
37
-
38
- if response.status_code != 200:
39
- return None, f"❌ Foydalanuvchi topilmadi: {username}"
40
-
41
- archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
42
- response = requests.get(archives_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
43
-
44
- if response.status_code != 200:
45
- return None, "❌ O'yinlar arxivi topilmadi."
46
-
47
- archives = response.json()['archives']
48
- if not archives:
49
- return None, "❌ O'yinlar topilmadi."
50
-
51
- all_games = []
52
- for archive_url in reversed(archives[-3:]):
53
- time.sleep(0.3)
54
- response = requests.get(archive_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
55
- if response.status_code == 200:
56
- games = response.json()['games']
57
- all_games.extend(games)
58
- if len(all_games) >= 50:
59
- break
60
-
61
- rapid_games = [g for g in all_games if g.get('time_class') in ['rapid', 'blitz']]
62
- if not rapid_games:
63
- rapid_games = all_games[:50]
64
-
65
- pgn_list = [g['pgn'] for g in rapid_games[:50] if 'pgn' in g]
66
-
67
- if not pgn_list:
68
- return None, "❌ PGN formatdagi o'yinlar topilmadi."
69
-
70
- return pgn_list, None
71
-
72
- except Exception as e:
73
- logger.error(f"Error fetching games: {str(e)}")
74
- return None, f"❌ Xatolik: {str(e)}"
75
-
76
- def extract_eco_from_pgn(pgn):
77
- eco_match = re.search(r'\[ECO "([A-E][0-9]{2})"\]', pgn)
78
- return eco_match.group(1) if eco_match else None
79
-
80
- def get_opening_name(eco_code):
81
- if eco_data is not None and eco_code:
82
- match = eco_data[eco_data['ECO Code'] == eco_code]
83
- if not match.empty:
84
- return match.iloc[0]['Name']
85
- return "Unknown Opening"
86
-
87
- def analyze_opponent_openings(pgn_list, target_username):
88
- target_username = target_username.lower()
89
- opponent_openings = []
90
-
91
- for pgn in pgn_list:
92
- white_match = re.search(r'\[White "([^"]+)"\]', pgn)
93
- black_match = re.search(r'\[Black "([^"]+)"\]', pgn)
94
-
95
- if not white_match or not black_match:
96
- continue
97
-
98
- white_player = white_match.group(1).lower()
99
- black_player = black_match.group(1).lower()
100
-
101
- is_white = target_username in white_player
102
- is_black = target_username in black_player
103
-
104
- if not is_white and not is_black:
105
- continue
106
-
107
- eco_code = extract_eco_from_pgn(pgn)
108
- if eco_code:
109
- opening_name = get_opening_name(eco_code)
110
-
111
- if is_white:
112
- opponent_color = "qora"
113
- else:
114
- opponent_color = "oq"
115
-
116
- opponent_openings.append({
117
- 'eco': eco_code,
118
- 'name': opening_name,
119
- 'opponent_color': opponent_color,
120
- 'user_color': 'oq' if is_white else 'qora'
121
- })
122
-
123
- return opponent_openings
124
-
125
- def get_counter_debuts(opponent_debuts, user_color, user_repertoire):
126
- if not opponent_debuts or not opponent_debuts.strip():
127
- return "❌ Iltimos, kamida bitta debyt kiriting!"
128
-
129
- color_context = "Siz oq rangli o'ynaysiz." if user_color == "Oq" else "Siz qora rangli o'ynaysiz."
130
-
131
- repertoire_context = ""
132
- if user_repertoire and user_repertoire.strip():
133
- repertoire_context = f"\n\nFOYDALANUVCHI REPERTUARI:\n{user_repertoire}\n\nIltimos, bu repertuarni hisobga olib tavsiyalar bering."
134
-
135
- prompt = f"""
136
- Siz professional shaxmat murabbiyisiz. {color_context}
137
-
138
- Raqib quyidagi debyutlarni o'ynaydi:
139
- {opponent_debuts}
140
- {repertoire_context}
141
-
142
- Har bir raqib debyuti uchun quyidagilarni bering:
143
-
144
- ## DEBYT NOMI
145
-
146
- **Qarshi Debyt:** [Eng yaxshi qarshi debyt]
147
-
148
- **Asosiy G'oya:**
149
- [2-3 jumlada tushuntirish]
150
-
151
- **Strategik Rejalar:**
152
- - [Reja 1]
153
- - [Reja 2]
154
- - [Reja 3]
155
-
156
- **Muhim Yurishlar:**
157
- [Boshlanish yurishlari ketma-ketligi]
158
-
159
- **Tuzoqlar va Ehtiyot Choralari:**
160
- [Diqqat qilish kerak bo'lgan narsalar]
161
-
162
- ---
163
-
164
- Javobni o'zbek tilida, toza markdown formatida bering.
165
- """
166
-
167
- try:
168
- response = model.generate_content(prompt)
169
- fixed_response = response.text.strip()
170
-
171
- result = f"""# πŸ† SHAXMAT TAHLILI NATIJALARI
172
-
173
- **Sana:** {datetime.now().strftime("%Y-%m-%d %H:%M")}
174
- **Sizning Rangingiz:** {user_color}
175
- ---
176
-
177
- {fixed_response}
178
-
179
- ---
180
-
181
- ## πŸ’‘ QO'SHIMCHA MASLAHATLAR
182
-
183
- 1. **O'rganish:** Har bir debyutni lichess.org/learn yoki chess.com da mashq qiling
184
- 2. **Tahlil:** O'yinlaringizni tahlil qiling va xatolarni toping
185
- 3. **Mashq:** Turli holatlarni mashq qiling
186
- 4. **Vaqt:** Har bir debyutga kamida 30 daqiqa ajrating
187
-
188
- βœ… **Omad tilaymiz! Yaxshi o'ynang!** β™ŸοΈ
189
- """
190
- return result
191
-
192
- except Exception as e:
193
- return f"❌ Xatolik yuz berdi: {str(e)}\n\nIltimos, GOOGLE_API_KEY to'g'ri o'rnatilganligini tekshiring."
194
-
195
- def analyze_chess_com_user(username, user_repertoire):
196
- if not username or not username.strip():
197
- return "❌ Iltimos, Chess.com foydalanuvchi nomini kiriting!"
198
-
199
- status_msg = f"πŸ” {username} foydalanuvchisi o'yinlari yuklanmoqda...\n\n"
200
-
201
- pgn_list, error = get_user_games_from_chess_com(username)
202
-
203
- if error:
204
- return error
205
-
206
- status_msg += f"βœ… {len(pgn_list)} ta o'yin topildi!\n\n"
207
- status_msg += "πŸ“Š Debyutlar tahlil qilinmoqda...\n\n"
208
-
209
- opponent_openings = analyze_opponent_openings(pgn_list, username)
210
-
211
- if not opponent_openings:
212
- return status_msg + "❌ Raqib debyutlari aniqlanmadi."
213
-
214
- white_openings = [o for o in opponent_openings if o['opponent_color'] == 'oq']
215
- black_openings = [o for o in opponent_openings if o['opponent_color'] == 'qora']
216
-
217
- white_counter = Counter([o['name'] for o in white_openings])
218
- black_counter = Counter([o['name'] for o in black_openings])
219
-
220
- analysis_text = "# πŸ“ˆ RAQIB DEBYUTLARI TAHLILI\n\n"
221
- analysis_text += f"**Foydalanuvchi:** {username}\n"
222
- analysis_text += f"**Tahlil qilingan o'yinlar:** {len(pgn_list)}\n\n"
223
-
224
- if white_openings:
225
- analysis_text += "## 🎯 Raqib OQ rang bilan o'ynaganida:\n\n"
226
- for opening, count in white_counter.most_common(5):
227
- analysis_text += f"- **{opening}** ({count} marta)\n"
228
- analysis_text += "\n"
229
-
230
- if black_openings:
231
- analysis_text += "## 🎯 Raqib QORA rang bilan o'ynaganida:\n\n"
232
- for opening, count in black_counter.most_common(5):
233
- analysis_text += f"- **{opening}** ({count} marta)\n"
234
- analysis_text += "\n"
235
-
236
- debuts_for_ai = ""
237
- if white_counter:
238
- debuts_for_ai += "Raqib OQ bilan: " + ", ".join([o for o, _ in white_counter.most_common(3)]) + "\n"
239
- if black_counter:
240
- debuts_for_ai += "Raqib QORA bilan: " + ", ".join([o for o, _ in black_counter.most_common(3)])
241
-
242
- analysis_text += "\n---\n\n"
243
- analysis_text += "## πŸ€– AI TAVSIYALARI\n\n"
244
-
245
- try:
246
- color_for_ai = "Oq" if white_openings else "Qora"
247
- ai_response = get_counter_debuts(debuts_for_ai, color_for_ai, user_repertoire)
248
- analysis_text += ai_response
249
- except Exception as e:
250
- analysis_text += f"❌ AI tahlil xatosi: {str(e)}"
251
-
252
- return analysis_text
253
-
254
  def create_interface():
255
  with gr.Blocks(theme=gr.themes.Soft(), title="Shaxmat AI Maslahatchi", css="""
256
  .gradio-container {font-family: 'Arial', sans-serif;}
@@ -306,38 +65,45 @@ def create_interface():
306
  label="πŸ’‘ Misollar"
307
  )
308
 
309
- with gr.Tab("🌐 Chess.com Tahlili"):
310
- gr.Markdown("### Raqib Chess.com profilini tahlil qiling")
311
-
312
- with gr.Row():
313
- with gr.Column(scale=1):
314
- chess_com_username = gr.Textbox(
315
- label="πŸ‘€ Chess.com Foydalanuvchi Nomi",
316
- placeholder="Misol: Hikaru",
317
- info="Raqibingiz Chess.com username"
318
- )
319
-
320
- user_repertoire2 = gr.Textbox(
321
- label="πŸ“š Sizning Repertuaringiz (ixtiyoriy)",
322
- placeholder="Misol: e4 ga qarshi Sicilian, d4 ga qarshi Kings Indian",
323
- lines=4,
324
- info="Sizning afzal ko'rgan debyutlaringiz"
325
- )
326
-
327
- analyze_btn2 = gr.Button("πŸ” Tahlil Qilish", variant="primary", size="lg")
328
 
329
- with gr.Column(scale=2):
330
- output2 = gr.Markdown(label="πŸ“Š Tahlil Natijasi")
 
 
 
 
 
 
 
 
 
 
 
 
331
 
332
- gr.Examples(
333
- examples=[
334
- ["Hikaru", ""],
335
- ["GothamChess", "e4 ga qarshi Sicilian"],
336
- ],
337
- inputs=[chess_com_username, user_repertoire2],
338
- label="πŸ’‘ Misollar"
339
- )
340
-
 
 
 
341
  analyze_btn1.click(
342
  fn=get_counter_debuts,
343
  inputs=[opponent_debuts, user_color, user_repertoire],
@@ -345,8 +111,8 @@ def create_interface():
345
  )
346
 
347
  analyze_btn2.click(
348
- fn=analyze_chess_com_user,
349
- inputs=[chess_com_username, user_repertoire2],
350
  outputs=output2
351
  )
352
 
 
1
+
 
2
  import gradio as gr
 
3
  import logging
4
+
5
+ from ai_integration import get_counter_debuts
6
+ from chess_api import get_user_games_from_chess_com, analyze_chess_com_user
7
+ import os
8
+ from core import load_eco_data
9
 
10
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
  logger = logging.getLogger(__name__)
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def create_interface():
14
  with gr.Blocks(theme=gr.themes.Soft(), title="Shaxmat AI Maslahatchi", css="""
15
  .gradio-container {font-family: 'Arial', sans-serif;}
 
65
  label="πŸ’‘ Misollar"
66
  )
67
 
68
+ with gr.Tab("🌐 Chess.com Tahlili"):
69
+ gr.Markdown("### Raqib Chess.com profilini tahlil qiling")
70
+
71
+ with gr.Row():
72
+ with gr.Column(scale=1):
73
+ user_color2 = gr.Radio(
74
+ choices=["Oq", "Qora"],
75
+ value="Oq",
76
+ label="🎨 Sizning Rangingiz",
77
+ info="Qaysi rang bilan o'ynaysiz?"
78
+ )
 
 
 
 
 
 
 
 
79
 
80
+ chess_com_username = gr.Textbox(
81
+ label="πŸ‘€ Chess.com Foydalanuvchi Nomi",
82
+ placeholder="Misol: Hikaru",
83
+ info="Raqibingiz Chess.com username"
84
+ )
85
+
86
+ user_repertoire2 = gr.Textbox(
87
+ label="πŸ“š Sizning Repertuaringiz (ixtiyoriy)",
88
+ placeholder="Misol: e4 ga qarshi Sicilian, d4 ga qarshi Kings Indian",
89
+ lines=4,
90
+ info="Sizning afzal ko'rgan debyutlaringiz"
91
+ )
92
+
93
+ analyze_btn2 = gr.Button("πŸ” Tahlil Qilish", variant="primary", size="lg")
94
 
95
+ with gr.Column(scale=2):
96
+ output2 = gr.Markdown(label="πŸ“Š Tahlil Natijasi")
97
+
98
+ gr.Examples(
99
+ examples=[
100
+ ["Oq", "Hikaru", ""],
101
+ ["Qora", "GothamChess", "e4 ga qarshi Sicilian"],
102
+ ],
103
+ inputs=[user_color2, chess_com_username, user_repertoire2],
104
+ label="πŸ’‘ Misollar"
105
+ )
106
+
107
  analyze_btn1.click(
108
  fn=get_counter_debuts,
109
  inputs=[opponent_debuts, user_color, user_repertoire],
 
111
  )
112
 
113
  analyze_btn2.click(
114
+ fn=lambda username, repertoire, color: analyze_chess_com_user(username, repertoire, color),
115
+ inputs=[chess_com_username, user_repertoire2, user_color2],
116
  outputs=output2
117
  )
118
 
chess_api.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import requests
3
+ import time
4
+ import logging
5
+ import pandas as pd
6
+ from core import analyze_opponent_openings
7
+ from ai_integration import get_counter_debuts
8
+ from collections import Counter
9
+
10
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def get_user_games_from_chess_com(username):
15
+ try:
16
+ logger.info(f"Fetching games for: {username}")
17
+ username = username.strip().lower()
18
+
19
+ user_url = f"https://api.chess.com/pub/player/{username}"
20
+ response = requests.get(user_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
21
+
22
+ if response.status_code != 200:
23
+ return None, f"❌ Foydalanuvchi topilmadi: {username}"
24
+
25
+ archives_url = f"https://api.chess.com/pub/player/{username}/games/archives"
26
+ response = requests.get(archives_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
27
+
28
+ if response.status_code != 200:
29
+ return None, "❌ O'yinlar arxivi topilmadi."
30
+
31
+ archives = response.json()['archives']
32
+ if not archives:
33
+ return None, "❌ O'yinlar topilmadi."
34
+
35
+ all_games = []
36
+ for archive_url in reversed(archives[-3:]):
37
+ time.sleep(0.3)
38
+ response = requests.get(archive_url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
39
+ if response.status_code == 200:
40
+ games = response.json()['games']
41
+ all_games.extend(games)
42
+ if len(all_games) >= 50:
43
+ break
44
+
45
+ rapid_games = [g for g in all_games if g.get('time_class') in ['rapid', 'blitz']]
46
+ if not rapid_games:
47
+ rapid_games = all_games[:50]
48
+
49
+ pgn_list = [g['pgn'] for g in rapid_games[:50] if 'pgn' in g]
50
+
51
+ if not pgn_list:
52
+ return None, "❌ PGN formatdagi o'yinlar topilmadi."
53
+
54
+ return pgn_list, None
55
+
56
+ except Exception as e:
57
+ logger.error(f"Error fetching games: {str(e)}")
58
+ return None, f"❌ Xatolik: {str(e)}"
59
+
60
+
61
+ def analyze_chess_com_user(username, user_repertoire, user_color="Oq"):
62
+ if not username or not username.strip():
63
+ return "❌ Iltimos, Chess.com foydalanuvchi nomini kiriting!"
64
+
65
+ status_msg = f"πŸ” {username} foydalanuvchisi o'yinlari yuklanmoqda...\n\n"
66
+
67
+ pgn_list, error = get_user_games_from_chess_com(username)
68
+
69
+ if error:
70
+ return error
71
+
72
+ status_msg += f"βœ… {len(pgn_list)} ta o'yin topildi!\n\n"
73
+ status_msg += "πŸ“Š Debyutlar tahlil qilinmoqda...\n\n"
74
+
75
+ opponent_openings = analyze_opponent_openings(pgn_list, username)
76
+
77
+ if not opponent_openings:
78
+ return status_msg + "❌ Raqib debyutlari aniqlanmadi."
79
+
80
+ white_openings = [o for o in opponent_openings if o['opponent_color'] == 'oq']
81
+ black_openings = [o for o in opponent_openings if o['opponent_color'] == 'qora']
82
+
83
+ white_counter = Counter([o['name'] for o in white_openings])
84
+ black_counter = Counter([o['name'] for o in black_openings])
85
+
86
+ analysis_text = "# πŸ“ˆ RAQIB DEBYUTLARI TAHLILI\n\n"
87
+ analysis_text += f"**Foydalanuvchi:** {username}\n"
88
+ analysis_text += f"**Tahlil qilingan o'yinlar:** {len(pgn_list)}\n\n"
89
+
90
+ if white_openings:
91
+ analysis_text += "## 🎯 Raqib OQ rang bilan o'ynaganida:\n\n"
92
+ for opening, count in white_counter.most_common(5):
93
+ analysis_text += f"- **{opening}** ({count} marta)\n"
94
+ analysis_text += "\n"
95
+
96
+ if black_openings:
97
+ analysis_text += "## 🎯 Raqib QORA rang bilan o'ynaganida:\n\n"
98
+ for opening, count in black_counter.most_common(5):
99
+ analysis_text += f"- **{opening}** ({count} marta)\n"
100
+ analysis_text += "\n"
101
+
102
+ debuts_for_ai = ""
103
+ if white_counter:
104
+ debuts_for_ai += "Raqib OQ bilan: " + ", ".join([o for o, _ in white_counter.most_common(3)]) + "\n"
105
+ if black_counter:
106
+ debuts_for_ai += "Raqib QORA bilan: " + ", ".join([o for o, _ in black_counter.most_common(3)])
107
+
108
+ analysis_text += "\n---\n\n"
109
+ analysis_text += "## πŸ€– AI TAVSIYALARI\n\n"
110
+
111
+ try:
112
+ ai_response = get_counter_debuts(debuts_for_ai, user_color, user_repertoire)
113
+ analysis_text += ai_response
114
+ except Exception as e:
115
+ analysis_text += f"❌ AI tahlil xatosi: {str(e)}"
116
+
117
+ return analysis_text
core.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ import pandas as pd
4
+ import re
5
+ import logging
6
+
7
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ eco_data = None
12
+
13
+ def load_eco_data():
14
+ global eco_data
15
+ try:
16
+ eco_data = pd.read_csv('data/Chess Opening Reference - Sheet1.csv')
17
+ logger.info(f"Loaded {len(eco_data)} ECO codes")
18
+ return True
19
+ except Exception as e:
20
+ logger.error(f"Error loading ECO data: {str(e)}")
21
+ return False
22
+
23
+ def extract_eco_from_pgn(pgn):
24
+ eco_match = re.search(r'\[ECO "([A-E][0-9]{2})"\]', pgn)
25
+ return eco_match.group(1) if eco_match else None
26
+
27
+ def get_opening_name(eco_code):
28
+ if eco_data is not None and eco_code:
29
+ match = eco_data[eco_data['ECO Code'] == eco_code]
30
+ if not match.empty:
31
+ return match.iloc[0]['Name']
32
+ return "Unknown Opening"
33
+
34
+
35
+ def analyze_opponent_openings(pgn_list, target_username):
36
+ target_username = target_username.lower()
37
+ opponent_openings = []
38
+
39
+ for pgn in pgn_list:
40
+ white_match = re.search(r'\[White "([^"]+)"\]', pgn)
41
+ black_match = re.search(r'\[Black "([^"]+)"\]', pgn)
42
+
43
+ if not white_match or not black_match:
44
+ continue
45
+
46
+ white_player = white_match.group(1).lower()
47
+ black_player = black_match.group(1).lower()
48
+
49
+ is_white = target_username in white_player
50
+ is_black = target_username in black_player
51
+
52
+ if not is_white and not is_black:
53
+ continue
54
+
55
+ eco_code = extract_eco_from_pgn(pgn)
56
+ if eco_code:
57
+ opening_name = get_opening_name(eco_code)
58
+
59
+ if is_white:
60
+ opponent_color = "qora"
61
+ else:
62
+ opponent_color = "oq"
63
+
64
+ opponent_openings.append({
65
+ 'eco': eco_code,
66
+ 'name': opening_name,
67
+ 'opponent_color': opponent_color,
68
+ 'user_color': 'oq' if is_white else 'qora'
69
+ })
70
+
71
+ return opponent_openings