boompack commited on
Commit
55ab780
·
verified ·
1 Parent(s): 113a323

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +6 -94
app.py CHANGED
@@ -16,22 +16,6 @@ logger = logging.getLogger(__name__)
16
 
17
  @dataclass
18
  class Comment:
19
- """
20
- Представляет комментарий Instagram со всеми метаданными и вложенной структурой.
21
- Attributes:
22
- id: Уникальный идентификатор комментария
23
- username: Имя пользователя
24
- time: Временная метка
25
- content: Текст комментария
26
- likes: Количество лайков
27
- level: Уровень вложенности
28
- parent_id: ID родительского комментария
29
- replies: Список ответов
30
- is_verified: Верифицированный аккаунт
31
- mentions: Упоминания пользователей
32
- hashtags: Хэштеги
33
- is_deleted: Флаг удаленного комментария
34
- """
35
  id: str = field(default_factory=lambda: str(uuid4()))
36
  username: str = ""
37
  time: str = ""
@@ -44,20 +28,14 @@ class Comment:
44
  mentions: List[str] = field(default_factory=list)
45
  hashtags: List[str] = field(default_factory=list)
46
  is_deleted: bool = False
 
47
 
48
  def __post_init__(self):
49
- """Валидация после инициализации"""
50
  if len(self.content) > 2200:
51
  logger.warning(f"Comment content exceeds 2200 characters for user {self.username}")
52
  self.content = self.content[:2200] + "..."
53
 
54
  class InstagramCommentAnalyzer:
55
- """
56
- Основной класс для обработки и анализа комментариев Instagram.
57
- Обрабатывает парсинг комментариев, вложенную структуру и особые случаи.
58
- """
59
-
60
- # Регулярное выражение для извлечения комментариев
61
  COMMENT_PATTERN = r'''
62
  (?P<username>[\w.-]+)\s+
63
  (?P<time>\d+\s+нед\.)
@@ -67,12 +45,6 @@ class InstagramCommentAnalyzer:
67
  '''
68
 
69
  def __init__(self, max_depth: int = 10, max_comment_length: int = 2200):
70
- """
71
- Инициализация анализатора с настраиваемыми параметрами.
72
- Args:
73
- max_depth: Максимальная глубина вложенности комментариев
74
- max_comment_length: Максимальная длина комментария
75
- """
76
  self.max_depth = max_depth
77
  self.max_comment_length = max_comment_length
78
  self.pattern = re.compile(self.COMMENT_PATTERN, re.VERBOSE | re.DOTALL)
@@ -87,63 +59,30 @@ class InstagramCommentAnalyzer:
87
  'processed_hashtags': 0
88
  }
89
 
90
- # Инициализация модели Hugging Face для анализа настроений
91
- self.sentiment_analyzer = pipeline("sentiment-analysis")
 
 
 
92
 
93
  def analyze_sentiment(self, text: str) -> str:
94
- """
95
- Анализ настроений в комментарии с использованием модели Hugging Face.
96
- Args:
97
- text: Текст комментария
98
- Returns:
99
- Строка с меткой настроения ('POSITIVE' или 'NEGATIVE')
100
- """
101
  result = self.sentiment_analyzer(text)
102
  return result[0]['label']
103
 
104
  def normalize_text(self, text: str) -> str:
105
- """
106
- Нормализация входного текста.
107
- Args:
108
- text: Исходный текст
109
- Returns:
110
- Нормализованный текст
111
- """
112
- # Декодирование HTML-сущностей
113
  text = html.unescape(text)
114
- # Нормализация пробелов
115
  text = ' '.join(text.split())
116
- # Удаление невидимых символов
117
  text = re.sub(r'[\u200b\ufeff\u200c]', '', text)
118
  return text
119
 
120
  def extract_metadata(self, comment: Comment) -> None:
121
- """
122
- Извлечение метаданных из комментария.
123
- Args:
124
- comment: Объект комментария
125
- """
126
- # Извлечение @упоминаний
127
  comment.mentions = re.findall(r'@(\w+)', comment.content)
128
  self.stats['processed_mentions'] += len(comment.mentions)
129
-
130
- # Извлечение #хэштегов
131
  comment.hashtags = re.findall(r'#(\w+)', comment.content)
132
  self.stats['processed_hashtags'] += len(comment.hashtags)
133
-
134
- # Проверка верификации
135
  comment.is_verified = bool(re.search(r'✓|Подтвержденный', comment.username))
136
 
137
  def process_comment(self, text: str, parent_id: Optional[str] = None, level: int = 0) -> Optional[Comment]:
138
- """
139
- Обработка отдельного комментария.
140
- Args:
141
- text: Текст комментария
142
- parent_id: ID родительского комментария
143
- level: Уровень вложенности
144
- Returns:
145
- Обработанный объект Comment или None
146
- """
147
  if level > self.max_depth:
148
  logger.warning(f"Maximum depth {self.max_depth} exceeded")
149
  self.stats['max_depth_reached'] += 1
@@ -172,7 +111,6 @@ class InstagramCommentAnalyzer:
172
  self.stats['truncated_comments'] += 1
173
  comment.content = comment.content[:self.max_comment_length] + "..."
174
 
175
- # Добавление анализа настроений
176
  comment.sentiment = self.analyze_sentiment(comment.content)
177
 
178
  self.extract_metadata(comment)
@@ -191,14 +129,6 @@ class InstagramCommentAnalyzer:
191
  return comment
192
 
193
  def format_comment(self, comment: Comment, index: int) -> str:
194
- """
195
- Форматирование комментария для вывода.
196
- Args:
197
- comment: Объект комментария
198
- index: Номер комментария
199
- Returns:
200
- Отформатированная строка комментария
201
- """
202
  if comment.is_deleted:
203
  return f'{index}. "[УДАЛЕНО]" "" "" "Нравится 0"'
204
 
@@ -208,23 +138,9 @@ class InstagramCommentAnalyzer:
208
  )
209
 
210
  def process_comments(self, text: str) -> List[str]:
211
- """
212
- Обработка всех комментариев в тексте.
213
- Args:
214
- text: Исходный текст с комментариями
215
- Returns:
216
- Список отформатированных комментариев
217
- """
218
- # Сброс статистики
219
  self.stats = {key: 0 for key in self.stats}
220
-
221
- # Нормализация текста
222
  text = self.normalize_text(text)
223
-
224
- # Разделение на отдельные комментарии
225
  raw_comments = text.split('ОтветитьНравится')
226
-
227
- # Обработка комментариев
228
  formatted_comments = []
229
  for i, raw_comment in enumerate(raw_comments, 1):
230
  if not raw_comment.strip():
@@ -237,10 +153,6 @@ class InstagramCommentAnalyzer:
237
  return formatted_comments
238
 
239
  def main():
240
- """
241
- Пример использования анализатора.
242
- """
243
- # Пример входного текста
244
  example_text = """
245
  user1 2 нед. This is a positive comment! Отметки "Нравится": 25
246
  user2 3 нед. This is a negative comment! Отметки "Нравится": 5
 
16
 
17
  @dataclass
18
  class Comment:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  id: str = field(default_factory=lambda: str(uuid4()))
20
  username: str = ""
21
  time: str = ""
 
28
  mentions: List[str] = field(default_factory=list)
29
  hashtags: List[str] = field(default_factory=list)
30
  is_deleted: bool = False
31
+ sentiment: Optional[str] = None
32
 
33
  def __post_init__(self):
 
34
  if len(self.content) > 2200:
35
  logger.warning(f"Comment content exceeds 2200 characters for user {self.username}")
36
  self.content = self.content[:2200] + "..."
37
 
38
  class InstagramCommentAnalyzer:
 
 
 
 
 
 
39
  COMMENT_PATTERN = r'''
40
  (?P<username>[\w.-]+)\s+
41
  (?P<time>\d+\s+нед\.)
 
45
  '''
46
 
47
  def __init__(self, max_depth: int = 10, max_comment_length: int = 2200):
 
 
 
 
 
 
48
  self.max_depth = max_depth
49
  self.max_comment_length = max_comment_length
50
  self.pattern = re.compile(self.COMMENT_PATTERN, re.VERBOSE | re.DOTALL)
 
59
  'processed_hashtags': 0
60
  }
61
 
62
+ # Явное указание модели для анализа настроений
63
+ self.sentiment_analyzer = pipeline(
64
+ "sentiment-analysis",
65
+ model="distilbert-base-uncased-finetuned-sst-2-english" # Выбор модели
66
+ )
67
 
68
  def analyze_sentiment(self, text: str) -> str:
 
 
 
 
 
 
 
69
  result = self.sentiment_analyzer(text)
70
  return result[0]['label']
71
 
72
  def normalize_text(self, text: str) -> str:
 
 
 
 
 
 
 
 
73
  text = html.unescape(text)
 
74
  text = ' '.join(text.split())
 
75
  text = re.sub(r'[\u200b\ufeff\u200c]', '', text)
76
  return text
77
 
78
  def extract_metadata(self, comment: Comment) -> None:
 
 
 
 
 
 
79
  comment.mentions = re.findall(r'@(\w+)', comment.content)
80
  self.stats['processed_mentions'] += len(comment.mentions)
 
 
81
  comment.hashtags = re.findall(r'#(\w+)', comment.content)
82
  self.stats['processed_hashtags'] += len(comment.hashtags)
 
 
83
  comment.is_verified = bool(re.search(r'✓|Подтвержденный', comment.username))
84
 
85
  def process_comment(self, text: str, parent_id: Optional[str] = None, level: int = 0) -> Optional[Comment]:
 
 
 
 
 
 
 
 
 
86
  if level > self.max_depth:
87
  logger.warning(f"Maximum depth {self.max_depth} exceeded")
88
  self.stats['max_depth_reached'] += 1
 
111
  self.stats['truncated_comments'] += 1
112
  comment.content = comment.content[:self.max_comment_length] + "..."
113
 
 
114
  comment.sentiment = self.analyze_sentiment(comment.content)
115
 
116
  self.extract_metadata(comment)
 
129
  return comment
130
 
131
  def format_comment(self, comment: Comment, index: int) -> str:
 
 
 
 
 
 
 
 
132
  if comment.is_deleted:
133
  return f'{index}. "[УДАЛЕНО]" "" "" "Нравится 0"'
134
 
 
138
  )
139
 
140
  def process_comments(self, text: str) -> List[str]:
 
 
 
 
 
 
 
 
141
  self.stats = {key: 0 for key in self.stats}
 
 
142
  text = self.normalize_text(text)
 
 
143
  raw_comments = text.split('ОтветитьНравится')
 
 
144
  formatted_comments = []
145
  for i, raw_comment in enumerate(raw_comments, 1):
146
  if not raw_comment.strip():
 
153
  return formatted_comments
154
 
155
  def main():
 
 
 
 
156
  example_text = """
157
  user1 2 нед. This is a positive comment! Отметки "Нравится": 25
158
  user2 3 нед. This is a negative comment! Отметки "Нравится": 5