slim-S commited on
Commit
0dec5db
ยท
1 Parent(s): 8252555

chore: add new data

Browse files
This view is limited to 50 files because it contains too many changes. ย  See raw diff
Files changed (50) hide show
  1. app.py +0 -757
  2. data/pending/text/Sound 1799.txt +1 -0
  3. data/pending/text/Sound 1800.txt +1 -0
  4. data/pending/text/Sound 1801.txt +1 -0
  5. data/pending/text/Sound 1802.txt +1 -0
  6. data/pending/text/Sound 1803.txt +1 -0
  7. data/pending/text/Sound 1804.txt +1 -0
  8. data/pending/text/Sound 1805.txt +1 -0
  9. data/pending/text/Sound 1806.txt +1 -0
  10. data/pending/text/Sound 1807.txt +1 -0
  11. data/pending/text/Sound 1808.txt +1 -0
  12. data/pending/text/Sound 1809.txt +1 -0
  13. data/pending/text/Sound 1810.txt +1 -0
  14. data/pending/text/Sound 1811.txt +1 -0
  15. data/pending/text/Sound 1812.txt +1 -0
  16. data/pending/text/Sound 1813.txt +1 -0
  17. data/pending/text/Sound 1814.txt +1 -0
  18. data/pending/text/Sound 1815.txt +1 -0
  19. data/pending/text/Sound 1816.txt +1 -0
  20. data/pending/text/Sound 1817.txt +1 -0
  21. data/pending/text/Sound 1818.txt +1 -0
  22. data/pending/text/Sound 1819.txt +1 -0
  23. data/pending/text/Sound 1820.txt +1 -0
  24. data/pending/text/Sound 1821.txt +1 -0
  25. data/pending/text/Sound 1822.txt +1 -0
  26. data/pending/text/Sound 1823.txt +1 -0
  27. data/pending/text/Sound 1824.txt +1 -0
  28. data/pending/text/Sound 1825.txt +1 -0
  29. data/pending/text/Sound 1826.txt +1 -0
  30. data/pending/text/Sound 1827.txt +1 -0
  31. data/pending/text/Sound 1828.txt +1 -0
  32. data/pending/text/Sound 1829.txt +1 -0
  33. data/pending/text/Sound 1830.txt +1 -0
  34. data/pending/text/Sound 1831.txt +1 -0
  35. data/pending/text/Sound 1832.txt +1 -0
  36. data/pending/text/Sound 1833.txt +1 -0
  37. data/pending/text/Sound 1834.txt +1 -0
  38. data/pending/text/Sound 1835.txt +1 -0
  39. data/pending/text/Sound 1836.txt +1 -0
  40. data/pending/text/Sound 1837.txt +1 -0
  41. data/pending/text/Sound 1838.txt +1 -0
  42. data/pending/text/Sound 1839.txt +1 -0
  43. data/pending/text/Sound 1840.txt +1 -0
  44. data/pending/text/Sound 1841.txt +1 -0
  45. data/pending/text/Sound 1842.txt +1 -0
  46. data/pending/text/Sound 1843.txt +1 -0
  47. data/pending/text/Sound 1844.txt +1 -0
  48. data/pending/text/Sound 1845.txt +1 -0
  49. data/pending/text/Sound 1846.txt +1 -0
  50. data/pending/text/Sound 1847.txt +1 -0
app.py DELETED
@@ -1,757 +0,0 @@
1
- import os
2
- import logging
3
- import random
4
- import shutil
5
- import re
6
- import asyncio
7
- import signal
8
- import traceback
9
- import stat
10
- from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
11
- from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes, ConversationHandler, CallbackQueryHandler
12
- from typing import Dict, Set, Tuple, Optional
13
-
14
- # Enable more detailed logging
15
- logging.basicConfig(
16
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
17
- level=logging.DEBUG # Changed to DEBUG for more details
18
- )
19
- logger = logging.getLogger(__name__)
20
-
21
- # Add specific logger for telegram
22
- telegram_logger = logging.getLogger('telegram')
23
- telegram_logger.setLevel(logging.DEBUG)
24
-
25
- # Define conversation states
26
- AWAITING_CORRECTION = 1
27
- AWAITING_VALIDATION = 2
28
-
29
- # Store active tasks per user
30
- # {user_id: (voice_filename, text_filename, seq_num, corrected_text)}
31
- user_tasks = {}
32
-
33
- # Track chunks being processed
34
- chunks_in_process = set() # set of sequence numbers that are currently being processed
35
-
36
- # Directory paths
37
- DATA_DIR = os.environ.get('DATA_DIR', 'data')
38
- PENDING_DIR = os.path.join(DATA_DIR, 'pending')
39
- PENDING_VOICE_DIR = os.path.join(PENDING_DIR, 'voice')
40
- PENDING_TEXT_DIR = os.path.join(PENDING_DIR, 'text')
41
- PROCESSED_DIR = os.path.join(DATA_DIR, 'processed')
42
- PROCESSED_VOICE_DIR = os.path.join(PROCESSED_DIR, 'voice')
43
- PROCESSED_TEXT_DIR = os.path.join(PROCESSED_DIR, 'text')
44
-
45
- # Ensure directories exist with proper permissions
46
-
47
-
48
- def ensure_directory_with_permissions(directory):
49
- """Create directory if it doesn't exist and set permissions."""
50
- try:
51
- if not os.path.exists(directory):
52
- os.makedirs(directory, exist_ok=True)
53
- # Set permissions: read/write/execute for everyone
54
- os.chmod(directory, stat.S_IRWXU | stat.S_IRWXG |
55
- stat.S_IRWXO) # 0777 permissions
56
- logger.info(f"Directory ensured with permissions: {directory}")
57
- except Exception as e:
58
- logger.error(f"Error setting permissions for {directory}: {str(e)}")
59
-
60
-
61
- # Initialize directories with proper permissions
62
- ensure_directory_with_permissions(PENDING_VOICE_DIR)
63
- ensure_directory_with_permissions(PENDING_TEXT_DIR)
64
- ensure_directory_with_permissions(PROCESSED_VOICE_DIR)
65
- ensure_directory_with_permissions(PROCESSED_TEXT_DIR)
66
-
67
- # Global application variable
68
- application = None
69
-
70
-
71
- def extract_sequence_number(filename: str) -> Optional[int]:
72
- """Extract sequence number from filename, e.g., 'Sound 100.wav' -> 100."""
73
- match = re.search(r'(\d+)', filename)
74
- if match:
75
- return int(match.group(1))
76
- return None
77
-
78
-
79
- def get_files_by_sequence_number():
80
- """Create dictionaries mapping sequence numbers to filenames."""
81
- voice_files = {}
82
- text_files = {}
83
-
84
- # Map voice files to sequence numbers
85
- if os.path.exists(PENDING_VOICE_DIR):
86
- for filename in os.listdir(PENDING_VOICE_DIR):
87
- if filename.endswith('.wav'):
88
- seq_num = extract_sequence_number(filename)
89
- if seq_num is not None:
90
- voice_files[seq_num] = filename
91
-
92
- # Map text files to sequence numbers
93
- if os.path.exists(PENDING_TEXT_DIR):
94
- for filename in os.listdir(PENDING_TEXT_DIR):
95
- if filename.endswith('.txt'):
96
- seq_num = extract_sequence_number(filename)
97
- if seq_num is not None:
98
- text_files[seq_num] = filename
99
-
100
- return voice_files, text_files
101
-
102
-
103
- async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
104
- """Send a welcome message when the /start command is issued."""
105
- logger.info(f"Start command received from user {update.effective_user.id}")
106
- try:
107
- await update.message.reply_text(
108
- "ุงู„ุณู„ุงู… ุนู„ูŠูƒู… ููŠ The Algerian Darija Transcription Correction Bot!\n\n"
109
- '''
110
- ๐ŸŒŸ ู‚ูˆุงุนุฏ ุงู„ุชู†ู…ูŠุท ุงู„ู„ุบูˆูŠ ูˆุงู„ุจุฏุงุฆู„ ๐ŸŒŸ
111
-
112
-
113
- ๐ŸŸฆ๐ŸŸฆ๐ŸŸฆ ู‚ูˆุงุนุฏ ุงู„ูƒุชุงุจุฉ ๐ŸŸฆ๐ŸŸฆ๐ŸŸฆ
114
-
115
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 00
116
- ูŠูุณู…ุญ ูู‚ุท ุจุงุณุชุฎุฏุงู… ุงู„ูƒู„ู…ุงุช ูˆุงู„ุญุฑูˆู ุงู„ุนุฑุจูŠุฉ ููŠ ุนู…ู„ูŠุฉ ุงู„ุชู†ุตูŠุต. ูŠูู…ู†ุน ุงุณุชุนู…ุงู„ ุงู„ุฃุญุฑู ุงู„ุฃุฌู†ุจูŠุฉ ุฃูˆ ู…ุง ูŠูุนุฑู ุจู€ "ุงู„ุนุฑุจูŠุฒูŠ".
117
- ๐Ÿ“ ู…ุซุงู„: "ุนู„ู‰" โœ… ูˆู„ูŠุณ "3la" โŒ
118
-
119
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 01
120
- ูŠุฌูˆุฒ ุฅู„ุตุงู‚ ุงู„ุฌุงุฑ ูˆุงู„ู…ุฌุฑูˆุฑ ุจุงู„ูุนู„ ู…ุจุงุดุฑุฉ ุฏูˆู† ูุตู„ู‡.
121
- ๐Ÿ“ ู…ุซุงู„: ู‚ุงู„ูˆู„ูŠ โœ… ุจุฏู„ุงู‹ ู…ู† ู‚ุงู„ูˆุง ู„ูŠ โŒ
122
-
123
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 02
124
- ู„ุง ูŠูุดุชุฑุท ุงู„ุงู„ุชุฒุงู… ุจุฃู„ู ุงู„ุฌู…ุงุนุฉ ููŠ ุงู„ุฃูุนุงู„.
125
- ๐Ÿ“ ู…ุซุงู„: ู‚ุงู„ูˆ โœ… ุจุฏู„ุงู‹ ู…ู† ู‚ุงู„ูˆุง โŒ
126
-
127
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 03
128
- ูŠุชู… ุงุณุชุจุฏุงู„ ู‡ู…ุฒุฉ ุงู„ุฃู„ู (ุฃ) ุจุญุฑู (ุง) ุฏุงุฆู…ุงู‹.
129
- ๐Ÿ“ ู…ุซุงู„: ุงูƒุชูˆุจ โœ… ุจุฏู„ุงู‹ ู…ู† ุฃูƒุชุจ โŒ
130
-
131
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 04
132
- ูŠููƒุชุจ ุงู„ุถู…ูŠุฑ ุงู„ู…ุชุตู„ (ู‡ูˆ) ุจุงู„ุด๏ฟฝ๏ฟฝู„ ุงู„ุตุญูŠุญ ุฏูˆู† ุชุบูŠูŠุฑ.
133
- ๐Ÿ“ ู…ุซุงู„: ุนู†ุฏู‡ โœ… ุจุฏู„ุงู‹ ู…ู† ุนู†ุฏูˆ โŒ
134
-
135
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 05
136
- ุนู†ุฏ ุงู„ู†ุทู‚ุŒ ูŠุชู… ุงุณุชุจุฏุงู„ ุญุฑู (ุช) ุจุญุฑู (ุซ) ุฅุฐุง ู†ูุทู‚ ูƒุฐู„ูƒ.
137
- ๐Ÿ“ ู…ุซุงู„: ุซุงู†ูŠ โœ… ุจุฏู„ุงู‹ ู…ู† ุชุงู†ูŠ โŒ
138
-
139
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 06
140
- ุชุญูˆูŠู„ ุงู„ูุงุก ุงู„ู…ู„ุชุตู‚ุฉ ุจุงู„ุงุณู… ุฅู„ู‰ ุญุฑู ุงู„ุฌุฑ "ููŠ".
141
- ๐Ÿ“ ู…ุซุงู„: ููŠ ุงู„ุจูŠุช โœ… ุจุฏู„ุงู‹ ู…ู† ูุงู„ุจูŠุช โŒ
142
-
143
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 07
144
- ูŠููุถู„ ูˆุตู„ "ู…ุง" ูˆ"ูˆุงูˆ ุงู„ุนุทู" ุจุงู„ูƒู„ู…ุฉ ู…ุจุงุดุฑุฉ.
145
- ๐Ÿ“ ู…ุซุงู„: ู…ุงู‚ูˆู„ุชุด โœ… ุจุฏู„ุงู‹ ู…ู† ู…ุงู‚ูˆู„ุชุด โŒ
146
-
147
- ๐Ÿ”ท ุงู„ู‚ุงุนุฏุฉ 09
148
- ุชูุญุงูุธ ุญุฑูˆู ุงู„ู…ุณุชู‚ุจู„ ู…ุซู„ "ุนู†ู‚ูˆู„" ุฃูˆ "ูƒู†ู‚ูˆู„" ุนู„ู‰ ุดูƒู„ู‡ุง ุงู„ุฃุตู„ูŠ ุฏูˆู† ุชุบูŠูŠุฑ.
149
- ๐Ÿ“ ู…ุซุงู„: ุนู†ู‚ูˆู„ โœ… (ู„ุง ุชุบูŠูŠุฑ)
150
-
151
-
152
- ๐ŸŸฉ๐ŸŸฉ๐ŸŸฉ ุงู„ุจุฏุงุฆู„ ุงู„ู„ุบูˆูŠุฉ ๐ŸŸฉ๐ŸŸฉ๐ŸŸฉ
153
- ๐Ÿšซ ุงู„ู„ูุธ ุบูŠุฑ ุงู„ู…ุนูŠุงุฑูŠ โ† โœ… ุงู„ู„ูุธ ุงู„ู…ุนูŠุงุฑูŠ
154
-
155
- ุฏุฑูƒ โ† ุถุฑูƒ โœ…
156
-
157
- ุนู„ุงุจุงู„ูŠ โ† ุนู„ู‰ ุจุงู„ูŠ โœ…
158
-
159
- ุดูˆูŠุง โ† ุดูˆูŠุฉ โœ…
160
-
161
- ูˆุงุด โ† ูˆุด โœ…
162
-
163
- ฺจุงู„ูˆ โ† ู‚ุงู„ูˆ โœ…
164
-
165
- ู†ุชุงุน / ู†ุชุน / ุชุน โ† ุชุงุน โœ…
166
-
167
- ุจุงู„ุตุญ / ุจุตุงุญ โ† ุจุตุญ โœ…
168
-
169
- ู‚ุชู„ูƒ โ† ู‚ู„ุชู„ูƒ โœ…
170
-
171
- ูŠู‚ูˆู„ ู„ูƒ โ† ูŠู‚ูˆู„ูƒ โœ…
172
-
173
- ุนู†ุง โ† ุนู†ุฏู†ุง โœ…
174
-
175
- ู‡ุงุฏุงูƒ / ู‡ุฐุงูƒ / ู‡ุงุฐุงูƒ โ† ู‡ุฏุงูƒ โœ…
176
-
177
- ู„ูŠ / ู„ูŠู‡ / ู„ูŠูƒ โ† ุงู„ู„ูŠ / ู„ู‡ / ู„ูƒ โœ…
178
-
179
-
180
- ๐Ÿ˜‰ ู‚ู… ุจุนู…ู„ pin ุฃูˆ ุชุซุจูŠุช ู„ู‡ุฐู‡ ุงู„ุฑุณุงู„ุฉ ู„ูƒูŠ ูŠุณู‡ู„ ุนู„ูŠูƒ ุงู„ุฑุฌูˆุน ุฅู„ูŠู‡ุง ู„ุงุญู‚ุง ู„ู…ุฑุงุฌุนุฉ ุงู„ู‚ูˆุงุนุฏโ€ผ๏ธ
181
- '''
182
- "ุงุณุชุนู…ู„ /correct ู„ู„ุจุฏุฃ ููŠ ุชุตุญูŠุญ ุงู„ู†ุตูˆุต\n"
183
- "ุงุณุชุนู…ู„ /skip ู„ุชุฌุงูˆุฒ ู…ู‚ุทุน ุตูˆุชูŠ ู…ุนูŠู†\n"
184
- "ุงุณุชุนู…ู„ /cancel ู„ุฅู„ุบุงุก ุงู„ุนู…ู„ูŠุฉ\n"
185
- )
186
- logger.info("Start message sent successfully")
187
- except Exception as e:
188
- logger.error(f"Error sending start message: {e}")
189
-
190
-
191
- async def get_next_available_chunk() -> Tuple[Optional[str], Optional[str], Optional[int]]:
192
- """Find the next available audio chunk that isn't being processed.
193
- Returns (voice_filename, text_filename, sequence_number) or (None, None, None)"""
194
- voice_files, text_files = get_files_by_sequence_number()
195
-
196
- # Find sequence numbers that exist in both voice and text files
197
- common_seq_nums = set(voice_files.keys()).intersection(
198
- set(text_files.keys()))
199
-
200
- # Filter out sequence numbers that are already being processed
201
- available_seq_nums = [
202
- seq_num for seq_num in common_seq_nums if seq_num not in chunks_in_process]
203
-
204
- logger.debug(f"Available sequence numbers: {available_seq_nums}")
205
-
206
- if available_seq_nums:
207
- # Get random available sequence number from the list
208
- seq_num = random.choice(available_seq_nums)
209
- logger.debug(f"Selected sequence number: {seq_num}")
210
- return voice_files[seq_num], text_files[seq_num], seq_num
211
-
212
- logger.debug("No available chunks found")
213
- return None, None, None
214
-
215
-
216
- async def send_chunk_to_user(update: Update, user_id: int, voice_filename: str, text_filename: str, seq_num: int) -> bool:
217
- """Send audio chunk and text to user. Returns True if successful, False otherwise."""
218
- # Send audio file
219
- audio_path = os.path.join(PENDING_VOICE_DIR, voice_filename)
220
-
221
- # Check if audio file exists
222
- if not os.path.exists(audio_path):
223
- logger.error(f"Audio file not found: {audio_path}")
224
- await update.message.reply_text("Error: Audio file not found. Please try again.")
225
- return False
226
-
227
- # Read the original transcription to send as reference
228
- text_path = os.path.join(PENDING_TEXT_DIR, text_filename)
229
- if not os.path.exists(text_path):
230
- logger.error(f"Text file not found: {text_path}")
231
- await update.message.reply_text("Error: Text file not found. Please try again.")
232
- return False
233
-
234
- try:
235
- with open(text_path, 'r', encoding='utf-8') as f:
236
- original_text = f.read().strip()
237
- except Exception as e:
238
- logger.error(f"Error reading text file: {e}")
239
- await update.message.reply_text(f"Error reading transcription file. Please try again.")
240
- return False
241
-
242
- # Send audio and original text
243
- try:
244
- with open(audio_path, 'rb') as audio_file:
245
- await update.message.reply_voice(voice=audio_file)
246
-
247
- await update.message.reply_text(
248
- f"ู…ู† ูุถู„ูƒ ุงุณุชู…ุน ุฅู„ู‰ ุงู„ู…ู‚ุทุน ุงู„ุตูˆุชูŠ ูˆุฃุนุฏ ูƒุชุงุจุฉ ุงู„ู†ุต.\n\n"
249
- f"ุงู„ู†ุต ุงู„ุฃุตู„ูŠ:\n{original_text}\n\n"
250
- f"ู…ู† ูุถู„ูƒ ู‚ู… ุจุฅุฑุณุงู„ ุงู„ู†ุต ุงู„ุฐูŠ ุชู… ุชุตุญูŠุญู‡ ุฃูˆ ุงุณุชุนู…ู„ /skip ู„ุชุฌุงูˆุฒ ู‡ุฐุง ุงู„ู…ู‚ุทุน."
251
- f"ุงุณุชุนู…ู„ /cancel ู„ุฅู„ุบุงุก ุงู„ุนู…ู„ูŠุฉ."
252
- )
253
-
254
- logger.info(f"Successfully sent audio and text to user {user_id}")
255
- return True
256
- except Exception as e:
257
- logger.error(f"Error sending audio or text: {e}")
258
- await update.message.reply_text("Error sending audio. Please try again.")
259
- return False
260
-
261
-
262
- async def correct(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
263
- """Start the correction process."""
264
- logger.info(
265
- f"ุชู… ุงุณุชู‚ุจุงู„ ุฃู…ุฑ ุงู„ุชุตุญูŠุญ ู…ู† ุงู„ู…ุณุชุนู…ู„ {update.effective_user.id}")
266
- user_id = update.effective_user.id
267
-
268
- # Check if user already has an active task
269
- if user_id in user_tasks:
270
- await update.message.reply_text("ุฃู†ุช ุงู„ุขู† ููŠ ุบุถูˆู† ุนู…ู„ูŠุฉ ุชุตุญูŠุญ. ู…ู† ูุถู„ูƒ ู‚ู… ุจุฅูƒู…ุงู„ู‡ุง ุฃูˆ ุฃู„ุบูŠ ุงู„ุนู…ู„ูŠุฉ ุนุจุฑ /cancel.")
271
- current_state = AWAITING_VALIDATION if len(
272
- user_tasks[user_id]) > 3 else AWAITING_CORRECTION
273
- return current_state
274
-
275
- # Ensure directory paths exist with proper permissions
276
- ensure_directory_with_permissions(PENDING_VOICE_DIR)
277
- ensure_directory_with_permissions(PENDING_TEXT_DIR)
278
-
279
- # Log directory contents for debugging
280
- logger.debug(
281
- f"PENDING_VOICE_DIR contents: {os.listdir(PENDING_VOICE_DIR)}")
282
- logger.debug(f"PENDING_TEXT_DIR contents: {os.listdir(PENDING_TEXT_DIR)}")
283
-
284
- # Get next available chunk
285
- voice_filename, text_filename, seq_num = await get_next_available_chunk()
286
-
287
- if not voice_filename or not text_filename:
288
- await update.message.reply_text("ู„ุง ุชูˆุฌุฏ ู†ุตูˆุต ู‚ูŠุฏ ุงู„ุงู†ุชุธุงุฑ ููŠ ุงู„ูˆู‚ุช ุงู„ุญุงู„ูŠ. ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰ ู„ุงุญู‚ู‹ุง.")
289
- return ConversationHandler.END
290
-
291
- # Mark chunk as being processed
292
- chunks_in_process.add(seq_num)
293
- user_tasks[user_id] = (voice_filename, text_filename, seq_num)
294
-
295
- # Send chunk to user
296
- success = await send_chunk_to_user(update, user_id, voice_filename, text_filename, seq_num)
297
-
298
- if not success:
299
- # Clean up on failure
300
- chunks_in_process.remove(seq_num)
301
- del user_tasks[user_id]
302
- return ConversationHandler.END
303
-
304
- return AWAITING_CORRECTION
305
-
306
-
307
- async def skip_chunk(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
308
- """Skip the current chunk and get a new one."""
309
- user_id = update.effective_user.id
310
-
311
- if user_id not in user_tasks:
312
- await update.message.reply_text("ุฃู†ุช ู„ุง ุชู…ู„ูƒ ู…ู‡ู…ุฉ ุชุตุญูŠุญ ู†ุดุทุฉ. ุงุณุชุฎุฏู… /correct ู„ู„ุจุฏุก.")
313
- return ConversationHandler.END
314
-
315
- # Get current task info
316
- current_task = user_tasks[user_id]
317
- if len(current_task) >= 3: # Has at least voice, text, seq_num
318
- _, _, current_seq_num = current_task[:3]
319
-
320
- # Remove current chunk from processing (making it available for others)
321
- chunks_in_process.discard(current_seq_num)
322
- logger.info(f"User {user_id} skipped chunk {current_seq_num}")
323
-
324
- # Remove current task
325
- del user_tasks[user_id]
326
-
327
- await update.message.reply_text("ุชุฌุงูˆุฒุช ุงู„ู…ู‚ุทุน ุงู„ุตูˆุชูŠ. ุฏุนู†ูŠ ุฃุจุญุซ ุนู† ู…ู‚ุทุน ุขุฎุฑ ู„ูƒ.")
328
-
329
- # Get next available chunk
330
- voice_filename, text_filename, seq_num = await get_next_available_chunk()
331
-
332
- if not voice_filename or not text_filename:
333
- await update.message.reply_text("ู„ุง ุชูˆุฌุฏ ู†ุตูˆุต ู‚ูŠุฏ ุงู„ุงู†ุชุธุงุฑ ููŠ ุงู„ูˆู‚ุช ุงู„ุญุงู„ูŠ. ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰ ู„ุงุญู‚ู‹ุง.")
334
- return ConversationHandler.END
335
-
336
- # Mark new chunk as being processed
337
- chunks_in_process.add(seq_num)
338
- user_tasks[user_id] = (voice_filename, text_filename, seq_num)
339
-
340
- # Send new chunk to user
341
- success = await send_chunk_to_user(update, user_id, voice_filename, text_filename, seq_num)
342
-
343
- if not success:
344
- # Clean up on failure
345
- chunks_in_process.remove(seq_num)
346
- del user_tasks[user_id]
347
- return ConversationHandler.END
348
-
349
- return AWAITING_CORRECTION
350
-
351
-
352
- async def receive_correction(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
353
- """Receive the user's correction and ask for validation."""
354
- user_id = update.effective_user.id
355
-
356
- if user_id not in user_tasks:
357
- await update.message.reply_text("ุฃู†ุช ู„ุง ุชู…ู„ูƒ ู…ู‡ู…ุฉ ุชุตุญูŠุญ ู†ุดุทุฉ. ุงุณุชุฎุฏู… /correct ู„ู„ุจุฏุก.")
358
- return ConversationHandler.END
359
-
360
- voice_filename, text_filename, seq_num = user_tasks[user_id]
361
- corrected_text = update.message.text
362
-
363
- # Update user task with corrected text
364
- user_tasks[user_id] = (voice_filename, text_filename,
365
- seq_num, corrected_text)
366
-
367
- # Create validation buttons
368
- keyboard = [
369
- [
370
- InlineKeyboardButton("โœ… ู†ุนู…, ุฃู†ุง ู…ุชุฃูƒุฏ ู…ู† ุงู„ุชุตุญูŠุญ",
371
- callback_data="validate_yes"),
372
- InlineKeyboardButton("โŒ ู„ุง, ุฃุฑูŠุฏ ุงู„ุชุตุญูŠุญ ู…ุฑุฉ ุฃุฎุฑู‰",
373
- callback_data="validate_no")
374
- ]
375
- ]
376
- reply_markup = InlineKeyboardMarkup(keyboard)
377
-
378
- await update.message.reply_text(
379
- f"ุงู„ู†ุต ุงู„ุฐูŠ ู‚ู…ุช ุจุชุตุญูŠุญู‡:\n{corrected_text}\n\n"
380
- f"ู‡ู„ ุฃู†ุช ู…ุชุฃูƒุฏ ู…ู† ุงู„ุชุตุญูŠุญุŸ",
381
- reply_markup=reply_markup
382
- )
383
-
384
- return AWAITING_VALIDATION
385
-
386
-
387
- async def handle_validation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
388
- """Handle the validation response."""
389
- query = update.callback_query
390
- await query.answer()
391
-
392
- user_id = query.from_user.id
393
-
394
- if user_id not in user_tasks or len(user_tasks[user_id]) < 4:
395
- await query.edit_message_text("ุฃู†ุช ู„ุง ุชู…ู„ูƒ ู…ู‡ู…ุฉ ุชุตุญูŠุญ ู†ุดุทุฉ. ุงุณุชุฎุฏู… /correct ู„ู„ุจุฏุก.")
396
- return ConversationHandler.END
397
-
398
- voice_filename, text_filename, seq_num, corrected_text = user_tasks[user_id]
399
-
400
- if query.data == "validate_yes":
401
- # User is confident - save the correction
402
- success = await save_final_correction(query, user_id, voice_filename, text_filename, seq_num, corrected_text)
403
- if success:
404
- await query.edit_message_text(
405
- "ุดูƒุฑุง. ุชุตุญูŠุญูƒ ุชู… ุญูุธู‡\n"
406
- "ุงุณุชุนู…ู„ /correct ู„ุงุณุชู‚ุจุงู„ ุนู…ู„ูŠุฉ ุชุตุญูŠุญ ุฌุฏูŠุฏุฉ"
407
- )
408
- return ConversationHandler.END
409
- else:
410
- # If saving failed, go back to correction state
411
- # Remove corrected text
412
- user_tasks[user_id] = (voice_filename, text_filename, seq_num)
413
- await query.edit_message_text(
414
- "ุญุฏุซ ุฎุทุฃ ุฃุซู†ุงุก ุญูุธ ุงู„ุชุตุญูŠุญ. ู…ู† ูุถู„ูƒ ุฃุนุฏ ุฅุฑุณุงู„ู‡."
415
- )
416
- return AWAITING_CORRECTION
417
-
418
- elif query.data == "validate_no":
419
- # User wants to correct again - remove corrected text and go back to correction state
420
- user_tasks[user_id] = (voice_filename, text_filename, seq_num)
421
- await query.edit_message_text(
422
- "ู…ู† ูุถู„ูƒ ุฃุนุฏ ูƒุชุงุจุฉ ุงู„ู†ุต ุงู„ุชุตุญูŠุญูŠ ู…ุฑุฉ ุฃุฎุฑู‰."
423
- )
424
- return AWAITING_CORRECTION
425
-
426
- return AWAITING_VALIDATION
427
-
428
-
429
- async def save_final_correction(query, user_id: int, voice_filename: str, text_filename: str, seq_num: int, corrected_text: str) -> bool:
430
- """Save the final validated correction."""
431
- # Get original file paths
432
- original_txt_path = os.path.join(PENDING_TEXT_DIR, text_filename)
433
- original_wav_path = os.path.join(PENDING_VOICE_DIR, voice_filename)
434
-
435
- # Create user-specific directory in processed TEXT folder only
436
- user_processed_text_dir = os.path.join(
437
- PROCESSED_TEXT_DIR, f"user_{user_id}")
438
-
439
- # Log the directory path for debugging
440
- logger.debug(f"Creating text directory: {user_processed_text_dir}")
441
-
442
- try:
443
- # Ensure text directory with proper permissions
444
- ensure_directory_with_permissions(user_processed_text_dir)
445
-
446
- # Save corrected text to processed directory
447
- processed_txt_path = os.path.join(
448
- user_processed_text_dir, text_filename)
449
-
450
- # Log file paths for debugging
451
- logger.debug(
452
- f"Original text path: {original_txt_path}, exists: {os.path.exists(original_txt_path)}")
453
- logger.debug(
454
- f"Original wav path: {original_wav_path}, exists: {os.path.exists(original_wav_path)}")
455
- logger.debug(f"Processed text path: {processed_txt_path}")
456
-
457
- # Save corrected text
458
- logger.debug(f"Saving corrected text to {processed_txt_path}")
459
- with open(processed_txt_path, 'w', encoding='utf-8') as f:
460
- f.write(corrected_text)
461
- # Set file permissions
462
- os.chmod(processed_txt_path, stat.S_IRUSR | stat.S_IWUSR |
463
- stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH)
464
-
465
- # Verify processed text file exists
466
- logger.debug(
467
- f"Verifying processed text file exists: {os.path.exists(processed_txt_path)}")
468
-
469
- # Remove both files from pending directory (text and voice)
470
- if os.path.exists(original_txt_path):
471
- logger.debug(f"Removing original text file at {original_txt_path}")
472
- os.remove(original_txt_path)
473
- else:
474
- logger.warning(
475
- f"Could not remove original text file as it doesn't exist at {original_txt_path}")
476
-
477
- if os.path.exists(original_wav_path):
478
- logger.debug(f"Removing original wav file at {original_wav_path}")
479
- os.remove(original_wav_path)
480
- else:
481
- logger.warning(
482
- f"Could not remove original wav file as it doesn't exist at {original_wav_path}")
483
-
484
- # Remove from active tasks
485
- logger.debug(f"Removing seq_num {seq_num} from chunks_in_process")
486
- chunks_in_process.remove(seq_num)
487
-
488
- logger.debug(f"Removing user {user_id} from user_tasks")
489
- del user_tasks[user_id]
490
-
491
- logger.info(
492
- f"Successfully saved validated correction for user {user_id}")
493
- return True
494
-
495
- except Exception as e:
496
- # Enhanced error logging with stack trace
497
- error_msg = f"Error saving correction: {str(e)}"
498
- logger.error(error_msg)
499
- logger.error(traceback.format_exc())
500
-
501
- # Try to provide more specific error messages
502
- if "Permission denied" in str(e):
503
- await query.edit_message_text("Error: Permission denied while saving files. Please contact the administrator.")
504
- elif "No such file or directory" in str(e):
505
- await query.edit_message_text("Error: File not found. The system couldn't find one of the files.")
506
- else:
507
- await query.edit_message_text(f"Error saving your correction: {str(e)}. Please try again.")
508
-
509
- return False
510
-
511
-
512
- async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
513
- """Cancel the current correction task."""
514
- user_id = update.effective_user.id
515
-
516
- if user_id in user_tasks:
517
- task_info = user_tasks[user_id]
518
- if len(task_info) >= 3: # Has at least voice, text, seq_num
519
- seq_num = task_info[2]
520
- chunks_in_process.discard(seq_num)
521
- del user_tasks[user_id]
522
-
523
- await update.message.reply_text("ุงู„ุนู…ู„ูŠุฉ ู‚ุฏ ุฃู„ุบูŠุช :( ุงุณุชุนู…ู„ /correct ู„ู„ุจุฏุก ุชุตุญูŠุญ ุฌุฏูŠุฏ.")
524
- else:
525
- await update.message.reply_text("ู„ุง ุชูˆุฌุฏ ุนู…ู„ูŠุฉ ุชุตุญูŠุญ ู†ุดุทุฉ ู„ุฅู„ุบุงุฆู‡ุง.")
526
-
527
- return ConversationHandler.END
528
-
529
-
530
- async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
531
- """Show status of pending and processed chunks."""
532
- logger.info(
533
- f"Status command received from user {update.effective_user.id}")
534
-
535
- # Count pending files
536
- pending_voice_count = len(
537
- [f for f in os.listdir(PENDING_VOICE_DIR) if f.endswith('.wav')])
538
- pending_text_count = len(
539
- [f for f in os.listdir(PENDING_TEXT_DIR) if f.endswith('.txt')])
540
-
541
- # Get sequence numbers
542
- voice_files, text_files = get_files_by_sequence_number()
543
- matching_pairs = len(
544
- set(voice_files.keys()).intersection(set(text_files.keys())))
545
-
546
- # Count processed files (only text files now)
547
- processed_text_count = 0
548
-
549
- # Count text files
550
- for root, dirs, files in os.walk(PROCESSED_TEXT_DIR):
551
- processed_text_count += len([f for f in files if f.endswith('.txt')])
552
-
553
- active_tasks = len(user_tasks)
554
-
555
- # Check file permissions
556
- permissions_info = ""
557
- try:
558
- # Check if we can write to the processed text directory
559
- can_write_text = os.access(PROCESSED_TEXT_DIR, os.W_OK)
560
- permissions_info = f"\nโ€ข Write permissions: Text: {can_write_text}"
561
- except Exception as e:
562
- permissions_info = f"\nโ€ข Error checking permissions: {str(e)}"
563
-
564
- await update.message.reply_text(
565
- f"๐Ÿ“Š Transcription Status:\n"
566
- f"โ€ข Pending voice files: {pending_voice_count}\n"
567
- f"โ€ข Pending text files: {pending_text_count}\n"
568
- f"โ€ข Matching pending pairs: {matching_pairs}\n"
569
- f"โ€ข Processed text files: {processed_text_count}\n"
570
- f"โ€ข Active tasks: {active_tasks}{permissions_info}\n"
571
- f"โ€ข Note: Only corrected text files are saved, voice files are not copied to processed folder"
572
- )
573
-
574
-
575
- async def debug_info(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
576
- """Command to show debug information about directories and permissions."""
577
- user_id = update.effective_user.id
578
-
579
- # Check directory structure
580
- debug_info = [
581
- "๐Ÿ“ Directory Check:",
582
- f"โ€ข DATA_DIR: {DATA_DIR}, exists: {os.path.exists(DATA_DIR)}",
583
- f"โ€ข PENDING_DIR: {PENDING_DIR}, exists: {os.path.exists(PENDING_DIR)}",
584
- f"โ€ข PENDING_VOICE_DIR: {PENDING_VOICE_DIR}, exists: {os.path.exists(PENDING_VOICE_DIR)}",
585
- f"โ€ข PENDING_TEXT_DIR: {PENDING_TEXT_DIR}, exists: {os.path.exists(PENDING_TEXT_DIR)}",
586
- f"โ€ข PROCESSED_DIR: {PROCESSED_DIR}, exists: {os.path.exists(PROCESSED_DIR)}",
587
- f"โ€ข PROCESSED_TEXT_DIR: {PROCESSED_TEXT_DIR}, exists: {os.path.exists(PROCESSED_TEXT_DIR)}",
588
- ]
589
-
590
- # Check permissions
591
- try:
592
- permission_info = [
593
- "๐Ÿ”‘ Permission Check:",
594
- f"โ€ข PENDING_VOICE_DIR writable: {os.access(PENDING_VOICE_DIR, os.W_OK)}",
595
- f"โ€ข PENDING_TEXT_DIR writable: {os.access(PENDING_TEXT_DIR, os.W_OK)}",
596
- f"โ€ข PROCESSED_TEXT_DIR writable: {os.access(PROCESSED_TEXT_DIR, os.W_OK)}",
597
- ]
598
- debug_info.extend(permission_info)
599
- except Exception as e:
600
- debug_info.append(f"Error checking permissions: {str(e)}")
601
-
602
- # Check active tasks
603
- task_info = [
604
- "๐Ÿ“‹ Active Tasks:",
605
- f"โ€ข Number of active users: {len(user_tasks)}",
606
- f"โ€ข Active chunks: {len(chunks_in_process)}",
607
- ]
608
- debug_info.extend(task_info)
609
-
610
- await update.message.reply_text("\n".join(debug_info))
611
-
612
-
613
- async def test_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
614
- """Test handler to verify bot is receiving messages."""
615
- logger.info(f"Test command received from user {update.effective_user.id}")
616
- await update.message.reply_text("Bot is working! โœ…")
617
-
618
-
619
- async def setup_application():
620
- """Setup the Application with all handlers."""
621
- global application
622
-
623
- # Get the token from environment variable
624
- token = os.environ.get("TELEGRAM_TOKEN")
625
- if not token:
626
- logger.error("TELEGRAM_TOKEN environment variable not set!")
627
- return None
628
-
629
- logger.info(f"Setting up bot with token: {token[:10]}...")
630
-
631
- # Create the Application with additional debugging
632
- application = Application.builder().token(token).build()
633
-
634
- # Add a test handler first
635
- application.add_handler(CommandHandler("test", test_handler))
636
-
637
- # Add conversation handler for correction workflow
638
- conv_handler = ConversationHandler(
639
- entry_points=[CommandHandler("correct", correct)],
640
- states={
641
- AWAITING_CORRECTION: [
642
- MessageHandler(filters.TEXT & ~filters.COMMAND,
643
- receive_correction),
644
- CommandHandler("skip", skip_chunk),
645
- ],
646
- AWAITING_VALIDATION: [
647
- CallbackQueryHandler(handle_validation, pattern="^validate_"),
648
- ],
649
- },
650
- fallbacks=[
651
- CommandHandler("cancel", cancel),
652
- CommandHandler("skip", skip_chunk),
653
- ],
654
- name="correction_conversation",
655
- )
656
-
657
- application.add_handler(conv_handler)
658
-
659
- # Add command handlers
660
- application.add_handler(CommandHandler("start", start))
661
- application.add_handler(CommandHandler("status", status))
662
- application.add_handler(CommandHandler("cancel", cancel))
663
- application.add_handler(CommandHandler(
664
- "skip", skip_chunk)) # Global skip handler
665
- application.add_handler(CommandHandler("debug", debug_info))
666
-
667
- logger.info("All handlers added successfully")
668
- return application
669
-
670
-
671
- async def start_bot():
672
- """Start the bot with proper signal handling."""
673
- global application
674
-
675
- logger.info("Starting bot setup...")
676
-
677
- # Create and configure the bot
678
- app = await setup_application()
679
- if not app:
680
- logger.error("Failed to create application")
681
- return
682
-
683
- logger.info("Application created successfully")
684
-
685
- # Start the Bot
686
- try:
687
- await app.initialize()
688
- logger.info("Application initialized")
689
-
690
- await app.start()
691
- logger.info("Application started")
692
-
693
- # Start polling for updates
694
- await app.updater.start_polling(drop_pending_updates=False)
695
- logger.info("Started polling for updates")
696
-
697
- except Exception as e:
698
- logger.error(f"Error starting bot: {e}")
699
- return
700
-
701
- # Setup signal handlers for graceful shutdown
702
- loop = asyncio.get_event_loop()
703
-
704
- for signal_name in ('SIGINT', 'SIGTERM'):
705
- try:
706
- loop.add_signal_handler(
707
- getattr(signal, signal_name),
708
- lambda s=signal_name: asyncio.create_task(shutdown(s))
709
- )
710
- except NotImplementedError:
711
- # Windows doesn't support this
712
- logger.info("Signal handlers not supported on this platform")
713
- pass
714
-
715
- try:
716
- # Just run forever until interrupted
717
- logger.info("Bot is now running and waiting for messages...")
718
- await asyncio.Event().wait()
719
- finally:
720
- # Ensure the bot is properly shut down
721
- await shutdown("Manual")
722
-
723
-
724
- async def shutdown(signal_type):
725
- """Cleanup tasks tied to the service's shutdown."""
726
- global application
727
-
728
- logger.info(f"Received exit signal {signal_type}...")
729
-
730
- # Stop the bot
731
- if application:
732
- logger.info("Stopping application...")
733
- await application.updater.stop()
734
- await application.stop()
735
- await application.shutdown()
736
-
737
- # Cancel all running tasks
738
- tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
739
- for task in tasks:
740
- task.cancel()
741
-
742
- # Wait for all tasks to be cancelled
743
- if tasks:
744
- logger.info(f"Waiting for {len(tasks)} tasks to complete...")
745
- await asyncio.gather(*tasks, return_exceptions=True)
746
-
747
- logger.info("Application shutdown complete")
748
-
749
-
750
- async def main():
751
- """Main function to setup and run the bot."""
752
- # Setup and start the bot
753
- await start_bot()
754
-
755
- # This is the entry point when run as the main process
756
- if __name__ == "__main__":
757
- asyncio.run(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/pending/text/Sound 1799.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ู†ุงุณ
data/pending/text/Sound 1800.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูŠูˆุงุฑุณูŠู† ุงู„ุณู…ูˆุงู†
data/pending/text/Sound 1801.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู‡ูˆ ุฒูˆู„ูƒู…ูŠ ูŠุนู†ูŠ ุงู„ุงู†ุณุงู† ูŠูƒูŠ
data/pending/text/Sound 1802.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ุญู‚ูŠู‚ ูˆุงู„ุง ุงูˆูƒูŠ ุนูŠูˆุงู† ุชูˆูˆูŠุดุฉ ูˆุงู„ุชู‡ู…
data/pending/text/Sound 1803.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู‡ุงุฏูŠ ุงู„ุญูˆุฌุฉ ุงู„ุชุงู†ูŠุฉ
data/pending/text/Sound 1804.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ุญุงุฌุฉ ุงู„ุชุงู„ุชุฉ ู„ูŠ ู‡ุถุฑุช ุนู„ุง
data/pending/text/Sound 1805.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูƒูŠูุงุด ุงู„ู†ุงุณ ุชุฎุฑุฌ ู…ู† ุนู‚ู„ูŠุฉ ุจูˆูƒูŠู…ูˆู† ูˆุชุฒูŠุฏ ูุงู„ู†ุงุณ
data/pending/text/Sound 1806.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุชู„ูˆูƒุงู† ู…ู†ู† ููˆุฑ ูˆู„ุง ุงูŠุดู†ุดุจ
data/pending/text/Sound 1807.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆุดู†ูˆ ู‡ูŠ
data/pending/text/Sound 1808.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูุณูŠูƒุงู†ุง ู†ุญุจ ูƒูŠู†ุฒูŠุฏ ุงู„ู†ุงุณ ูู„ูŠู†ูƒุงู†
data/pending/text/Sound 1809.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู†ุจุนุช ู„ู‡ู… ุจูˆุณูˆู†ู„ุงูŠุฒ
data/pending/text/Sound 1810.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ุง ุณุงุฏุด ุชู…ุง ู…ุง ู†ุฒูŠุฏุด ู‡ุงุฏูŠ ูƒุชุงุน
data/pending/text/Sound 1811.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงุฏ ุณู…ูˆุงู† ุงุฒูŠู„ ูƒู†ุงูƒุด
data/pending/text/Sound 1812.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ุตูˆู†ู„ุงูŠุณ ุงู†ููŠุชูŠู‡ุด ู†ุฒูŠุฏ ู‡ุงุฏูŠูƒ
data/pending/text/Sound 1813.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ูƒู„ู…ุฉ ู‡ุงุฏูŠูƒ ุงู„ุณู„ุงู… ุนู„ูŠูƒู… ุฒุจูŠุฑ ุดูุชูƒ ุจู„ูŠ ุฑุงูƒ ูุงู„ุจูˆุทูƒุงุณุช ู…ุน ุทุงู‡ุง
data/pending/text/Sound 1814.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ุง ู†ุนุฑููƒุด ุจุตุญ ู†ูƒูˆู† ุชุดุฑู ู„ูˆูƒุงู†
data/pending/text/Sound 1815.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุชู…ู†ุฒูŠุฏ ู‡ุงุฏูŠูƒ ุฒูˆุฌ ูƒู„ู…ุงุช ูˆู„ุง ุชู„ุงุชุฉ
data/pending/text/Sound 1816.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูƒ ุงู„ุงู†ุณุงู† ุงุฏุง ุงูƒุณุจุชู‡ ูˆ ุงู„ุงูƒุณุจุชูŠ ูˆุงู„ู„ุงู…ูƒุงู† ุงู„ุงู†ููŠุชูŠู‡ุดุงู†
data/pending/text/Sound 1817.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุชุฑูˆุญู„ูˆ ู‡ุงุฏูŠูƒ ุงู„ูƒุชูŠุจุฉ ู‡ุงุฏูŠูƒ ุชุฑูˆุญู„ูˆ ูู…ูŠุณุงุฌ ุงู†ุจุงูƒุณุณุชุงุนูˆ
data/pending/text/Sound 1818.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆุจุงู„ุชุงู„ูŠ ู‡ูˆ ุงู„ุง ูƒุงู† ุงู†ุณุงู† ู†ุฑู…ุฑู…ูˆุฑ ู…ุง ุดุงุก ุงู„ู„ู‡
data/pending/text/Sound 1819.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู„ุงุฒู… ูŠุชุฌุงูˆุจุฏ ุจุงุณูƒ ู…ุชู„ุง ุดุฌ ูŠุดูˆูู‡ุง ูƒุฏุง ู…ุง ุบูŠุชุฌุงูˆุจุด ุดุบู„ ูŠุฏูŠุฑ ู„ูƒ ูู‡ ู‡ุงุฏูŠูƒ ู„ุงู†ูƒ ุฑุงู‡
data/pending/text/Sound 1820.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ุง ู‚ุงู„ ู‚ุงู„ ูˆู„ูƒุง
data/pending/text/Sound 1821.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ุฑุญุจุง ุฒุนู…ุง ุฑุงูƒ ุงูŠู†ู‡ุงุฑูŠ ุฒุนู…ุง ู…ุง ุนู†ุฏูƒุด ูˆู‚ุช ุจุงุด ู„ูƒ ุชุจ ู‚ุง ู…ูŠุบุณูŠ
data/pending/text/Sound 1822.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆู„ุง ุชูŠู†ูƒูŠูˆ
data/pending/text/Sound 1823.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆูŠุจุนุช ู„ูŠู…ูŠุณุงุฑ
data/pending/text/Sound 1824.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุฏูˆู†ูƒ ู„ูŠู…ูŠุณุงุฌ ู‡ุงุฏูˆูƒ ุงู„ู„ูˆู„ูŠู† ุจุงุณูƒ ุงู†ุช ุฏุฑุช
data/pending/text/Sound 1825.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูุฑูˆุณุชุงุจ ูˆูƒุชุจุช ู…ูŠุณุงุฌ
data/pending/text/Sound 1826.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆุนู„ุงุด ุงู†ุญุงุจู„ ู†ุฏุฎู„ ู…ุนุงูƒ ูุงุชุตุงู„
data/pending/text/Sound 1827.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ุงูˆู„ุง ุงู†ุง ู†ูู„ุชุฑูŠ ุจุงุด ุดูƒูˆู† ู„ูŠ ู†ุฒูŠุฏู‡ู… ูˆุดูƒูˆู† ู„ูŠ ู†ุฑูุถ ุจุงุณูƒุณุงุนุงุช ู‡ูˆ ู†ุฑูุถ ูƒู†ุงูƒ ุดูŠู†ูˆ ู„ูˆูƒ ูˆูŠุณุช
data/pending/text/Sound 1828.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุชุฌูŠู†ูŠ ุนู†ุง ูƒูˆู†ูŠูƒุดู†ูˆุจ ุงู„ูƒูˆุงุณุชูˆุน ูู„ูŠู† ูƒุชูŠุงู†
data/pending/text/Sound 1829.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ู† ูƒุงู†ูˆูˆุงุญุฏ ู…ุง ูŠู‡ุถุฑ ู†ูŠ ูุฑูˆู†ุณูŠ ู†ูŠ ุนุฑุจูŠุฉ ู†ูŠ ุงูˆู†ุฌู„ูŠ
data/pending/text/Sound 1830.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ูƒุงุด ุจู„ุงุฏ ู…ุง ุนุจุงุฏูŠุด ุงู†ุง ู…ุง ุนู†ุฏูŠ ุญุชุง ุนู„ุงู‚ุฉ ู…ุญ ูˆู„ุงุด ู†ุฒูŠุฏูƒ ูู„ูŠู† ู‚ุชุงู†
data/pending/text/Sound 1831.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูŠุงุฑู†ูˆุช ุฌุงุณุชุงู„ู†ุงู…ุจุนูˆุฑ ุงู†ุง ุงูŠุถ
data/pending/text/Sound 1832.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ุง ู†ูŠุด ู†ุญูˆุณุด ุงู†ุง ุจุงุด ู†ุฒูŠุฏ ุงู†ุง ุจุงุด ู†ุทู„ุน
data/pending/text/Sound 1833.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆูŠูƒูˆู† ุนู†ุฏูŠ ู…ุฆุฉ ุงู„ู ููŠู† ู†ุฌุฏู†ุงุก
data/pending/text/Sound 1834.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงูŠ ู†ูˆุท ุชูŠุฏุดูŠูˆ ุณุชุงุฏ
data/pending/text/Sound 1835.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูˆุดู†ุญุงุจ ู…ู†ุญุจ
data/pending/text/Sound 1836.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู…ู†ูŠ ูุฑูˆู„ุฉ ุด ู†ุดูุชุงู†ูŠ ุญุจ ูƒูˆุงู„ูŠุชูŠ ุงูˆูุงู„ูƒูˆุงู†ุชุชูŠ
data/pending/text/Sound 1837.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุฏูˆู†ูƒ ุงู†ุง ู†ุดูˆู ู†ุดูˆู ูุงู„ุจุฑูˆูุงูŠู„ ุชุงุนุง ุงู„ุงู†ุณุงู† ู†ุดูˆู ูˆุงุด ูƒุชุจ ู„ูŠ
data/pending/text/Sound 1838.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุจุงุด ู†ุฒูŠุฏูˆ ูˆูƒุงูŠู† ู†ู„ู‚ุง ู…ูŠุณุงุฌ
data/pending/text/Sound 1839.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุณู… ู„ุงูŠุฒ ุฏ ุงู„ุงู†ููŠุชุงูŠุดู„
data/pending/text/Sound 1840.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุฏูŠ ุงู„ุณู„ูŠุฏ ุชูˆูƒู… ูุณุงูŠุดู„ ูƒุงูŠู† ูƒู„ ู…ุฉ ู†ุณุชุนู…ู„ู‡ุง ุจุฒุงู ุงู†ุง ููƒุงูŠู†
data/pending/text/Sound 1841.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูƒูŠูƒูˆู†ูˆ ุนู†ุฏูŠ
data/pending/text/Sound 1842.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ู†ุงุณ ู†ุชุนุงู…ู„ ู…ุนู‡ู… ูุงู„ุจุฑุงู†ุฏูŠู†ุบ ูˆูุงู„ุจุฑุณู† ุจู„ุงู†ุฏูŠ
data/pending/text/Sound 1843.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู†ูƒูˆู„ ู„ู‡ู… ูŠูู†ูˆ
data/pending/text/Sound 1844.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ูƒูˆู† ูู„ูˆ ุณูŠุดู†
data/pending/text/Sound 1845.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ู†ูˆูƒ ู…ููˆุฌู†
data/pending/text/Sound 1846.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ุง ู…ุง ูƒุงู†ุด
data/pending/text/Sound 1847.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ุงู„ูƒูˆู†ููŠุฑุณุงุณูŠูˆู† ู…ุง ูƒุงู†ุด ุญูˆุงุฑ