PerSent 1.0.0__tar.gz → 1.0.2__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.
- persent-1.0.2/PKG-INFO +121 -0
- persent-1.0.2/PerSent/CommentAnalyzer.py +199 -0
- persent-1.0.2/PerSent/__init__.py +4 -0
- persent-1.0.2/PerSent/model/classifier.joblib +0 -0
- persent-1.0.2/PerSent/model/word2vec.model +0 -0
- persent-1.0.2/PerSent.egg-info/PKG-INFO +121 -0
- {persent-1.0.0 → persent-1.0.2}/PerSent.egg-info/SOURCES.txt +3 -2
- persent-1.0.2/PerSent.egg-info/requires.txt +6 -0
- persent-1.0.2/README.md +91 -0
- persent-1.0.2/setup.py +34 -0
- persent-1.0.0/PKG-INFO +0 -44
- persent-1.0.0/PerSent/__init__.py +0 -50
- persent-1.0.0/PerSent/core/models/base_model.py +0 -31
- persent-1.0.0/PerSent.egg-info/PKG-INFO +0 -44
- persent-1.0.0/PerSent.egg-info/requires.txt +0 -6
- persent-1.0.0/README.md +0 -11
- persent-1.0.0/setup.py +0 -51
- persent-1.0.0/tests/test_core.py +0 -20
- {persent-1.0.0 → persent-1.0.2}/PerSent.egg-info/dependency_links.txt +0 -0
- {persent-1.0.0 → persent-1.0.2}/PerSent.egg-info/top_level.txt +0 -0
- {persent-1.0.0 → persent-1.0.2}/setup.cfg +0 -0
persent-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PerSent
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Persian Sentiment Analysis Toolkit
|
|
5
|
+
Home-page: https://github.com/RezaGooner/PerSent
|
|
6
|
+
Author: RezaGooner
|
|
7
|
+
Author-email: RezaAsadiProgrammer@Gmail.com
|
|
8
|
+
Keywords: persian sentiment analysis nlp
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: hazm>=0.7.0
|
|
15
|
+
Requires-Dist: gensim>=4.0.0
|
|
16
|
+
Requires-Dist: scikit-learn>=1.0.0
|
|
17
|
+
Requires-Dist: pandas>=1.3.0
|
|
18
|
+
Requires-Dist: tqdm>=4.62.0
|
|
19
|
+
Requires-Dist: joblib>=1.1.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: keywords
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# PerSent - Persian Sentiment Analyzer
|
|
32
|
+
[](README.fa.md)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## Introduction
|
|
38
|
+
PerSent is a Python library designed for Persian sentiment analysis. The name stands for "Persian Sentiment Analyzer". Currently in its early testing phase, PerSent provides tools for analyzing sentiment in Persian text, particularly useful for product reviews and service feedback.
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
- Sentiment classification into three categories:
|
|
42
|
+
- `recommended`
|
|
43
|
+
- `not_recommended`
|
|
44
|
+
- `no_idea`
|
|
45
|
+
- Single text analysis
|
|
46
|
+
- Batch processing from CSV files
|
|
47
|
+
- Summary report generation
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
Install the latest version using pip:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install PerSent
|
|
54
|
+
```
|
|
55
|
+
For a specific version:
|
|
56
|
+
|
|
57
|
+
``` bash
|
|
58
|
+
pip install PerSent==<VERSION_NUMBER>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Basic Usage
|
|
62
|
+
### Single Text Analysis
|
|
63
|
+
``` bash
|
|
64
|
+
from PerSent import CommentAnalyzer
|
|
65
|
+
|
|
66
|
+
# Initialize analyzer
|
|
67
|
+
analyzer = CommentAnalyzer()
|
|
68
|
+
|
|
69
|
+
# Load pre-trained model
|
|
70
|
+
analyzer.load_model()
|
|
71
|
+
|
|
72
|
+
# Analyze text
|
|
73
|
+
text = "کیفیت عالی داشت"
|
|
74
|
+
result = analyzer.predict(text)
|
|
75
|
+
print(f"Sentiment: {result}")
|
|
76
|
+
# Output: Sentiment: recommended
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Training Your Own Model
|
|
80
|
+
``` bash
|
|
81
|
+
'''
|
|
82
|
+
Train the model using a CSV file containing:
|
|
83
|
+
- Comments
|
|
84
|
+
- Recommendation status (recommended/not_recommended/no_idea)
|
|
85
|
+
'''
|
|
86
|
+
analyzer.train("train.csv")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Batch Processing
|
|
90
|
+
### CSV Processing
|
|
91
|
+
|
|
92
|
+
``` bash
|
|
93
|
+
analyzer.csvPredict(
|
|
94
|
+
input_csv="comments.csv",
|
|
95
|
+
output_path="results.csv"
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Advanced CSV Processing Options
|
|
100
|
+
``` bash
|
|
101
|
+
# Using column index
|
|
102
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, 0)
|
|
103
|
+
|
|
104
|
+
# Using column name
|
|
105
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, "Comments")
|
|
106
|
+
|
|
107
|
+
# With summary report
|
|
108
|
+
analyzer.csvPredict("comments.csv", "results.csv", "summary.csv")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Dataset
|
|
112
|
+
A sample training dataset is available:
|
|
113
|
+
[Download Dataset](https://github.com/RezaGooner/Sentiment-Survey-Analyzer/tree/main/Dataset/big_train)
|
|
114
|
+
|
|
115
|
+
## Contribution
|
|
116
|
+
We welcome contributions and feedback:
|
|
117
|
+
|
|
118
|
+
- [Fork Repository & Pull Request](https://github.com/RezaGooner/PerSent/fork)
|
|
119
|
+
- [Make Issue](https://github.com/RezaGooner/PerSent/issues/new)
|
|
120
|
+
- E-Mail : ```RezaAsadiProgrammer@gmail.com```
|
|
121
|
+
- Telegram : ```@RezaGooner```
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#import necessary library
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from hazm import Normalizer, word_tokenize, Stemmer, stopwords_list
|
|
4
|
+
import re
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
from gensim.models import Word2Vec
|
|
7
|
+
import numpy as np
|
|
8
|
+
from sklearn.linear_model import LogisticRegression
|
|
9
|
+
from sklearn.model_selection import train_test_split
|
|
10
|
+
import os
|
|
11
|
+
import joblib
|
|
12
|
+
|
|
13
|
+
class CommentAnalyzer:
|
|
14
|
+
def __init__(self, model_dir='PerSent/model'):
|
|
15
|
+
self.normalizer = Normalizer()
|
|
16
|
+
self.stemmer = Stemmer()
|
|
17
|
+
self.stopwords = set(stopwords_list())
|
|
18
|
+
self.model_dir = model_dir
|
|
19
|
+
self.vectorizer = None
|
|
20
|
+
self.classifier = None
|
|
21
|
+
|
|
22
|
+
# make /model Directory if not exist
|
|
23
|
+
os.makedirs(self.model_dir, exist_ok=True)
|
|
24
|
+
|
|
25
|
+
def _preprocess_text(self, text):
|
|
26
|
+
"""PreProcess Persian Text"""
|
|
27
|
+
# Normalizing
|
|
28
|
+
text = self.normalizer.normalize(str(text))
|
|
29
|
+
|
|
30
|
+
# remove number and sign
|
|
31
|
+
text = re.sub(r'[!()-\[\]{};:\'",؟<>./?@#$%^&*_~۰-۹\d]+', ' ', text)
|
|
32
|
+
text = re.sub(r'\s+', ' ', text).strip()
|
|
33
|
+
|
|
34
|
+
# tokenize and stemming
|
|
35
|
+
tokens = word_tokenize(text)
|
|
36
|
+
processed_tokens = [
|
|
37
|
+
self.stemmer.stem(token)
|
|
38
|
+
for token in tokens
|
|
39
|
+
if token not in self.stopwords and len(token) > 1
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
return processed_tokens
|
|
43
|
+
|
|
44
|
+
def _sentence_vector(self, sentence, model):
|
|
45
|
+
"""convert sentences to vector by word2vec model"""
|
|
46
|
+
vectors = []
|
|
47
|
+
for word in sentence:
|
|
48
|
+
try:
|
|
49
|
+
vectors.append(model.wv[word])
|
|
50
|
+
except KeyError:
|
|
51
|
+
vectors.append(np.zeros(100))
|
|
52
|
+
return np.mean(vectors, axis=0) if vectors else np.zeros(100)
|
|
53
|
+
|
|
54
|
+
def train(self, train_csv, test_size=0.2, vector_size=100, window=5):
|
|
55
|
+
"""Train model"""
|
|
56
|
+
# read data
|
|
57
|
+
df = pd.read_csv(train_csv)
|
|
58
|
+
df['tokens'] = df['body'].apply(self._preprocess_text)
|
|
59
|
+
|
|
60
|
+
# train Word2Vec model
|
|
61
|
+
self.vectorizer = Word2Vec(
|
|
62
|
+
sentences=df['tokens'],
|
|
63
|
+
vector_size=vector_size,
|
|
64
|
+
window=window,
|
|
65
|
+
min_count=1,
|
|
66
|
+
workers=4
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# convert sentences to vector
|
|
70
|
+
X = np.array([self._sentence_vector(s, self.vectorizer) for s in df['tokens']])
|
|
71
|
+
y = df['recommendation_status'].map({
|
|
72
|
+
"no_idea": 2,
|
|
73
|
+
"recommended": 1,
|
|
74
|
+
"not_recommended": 0
|
|
75
|
+
}).values
|
|
76
|
+
|
|
77
|
+
# make train and test data
|
|
78
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size)
|
|
79
|
+
|
|
80
|
+
self.classifier = LogisticRegression(max_iter=1000)
|
|
81
|
+
self.classifier.fit(X_train, y_train)
|
|
82
|
+
|
|
83
|
+
# save model
|
|
84
|
+
self.save_model()
|
|
85
|
+
|
|
86
|
+
# evaluation
|
|
87
|
+
accuracy = self.classifier.score(X_test, y_test)
|
|
88
|
+
return accuracy
|
|
89
|
+
|
|
90
|
+
def predict(self, text):
|
|
91
|
+
"""Predict text sentiment"""
|
|
92
|
+
if not self.classifier or not self.vectorizer:
|
|
93
|
+
raise Exception("Model not trained! Call train() first or load a pretrained model.")
|
|
94
|
+
|
|
95
|
+
tokens = self._preprocess_text(text)
|
|
96
|
+
vector = self._sentence_vector(tokens, self.vectorizer)
|
|
97
|
+
prediction = self.classifier.predict([vector])[0]
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
0: "not_recommended",
|
|
101
|
+
1: "recommended",
|
|
102
|
+
2: "no_idea"
|
|
103
|
+
}[prediction]
|
|
104
|
+
|
|
105
|
+
def save_model(self):
|
|
106
|
+
"""save trained model"""
|
|
107
|
+
joblib.dump(self.classifier, os.path.join(self.model_dir, 'classifier.joblib'))
|
|
108
|
+
self.vectorizer.save(os.path.join(self.model_dir, 'word2vec.model'))
|
|
109
|
+
|
|
110
|
+
def load_model(self):
|
|
111
|
+
"""reload from file"""
|
|
112
|
+
self.classifier = joblib.load(os.path.join(self.model_dir, 'classifier.joblib'))
|
|
113
|
+
self.vectorizer = Word2Vec.load(os.path.join(self.model_dir, 'word2vec.model'))
|
|
114
|
+
|
|
115
|
+
def csvPredict(self, input_csv, output_path, summary_path=None, text_column=0):
|
|
116
|
+
"""
|
|
117
|
+
Analyze sentiment for comments in a CSV file and save results
|
|
118
|
+
|
|
119
|
+
Parameters:
|
|
120
|
+
input_csv (str): Path to input CSV file
|
|
121
|
+
output_path (str): Path to save output CSV file
|
|
122
|
+
text_column (str/int, optional): Name or index (0-based) of column containing comments.
|
|
123
|
+
Defaults to 0 (first column).
|
|
124
|
+
summary_path (str, optional): Path to save prediction summary report.
|
|
125
|
+
If None, no summary will be saved.
|
|
126
|
+
"""
|
|
127
|
+
try:
|
|
128
|
+
# Read input CSV
|
|
129
|
+
df = pd.read_csv(input_csv)
|
|
130
|
+
|
|
131
|
+
# Determine the correct column
|
|
132
|
+
if isinstance(text_column, int):
|
|
133
|
+
# Handle negative indices
|
|
134
|
+
if text_column < 0:
|
|
135
|
+
text_column = len(df.columns) + text_column
|
|
136
|
+
|
|
137
|
+
if text_column >= len(df.columns) or text_column < 0:
|
|
138
|
+
raise ValueError(f"Column index {text_column} is out of range")
|
|
139
|
+
|
|
140
|
+
column_name = df.columns[text_column]
|
|
141
|
+
else:
|
|
142
|
+
if text_column not in df.columns:
|
|
143
|
+
raise ValueError(f"Column '{text_column}' not found in CSV file")
|
|
144
|
+
column_name = text_column
|
|
145
|
+
|
|
146
|
+
# Analyze each comment
|
|
147
|
+
tqdm.pandas(desc="Analyzing comments")
|
|
148
|
+
df['sentiment'] = df[column_name].progress_apply(self.predict)
|
|
149
|
+
|
|
150
|
+
# Save results
|
|
151
|
+
df.to_csv(output_path, index=False, encoding='utf-8-sig')
|
|
152
|
+
print(f"Results saved to {output_path}")
|
|
153
|
+
|
|
154
|
+
# Generate and save summary if requested
|
|
155
|
+
if summary_path:
|
|
156
|
+
summary = self._generate_summary(df)
|
|
157
|
+
summary.to_csv(summary_path, index=False, encoding='utf-8-sig')
|
|
158
|
+
print(f"Summary report saved to {summary_path}")
|
|
159
|
+
|
|
160
|
+
return df
|
|
161
|
+
|
|
162
|
+
except Exception as e:
|
|
163
|
+
print(f"Error: {str(e)}")
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def _generate_summary(self, df):
|
|
167
|
+
"""Generate prediction summary statistics"""
|
|
168
|
+
# Count each sentiment
|
|
169
|
+
counts = df['sentiment'].value_counts().to_dict()
|
|
170
|
+
|
|
171
|
+
# Create summary dataframe
|
|
172
|
+
summary = pd.DataFrame({
|
|
173
|
+
'Category': [
|
|
174
|
+
'Recommended',
|
|
175
|
+
'Not Recommended',
|
|
176
|
+
'No Idea',
|
|
177
|
+
'Total',
|
|
178
|
+
'Model Accuracy'
|
|
179
|
+
],
|
|
180
|
+
'Count': [
|
|
181
|
+
counts.get('recommended', 0),
|
|
182
|
+
counts.get('not_recommended', 0),
|
|
183
|
+
counts.get('no_idea', 0),
|
|
184
|
+
len(df),
|
|
185
|
+
'N/A' # Accuracy needs to be calculated during training
|
|
186
|
+
],
|
|
187
|
+
'Percentage': [
|
|
188
|
+
f"{100 * counts.get('recommended', 0) / len(df):.2f}%",
|
|
189
|
+
f"{100 * counts.get('not_recommended', 0) / len(df):.2f}%",
|
|
190
|
+
f"{100 * counts.get('no_idea', 0) / len(df):.2f}%",
|
|
191
|
+
'100%',
|
|
192
|
+
'N/A'
|
|
193
|
+
]
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
return summary
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# Github : RezaGooner
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PerSent
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Persian Sentiment Analysis Toolkit
|
|
5
|
+
Home-page: https://github.com/RezaGooner/PerSent
|
|
6
|
+
Author: RezaGooner
|
|
7
|
+
Author-email: RezaAsadiProgrammer@Gmail.com
|
|
8
|
+
Keywords: persian sentiment analysis nlp
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: hazm>=0.7.0
|
|
15
|
+
Requires-Dist: gensim>=4.0.0
|
|
16
|
+
Requires-Dist: scikit-learn>=1.0.0
|
|
17
|
+
Requires-Dist: pandas>=1.3.0
|
|
18
|
+
Requires-Dist: tqdm>=4.62.0
|
|
19
|
+
Requires-Dist: joblib>=1.1.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: keywords
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# PerSent - Persian Sentiment Analyzer
|
|
32
|
+
[](README.fa.md)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## Introduction
|
|
38
|
+
PerSent is a Python library designed for Persian sentiment analysis. The name stands for "Persian Sentiment Analyzer". Currently in its early testing phase, PerSent provides tools for analyzing sentiment in Persian text, particularly useful for product reviews and service feedback.
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
- Sentiment classification into three categories:
|
|
42
|
+
- `recommended`
|
|
43
|
+
- `not_recommended`
|
|
44
|
+
- `no_idea`
|
|
45
|
+
- Single text analysis
|
|
46
|
+
- Batch processing from CSV files
|
|
47
|
+
- Summary report generation
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
Install the latest version using pip:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install PerSent
|
|
54
|
+
```
|
|
55
|
+
For a specific version:
|
|
56
|
+
|
|
57
|
+
``` bash
|
|
58
|
+
pip install PerSent==<VERSION_NUMBER>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Basic Usage
|
|
62
|
+
### Single Text Analysis
|
|
63
|
+
``` bash
|
|
64
|
+
from PerSent import CommentAnalyzer
|
|
65
|
+
|
|
66
|
+
# Initialize analyzer
|
|
67
|
+
analyzer = CommentAnalyzer()
|
|
68
|
+
|
|
69
|
+
# Load pre-trained model
|
|
70
|
+
analyzer.load_model()
|
|
71
|
+
|
|
72
|
+
# Analyze text
|
|
73
|
+
text = "کیفیت عالی داشت"
|
|
74
|
+
result = analyzer.predict(text)
|
|
75
|
+
print(f"Sentiment: {result}")
|
|
76
|
+
# Output: Sentiment: recommended
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Training Your Own Model
|
|
80
|
+
``` bash
|
|
81
|
+
'''
|
|
82
|
+
Train the model using a CSV file containing:
|
|
83
|
+
- Comments
|
|
84
|
+
- Recommendation status (recommended/not_recommended/no_idea)
|
|
85
|
+
'''
|
|
86
|
+
analyzer.train("train.csv")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Batch Processing
|
|
90
|
+
### CSV Processing
|
|
91
|
+
|
|
92
|
+
``` bash
|
|
93
|
+
analyzer.csvPredict(
|
|
94
|
+
input_csv="comments.csv",
|
|
95
|
+
output_path="results.csv"
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Advanced CSV Processing Options
|
|
100
|
+
``` bash
|
|
101
|
+
# Using column index
|
|
102
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, 0)
|
|
103
|
+
|
|
104
|
+
# Using column name
|
|
105
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, "Comments")
|
|
106
|
+
|
|
107
|
+
# With summary report
|
|
108
|
+
analyzer.csvPredict("comments.csv", "results.csv", "summary.csv")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Dataset
|
|
112
|
+
A sample training dataset is available:
|
|
113
|
+
[Download Dataset](https://github.com/RezaGooner/Sentiment-Survey-Analyzer/tree/main/Dataset/big_train)
|
|
114
|
+
|
|
115
|
+
## Contribution
|
|
116
|
+
We welcome contributions and feedback:
|
|
117
|
+
|
|
118
|
+
- [Fork Repository & Pull Request](https://github.com/RezaGooner/PerSent/fork)
|
|
119
|
+
- [Make Issue](https://github.com/RezaGooner/PerSent/issues/new)
|
|
120
|
+
- E-Mail : ```RezaAsadiProgrammer@gmail.com```
|
|
121
|
+
- Telegram : ```@RezaGooner```
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
setup.py
|
|
3
|
+
PerSent/CommentAnalyzer.py
|
|
3
4
|
PerSent/__init__.py
|
|
4
5
|
PerSent.egg-info/PKG-INFO
|
|
5
6
|
PerSent.egg-info/SOURCES.txt
|
|
6
7
|
PerSent.egg-info/dependency_links.txt
|
|
7
8
|
PerSent.egg-info/requires.txt
|
|
8
9
|
PerSent.egg-info/top_level.txt
|
|
9
|
-
PerSent/
|
|
10
|
-
|
|
10
|
+
PerSent/model/classifier.joblib
|
|
11
|
+
PerSent/model/word2vec.model
|
persent-1.0.2/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# PerSent - Persian Sentiment Analyzer
|
|
2
|
+
[](README.fa.md)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
PerSent is a Python library designed for Persian sentiment analysis. The name stands for "Persian Sentiment Analyzer". Currently in its early testing phase, PerSent provides tools for analyzing sentiment in Persian text, particularly useful for product reviews and service feedback.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
- Sentiment classification into three categories:
|
|
12
|
+
- `recommended`
|
|
13
|
+
- `not_recommended`
|
|
14
|
+
- `no_idea`
|
|
15
|
+
- Single text analysis
|
|
16
|
+
- Batch processing from CSV files
|
|
17
|
+
- Summary report generation
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
Install the latest version using pip:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install PerSent
|
|
24
|
+
```
|
|
25
|
+
For a specific version:
|
|
26
|
+
|
|
27
|
+
``` bash
|
|
28
|
+
pip install PerSent==<VERSION_NUMBER>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Basic Usage
|
|
32
|
+
### Single Text Analysis
|
|
33
|
+
``` bash
|
|
34
|
+
from PerSent import CommentAnalyzer
|
|
35
|
+
|
|
36
|
+
# Initialize analyzer
|
|
37
|
+
analyzer = CommentAnalyzer()
|
|
38
|
+
|
|
39
|
+
# Load pre-trained model
|
|
40
|
+
analyzer.load_model()
|
|
41
|
+
|
|
42
|
+
# Analyze text
|
|
43
|
+
text = "کیفیت عالی داشت"
|
|
44
|
+
result = analyzer.predict(text)
|
|
45
|
+
print(f"Sentiment: {result}")
|
|
46
|
+
# Output: Sentiment: recommended
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Training Your Own Model
|
|
50
|
+
``` bash
|
|
51
|
+
'''
|
|
52
|
+
Train the model using a CSV file containing:
|
|
53
|
+
- Comments
|
|
54
|
+
- Recommendation status (recommended/not_recommended/no_idea)
|
|
55
|
+
'''
|
|
56
|
+
analyzer.train("train.csv")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Batch Processing
|
|
60
|
+
### CSV Processing
|
|
61
|
+
|
|
62
|
+
``` bash
|
|
63
|
+
analyzer.csvPredict(
|
|
64
|
+
input_csv="comments.csv",
|
|
65
|
+
output_path="results.csv"
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Advanced CSV Processing Options
|
|
70
|
+
``` bash
|
|
71
|
+
# Using column index
|
|
72
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, 0)
|
|
73
|
+
|
|
74
|
+
# Using column name
|
|
75
|
+
analyzer.csvPredict("comments.csv", "results.csv", None, "Comments")
|
|
76
|
+
|
|
77
|
+
# With summary report
|
|
78
|
+
analyzer.csvPredict("comments.csv", "results.csv", "summary.csv")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Dataset
|
|
82
|
+
A sample training dataset is available:
|
|
83
|
+
[Download Dataset](https://github.com/RezaGooner/Sentiment-Survey-Analyzer/tree/main/Dataset/big_train)
|
|
84
|
+
|
|
85
|
+
## Contribution
|
|
86
|
+
We welcome contributions and feedback:
|
|
87
|
+
|
|
88
|
+
- [Fork Repository & Pull Request](https://github.com/RezaGooner/PerSent/fork)
|
|
89
|
+
- [Make Issue](https://github.com/RezaGooner/PerSent/issues/new)
|
|
90
|
+
- E-Mail : ```RezaAsadiProgrammer@gmail.com```
|
|
91
|
+
- Telegram : ```@RezaGooner```
|
persent-1.0.2/setup.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="PerSent",
|
|
8
|
+
version="1.0.2",
|
|
9
|
+
author="RezaGooner",
|
|
10
|
+
author_email="RezaAsadiProgrammer@Gmail.com",
|
|
11
|
+
description="Persian Sentiment Analysis Toolkit",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/RezaGooner/PerSent",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
package_data={
|
|
17
|
+
'PerSent': ['CommentAnalyzer.py', 'model/*'],
|
|
18
|
+
},
|
|
19
|
+
install_requires=[
|
|
20
|
+
'hazm>=0.7.0',
|
|
21
|
+
'gensim>=4.0.0',
|
|
22
|
+
'scikit-learn>=1.0.0',
|
|
23
|
+
'pandas>=1.3.0',
|
|
24
|
+
'tqdm>=4.62.0',
|
|
25
|
+
'joblib>=1.1.0'
|
|
26
|
+
],
|
|
27
|
+
classifiers=[
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"License :: OSI Approved :: MIT License",
|
|
30
|
+
"Operating System :: OS Independent",
|
|
31
|
+
],
|
|
32
|
+
python_requires='>=3.8',
|
|
33
|
+
keywords='persian sentiment analysis nlp',
|
|
34
|
+
)
|
persent-1.0.0/PKG-INFO
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: PerSent
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Comprehensive Persian Sentiment Analysis Toolkit
|
|
5
|
-
Home-page: https://github.com/RezaGooner/PerSent
|
|
6
|
-
Author: RezaGooner
|
|
7
|
-
Author-email: RezaAsadiProgrammer@Gmail.com
|
|
8
|
-
Keywords: persian-nlp,sentiment-analysis,text-analytics,farsi-text-processing
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Natural Language :: Persian
|
|
12
|
-
Classifier: Topic :: Text Processing :: Linguistic
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Requires-Python: >=3.8
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: hazm>=0.9.0
|
|
18
|
-
Requires-Dist: gensim>=4.3.0
|
|
19
|
-
Requires-Dist: scikit-learn>=1.3.0
|
|
20
|
-
Requires-Dist: pandas>=2.0.0
|
|
21
|
-
Requires-Dist: joblib>=1.3.0
|
|
22
|
-
Requires-Dist: jdatetime>=4.1.0
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: keywords
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-
# PerSent - Persian Sentiment Analysis Toolkit
|
|
35
|
-
|
|
36
|
-
کتابخانه جامع تحلیل احساسات متن فارسی برای حوزههای مختلف
|
|
37
|
-
|
|
38
|
-
## قابلیتهای کلیدی
|
|
39
|
-
|
|
40
|
-
- پردازش هوشمند متنهای فارسی
|
|
41
|
-
- پشتیبانی از حوزههای مختلف (عمومی، خبری، شبکهاجتماعی)
|
|
42
|
-
- ترکیب روشهای مبتنی بر دیکشنری و یادگیری ماشین
|
|
43
|
-
- محاسبه شدت احساسات
|
|
44
|
-
- تشخیص خودکار حوزه متن
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
PerSent - کتابخانه جامع تحلیل احساسات متن فارسی
|
|
4
|
-
|
|
5
|
-
نسخه: 1.0.0
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from .core.analyzer import PersianSentimentAnalyzer
|
|
9
|
-
from .domains.news import NewsAnalyzer
|
|
10
|
-
from .domains.social import SocialMediaAnalyzer
|
|
11
|
-
from .domains.comments import CommentAnalyzer
|
|
12
|
-
from .utils.dictionary import load_custom_dictionary
|
|
13
|
-
|
|
14
|
-
# تعریف نسخه
|
|
15
|
-
__version__ = "1.0.0"
|
|
16
|
-
__all__ = [
|
|
17
|
-
'PersianSentimentAnalyzer',
|
|
18
|
-
'NewsAnalyzer',
|
|
19
|
-
'SocialMediaAnalyzer',
|
|
20
|
-
'CommentAnalyzer',
|
|
21
|
-
'load_custom_dictionary'
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
# تنظیمات اولیه
|
|
25
|
-
class Config:
|
|
26
|
-
DEFAULT_MODEL_PATH = "models/v1/"
|
|
27
|
-
ENABLE_LOGGING = True
|
|
28
|
-
MAX_TEXT_LENGTH = 5000
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
def set_model_path(cls, path):
|
|
32
|
-
cls.DEFAULT_MODEL_PATH = path
|
|
33
|
-
|
|
34
|
-
# بارگذاری خودکار مدلهای پایه
|
|
35
|
-
try:
|
|
36
|
-
from .core.models import BaseModel
|
|
37
|
-
base_model = BaseModel()
|
|
38
|
-
except ImportError as e:
|
|
39
|
-
import warnings
|
|
40
|
-
warnings.warn(f"Failed to load base models: {str(e)}")
|
|
41
|
-
|
|
42
|
-
# فعال کردن لوگر پیشفرض
|
|
43
|
-
if Config.ENABLE_LOGGING:
|
|
44
|
-
import logging
|
|
45
|
-
logging.basicConfig(
|
|
46
|
-
level=logging.INFO,
|
|
47
|
-
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
48
|
-
)
|
|
49
|
-
logger = logging.getLogger('PerSent')
|
|
50
|
-
logger.info(f"PerSent v{__version__} initialized")
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import joblib
|
|
2
|
-
import numpy as np
|
|
3
|
-
from gensim.models import Word2Vec
|
|
4
|
-
from typing import List
|
|
5
|
-
|
|
6
|
-
class BaseModel:
|
|
7
|
-
def __init__(self, model_path: str = None):
|
|
8
|
-
self.vectorizer = None
|
|
9
|
-
self.classifier = None
|
|
10
|
-
if model_path:
|
|
11
|
-
self.load(model_path)
|
|
12
|
-
|
|
13
|
-
def predict(self, tokens: List[str]) -> str:
|
|
14
|
-
"""پیشبینی احساس از توکنها"""
|
|
15
|
-
vector = self._vectorize(tokens)
|
|
16
|
-
pred = self.classifier.predict([vector])[0]
|
|
17
|
-
return self._decode_prediction(pred)
|
|
18
|
-
|
|
19
|
-
def _vectorize(self, tokens: List[str]) -> np.ndarray:
|
|
20
|
-
"""تبدیل توکنها به بردار"""
|
|
21
|
-
vectors = [self.vectorizer.wv[t] for t in tokens if t in self.vectorizer.wv]
|
|
22
|
-
return np.mean(vectors, axis=0) if vectors else np.zeros(100)
|
|
23
|
-
|
|
24
|
-
def _decode_prediction(self, code: int) -> str:
|
|
25
|
-
"""تبدیل کد پیشبینی به متن"""
|
|
26
|
-
return {0: 'negative', 1: 'positive', 2: 'neutral'}.get(code, 'neutral')
|
|
27
|
-
|
|
28
|
-
def load(self, model_dir: str):
|
|
29
|
-
"""بارگذاری مدل از مسیر"""
|
|
30
|
-
self.vectorizer = Word2Vec.load(f"{model_dir}/word2vec.model")
|
|
31
|
-
self.classifier = joblib.load(f"{model_dir}/classifier.joblib")
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: PerSent
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Comprehensive Persian Sentiment Analysis Toolkit
|
|
5
|
-
Home-page: https://github.com/RezaGooner/PerSent
|
|
6
|
-
Author: RezaGooner
|
|
7
|
-
Author-email: RezaAsadiProgrammer@Gmail.com
|
|
8
|
-
Keywords: persian-nlp,sentiment-analysis,text-analytics,farsi-text-processing
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Natural Language :: Persian
|
|
12
|
-
Classifier: Topic :: Text Processing :: Linguistic
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Requires-Python: >=3.8
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
Requires-Dist: hazm>=0.9.0
|
|
18
|
-
Requires-Dist: gensim>=4.3.0
|
|
19
|
-
Requires-Dist: scikit-learn>=1.3.0
|
|
20
|
-
Requires-Dist: pandas>=2.0.0
|
|
21
|
-
Requires-Dist: joblib>=1.3.0
|
|
22
|
-
Requires-Dist: jdatetime>=4.1.0
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: keywords
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-
# PerSent - Persian Sentiment Analysis Toolkit
|
|
35
|
-
|
|
36
|
-
کتابخانه جامع تحلیل احساسات متن فارسی برای حوزههای مختلف
|
|
37
|
-
|
|
38
|
-
## قابلیتهای کلیدی
|
|
39
|
-
|
|
40
|
-
- پردازش هوشمند متنهای فارسی
|
|
41
|
-
- پشتیبانی از حوزههای مختلف (عمومی، خبری، شبکهاجتماعی)
|
|
42
|
-
- ترکیب روشهای مبتنی بر دیکشنری و یادگیری ماشین
|
|
43
|
-
- محاسبه شدت احساسات
|
|
44
|
-
- تشخیص خودکار حوزه متن
|
persent-1.0.0/README.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# PerSent - Persian Sentiment Analysis Toolkit
|
|
2
|
-
|
|
3
|
-
کتابخانه جامع تحلیل احساسات متن فارسی برای حوزههای مختلف
|
|
4
|
-
|
|
5
|
-
## قابلیتهای کلیدی
|
|
6
|
-
|
|
7
|
-
- پردازش هوشمند متنهای فارسی
|
|
8
|
-
- پشتیبانی از حوزههای مختلف (عمومی، خبری، شبکهاجتماعی)
|
|
9
|
-
- ترکیب روشهای مبتنی بر دیکشنری و یادگیری ماشین
|
|
10
|
-
- محاسبه شدت احساسات
|
|
11
|
-
- تشخیص خودکار حوزه متن
|
persent-1.0.0/setup.py
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from setuptools import setup, find_packages
|
|
2
|
-
import os
|
|
3
|
-
|
|
4
|
-
def get_version():
|
|
5
|
-
here = os.path.abspath(os.path.dirname(__file__))
|
|
6
|
-
with open(os.path.join(here, "PerSent", "__init__.py"), encoding="utf-8") as f:
|
|
7
|
-
for line in f.readlines():
|
|
8
|
-
if line.startswith("__version__"):
|
|
9
|
-
return line.split("=")[1].strip().strip('"\'')
|
|
10
|
-
return "0.1.0"
|
|
11
|
-
|
|
12
|
-
setup(
|
|
13
|
-
name="PerSent",
|
|
14
|
-
version=get_version(),
|
|
15
|
-
packages=find_packages(),
|
|
16
|
-
package_data={
|
|
17
|
-
"PerSent": [
|
|
18
|
-
"core/models/*",
|
|
19
|
-
"utils/lexicons/*.json"
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
install_requires=[
|
|
23
|
-
"hazm>=0.9.0",
|
|
24
|
-
"gensim>=4.3.0",
|
|
25
|
-
"scikit-learn>=1.3.0",
|
|
26
|
-
"pandas>=2.0.0",
|
|
27
|
-
"joblib>=1.3.0",
|
|
28
|
-
"jdatetime>=4.1.0"
|
|
29
|
-
],
|
|
30
|
-
python_requires=">=3.8",
|
|
31
|
-
author="RezaGooner",
|
|
32
|
-
author_email="RezaAsadiProgrammer@Gmail.com",
|
|
33
|
-
description="Comprehensive Persian Sentiment Analysis Toolkit",
|
|
34
|
-
long_description=open("README.md", encoding="utf-8").read(),
|
|
35
|
-
long_description_content_type="text/markdown",
|
|
36
|
-
url="https://github.com/RezaGooner/PerSent",
|
|
37
|
-
classifiers=[
|
|
38
|
-
"Development Status :: 4 - Beta",
|
|
39
|
-
"Intended Audience :: Developers",
|
|
40
|
-
"Natural Language :: Persian",
|
|
41
|
-
"Topic :: Text Processing :: Linguistic",
|
|
42
|
-
"Programming Language :: Python :: 3.8",
|
|
43
|
-
"License :: OSI Approved :: MIT License",
|
|
44
|
-
],
|
|
45
|
-
keywords=[
|
|
46
|
-
"persian-nlp",
|
|
47
|
-
"sentiment-analysis",
|
|
48
|
-
"text-analytics",
|
|
49
|
-
"farsi-text-processing"
|
|
50
|
-
],
|
|
51
|
-
)
|
persent-1.0.0/tests/test_core.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from PerSent.core.analyzer import PersianSentimentAnalyzer
|
|
3
|
-
from PerSent.domains import NewsAnalyzer
|
|
4
|
-
|
|
5
|
-
class TestCoreFunctionality(unittest.TestCase):
|
|
6
|
-
def setUp(self):
|
|
7
|
-
self.general_analyzer = PersianSentimentAnalyzer()
|
|
8
|
-
self.news_analyzer = NewsAnalyzer()
|
|
9
|
-
|
|
10
|
-
def test_general_analysis(self):
|
|
11
|
-
result = self.general_analyzer.analyze("این محصول خوب است")
|
|
12
|
-
self.assertIn(result, ['positive', 'negative', 'neutral'])
|
|
13
|
-
|
|
14
|
-
def test_news_analysis(self):
|
|
15
|
-
news_text = "رشد اقتصادی در سال جاری مثبت بود"
|
|
16
|
-
result = self.news_analyzer.analyze(news_text)
|
|
17
|
-
self.assertEqual(result, 'positive')
|
|
18
|
-
|
|
19
|
-
if __name__ == '__main__':
|
|
20
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|