Spaces:
Build error
Build error
File size: 6,552 Bytes
dfbf6c3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | """
🔧 توابع کمکی عمومی
Utility functions for text processing
"""
import re
import logging
from typing import List
logger = logging.getLogger(__name__)
def count_tokens(text: str, method: str = 'simple') -> int:
"""
شمارش تعداد tokens در متن
Args:
text: متن ورودی
method: روش شمارش - 'simple' یا 'accurate'
Returns:
تعداد tokens تخمینی
Examples:
>>> count_tokens("این یک متن تست است")
6
"""
if not text or not text.strip():
return 0
if method == 'simple':
# تخمین ساده: 1 token ≈ 4 کاراکتر
# این تخمین برای فارسی و انگلیسی کار میکند
return max(1, len(text) // 4)
elif method == 'accurate':
try:
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base")
return len(encoding.encode(text))
except ImportError:
logger.warning("⚠️ tiktoken not installed, falling back to simple method")
return max(1, len(text) // 4)
except Exception as e:
logger.error(f"❌ Error in tiktoken: {e}")
return max(1, len(text) // 4)
else:
raise ValueError(f"Invalid method: {method}. Use 'simple' or 'accurate'")
def should_use_chunking(text: str, threshold: int = 6000) -> bool:
"""
تصمیمگیری: آیا نیاز به chunking داریم؟
Args:
text: متن ورودی
threshold: حد آستانه (tokens) - پیشفرض 6000
Returns:
True اگر تعداد tokens بیشتر از threshold باشد
Examples:
>>> should_use_chunking("متن کوتاه", threshold=100)
False
"""
if not text or not text.strip():
return False
token_count = count_tokens(text)
if token_count > threshold:
logger.info(
f"📊 متن بلند تشخیص داده شد: {token_count} tokens > {threshold} "
f"→ استفاده از chunking"
)
return True
else:
logger.info(
f"📊 متن کوتاه: {token_count} tokens ≤ {threshold} "
f"→ بدون chunking"
)
return False
def split_sentences(text: str) -> List[str]:
"""
تقسیم متن به جملات
از الگوهای regex برای تشخیص پایان جملات فارسی استفاده میکند
Args:
text: متن ورودی
Returns:
لیست جملات
Examples:
>>> split_sentences("جمله اول. جمله دوم؟ جمله سوم!")
['جمله اول', 'جمله دوم', 'جمله سوم']
"""
if not text or not text.strip():
return []
# الگوهای پایان جمله در فارسی
# . ! ? ؟ و همچنین نسخههای فارسی آنها
pattern = r'[.!?؟]\s+'
sentences = re.split(pattern, text)
# حذف جملات خالی و فضای خالی اضافی
sentences = [s.strip() for s in sentences if s.strip()]
return sentences
def get_last_n_tokens(text: str, n: int) -> str:
"""
استخراج n توکن آخر از متن (برای ایجاد overlap در chunking)
Args:
text: متن ورودی
n: تعداد tokens مورد نظر
Returns:
بخش آخر متن که تقریباً n توکن دارد
Examples:
>>> get_last_n_tokens("این یک متن بلند است", 2)
'است' # تقریباً 2 توکن آخر
"""
if not text or n <= 0:
return ""
# تقریب: هر token ≈ 4 کاراکتر
approx_chars = n * 4
if len(text) <= approx_chars:
return text
return text[-approx_chars:]
def get_first_n_tokens(text: str, n: int) -> str:
"""
استخراج n توکن اول از متن
Args:
text: متن ورودی
n: تعداد tokens مورد نظر
Returns:
بخش اول متن که تقریباً n توکن دارد
"""
if not text or n <= 0:
return ""
# تقریب: هر token ≈ 4 کاراکتر
approx_chars = n * 4
if len(text) <= approx_chars:
return text
return text[:approx_chars]
def clean_text(text: str) -> str:
"""
پاکسازی و نرمالسازی اولیه متن
Args:
text: متن ورودی
Returns:
متن پاکسازی شده
"""
if not text:
return ""
# حذف فضاهای خالی اضافی
text = re.sub(r'\s+', ' ', text)
# حذف فضای خالی ابتدا و انتها
text = text.strip()
return text
# ✅ تستهای سریع
if __name__ == "__main__":
print("=" * 60)
print("🧪 Testing Utils Module")
print("=" * 60)
# تست 1: Token counting
test_text = "این یک متن تست برای بررسی تعداد توکنها است."
tokens = count_tokens(test_text)
print(f"\n📊 Test 1: Token Counting")
print(f" Text: {test_text}")
print(f" Tokens: {tokens}")
# تست 2: Chunking decision
short_text = "متن کوتاه"
long_text = "متن بلند " * 1000
print(f"\n📊 Test 2: Chunking Decision")
print(f" Short text ({count_tokens(short_text)} tokens): {should_use_chunking(short_text)}")
print(f" Long text ({count_tokens(long_text)} tokens): {should_use_chunking(long_text)}")
# تست 3: Sentence splitting
multi_sentence = "جمله اول. جمله دوم؟ جمله سوم! چطور هستید؟"
sentences = split_sentences(multi_sentence)
print(f"\n📊 Test 3: Sentence Splitting")
print(f" Input: {multi_sentence}")
print(f" Sentences: {sentences}")
print(f" Count: {len(sentences)}")
# تست 4: Last n tokens
sample_text = "این یک متن نمونه برای تست است که میخواهیم بخش آخر آن را بگیریم"
last_part = get_last_n_tokens(sample_text, 5)
print(f"\n📊 Test 4: Get Last N Tokens")
print(f" Original: {sample_text}")
print(f" Last 5 tokens (~20 chars): {last_part}")
print("\n" + "=" * 60)
print("✅ All tests completed!")
print("=" * 60)
|