PerSent 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of PerSent might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PerSent
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Persian Sentiment Analysis Toolkit
5
5
  Home-page: https://github.com/RezaGooner/PerSent
6
6
  Author: RezaGooner
@@ -1,4 +1,4 @@
1
1
  from .analyzer import PersianSentimentAnalyzer
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.3"
4
4
  __all__ = ['PersianSentimentAnalyzer']
@@ -1,13 +1,16 @@
1
1
  import pandas as pd
2
2
  from hazm import Normalizer, word_tokenize, Stemmer, stopwords_list
3
3
  import re
4
- from tqdm import tqdm
4
+ from tqdm import tqdm
5
5
  from gensim.models import Word2Vec
6
6
  import numpy as np
7
7
  from sklearn.linear_model import LogisticRegression
8
8
  from sklearn.model_selection import train_test_split
9
9
  import os
10
10
  import joblib
11
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
12
+ import torch
13
+ from torch.nn.functional import softmax
11
14
 
12
15
  class PersianSentimentAnalyzer:
13
16
  def __init__(self, model_dir='persian_sentiment/model'):
@@ -17,19 +20,18 @@ class PersianSentimentAnalyzer:
17
20
  self.model_dir = model_dir
18
21
  self.vectorizer = None
19
22
  self.classifier = None
20
- self.emotion_keywords = {
21
- 'Fear': ['ترس', 'وحشت', 'هراس'],
22
- 'Surprise': ['تعجب', 'شگفت', 'حیرت'],
23
- 'Anger': ['خشم', 'عصبانیت', 'خشونت'],
24
- 'Contempt': ['تحقیر', 'توهین', 'حقارت'],
25
- 'Joy': ['شادی', 'خوشحالی', 'خنده'],
26
- 'Sadness': ['غم', 'اندوه', 'ناراحتی'],
27
- 'Disgust': ['انزجار', 'تهوع', 'نفرت']
28
- }
29
23
 
30
- os.makedirs(self.model_dir, exist_ok=True)
24
+ # مدل تحلیل احساسات
25
+ self.emotion_tokenizer = AutoTokenizer.from_pretrained(
26
+ "HooshvareLab/bert-fa-base-uncased-emotion")
27
+ self.emotion_model = AutoModelForSequenceClassification.from_pretrained(
28
+ "HooshvareLab/bert-fa-base-uncased-emotion")
29
+ self.emotion_labels = ['ترس', 'تعجب', 'خشم', 'تحقیر', 'شادی', 'غم', 'انزجار']
31
30
 
31
+ os.makedirs(self.model_dir, exist_ok=True)
32
+
32
33
  def _preprocess_text(self, text):
34
+ """پیش‌پردازش متن فارسی"""
33
35
  text = self.normalizer.normalize(str(text))
34
36
  text = re.sub(r'[!()-\[\]{};:\'",؟<>./?@#$%^&*_~۰-۹\d]+', ' ', text)
35
37
  text = re.sub(r'\s+', ' ', text).strip()
@@ -40,8 +42,9 @@ class PersianSentimentAnalyzer:
40
42
  if token not in self.stopwords and len(token) > 1
41
43
  ]
42
44
  return processed_tokens
43
-
45
+
44
46
  def _sentence_vector(self, sentence, model):
47
+ """تبدیل جمله به بردار با میانگین بردارهای کلمات"""
45
48
  vectors = []
46
49
  for word in sentence:
47
50
  try:
@@ -49,20 +52,34 @@ class PersianSentimentAnalyzer:
49
52
  except KeyError:
50
53
  vectors.append(np.zeros(100))
51
54
  return np.mean(vectors, axis=0) if vectors else np.zeros(100)
52
-
53
- def _emotion_analysis(self, tokens):
54
- """تحلیل احساسات بر اساس کلیدواژه‌های از پیش تعریف شده"""
55
- emotions = {emotion: 0 for emotion in self.emotion_keywords.keys()}
56
- for word in tokens:
57
- for emotion, keywords in self.emotion_keywords.items():
58
- if word in keywords:
59
- emotions[emotion] += 1
60
- return emotions
61
-
55
+
56
+ def _emotion_analysis(self, text):
57
+ """تحلیل احساسات با مدل BERT فارسی"""
58
+ inputs = self.emotion_tokenizer(
59
+ text,
60
+ return_tensors="pt",
61
+ truncation=True,
62
+ padding=True,
63
+ max_length=128
64
+ )
65
+
66
+ with torch.no_grad():
67
+ outputs = self.emotion_model(**inputs)
68
+
69
+ probs = softmax(outputs.logits, dim=1)
70
+ scores = probs.numpy()[0]
71
+
72
+ return {
73
+ label: round(float(score), 4)
74
+ for label, score in zip(self.emotion_labels, scores)
75
+ }
76
+
62
77
  def train(self, train_csv, test_size=0.2, vector_size=100, window=5):
78
+ """آموزش مدل تحلیل توصیه"""
63
79
  df = pd.read_csv(train_csv)
64
80
  df['tokens'] = df['body'].apply(self._preprocess_text)
65
81
 
82
+ # آموزش مدل Word2Vec
66
83
  self.vectorizer = Word2Vec(
67
84
  sentences=df['tokens'],
68
85
  vector_size=vector_size,
@@ -71,6 +88,7 @@ class PersianSentimentAnalyzer:
71
88
  workers=4
72
89
  )
73
90
 
91
+ # تبدیل جملات به بردار
74
92
  X = np.array([self._sentence_vector(s, self.vectorizer) for s in df['tokens']])
75
93
  y = df['recommendation_status'].map({
76
94
  "no_idea": 2,
@@ -78,29 +96,34 @@ class PersianSentimentAnalyzer:
78
96
  "not_recommended": 0
79
97
  }).values
80
98
 
99
+ # تقسیم داده‌ها و آموزش مدل
81
100
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size)
82
-
83
101
  self.classifier = LogisticRegression(max_iter=1000)
84
102
  self.classifier.fit(X_train, y_train)
85
103
 
104
+ # ذخیره مدل
86
105
  self.save_model()
87
106
  accuracy = self.classifier.score(X_test, y_test)
88
- return accuracy
89
-
107
+ return round(accuracy, 4)
108
+
90
109
  def predict(self, text, mode=0):
91
- """پیش‌بینی احساس متن با قابلیت انتخاب حالت تحلیل
110
+ """
111
+ پیش‌بینی احساس متن
92
112
 
93
113
  پارامترها:
114
+ text (str): متن ورودی
94
115
  mode (int):
95
116
  0 = تحلیل توصیه (پیش‌فرض)
96
- 1 = تحلیل احساسات (Fear, Joy, etc.)
117
+ 1 = تحلیل احساسات با مدل BERT
118
+
119
+ بازگشتی:
120
+ dict یا str: نتایج تحلیل
97
121
  """
98
- if not self.classifier or not self.vectorizer:
99
- raise Exception("Model not trained! Call train() first or load a pretrained model.")
100
-
101
- tokens = self._preprocess_text(text)
102
-
103
122
  if mode == 0:
123
+ if not self.classifier or not self.vectorizer:
124
+ raise Exception("Recommendation model not trained! Call train() first.")
125
+
126
+ tokens = self._preprocess_text(text)
104
127
  vector = self._sentence_vector(tokens, self.vectorizer)
105
128
  prediction = self.classifier.predict([vector])[0]
106
129
  return {
@@ -110,15 +133,17 @@ class PersianSentimentAnalyzer:
110
133
  }[prediction]
111
134
 
112
135
  elif mode == 1:
113
- return self._emotion_analysis(tokens)
136
+ return self._emotion_analysis(text)
114
137
 
115
138
  else:
116
- raise ValueError("Invalid mode. Use 0 (recommendation analysis) or 1 (emotion analysis)")
117
-
139
+ raise ValueError("Invalid mode. Use 0 (recommendation) or 1 (emotion)")
140
+
118
141
  def save_model(self):
142
+ """ذخیره مدل تحلیل توصیه"""
119
143
  joblib.dump(self.classifier, os.path.join(self.model_dir, 'classifier.joblib'))
120
144
  self.vectorizer.save(os.path.join(self.model_dir, 'word2vec.model'))
121
-
145
+
122
146
  def load_model(self):
147
+ """بارگذاری مدل تحلیل توصیه"""
123
148
  self.classifier = joblib.load(os.path.join(self.model_dir, 'classifier.joblib'))
124
149
  self.vectorizer = Word2Vec.load(os.path.join(self.model_dir, 'word2vec.model'))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PerSent
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Persian Sentiment Analysis Toolkit
5
5
  Home-page: https://github.com/RezaGooner/PerSent
6
6
  Author: RezaGooner
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="PerSent",
8
- version="0.1.2",
8
+ version="0.1.3",
9
9
  author="RezaGooner",
10
10
  author_email="RezaAsadiProgrammer@Gmail.com",
11
11
  description="Persian Sentiment Analysis Toolkit",
File without changes
File without changes
File without changes
File without changes