Files
Mehvar/modules/segmenter.py
T

116 lines
5.0 KiB
Python
Raw Normal View History

2026-06-29 15:32:24 +03:30
import re
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
class Segmenter:
def __init__(self):
print("Loading models :")
self.model_bge = SentenceTransformer("C:/Models/bge-m3", model_kwargs={"use_safetensors": False})
self.model_e5 = SentenceTransformer("C:/Models/multilingual-e5-large")
self.model_labse = SentenceTransformer("C:/Models/LaBSE_Local")
self.model_parsroberta = SentenceTransformer("C:/Models/ParsRoberta")
print("4 models loaded successfully")
def get_similarities(self, text1, text2):
"""محاسبه میانگین شباهت کسینوسی از ۴ مدل برای دو متن داده شده"""
emb_bge = self.model_bge.encode([text1, text2])
emb_e5 = self.model_e5.encode([text1, text2])
emb_labse = self.model_labse.encode([text1, text2])
emb_parsroberta = self.model_parsroberta.encode([text1, text2])
sim_bge = cosine_similarity([emb_bge[0]], [emb_bge[1]])[0][0]
sim_e5 = cosine_similarity([emb_e5[0]], [emb_e5[1]])[0][0]
sim_labse = cosine_similarity([emb_labse[0]], [emb_labse[1]])[0][0]
sim_parsroberta = cosine_similarity([emb_parsroberta[0]], [emb_parsroberta[1]])[0][0]
# میانگین‌گیری از هر ۴ مدل
return np.mean([sim_bge, sim_e5, sim_labse, sim_parsroberta])
def calculate_depth_scores(self, similarities):
"""محاسبه عمق دره‌ها (Gap Scores) با استفاده از قله‌های چپ و راست"""
depth_scores = []
n = len(similarities)
for i in range(n):
left_peak = similarities[i]
for j in range(i, -1, -1):
if similarities[j] >= left_peak:
left_peak = similarities[j]
else:
break
right_peak = similarities[i]
for j in range(i, n):
if similarities[j] >= right_peak:
right_peak = similarities[j]
else:
break
depth = (left_peak - similarities[i]) + (right_peak - similarities[i])
depth_scores.append(depth)
return depth_scores
def extract_sentences(self, text):
"""جداسازی متن اولیه به جملات"""
text = text.replace('\n', ' ')
sentences = [s.strip() for s in re.split(r'(?<=[.!?؟]) +', text) if s.strip()]
return sentences
def segment_items(self, items, force_count=None, std_multiplier=0.5, min_depth=0.02):
"""
دریافت جملات یا واحدهای معنایی و کلاسترینگ آن‌ها.
اگر پارامتر force_count ارسال شود، الگوریتم موظف است دقیقاً همان تعداد سگمنت تولید کند.
"""
n_items = len(items)
if n_items < 2:
return [items]
similarities = []
for i in range(n_items - 1):
sim = self.get_similarities(items[i], items[i + 1])
similarities.append(sim)
depth_scores = self.calculate_depth_scores(similarities)
# -------------------------------------------------------------
# حالت اجباری: رساندن تعداد سگمنت‌ها به عدد دقیق (مثلا 7)
# -------------------------------------------------------------
if force_count and 1 < force_count < n_items:
# پیدا کردن عمیق‌ترین دره‌ها برای ایجاد دقیقا force_count - 1 برش
top_cut_indices = np.argsort(depth_scores)[-(force_count - 1):]
top_cut_indices = sorted(top_cut_indices)
grouped_segments = []
start = 0
for idx in top_cut_indices:
grouped_segments.append(items[start:idx + 1])
start = idx + 1
grouped_segments.append(items[start:])
return grouped_segments
# -------------------------------------------------------------
# حالت عادی داینامیک: در سطوح پایین‌تر که هنوز به تعداد هدف نرسیده‌ایم
# -------------------------------------------------------------
mean_depth = np.mean(depth_scores)
std_depth = np.std(depth_scores)
cutoff_threshold = mean_depth + (std_multiplier * std_depth)
grouped_segments = []
current_segment = [items[0]]
for i in range(len(similarities)):
if depth_scores[i] >= cutoff_threshold and depth_scores[i] > min_depth:
grouped_segments.append(current_segment)
current_segment = [items[i + 1]]
else:
current_segment.append(items[i + 1])
if current_segment:
grouped_segments.append(current_segment)
return grouped_segments