You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 line
3.2 KiB

  1. import logging
  2. from services.headlines import prepare_headlines
  3. from services.normalization import get_stopwords, normalize_headline
  4. from services.sources import get_sources
  5. logging.basicConfig(
  6. level=logging.INFO,
  7. format='%(asctime)s [%(levelname)s] [%(name)s]: %(message)s'
  8. )
  9. logger = logging.getLogger(__name__)
  10. SOURCE_FILE = './resources/sources.txt'
  11. STOPWORDS_FILE = './resources/stopwords.txt'
  12. SIMILARITY_THRESHOLD = 0.75
  13. def main():
  14. logger.info("Starting duplicate headline detection application")
  15. logger.debug("Source file configured at: '%s'", SOURCE_FILE)
  16. logger.debug("Stopwords file configured at: '%s'", STOPWORDS_FILE)
  17. try:
  18. logger.info("Loading news sources from '%s'", SOURCE_FILE)
  19. sources = get_sources(SOURCE_FILE)
  20. logger.info("Loaded %d sources successfully", len(sources) if sources else 0)
  21. except Exception as e:
  22. logger.critical("Failed to load sources from '%s': %s", SOURCE_FILE, e, exc_info=True)
  23. return
  24. try:
  25. logger.info("Loading stopwords from '%s'", STOPWORDS_FILE)
  26. stopwords = get_stopwords(STOPWORDS_FILE)
  27. logger.info("Loaded %d stopwords successfully", len(stopwords) if stopwords else 0)
  28. except Exception as e:
  29. logger.critical("Failed to load stopwords from '%s': %s", STOPWORDS_FILE, e, exc_info=True)
  30. return
  31. try:
  32. logger.info("Fetching and preparing headlines from %d sources", len(sources))
  33. headlines = prepare_headlines(sources, stopwords)
  34. logger.info("Total prepared headlines available for comparison: %d", len(headlines))
  35. except Exception as e:
  36. logger.critical("Failed during headline preparation: %s", e, exc_info=True)
  37. return
  38. total_comparisons = (len(headlines) * (len(headlines) - 1)) // 2 if len(headlines) > 1 else 0
  39. logger.info("Beginning pairwise headline comparisons (total comparisons to execute: %d)", total_comparisons)
  40. duplicate_count = 0
  41. comparison_idx = 0
  42. for i in range(len(headlines)):
  43. for j in range(i + 1, len(headlines)):
  44. comparison_idx += 1
  45. logger.debug("Comparison [%d/%d]: Headline %d vs Headline %d", comparison_idx, total_comparisons, i, j)
  46. try:
  47. similarity_score = headlines[i].compare_headlines(headlines[j])
  48. logger.debug("Similarity score between [%d] and [%d] is %.4f (threshold: %f)", i, j, similarity_score, SIMILARITY_THRESHOLD)
  49. if similarity_score >= SIMILARITY_THRESHOLD:
  50. duplicate_count += 1
  51. logger.warning("Duplicate/similar headline match found (score: %.4f < %f): '%s' vs '%s'",
  52. similarity_score, SIMILARITY_THRESHOLD, headlines[i].display_text, headlines[j].display_text)
  53. print(f"Duplicate headlines found: {headlines[i].display_text}")
  54. except Exception as e:
  55. logger.error("Error during comparison between headline %d (%r) and headline %d (%r): %s",
  56. i, headlines[i].display_text, j, headlines[j].display_text, e, exc_info=True)
  57. logger.info("Headline comparison completed. Evaluated %d pairs and found %d duplicate alerts.",
  58. comparison_idx, duplicate_count)
  59. if __name__ == '__main__':
  60. main()