您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import logging
  2. from urllib.parse import urlparse
  3. from services.similarity import cosine_lists
  4. logger = logging.getLogger(__name__)
  5. class Headline:
  6. display_text: str
  7. normalized_text: list[str]
  8. source_url: str
  9. domain: str
  10. published_at: object
  11. def __init__(self, display_text: str, normalized_text: list[str], source_url: str = "", published_at=None):
  12. self.display_text = display_text
  13. self.normalized_text = normalized_text
  14. self.source_url = source_url
  15. self.domain = self._extract_domain(source_url)
  16. self.published_at = published_at
  17. logger.debug(
  18. "Initialized Headline instance (display_text=%r, token_count=%d, source=%r, domain=%r, published_at=%r)",
  19. self.display_text, len(self.normalized_text), self.source_url, self.domain, self.published_at,
  20. )
  21. @staticmethod
  22. def _extract_domain(url: str):
  23. """Return a normalized outlet domain for a source URL, or None if absent.
  24. Strips scheme, whitespace and a leading ``www.``/feed/redirect subdomain
  25. (``www.``, ``feeds.``, ``rss.``, ``moxie.``) so that ``https://www.cnn.com/us``
  26. and ``https://feeds.npr.org/1001/rss.xml`` both resolve to their outlet
  27. (``cnn.com``, ``npr.org``) — one outlet counts once regardless of section
  28. URL or feed host.
  29. """
  30. if not url or not isinstance(url, str) or not url.strip():
  31. return None
  32. host = urlparse(url.strip()).netloc.lower()
  33. if not host:
  34. return None
  35. for prefix in ("www.", "feeds.", "rss.", "moxie."):
  36. if host.startswith(prefix):
  37. host = host[len(prefix):]
  38. break
  39. return host
  40. def compare_headlines(self, other_headline):
  41. if not isinstance(other_headline, Headline):
  42. logger.warning("Comparing Headline %r with incompatible object of type %s: %r",
  43. self.display_text, type(other_headline).__name__, other_headline)
  44. logger.debug("Comparing Headline %r against %r",
  45. self.display_text, getattr(other_headline, 'display_text', repr(other_headline)))
  46. try:
  47. score = cosine_lists(self.normalized_text, other_headline.normalized_text)
  48. logger.debug("Headline comparison score: %.4f between %r and %r",
  49. score, self.display_text, getattr(other_headline, 'display_text', repr(other_headline)))
  50. return score
  51. except Exception as e:
  52. logger.error("Error comparing headlines (%r vs %r): %s",
  53. self.display_text, getattr(other_headline, 'display_text', repr(other_headline)), e, exc_info=True)
  54. raise