From b85987e17955f109261d05d69feb15df3e1a963c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Thu, 2 Apr 2026 18:59:32 +0100 Subject: [PATCH 01/30] docs: add system architecture diagram --- report/img/architecture.png | Bin 0 -> 72018 bytes report/main.tex | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 report/img/architecture.png diff --git a/report/img/architecture.png b/report/img/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..7544a53141cb20b7756bd249c7ff2eba13164d73 GIT binary patch literal 72018 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 literal 0 HcmV?d00001 diff --git a/report/main.tex b/report/main.tex index 14e525b..603cfc2 100644 --- a/report/main.tex +++ b/report/main.tex @@ -272,11 +272,17 @@ In addition, the simplification of complex human interactions and emotions into \subsubsection{Computational Constraints} The performance and speed of the system will be influenced by the computational resources available during development and execution. While the system will attempt to use GPU acceleration during NLP inference, these resource may not always be available or may not be particularly strong should they exist. -As a result, there are practical limits on the size of datasets that can be processed efficiently. Large datasets may produce long processing times, +As a result, there are practical limits on the size of datasets that can be processed efficiently. Large datasets may produce long processing times, \newpage \section{Design} \subsection{System Architecture} +\begin{figure}[h] + \centering + \includegraphics[width=1.2\textwidth]{img/architecture.png} + \caption{System Architecture Diagram} + \label{fig:architecture} +\end{figure} \newpage \section{Implementation} From 74ecdf238a200e124a9ae43702666f12209a5083 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Thu, 2 Apr 2026 19:30:20 +0100 Subject: [PATCH 02/30] docs: add database schema diagram --- report/img/schema.png | Bin 0 -> 65132 bytes report/main.tex | 32 +++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 report/img/schema.png diff --git a/report/img/schema.png b/report/img/schema.png new file mode 100644 index 0000000000000000000000000000000000000000..a6e29853914378a3b44953e4b44c34de600cb404 GIT binary patch literal 65132 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 literal 0 HcmV?d00001 diff --git a/report/main.tex b/report/main.tex index 603cfc2..135333b 100644 --- a/report/main.tex +++ b/report/main.tex @@ -279,11 +279,41 @@ As a result, there are practical limits on the size of datasets that can be proc \subsection{System Architecture} \begin{figure}[h] \centering - \includegraphics[width=1.2\textwidth]{img/architecture.png} + \includegraphics[width=1.0\textwidth]{img/architecture.png} \caption{System Architecture Diagram} \label{fig:architecture} \end{figure} +An asynchronous processing queue using Redis and Celery will be implemented to handle long-running NLP tasks without blocking the main Flask API application. This prevents timeouts and allows for proper scaling of computationally intensive operations. The asynchronous queue will also manage retreival of new datasets from social media sites, which itself is time-consuming due to API rate limits and data volume. + +\begin{figure}[h] + \centering + \includegraphics[width=1.0\textwidth]{img/schema.png} + \caption{System Schema} + \label{fig:schema} +\end{figure} + +\subsection{Client-Server Architecture} +The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. + +\subsubsection{Flask API} +The Flask backend will expose a RESTful API with endpoints for dataset management, authentication and user management, and analytical queries. Flask will call on backend components for data parsing, normalisation, NLP processing and database interfacing. + +Flask was chosen for its simplicity, familiarity and speed of development. It also has many extensions that can be used for authentication (Flask-Bcrypt, Flask-Login). + +\subsubsection{React Frontend} +React was chosen for the frontend due to its massive library of pre-built components with efficient rendering capabilities and ability to display many different types of data. The frontend will be structured around a tabbed interface, with each tab corresponding to a different analytical endpoint (e.g., temporal analysis, linguistic analysis, emotional analysis). Each tab will fetch data from the backend API and render it using appropriate visualisation libraries (react-wordcloud for word clouds, react-chartjs-2 for charts, etc). The frontend will also include controls for filtering the dataset based on keywords, date ranges, and data sources. + + +\subsection{Database vs On-Disk Storage} +Originally, the system was designed to store \texttt{json} datasets on disk and load them into memory for processing. This was simple and time-efficient for early development and testing. However, as the functionality of the system expanded, it become clear that a more persistent and scalable storage solution was needed. + +Storing datasets in a database allows for more efficient querying, filtering, and updating of data without needing to reload entire datasets into memory. However the priamry benefit of using a database is support for \textbf{ multiple users and multiple datasets per user}. + +An additional benefit of using a database was that it allowed the NLP processing to be done once, with the NLP results stored alongside the original data in the database. This meant that the system could avoid redundant NLP processing on the same data, which was a significant performance improvement. + +\texttt{PostgreSQL} was chosen as the database solution due to its robustness, support for complex queries, and compatibility with Python through \texttt{psycopg2}. PostgreSQL's support for JSONB fields allows for storage of unstructured NLP outputs, which alternatives like SQLite does not support. + \newpage \section{Implementation} From 9375abded5f3b19926a0fd52452c7f5cc050a734 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Fri, 3 Apr 2026 17:59:01 +0100 Subject: [PATCH 03/30] docs(design): add docker & async processing sections --- report/main.tex | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/report/main.tex b/report/main.tex index 135333b..1ab5558 100644 --- a/report/main.tex +++ b/report/main.tex @@ -284,8 +284,6 @@ As a result, there are practical limits on the size of datasets that can be proc \label{fig:architecture} \end{figure} -An asynchronous processing queue using Redis and Celery will be implemented to handle long-running NLP tasks without blocking the main Flask API application. This prevents timeouts and allows for proper scaling of computationally intensive operations. The asynchronous queue will also manage retreival of new datasets from social media sites, which itself is time-consuming due to API rate limits and data volume. - \begin{figure}[h] \centering \includegraphics[width=1.0\textwidth]{img/schema.png} @@ -296,6 +294,8 @@ An asynchronous processing queue using Redis and Celery will be implemented to h \subsection{Client-Server Architecture} The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. +The reasoning behind this architecture is that it allows the analytics to be aggregated and computed on the server side using Pandas which is much faster than doing it on the client frontend. The frontend will focus on rendering and visualising the data. + \subsubsection{Flask API} The Flask backend will expose a RESTful API with endpoints for dataset management, authentication and user management, and analytical queries. Flask will call on backend components for data parsing, normalisation, NLP processing and database interfacing. @@ -314,6 +314,29 @@ An additional benefit of using a database was that it allowed the NLP processing \texttt{PostgreSQL} was chosen as the database solution due to its robustness, support for complex queries, and compatibility with Python through \texttt{psycopg2}. PostgreSQL's support for JSONB fields allows for storage of unstructured NLP outputs, which alternatives like SQLite does not support. +\subsection{Asynchronous Processing} +The usage of NLP models for tasks such as sentiment analysis, topic classification, and entity recognition can be computationally intensive, especially for large datasets. To prevent the Flask API from blocking while these tasks are being processed, an asynchronous processing queue will be implemented using \textbf{Redis} and \textbf{Celery}. + +When NLP processing is triggered or data is being fetched from social media APIs, a task will be added to the Redis queue. Celery workers will then pop tasks off the Redis queue and process these tasks in the background, which ensures the API to remain responsive to user requests. This approach also allows for better scalability, as additional workers can be added to handle increased load. + +Some of the these tasks, like fetching data from social media APIs are very long-running tasks that can take hours to complete. By using asynchronous processing that updates the database with progress updates, users can see the status of their data fetching through the frontend. + +\subsection{Docker Deployment} +Docker Compose will be used to containerise the entire application, including: +\begin{itemize} + \item The Flask backend API + \item The React frontend interface + \item The PostgreSQL database + \item The Redis server for task queuing + \item Celery workers for asynchronous processing + \item NLP model caching and management +\end{itemize} + +In addition, the source code for the backend and frontend will be mounted as volumes within the containers to allow for live code updates during development, which will speed up the process. + +Enviornment variables, such as database credentials and social media API keys, will be managed through an \texttt{.env} file that is passed into the Docker containers through \texttt{docker-compose.yml}. + + \newpage \section{Implementation} From 9ef96661fc9396248069abcec4bea025c1d9997d Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Fri, 3 Apr 2026 18:35:08 +0100 Subject: [PATCH 04/30] report(analysis): update structure & add justifications --- report/main.tex | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/report/main.tex b/report/main.tex index 1ab5558..17c789e 100644 --- a/report/main.tex +++ b/report/main.tex @@ -102,6 +102,11 @@ Cultural markers are the words, phrases, memes, and behaviours that are specific NLP can carry out many different types of tasks, such as classifying sentences or paragraphs, generating text content, extracting answers from text or even speech recognition in audio. However, even with the advances in NLP models, many challenges and limitations remain. These include understanding ambiguity, cultural context, sarcasm, and humour. +\subsubsection{Why Natural Language Processing?} +Digital ethnography traditionally relied on manual reading of texts and interviews. These approaches are valuable for deep interpretive analysis, but they do not scale well to the volume of data generated in online communities. A single subreddit might contain hundreds of thousands of posts and comments, far beyond what any single researcher could read and analyse by hand. + +NLP techniques can be used to automatically process and analyse large volumes and applying ethnographic methods at scale. For example, NLP can be used to identify common themes and topics in a subreddit, track how these themes evolve over time, and even detect the emotional tone of discussions. This allows researchers to gain insights into the dynamics of online communities that would be impossible to achieve through manual analysis alone. + \subsubsection{Sentiment Analysis} \textbf{Sentiment Analysis} involves determining the emotional tone behind a piece of text. It is commonly used to classify text as positive, negative, or neutral. This technique is widely applied in areas such as customer feedback analysis, social media monitoring, and market research. More advanced sentiment analysis models can detect nuanced emotions, such as frustration, satisfaction, or sarcasm, although accurately identifying these emotions remains a challenge. @@ -113,8 +118,19 @@ NLP can carry out many different types of tasks, such as classifying sentences o This method is often used to organise lots of unstructured data, such as news articles, research papers, or social media posts. -\subsection{Cork Dataset} +\subsection{Limits of Computation Analysis} +While computational methods enable large-scale observation and analysis of online communities, there are many limitations that must be acknowledged. Many limitations come from NLP techniques and the practical boundaries of computational resources. +Natural Language Processors will be central to many aspects of the virtual ethnography, such as emotional and topic classification. While these models are strong and have shown results in many areas, they are imperfect and may produce inaccurate or misleading results. + +One key limitation is how the models will likely find it difficult to interpret context-dependent language. Online communities will often use sarcasm, irony or culturally specific references, all of which will be challenging to for NLP models to correctly interpret. For example, a sarcastic comment might be incorrectly classified as positive, despite conveying negativity. This could be especially prominent in online Irish communities which often include regional slang, abbreviations or informal grammar. Many NLP models are trained on standardised datasets like research papers or novels, therefore reducing accuracy in informal data. + +In addition, the simplification of complex human interactions and emotions into discrete categories like "happy" or "sad" will more than likely overlook some nuance and ambiguity, even if the model is not inherently "wrong". As a result, the outputs of NLP models should be interpreted as indicative patterns rather than definitive representations of user meaning. + +\subsubsection{Computational Constraints} +The performance and speed of the system will be influenced by the computational resources available during development and execution. While the system will attempt to use GPU acceleration during NLP inference, these resource may not always be available or may not be particularly strong should they exist. + +\subsection{Cork Dataset} The Cork dataset serves as the foundation for this project, providing a geographically and culturally grounded corpus for analysis. Rather than examining a globally distributed or topic-neutral community, the dataset centres on a single city with Cork, Ireland which allows the system's analytical outputs to be interpreted against a known social and cultural context. The dataset is drawn from four distinct online platforms, each of which represents a structurally different mode of online community participation: @@ -132,8 +148,6 @@ Collecting data across multiple platforms also introduces the challenge of norma \newpage \section{Analysis} -This section describes the background to digital ethnography, why it's used, and the objectives of the project. - \subsection{Goals \& Objectives} The objective of this project is to provide a tool that can assist social scientists, digital ethnographers, and researchers to observing and interpret online communities and the interactions between them. Rather than replacing the study of digital ethnography or the related fields, this tool aims to aid researchers analyse communities. @@ -260,19 +274,15 @@ The following requirements are derived from the backend architecture, NLP proces \item The dataset reset functionality shall preserve data integrity. \end{itemize} -\subsection{Limits of Computation Analysis} -While computational methods enable large-scale observation and analysis of online communities, there are many limitations that must be acknowledged. Many limitations come from NLP techniques and the practical boundaries of computational resources. +\subsection{Data Normalisation} +Different social media platforms will produce data in many different formats. For example, Reddit data will have a much different reply structure to a forum-based platform like Boards.ie where there are no nested replies. Therefore, a core design requirement of the system is to normalise all incoming data into a single unified internal data model. This allows the same analytical functions to be applied across all data sources, regardless of their original structure. -Natural Language Processors will be central to many aspects of the system, such as emotional and topic classification. While these models are strong and have shown results in many areas, they are imperfect and may produce inaccurate or misleading results. +Posts and comments are two different types of user-generated content, however when it comes to ethnographic analysis, they are both just "events" or information that is being shared by a user. From an ethnographic perspective, the distinction between a post and a comment is not particularly important, since they both represent user-generated content that contributes to the community discourse. Therefore, the system will normalise all posts and comments into a single "event" data model, which will allow the same analytical functions to be applied uniformly across all content. This also simplifies the data model and reduces the complexity of the analytical pipeline, since there is no need to maintain separate processing paths for posts and comments. -One key limitation is how the models will likely find it difficult to interpret context-dependent language. Online communities will often use sarcasm, irony or culturally specific references, all of which will be challenging to for NLP models to correctly interpret. For example, a sarcastic comment might be incorrectly classified as positive, despite conveying negativity. This could be especially prominent in online Irish communities which often include regional slang, abbreviations or informal grammar. Many NLP models are trained on standardised datasets like research papers or novels, therefore reducing accuracy in informal data. +Though separate processing paths are not needed, the system will still retain metadata that indicates whether an event was originally a post or a comment, as well as any relevant structural information (e.g., parent-child relationships in Reddit threads). -In addition, the simplification of complex human interactions and emotions into discrete categories like "happy" or "sad" will inevitably overlook some nuance and ambiguity, even if the model is not inherently "wrong". As a result, the outputs of NLP models should be interpreted as indicative patterns rather than definitive representations of user meaning. +\subsection{Ethics} -\subsubsection{Computational Constraints} -The performance and speed of the system will be influenced by the computational resources available during development and execution. While the system will attempt to use GPU acceleration during NLP inference, these resource may not always be available or may not be particularly strong should they exist. - -As a result, there are practical limits on the size of datasets that can be processed efficiently. Large datasets may produce long processing times, \newpage \section{Design} From 361b532766a6bc50ed37265a8b962450c4b21c26 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Fri, 3 Apr 2026 20:02:22 +0100 Subject: [PATCH 05/30] docs(analysis): add feasability analysis --- report/main.tex | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/report/main.tex b/report/main.tex index 17c789e..66b6a7a 100644 --- a/report/main.tex +++ b/report/main.tex @@ -123,7 +123,7 @@ While computational methods enable large-scale observation and analysis of onlin Natural Language Processors will be central to many aspects of the virtual ethnography, such as emotional and topic classification. While these models are strong and have shown results in many areas, they are imperfect and may produce inaccurate or misleading results. -One key limitation is how the models will likely find it difficult to interpret context-dependent language. Online communities will often use sarcasm, irony or culturally specific references, all of which will be challenging to for NLP models to correctly interpret. For example, a sarcastic comment might be incorrectly classified as positive, despite conveying negativity. This could be especially prominent in online Irish communities which often include regional slang, abbreviations or informal grammar. Many NLP models are trained on standardised datasets like research papers or novels, therefore reducing accuracy in informal data. +One key limitation is how the models will likely find it difficult to interpret context-dependent language. Online communities will often use sarcasm, irony or culturally specific references, all of which will be challenging to for NLP models to correctly interpret. For example, a sarcastic comment might be incorrectly classified as positive, despite conveying negativity. In addition, the simplification of complex human interactions and emotions into discrete categories like "happy" or "sad" will more than likely overlook some nuance and ambiguity, even if the model is not inherently "wrong". As a result, the outputs of NLP models should be interpreted as indicative patterns rather than definitive representations of user meaning. @@ -274,7 +274,22 @@ The following requirements are derived from the backend architecture, NLP proces \item The dataset reset functionality shall preserve data integrity. \end{itemize} -\subsection{Data Normalisation} +\subsection{Feasability Analysis} +\subsubsection{NLP Limitations} +Online communities often use sarcasm, irony or context-specific references, all of which will be challenging for NLP models, especially weaker ones, to correctly interpret. In a Cork-specific dataset, this will be especially apparent due to the use of regional slang or informal grammar. + +Therefore, the outputs of the model for any single event should be considered as definitive, but rather as an indicative pattern that is more likely to be correct when aggregated across the entire dataset. For example, while a single comment about a specific topic might be misclassified as positive, the overall sentiment of that topic across thousands of comments is more likely to reflect the true emotional tone of the community. + +To account for NLP limitations, the system will: +\begin{itemize} + \item Rely on \textbf{aggregated results} rather than individual classifications. + \item Provide \textbf{context for outputs}, such as confidence scores where available. + \item Allow \textbf{access to original text} behind each NLP result. +\end{itemize} + +Overall, while NLP provides powerful tools for analysing large datasets, its limitations must be acknowledged and mitigated through careful design and interpretation of results. + +\subsubsection{Data Normalisation} Different social media platforms will produce data in many different formats. For example, Reddit data will have a much different reply structure to a forum-based platform like Boards.ie where there are no nested replies. Therefore, a core design requirement of the system is to normalise all incoming data into a single unified internal data model. This allows the same analytical functions to be applied across all data sources, regardless of their original structure. Posts and comments are two different types of user-generated content, however when it comes to ethnographic analysis, they are both just "events" or information that is being shared by a user. From an ethnographic perspective, the distinction between a post and a comment is not particularly important, since they both represent user-generated content that contributes to the community discourse. Therefore, the system will normalise all posts and comments into a single "event" data model, which will allow the same analytical functions to be applied uniformly across all content. This also simplifies the data model and reduces the complexity of the analytical pipeline, since there is no need to maintain separate processing paths for posts and comments. @@ -283,6 +298,8 @@ Though separate processing paths are not needed, the system will still retain me \subsection{Ethics} +\subsection{Design Tradeoffs} + \newpage \section{Design} From 5f81c519795eee277f71ee5c616662e697009b6c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Fri, 3 Apr 2026 20:06:19 +0100 Subject: [PATCH 06/30] docs(report): add scalability constraints --- report/main.tex | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/report/main.tex b/report/main.tex index 66b6a7a..2937363 100644 --- a/report/main.tex +++ b/report/main.tex @@ -274,11 +274,11 @@ The following requirements are derived from the backend architecture, NLP proces \item The dataset reset functionality shall preserve data integrity. \end{itemize} -\subsection{Feasability Analysis} +\subsection{Feasibility Analysis} \subsubsection{NLP Limitations} Online communities often use sarcasm, irony or context-specific references, all of which will be challenging for NLP models, especially weaker ones, to correctly interpret. In a Cork-specific dataset, this will be especially apparent due to the use of regional slang or informal grammar. -Therefore, the outputs of the model for any single event should be considered as definitive, but rather as an indicative pattern that is more likely to be correct when aggregated across the entire dataset. For example, while a single comment about a specific topic might be misclassified as positive, the overall sentiment of that topic across thousands of comments is more likely to reflect the true emotional tone of the community. +Therefore, the outputs of the model for any single event should not be considered as definitive, but rather as an indicative pattern that is more likely to be correct when aggregated across the entire dataset. For example, while a single comment about a specific topic might be misclassified as positive, the overall sentiment of that topic across thousands of comments is more likely to reflect the true emotional tone of the community. To account for NLP limitations, the system will: \begin{itemize} @@ -296,6 +296,20 @@ Posts and comments are two different types of user-generated content, however wh Though separate processing paths are not needed, the system will still retain metadata that indicates whether an event was originally a post or a comment, as well as any relevant structural information (e.g., parent-child relationships in Reddit threads). +\subsubsection{Scalability Constraints} +This system should be scalable enough to handle large datasets, but there are practical limits to how much data can be processed within reasonable timeframes, especially given the computational demands of NLP models. + +To migiate this, the system will: +\begin{itemize} + \item Utilise GPU acceleration where available for NLP inference. + \item Pre-compute some analytical results during data ingestion to speed up subsequent queries. + \item Store NLP outputs in the database to avoid redundant processing. + \item Implement asynchronous processing for long-running tasks. +\end{itemize} + +Overall, while the system is designed to be scalable, it is important to set realistic expectations regarding performance and processing times, especially for very large datasets. + + \subsection{Ethics} \subsection{Design Tradeoffs} From 98aa04256bf56feb9a6e2bf178fe0d14ad2cb597 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 4 Apr 2026 10:20:48 +0100 Subject: [PATCH 07/30] fix(reddit_api): fix reddit ratelimit check --- server/connectors/reddit_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/connectors/reddit_api.py b/server/connectors/reddit_api.py index ef618cf..90a08d8 100644 --- a/server/connectors/reddit_api.py +++ b/server/connectors/reddit_api.py @@ -188,7 +188,7 @@ class RedditAPI(BaseConnector): ) if response.status_code == 429: - wait_time = response.headers.get("Retry-After", backoff) + wait_time = response.headers.get("X-Ratelimit-Reset", backoff) logger.warning( f"Rate limited by Reddit API. Retrying in {wait_time} seconds..." From de61e7653f40fc14429c2b4e8e63bde205dff708 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 4 Apr 2026 12:26:54 +0100 Subject: [PATCH 08/30] perf(connector): add reddit API authentication to speed up fetching This aligns better with ethics and massively increases rate limits. --- example.env | 2 ++ server/connectors/reddit_api.py | 48 +++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/example.env b/example.env index 5e62ce6..e718a5a 100644 --- a/example.env +++ b/example.env @@ -1,5 +1,7 @@ # API Keys YOUTUBE_API_KEY= +REDDIT_CLIENT_ID= +REDDIT_CLIENT_SECRET= # Database POSTGRES_USER= diff --git a/server/connectors/reddit_api.py b/server/connectors/reddit_api.py index 90a08d8..dc07daf 100644 --- a/server/connectors/reddit_api.py +++ b/server/connectors/reddit_api.py @@ -1,6 +1,10 @@ import requests import logging import time +import os + +from dotenv import load_dotenv +from requests.auth import HTTPBasicAuth from dto.post import Post from dto.user import User @@ -9,6 +13,8 @@ from server.connectors.base import BaseConnector logger = logging.getLogger(__name__) +CLIENT_ID = os.getenv("REDDIT_CLIENT_ID") +CLIENT_SECRET = os.getenv("REDDIT_CLIENT_SECRET") class RedditAPI(BaseConnector): source_name: str = "reddit" @@ -18,6 +24,8 @@ class RedditAPI(BaseConnector): def __init__(self): self.url = "https://www.reddit.com/" + self.token = None + self.token_expiry = 0 # Public Methods # def get_new_posts_by_search( @@ -171,9 +179,44 @@ class RedditAPI(BaseConnector): user = User(username=user_data["name"], created_utc=user_data["created_utc"]) user.karma = user_data["total_karma"] return user + + def _get_token(self): + if self.token and time.time() < self.token_expiry: + return self.token + + logger.info("Fetching new Reddit access token...") + + auth = HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET) + + data = { + "grant_type": "client_credentials" + } + + headers = { + "User-Agent": "python:ethnography-college-project:0.1 (by /u/ThisBirchWood)" + } + + response = requests.post( + "https://www.reddit.com/api/v1/access_token", + auth=auth, + data=data, + headers=headers, + ) + + response.raise_for_status() + token_json = response.json() + + self.token = token_json["access_token"] + self.token_expiry = time.time() + token_json["expires_in"] - 60 + + logger.info( + f"Obtained new Reddit access token (expires in {token_json['expires_in']}s)" + ) + + return self.token def _fetch_post_overviews(self, endpoint: str, params: dict) -> dict: - url = f"{self.url}{endpoint}" + url = f"https://oauth.reddit.com/{endpoint.lstrip('/')}" max_retries = 15 backoff = 1 # seconds @@ -182,7 +225,8 @@ class RedditAPI(BaseConnector): response = requests.get( url, headers={ - "User-agent": "python:ethnography-college-project:0.1 (by /u/ThisBirchWood)" + "User-agent": "python:ethnography-college-project:0.1 (by /u/ThisBirchWood)", + "Authorization": f"Bearer {self._get_token()}", }, params=params, ) From 6efa75dfe6c522299fc776e5c321663bb63196ee Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 4 Apr 2026 12:33:06 +0100 Subject: [PATCH 09/30] chore(connectors): reduce aggressive parallel connections to boards.ie --- server/connectors/boards_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/connectors/boards_api.py b/server/connectors/boards_api.py index f5c04e6..a2c64ef 100644 --- a/server/connectors/boards_api.py +++ b/server/connectors/boards_api.py @@ -88,7 +88,7 @@ class BoardsAPI(BaseConnector): post = self._parse_thread(html, post_url) return post - with ThreadPoolExecutor(max_workers=30) as executor: + with ThreadPoolExecutor(max_workers=10) as executor: futures = {executor.submit(fetch_and_parse, url): url for url in urls} for i, future in enumerate(as_completed(futures)): From ac65e26eabdf335c77ce063baa257653538dbc6b Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 4 Apr 2026 13:52:56 +0100 Subject: [PATCH 10/30] docs(report): add ethics section --- report/main.tex | 76 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/report/main.tex b/report/main.tex index 2937363..f4a07be 100644 --- a/report/main.tex +++ b/report/main.tex @@ -1,6 +1,8 @@ -\documentclass{article} +\documentclass{article}[12pt] \usepackage{graphicx} \usepackage{setspace} +\usepackage{hyperref} + \begin{document} \begin{titlepage} @@ -39,7 +41,7 @@ There are many beneficiaries of a digital ethnography analytic system: social sc \subsection{Goals \& Objectives} \begin{itemize} - \item \textbf{Collect data ethically}: enable users to link/upload text, and interaction data (messages etc) from specified online communities. Potentially and automated method for importing (using APIs or scraping techniques) could be included as well. + \item \textbf{Collect data ethically}: enable users to link/upload text, and interaction data (messages etc) from specified online communities. Potentially an automated method for importing (using APIs or scraping techniques) could be included as well. \item \textbf{Organise content}: Store gathered material in a structured database with tagging for themes, dates, and sources. \item \textbf{Analyse patterns}: Use natural language processing (NLP) to detect frequent keywords, sentiment, and interaction networks. \item \textbf{Visualise insights}: Present findings as charts, timelines, and network diagrams to reveal how conversations and topics evolve. @@ -299,7 +301,9 @@ Though separate processing paths are not needed, the system will still retain me \subsubsection{Scalability Constraints} This system should be scalable enough to handle large datasets, but there are practical limits to how much data can be processed within reasonable timeframes, especially given the computational demands of NLP models. -To migiate this, the system will: +Some of the data can be precomputed during the data ingestion phases, such as datetime column derivations and NLP outputs, which can speed up and make queries more efficient. However, the initial processing time of large datasets will still be significant, especially if the dataset contains hundreds of thousands of posts and comments. + +To mitigate this, the system will: \begin{itemize} \item Utilise GPU acceleration where available for NLP inference. \item Pre-compute some analytical results during data ingestion to speed up subsequent queries. @@ -309,8 +313,72 @@ To migiate this, the system will: Overall, while the system is designed to be scalable, it is important to set realistic expectations regarding performance and processing times, especially for very large datasets. - \subsection{Ethics} +The system will process only publicly available data, and will not attempt to access private or restricted content. + +\subsubsection{Automated Data Collection} +The system will provide an option for users to automatically fetch datasets from social media sites filtered for keywords or categories. Therefore, it's important to ensure that this data collection is done ethically. + +The system will: +\begin{itemize} + \item Respect rate limits by implementing an exponential backoff strategy for API requests. + \item Only collect data that is publicly available and does not require authentication or violate platform terms of service. + \item Provide user-agent headers that identify the system and its purposes + \item Allow users the option to upload their own datasets instead of automated collection. + \item For websites without an API, the \texttt{robots.txt} file will be examined to ensure compliance with platform guidelines. + \item Data volume limits of up to 1000 posts per source will be enforced server-side to prevent excessive data collection. +\end{itemize} + +Some platforms provide APIs that allow for easy and ethical data collection, such as YouTube and Reddit. These APIs have clear guidelines and rate limits that the system will adhere to. + +\paragraph{Reddit (API)} +Reddit provides a public API that allows for the retrieval of posts, comments, and metadata from subreddits. The system will use the official Reddit API with proper authentication via OAuth2 and access tokens. + +In November 2025, Reddit introduced a new approval process for API access, which requires developers to apply for access and specify their intended use case. While the public unauthenticated endpoints are still accessible, they have far stricter rate limits (100 requests every 10 minutes) compared to authenticated access (100 requests per minute). Therefore, the system shall allow for authenticated access to the Reddit API to speed up data retrival. + +Unauthenticated access will still be available as a fallback if client credentials are not provided on the backend, but this will massively slow the data retreival process, and this will still only fetch public posts and comments. + +From reddit, the system will collect posts, comments and all replies to comments, as well as metadata such as the author name and timestamp. + +\paragraph{Boards.ie (Web Scraping)} +Boards.ie is an Irish discussion forum with no public API, so the system will use web scraping instead. The platforms \texttt{robots.txt} will be used to ensure compliance with the site's guidelines for automated access. The boards.ie \texttt{robots.txt} file contains the following information: + +\begin{verbatim} +Sitemap: https://www.boards.ie/sitemapindex.xml +User-agent: * +Disallow: /entry/ +Disallow: /messages/ +Disallow: /profile/comments/ +Disallow: /profile/discussions/ +Disallow: /search/ +Disallow: /sso/ +Disallow: /sso +\end{verbatim} + +Public discussion threads are allowed to be automatically crawled, while user profiles, private messages, and authentication endpoints are not allowed. The system will respect these boundaries and will not attempt to access any restricted path. + +\paragraph{YouTube (Data API v3)} +YouTube is supported via the official YouTube Data API v3, provided by Google. The API exposes structured endpoints for querying videos, comments, channels, and playlists, making it well-suited for collecting public discourse around specific topics or keywords. + +Authentication is handled through an API key issued via the Google Cloud Console. The API enforces a quota system rather than a traditional rate limit: each project is allocated 10,000 quota units per day by default, with different operations consuming different amounts. + +In addition, comment retreival can be disabled by the video uploader, so the system will handle this case by skipping videos where comments are not accessible. + +\subsubsection{Data Storage \& Retention} +All data fetched from social media sites are stored locally in a PostgreSQL database. The system will not share or expose any of this data to third parties beyond the users of this application. Raw API responses are discarded once the relevant information is extracted. + +All datasets are associated with one and only one user account, and the users themselves are responsible for uploading or fetching the data, analysing the data, and deleting the data when they are done. The system will not retain any data beyond what is necessary for the end-user to carry out their analysis, and users will have the option to delete their datasets at any time. + +The system will not store any personally identifiable information beyond what is necessary for the analysis, which includes only usernames and timestamps. The system will not attempt to de-anonymise content creators or link data across platforms. + +\subsubsection{User Security} +Standard security practices will be followed to protect user data and prevent unauthorized access. This includes: +\begin{itemize} + \item The hashing of all user passwords and no storage of plaintext passwords. + \item The use of JWTs for session management, with secure signing and an expiration time of 24 hours. + \item Access control on all analysis API endpoints to ensure that end-users can only access their own datasets and results. + \item Parameterised queries for all database interactions to prevent SQL injection attacks. +\end{itemize} \subsection{Design Tradeoffs} From b57a8d3c6567e685988fe3d56ce5cb0b34128c32 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Sat, 4 Apr 2026 14:36:52 +0100 Subject: [PATCH 11/30] docs(report): add data pipeline and connector sections Also moved requirements to the end of design, where it is more appropriately placed. Requirements can be specified after discussing potential pitfalls. --- report/main.tex | 222 ++++++++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 103 deletions(-) diff --git a/report/main.tex b/report/main.tex index f4a07be..70b6a54 100644 --- a/report/main.tex +++ b/report/main.tex @@ -174,108 +174,6 @@ Specifically, the system aims to: Ultimately, the project seeks to demonstrate how computational systems can aid and augment social scientists and digital ethnographers toolkits. -\subsection{Requirements} - -The following requirements are derived from the backend architecture, NLP processing pipeline, and the React-based frontend interface. - -\subsubsection{Functional Requirements} - -\paragraph{Data Ingestion and Preparation} -\begin{itemize} - \item The system shall accept social media data in \texttt{.jsonl} format containing posts and nested comments. - \item The system shall validate uploaded files and return structured error responses for invalid formats or malformed data. - \item The system shall normalise posts and comments into a unified event-based dataset. - \item The system shall give the user the option to automatically fetch datasets from social media sites filtered for specific keywords or categories. - \item The system shall provide a loading screen with a progress bar after the dataset is uploaded. -\end{itemize} - -\paragraph{Dataset Management} -\begin{itemize} - \item The system shall utilise Natural Language Processing models to generate average emotions per event. - \item The system shall utilise Natural Language Processing models to classify each event into a topic. - \item The system shall utilise Natural Language Processing models to identify entities in each event. - \item The system shall allow the users to view the raw dataset. - \item The system shall return detailed endpoints that return calculated statistics grouped into themes. -\end{itemize} - -\paragraph{Filtering and Search} -\begin{itemize} - \item The system shall support keyword-based filtering across content, author, and optionally title fields. - \item The system shall support filtering by start and end date ranges. - \item The system shall support filtering by one or more data sources. - \item The system shall allow multiple filters to be applied simultaneously. - \item The system shall return a filtered dataset reflecting all active filters. -\end{itemize} - -\paragraph{Temporal Analysis} -\begin{itemize} - \item The system shall compute event frequency per day. - \item The system shall generate weekday--hour heatmap data representing activity distribution. -\end{itemize} - -\paragraph{Linguistic Analysis} -\begin{itemize} - \item The system shall compute word frequency statistics excluding standard and domain-specific stopwords. - \item The system shall extract common bi-grams and tri-grams from textual content. - \item The system shall compute lexical diversity metrics for the dataset. -\end{itemize} - -\paragraph{Emotional Analysis} -\begin{itemize} - \item The system shall compute average emotional distribution per topic. - \item The system shall compute overall average emotional distribution across the dataset. - \item The system shall determine dominant emotion distributions. - \item The system shall compute emotional distribution grouped by data source. -\end{itemize} - -\paragraph{User Analysis} -\begin{itemize} - \item The system shall identify top users based on activity. - \item The system shall compute per-user activity and behavioural metrics. -\end{itemize} - -\paragraph{Interaction Analysis} -\begin{itemize} - \item The system shall compute average conversation thread depth. - \item The system shall identify top interaction pairs between users. - \item The system shall generate an interaction graph based on user relationships. - \item The system shall compute conversation concentration metrics. -\end{itemize} - -\paragraph{Cultural Analysis} -\begin{itemize} - \item The system shall identify identity-related linguistic markers. - \item The system shall detect stance-related linguistic markers. - \item The system shall compute average emotional expression per detected entity. -\end{itemize} - -\paragraph{Frontend} -\begin{itemize} - \item The system shall provide a frontend UI to accommodate all of the above functions - \item The system shall provide a tab for each endpoint in the frontend -\end{itemize} - -\subsubsection{Non-Functional Requirements} - -\paragraph{Performance} -\begin{itemize} - \item The system shall utilise GPU acceleration where available for NLP. - \item The system shall utilise existing React libraries for visualisations. -\end{itemize} - -\paragraph{Scalability} -\begin{itemize} - \item The system shall utilise cookies and session tracking for multi-user support. - \item NLP models shall be cached to prevent redundant loading. -\end{itemize} - -\paragraph{Reliability and Robustness} -\begin{itemize} - \item The system shall implement structured exception handling. - \item The system shall return meaningful JSON error responses for invalid requests. - \item The dataset reset functionality shall preserve data integrity. -\end{itemize} - \subsection{Feasibility Analysis} \subsubsection{NLP Limitations} Online communities often use sarcasm, irony or context-specific references, all of which will be challenging for NLP models, especially weaker ones, to correctly interpret. In a Cork-specific dataset, this will be especially apparent due to the use of regional slang or informal grammar. @@ -380,8 +278,107 @@ Standard security practices will be followed to protect user data and prevent un \item Parameterised queries for all database interactions to prevent SQL injection attacks. \end{itemize} -\subsection{Design Tradeoffs} +\subsection{Requirements} +The following requirements are derived from the backend architecture, NLP processing pipeline, and the React-based frontend interface. + +\subsubsection{Functional Requirements} + +\paragraph{Data Ingestion and Preparation} +\begin{itemize} + \item The system shall accept social media data in \texttt{.jsonl} format containing posts and nested comments. + \item The system shall validate uploaded files and return structured error responses for invalid formats or malformed data. + \item The system shall normalise posts and comments into a unified event-based dataset. + \item The system shall give the user the option to automatically fetch datasets from social media sites filtered for specific keywords or categories. + \item The system shall provide a loading screen with a progress bar after the dataset is uploaded. +\end{itemize} + +\paragraph{Dataset Management} +\begin{itemize} + \item The system shall utilise Natural Language Processing models to generate average emotions per event. + \item The system shall utilise Natural Language Processing models to classify each event into a topic. + \item The system shall utilise Natural Language Processing models to identify entities in each event. + \item The system shall allow the users to view the raw dataset. + \item The system shall return detailed endpoints that return calculated statistics grouped into themes. +\end{itemize} + +\paragraph{Filtering and Search} +\begin{itemize} + \item The system shall support keyword-based filtering across content, author, and optionally title fields. + \item The system shall support filtering by start and end date ranges. + \item The system shall support filtering by one or more data sources. + \item The system shall allow multiple filters to be applied simultaneously. + \item The system shall return a filtered dataset reflecting all active filters. +\end{itemize} + +\paragraph{Temporal Analysis} +\begin{itemize} + \item The system shall compute event frequency per day. + \item The system shall generate weekday--hour heatmap data representing activity distribution. +\end{itemize} + +\paragraph{Linguistic Analysis} +\begin{itemize} + \item The system shall compute word frequency statistics excluding standard and domain-specific stopwords. + \item The system shall extract common bi-grams and tri-grams from textual content. + \item The system shall compute lexical diversity metrics for the dataset. +\end{itemize} + +\paragraph{Emotional Analysis} +\begin{itemize} + \item The system shall compute average emotional distribution per topic. + \item The system shall compute overall average emotional distribution across the dataset. + \item The system shall determine dominant emotion distributions. + \item The system shall compute emotional distribution grouped by data source. +\end{itemize} + +\paragraph{User Analysis} +\begin{itemize} + \item The system shall identify top users based on activity. + \item The system shall compute per-user activity and behavioural metrics. +\end{itemize} + +\paragraph{Interaction Analysis} +\begin{itemize} + \item The system shall compute average conversation thread depth. + \item The system shall identify top interaction pairs between users. + \item The system shall generate an interaction graph based on user relationships. + \item The system shall compute conversation concentration metrics. +\end{itemize} + +\paragraph{Cultural Analysis} +\begin{itemize} + \item The system shall identify identity-related linguistic markers. + \item The system shall detect stance-related linguistic markers. + \item The system shall compute average emotional expression per detected entity. +\end{itemize} + +\paragraph{Frontend} +\begin{itemize} + \item The system shall provide a frontend UI to accommodate all of the above functions + \item The system shall provide a tab for each endpoint in the frontend +\end{itemize} + +\subsubsection{Non-Functional Requirements} + +\paragraph{Performance} +\begin{itemize} + \item The system shall utilise GPU acceleration where available for NLP. + \item The system shall utilise existing React libraries for visualisations. +\end{itemize} + +\paragraph{Scalability} +\begin{itemize} + \item The system shall utilise cookies and session tracking for multi-user support. + \item NLP models shall be cached to prevent redundant loading. +\end{itemize} + +\paragraph{Reliability and Robustness} +\begin{itemize} + \item The system shall implement structured exception handling. + \item The system shall return meaningful JSON error responses for invalid requests. + \item The dataset reset functionality shall preserve data integrity. +\end{itemize} \newpage \section{Design} @@ -400,6 +397,25 @@ Standard security practices will be followed to protect user data and prevent un \label{fig:schema} \end{figure} +\subsection{Data Pipeline} +As this project is focused on the collection and analysis of online community data, the primary component that must be well-designed is the data pipeline, which encompasses the processes of data ingestion, normalisation, enrichment, storage, and retrieval for analysis. + +A unified data model is used to represent all incoming data, regardless of its original source or structure. This ensures that the same pipeline works across YouTube, Reddit and boards.ie data, and can be easily extended to new sources in the future. + + + +\subsection{Connector Abstraction} +While the system is designed around a Cork-based dataset, it is intentionally source-agnostic, meaning that additional data sources could be added in the future without changes to the core analytical pipeline. + +\textbf{Data Connectors} are components responsible for fetching and normalising data from specific sources. Each connector implements a standard interface for data retrieval, such as: +\begin{itemize} + \item \texttt{get\_new\_posts()} — retrieves raw data from the source, either through API calls or web scraping. +\end{itemize} + +Creating a base interface for what a connector should look like allows for the easy addition of new data sources in the future. For example, if a new social media platform becomes popular, a new connector can be implemented to fetch data from that platform without needing to modify the existing data pipeline or analytical modules. + +The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. + \subsection{Client-Server Architecture} The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. From f2b6917f1f28374f941cbaff327759ee8f1f0104 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 12:44:17 +0100 Subject: [PATCH 12/30] docs(report); add data ingestion section --- report/main.tex | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/report/main.tex b/report/main.tex index 70b6a54..2eaccd0 100644 --- a/report/main.tex +++ b/report/main.tex @@ -60,19 +60,18 @@ A defining feature of this project is its focus on a geographically grounded dat \newpage \section{Background} -This section describes what digital ethnography is, how it stems from traditional ethnography and why it is useful. -\subsection{Digital Ethnography} +\subsection{What is Digital Ethnography?} Digital Ethnography is the study of cultures and interactions in various online spaces, such as forums, posts and video comments. The goal is not only to describe the high-level statistics such as number of posts and posts per day, but also analyse people's behaviour at an interactional and cultural level, delving into common phrases, interactions patterns and common topics and entities. There are multiple methods to carry out digital ethnography, such as online participant observation through automated or manual methods, digital interviews via text or video or tracing digital footprints. Compared to traditional ethnography, digital ethnography is usually faster and more cost-effective due to the availability of large swathes of data across social media sites such as Reddit, YouTube, and Facebook and lack of need to travel. Traditional ethnography often relied on in-person interviews and in-person observation of communities -\subsection{Traditional Ethnography} +\subsubsection{Traditional Ethnography} Ethnography originated in the late nineteenth and early twentieth centuries as a method for understanding cultures through long-term fieldwork. The goal was not just to describe behaviour, but to show how people made sense of that world. Over time, ethnography grew beyond anthropology into sociology, media studies, education, and human computer interaction, becoming a broadly used qualitative research approach. Traditional ethnography was closely tied to physical locations: villages, workplaces or towns. However, as communication technologies developed and social life increasingly took place through technological mediums, it was no longer tied to a physical place. Researchers questioned whether social interactions could still be studied properly if they were no longer tied to physical places. -\subsection{Transition to Digital Spaces} +\subsubsection{Transition to Digital Spaces} The rise of the internet in the late twentieth century massively changed social interaction. Online forums, emails, SMS and social media platforms became central to human communication. All types of groups and identities were constructed. As a result, ethnographic methods were adapted to study these emerging digital environments. Early work in this area was referred to as "virtual ethnography" or "digital ethnography", where online spaces began to mixed and intertwine with traditional cultural spaces. Digital ethnography gives us new challenges to overcome in comparison to traditional ethnography. The field is distributed across platforms, devices and online-offline interactions. For example, a digital ethnographer studying influencer culture might examine Instagram posts, comment sections, private messages, algorithms, and also conduct interviews or observe offline events. This transitions requires flexibility, since researchers can no longer rely solely on face-to-face interactions. @@ -82,6 +81,14 @@ There are many different types of online communities, often structured in variou Participation within these communities is usually not evenly distributed. The majority of users are passive consumers (lurkers), a smaller percentage contribute occasionally, and a very small core group produces most of the content. This uneven contribution structure has significant implications for digital ethnography, as visible discourse may disproportionately reflect the perspectives of highly active members rather than the broader community. This is particularly evident in some reputation-based systems such as Reddit, which allows for the opinions of a few to rise above the rest. +Examples of digital spaces include: +\begin{itemize} + \item \textbf{Social media platforms} (e.g., Facebook, Twitter, Instagram) where users create profiles, share content, and interact with others. + \item \textbf{Online forums and communities} (e.g., Reddit, Boards.ie) where users engage in threaded discussions around specific topics or interests. + \item \textbf{Video platforms} (e.g., YouTube) where users share and comment on video content, often fostering communities around specific channels or topics. + \item \textbf{Messaging apps} (e.g., WhatsApp, Discord) where users engage in private or group conversations, often with a more informal and intimate tone. +\end{itemize} + \subsection{Digital Ethnography Metrics} This section describes common keywords and metrics use to measure and quantify online communities using digital ethnography. @@ -402,6 +409,34 @@ As this project is focused on the collection and analysis of online community da A unified data model is used to represent all incoming data, regardless of its original source or structure. This ensures that the same pipeline works across YouTube, Reddit and boards.ie data, and can be easily extended to new sources in the future. +\subsubsection{Data Ingestion} +The system will support two methods of data ingestion: +\begin{itemize} + \item \textbf{File Upload}: Users can upload datasets in a specified \texttt{.jsonl} format, which contains posts and nested comments. + \item \textbf{Automated Fetching}: Users can trigger the system to automatically fetch data from supported social media platforms using specified keywords or filters. +\end{itemize} + +Originally, only file upload was supported, but the goal of the platform is to aid researchers with ethnograpic analysis, and many researchers will not have the technical expertise to fetch data from social media APIs or scrape websites. Therefore, the system was designed to support automated fetching of data from social media platforms, which allows users to easily obtain datasets without needing to manually collect and format data themselves. + +Each method of ingestion will format the raw data into a standardised structure, where each post will be represented as a "Post" object and each comment will be represented as a "Comment" object. Both objects will have a common set of fields, such as: +\begin{itemize} + \item \texttt{id} - a unique identifier for the post or comment. + \item \texttt{content} — the text content of the post or comment. + \item \texttt{author} — the username of the content creator. + \item \texttt{timestamp} — the date and time when the content was created + \item \texttt{source} — the original platform from which the content was retrieved (e.g., Reddit, YouTube, Boards.ie). + \item \texttt{type} — a field indicating whether the event is a "post" or a "comment". + \item \texttt{parent\_id} — for comments, this field will reference the original id of the post it's commenting on. + \item \texttt{reply\_to} - for comments, this field will reference the original id of the comment it's replying to. If the comment is a direct reply to a post, this field will be null. +\end{itemize} + +The decision to normalise posts and comments into a single "event" data model allows the same analytical functions to be applied uniformly across all content, regardless of whether it was originally a post or a comment. This simplifies the data model and reduces the complexity of the analytical pipeline, since there is no need to maintain separate processing paths for posts and comments. + + + +\subsubsection{Data Normalisation} + + \subsection{Connector Abstraction} From 23833e2c5b37934b147ffe4adbf53585a8be432c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 18:47:29 +0100 Subject: [PATCH 13/30] docs(report): add custom topic section --- report/main.tex | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/report/main.tex b/report/main.tex index 2eaccd0..c895344 100644 --- a/report/main.tex +++ b/report/main.tex @@ -2,6 +2,7 @@ \usepackage{graphicx} \usepackage{setspace} \usepackage{hyperref} +\usepackage{fvextra} \begin{document} @@ -418,6 +419,21 @@ The system will support two methods of data ingestion: Originally, only file upload was supported, but the goal of the platform is to aid researchers with ethnograpic analysis, and many researchers will not have the technical expertise to fetch data from social media APIs or scrape websites. Therefore, the system was designed to support automated fetching of data from social media platforms, which allows users to easily obtain datasets without needing to manually collect and format data themselves. +In addition to social media posts, the system will allow users to upload a list of topics that they want to track in the dataset. This allows the system to generate custom topic analysis based on user-defined topics, which can be more relevant and insightful for specific research questions. For example, a researcher studying discussions around local politics in Cork might upload a list of political parties, politicians, and policy issues as topics to track. + +Below is a snippet of what a custom topic list might look like in \texttt{.json} format: +\begin{Verbatim}[breaklines=true] +{ + "Public Transport": "buses, bus routes, bus eireann, public transport, late buses, bus delays, trains, commuting without a car, transport infrastructure in Cork", + "Traffic": "traffic jams, congestion, rush hour, cars backed up, gridlock, driving in Cork, road delays", + "Parking": "parking spaces, parking fines, clamping, pay parking, parking permits, finding parking in the city", + "Cycling": "cycling in Cork, bike lanes, cyclists, cycle safety, bikes on roads, cycling infrastructure" +} +\end{Verbatim} + +If a custom topic list is not provided by the user, the system will use a pre-defined generalised topic list that is designed to capture common themes across a wide range of online communities. + +\subsubsection{Data Normalisation} Each method of ingestion will format the raw data into a standardised structure, where each post will be represented as a "Post" object and each comment will be represented as a "Comment" object. Both objects will have a common set of fields, such as: \begin{itemize} \item \texttt{id} - a unique identifier for the post or comment. @@ -434,11 +450,6 @@ The decision to normalise posts and comments into a single "event" data model al -\subsubsection{Data Normalisation} - - - - \subsection{Connector Abstraction} While the system is designed around a Cork-based dataset, it is intentionally source-agnostic, meaning that additional data sources could be added in the future without changes to the core analytical pipeline. From 107dae0e951a1c1f83cc67e9f3ac1b9ac441b317 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 19:26:10 +0100 Subject: [PATCH 14/30] docs(report): add data storage section --- report/main.tex | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/report/main.tex b/report/main.tex index c895344..364e7d4 100644 --- a/report/main.tex +++ b/report/main.tex @@ -433,8 +433,10 @@ Below is a snippet of what a custom topic list might look like in \texttt{.json} If a custom topic list is not provided by the user, the system will use a pre-defined generalised topic list that is designed to capture common themes across a wide range of online communities. +Each method of ingestion will format the raw data into a standardised structure, where each post will be represented as a "Post" object and each comment will be represented as a "Comment" object. + \subsubsection{Data Normalisation} -Each method of ingestion will format the raw data into a standardised structure, where each post will be represented as a "Post" object and each comment will be represented as a "Comment" object. Both objects will have a common set of fields, such as: +After a dataset is ingested, the system will normalise all posts and nested comments into a single unified "event" data model. This means that both posts and comments will be represented as the same type of object, with a common set of fields that capture the relevant information for analysis. The fields in this unified data model will include: \begin{itemize} \item \texttt{id} - a unique identifier for the post or comment. \item \texttt{content} — the text content of the post or comment. @@ -448,10 +450,47 @@ Each method of ingestion will format the raw data into a standardised structure, The decision to normalise posts and comments into a single "event" data model allows the same analytical functions to be applied uniformly across all content, regardless of whether it was originally a post or a comment. This simplifies the data model and reduces the complexity of the analytical pipeline, since there is no need to maintain separate processing paths for posts and comments. +As part of this normalisation process, the dataset is also \textbf{flattened}, so rather than comments being nested within their parent posts as they are in the raw source data, all events are stored as a flat sequence of records. The relationships between posts and comments are preserved through the \texttt{parent\_id} and \texttt{reply\_to} fields. This allows for more efficient querying and analysis of the data, as well as simplifying the data model. + +Overall, the data normalisation process unifies the structure of the dataset, and flattens the data into a format that makes analysis more efficient and easier. -\subsection{Connector Abstraction} -While the system is designed around a Cork-based dataset, it is intentionally source-agnostic, meaning that additional data sources could be added in the future without changes to the core analytical pipeline. +\subsubsection{Data Enrichment} +After normalisation, the dataset is enriched with additional derived fields and NLP outputs. This includes: +\begin{itemize} + \item \textbf{Datetime Derivations}: Fields such as day of week, hour of day, and week of year are derived from the raw timestamp and stored alongside the event, so they do not need to be recomputed on every query. + \item \textbf{Emotion Classification}: Each event is run through an NLP model that assigns an emotional label to the text content, such as joy, anger, or sadness. + \item \textbf{Topic Classification}: Each event is classified into its most relevant topic using an NLP model, based on either the user-provided topic list or the system default. + \item \textbf{Named Entity Recognition}: Each event is processed to identify any named entities mentioned in the text, such as people, places, or organisations, which are stored as a list associated with the event. +\end{itemize} + +NLP processing allows for much richer analysis of the dataset, as it provides additional layers of information beyond just the raw text content. After enrichment, the dataset is ready to be stored in the database and made available for analysis through the API endpoints. + +\subsubsection{Data Storage} +The enriched dataset is stored in a PostgreSQL database, with a schema similar to the unified data model defined in the normalisation section, with additional fields for the derived data, NLP outputs, and user ownership. Each dataset is associated with a specific user account, and the system supports multiple datasets per user. + +The \texttt{events} table in PostgreSQL contains the following fields: +\begin{itemize} + \item \texttt{id}: a unique identifier for the event. + \item \texttt{dataset\_id}: a foreign key referencing the dataset this event belongs to. If the dataset is deleted. + \item \texttt{post\_id}: the original identifier of the post or comment as it appeared on the source platform. + \item \texttt{type}: whether the event is a post or a comment. + \item \texttt{author}: the username of the content creator. + \item \texttt{content}: the text content of the event. + \item \texttt{timestamp}: the Unix epoch time at which the content was created. + \item \texttt{date}, \texttt{dt}, \texttt{hour}, \texttt{weekday}: datetime fields derived from the timestamp at ingestion time. + \item \texttt{title}: the title of the post, if the event is a post. Null for comments. + \item \texttt{parent\_id}: for comments, the identifier of the post it belongs to. Null for posts. + \item \texttt{reply\_to}: for comments, the identifier of the comment it directly replies to. Null if the comment is a direct reply to a post. + \item \texttt{source}: the platform from which the content was retrieved. + \item \texttt{topic}, \texttt{topic\_confidence}: the topic assigned to the event by the NLP model, along with a confidence score. + \item \texttt{ner\_entities}: a list of named entities identified in the content, stored as a \texttt{JSONB} field. + \item \texttt{emotion\_anger}, \texttt{emotion\_disgust}, \texttt{emotion\_fear}, \texttt{emotion\_joy}, \texttt{emotion\_sadness}: emotion scores assigned to the event by the NLP model. +\end{itemize} + +\subsection{Automatic Data Collection} +\subsubsection{Connector Abstractions} +While the system is designed around a Cork-based dataset, it is intentionally source-agnostic, meaning that additional data sources for data ingestion could be added in the future without changes to the core analytical pipeline. \textbf{Data Connectors} are components responsible for fetching and normalising data from specific sources. Each connector implements a standard interface for data retrieval, such as: \begin{itemize} @@ -462,6 +501,9 @@ Creating a base interface for what a connector should look like allows for the e The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. +\subsection{Ethnographic Analysis} + + \subsection{Client-Server Architecture} The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. From cedbce128ede71dcdc7017b7a5ad0d110569c6a9 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 19:32:49 +0100 Subject: [PATCH 15/30] docs(report): add auto-fetch section --- report/main.tex | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/report/main.tex b/report/main.tex index 364e7d4..cc8fb62 100644 --- a/report/main.tex +++ b/report/main.tex @@ -488,14 +488,25 @@ The \texttt{events} table in PostgreSQL contains the following fields: \item \texttt{emotion\_anger}, \texttt{emotion\_disgust}, \texttt{emotion\_fear}, \texttt{emotion\_joy}, \texttt{emotion\_sadness}: emotion scores assigned to the event by the NLP model. \end{itemize} +\subsubsection{Data Retrieval} +The stored dataset can then be retrieved through the Flask API endpoints for analysis. The API supports filtering by keywords and date ranges, as well as grouping and aggregation for various analytical outputs. + \subsection{Automatic Data Collection} +Originally, the system was designed to only support manual dataset uploads, where users would collect their own data from social media platforms and format it into the required \texttt{.jsonl} format. + +However, this approach is time consuming and since this system is designed to aid researchers rather than burden them, the system includes functionality to automatically fetch data from social media platforms. This allows users to easily obtain datasets without needing to manually collect and format data themselves, which is especially beneficial for researchers who may not have technical expertise in data collection. + +The initial system will contain connectors for: +\begin{itemize} + \item \textbf{Reddit} — using the official Reddit API to fetch posts and comments from specified subreddits or filtered by keywords. + \item \textbf{YouTube} — using the YouTube Data API v3 to fetch video comments based on search queries. + \item \textbf{Boards.ie} — using web scraping techniques to collect posts and comments from the Cork section of the Boards.ie forum. +\end{itemize} + \subsubsection{Connector Abstractions} While the system is designed around a Cork-based dataset, it is intentionally source-agnostic, meaning that additional data sources for data ingestion could be added in the future without changes to the core analytical pipeline. -\textbf{Data Connectors} are components responsible for fetching and normalising data from specific sources. Each connector implements a standard interface for data retrieval, such as: -\begin{itemize} - \item \texttt{get\_new\_posts()} — retrieves raw data from the source, either through API calls or web scraping. -\end{itemize} +\textbf{Data Connectors} are components responsible for fetching and normalising data from specific sources. Each connector implements a standard interface for data retrieval. Creating a base interface for what a connector should look like allows for the easy addition of new data sources in the future. For example, if a new social media platform becomes popular, a new connector can be implemented to fetch data from that platform without needing to modify the existing data pipeline or analytical modules. From 33e4291def5343f2f85f9001007a697cd2d43d61 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 19:34:38 +0100 Subject: [PATCH 16/30] docs(report): add table of contents --- report/main.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/report/main.tex b/report/main.tex index cc8fb62..1c85143 100644 --- a/report/main.tex +++ b/report/main.tex @@ -31,6 +31,10 @@ \vspace{2cm} \end{titlepage} + +\tableofcontents +\newpage + \section{Introduction} This project presents the design and implementation of a web-based analytics engine for the exploration and analysis of online discussion data. Built using \textbf{Flask and Pandas}, and supplemented with \textbf{Natural Language Processing} (NLP) techniques, the system provides an API for extracting structural, temporal, linguistic, and emotional insights from social media posts. A React-based frontend delivers interactive visualizations and user controls, the backend architecture implements analytical pipeline for the data, including data parsing, manipulation and analysis. From 0c4dc02852fbb8547e7ce86932c5db71bac13143 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Mon, 6 Apr 2026 19:39:09 +0100 Subject: [PATCH 17/30] docs(report): add ethnographic analysis section --- report/main.tex | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/report/main.tex b/report/main.tex index 1c85143..c683766 100644 --- a/report/main.tex +++ b/report/main.tex @@ -409,6 +409,23 @@ The following requirements are derived from the backend architecture, NLP proces \label{fig:schema} \end{figure} +\subsection{Ethnographic Analysis} +Ethnographic analysis can be carried out from many different perspectives, such as the perspective of a single user or the community as a whole. The system is designed to support both of these perspectives, as well as the ability to zoom in and out between them. For example, a researcher might want to look at the overall emotional tone of a community, but then zoom in to see how a specific user contributes to that tone. + +The system is designed to support multiple types of analysis, such as: +\begin{itemize} + \item \textbf{Temporal Analysis}: looking at when a community is active and how that activity changes over time. + \item \textbf{Linguistic Analysis}: looking at the words and phrases that are commonly used in a community, and how they relate to identity and culture. + \item \textbf{Emotional Analysis}: looking at the emotional tone of a community, and how it varies across different topics or users. + \item \textbf{User Analysis}: looking at the behaviour and activity of individual users, and how they contribute to the community. + \item \textbf{Interaction Analysis}: looking at how users interact with each other, such as who replies to whom and how conversations develop. + \item \textbf{Cultural Analysis}: looking at the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. +\end{itemize} + +Each of these types of analysis are available at different API endpoints for any given dataset, and the frontend is designed to allow users to easily switch between them and explore the data from different angles. + + + \subsection{Data Pipeline} As this project is focused on the collection and analysis of online community data, the primary component that must be well-designed is the data pipeline, which encompasses the processes of data ingestion, normalisation, enrichment, storage, and retrieval for analysis. @@ -516,9 +533,6 @@ Creating a base interface for what a connector should look like allows for the e The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. -\subsection{Ethnographic Analysis} - - \subsection{Client-Server Architecture} The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. From e903e1b738c2b2a92f231ac8046d3f61279f788c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 11:34:03 +0100 Subject: [PATCH 18/30] feat(user): add dominant topic information to user data --- frontend/src/components/UserModal.tsx | 9 +++++++++ frontend/src/types/ApiTypes.ts | 7 +++++++ server/analysis/user.py | 27 +++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/frontend/src/components/UserModal.tsx b/frontend/src/components/UserModal.tsx index 6321804..30ab6c9 100644 --- a/frontend/src/components/UserModal.tsx +++ b/frontend/src/components/UserModal.tsx @@ -88,6 +88,15 @@ export default function UserModal({ ) : null} + + {userData.dominant_topic ? ( +
+
Most Common Topic
+
+ {userData.dominant_topic.topic} ({userData.dominant_topic.count} events) +
+
+ ) : null} )} diff --git a/frontend/src/types/ApiTypes.ts b/frontend/src/types/ApiTypes.ts index 9492119..3143c32 100644 --- a/frontend/src/types/ApiTypes.ts +++ b/frontend/src/types/ApiTypes.ts @@ -34,6 +34,11 @@ type Vocab = { top_words: FrequencyWord[]; }; +type DominantTopic = { + topic: string; + count: number; +}; + type User = { author: string; post: number; @@ -41,6 +46,7 @@ type User = { comment_post_ratio: number; comment_share: number; avg_emotions?: Record; + dominant_topic?: DominantTopic | null; vocab?: Vocab | null; }; @@ -202,6 +208,7 @@ type FilterResponse = { export type { TopUser, + DominantTopic, Vocab, User, InteractionGraph, diff --git a/server/analysis/user.py b/server/analysis/user.py index f4837d3..2fc5c94 100644 --- a/server/analysis/user.py +++ b/server/analysis/user.py @@ -71,6 +71,7 @@ class UserAnalysis: per_user = df.groupby(["author", "type"]).size().unstack(fill_value=0) emotion_cols = [col for col in df.columns if col.startswith("emotion_")] + dominant_topic_by_author = {} avg_emotions_by_author = {} if emotion_cols: @@ -80,6 +81,31 @@ class UserAnalysis: for author, row in avg_emotions.iterrows() } + if "topic" in df.columns: + topic_df = df[ + df["topic"].notna() + & (df["topic"] != "") + & (df["topic"] != "Misc") + ] + if not topic_df.empty: + topic_counts = ( + topic_df.groupby(["author", "topic"]) + .size() + .reset_index(name="count") + .sort_values( + ["author", "count", "topic"], + ascending=[True, False, True], + ) + .drop_duplicates(subset=["author"]) + ) + dominant_topic_by_author = { + row["author"]: { + "topic": row["topic"], + "count": int(row["count"]), + } + for _, row in topic_counts.iterrows() + } + # ensure columns always exist for col in ("post", "comment"): if col not in per_user.columns: @@ -109,6 +135,7 @@ class UserAnalysis: "comment_post_ratio": float(row.get("comment_post_ratio", 0)), "comment_share": float(row.get("comment_share", 0)), "avg_emotions": avg_emotions_by_author.get(author, {}), + "dominant_topic": dominant_topic_by_author.get(author), "vocab": vocab_by_author.get( author, { From 225133a07488da5b9b5a8a647c2d27bac248e8ee Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 11:54:57 +0100 Subject: [PATCH 19/30] docs(report): add ethnographic analysis section --- report/main.tex | 99 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/report/main.tex b/report/main.tex index c683766..bdb75a1 100644 --- a/report/main.tex +++ b/report/main.tex @@ -132,6 +132,11 @@ NLP techniques can be used to automatically process and analyse large volumes an This method is often used to organise lots of unstructured data, such as news articles, research papers, or social media posts. +\subsubsection{Stop Words} +\textbf{Stop Words} are common words that are often filtered out in NLP tasks because they carry little meaningful information. Examples of stop words include "the", "is", "in", "and", etc. Removing stop words can help improve the performance of NLP models by reducing noise and focusing on more informative words. However, the choice of stop words can vary depending on the context and the specific task at hand. + +For example, in a Cork-specific dataset, words like "ah", or "grand" might be considered stop words, as they are commonly used in everyday speech but do not carry significant meaning for analysis. + \subsection{Limits of Computation Analysis} While computational methods enable large-scale observation and analysis of online communities, there are many limitations that must be acknowledged. Many limitations come from NLP techniques and the practical boundaries of computational resources. @@ -409,7 +414,23 @@ The following requirements are derived from the backend architecture, NLP proces \label{fig:schema} \end{figure} +\subsection{Client-Server Architecture} +The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. + +The reasoning behind this architecture is that it allows the analytics to be aggregated and computed on the server side using Pandas which is much faster than doing it on the client frontend. The frontend will focus on rendering and visualising the data. + +\subsubsection{Flask API} +The Flask backend will expose a RESTful API with endpoints for dataset management, authentication and user management, and analytical queries. Flask will call on backend components for data parsing, normalisation, NLP processing and database interfacing. + +Flask was chosen for its simplicity, familiarity and speed of development. It also has many extensions that can be used for authentication (Flask-Bcrypt, Flask-Login). + +\subsubsection{React Frontend} +React was chosen for the frontend due to its massive library of pre-built components with efficient rendering capabilities and ability to display many different types of data. The frontend will be structured around a tabbed interface, with each tab corresponding to a different analytical endpoint (e.g., temporal analysis, linguistic analysis, emotional analysis). Each tab will fetch data from the backend API and render it using appropriate visualisation libraries (react-wordcloud for word clouds, react-chartjs-2 for charts, etc). The frontend will also include controls for filtering the dataset based on keywords, date ranges, and data sources. + + \subsection{Ethnographic Analysis} +The main goal of this project is to provide a tool that can assist researchers with ethnographic analysis of online communities. Therefore, ethnographic analysis will be a core component of the system. + Ethnographic analysis can be carried out from many different perspectives, such as the perspective of a single user or the community as a whole. The system is designed to support both of these perspectives, as well as the ability to zoom in and out between them. For example, a researcher might want to look at the overall emotional tone of a community, but then zoom in to see how a specific user contributes to that tone. The system is designed to support multiple types of analysis, such as: @@ -424,7 +445,71 @@ The system is designed to support multiple types of analysis, such as: Each of these types of analysis are available at different API endpoints for any given dataset, and the frontend is designed to allow users to easily switch between them and explore the data from different angles. +\subsubsection{Temporal Analysis} +Temporal analysis allows researchers to understand what a community is talking about over time, and how the emotional tone of the community changes over time. For example, a researcher might want to see how discussions around a specific topic evolve over time, or how the emotional tone of a community changes in response to external events. +However a major limitation of the data captured for this system, whether it's the Cork dataset, or any automatically fetched dataset, it will only stretch at most a few weeks back in time. This is because the system is designed to fetch only the most recent posts and comments from social media platforms, which means that it will not capture historical data beyond a certain point. Therefore, while temporal analysis can still be carried out on the dataset, it will be limited to a relatively short timeframe. + +In this system, temporal analysis will be limited to: +\begin{itemize} + \item Event frequency per day. + \item Weekday--hour heatmap data representing activity distribution. +\end{itemize} + +\textbf{Average reply time per emotion} was considered as a potential temporal analysis metric, but was eventually excluded due to inconsistent and statistically insignificant results that yielded no meaningful analytical insight. + +\subsubsection{Linguistic Analysis} +Linguistic analysis allows researchers to understand the language and words used in a community. For example, a researcher might want to see what words are most commonly used in a community, or how the language used in a community relates to identity and culture. + +In this system, linguistic analysis will include: +\begin{itemize} + \item Word frequency statistics excluding standard and domain-specific stopwords. + \item Common bi-grams and tri-grams from textual content. + \item Lexical diversity metrics for the dataset. +\end{itemize} + +Outlining a list of stopwords is essential for linguistic analysis, as it filters out common words that wouldn't be useful for linguistic analysis. Stop Word lists can be provided by a Python library such as NLTK. + +In addition to standard stop words, the system also excludes link tokens such as "www", "http", and "https" from the word frequency analysis, as social media users will often include links in their posts and comments, and these tokens can become quite common and skew the word frequency results without adding meaningful insight. + +\subsubsection{User Analysis} +User analysis allows researchers to understand the behaviour and activity of individual users within a community. For example, a researcher might want to see who the most active users are in a community, or how different users contribute to the overall emotional tone of the community. + +In this system, user analysis will include: +\begin{itemize} + \item Identification of top users based on activity. + \item Per-user activity such as: + \begin{itemize} + \item Total number of events (posts and comments). + \item Average emotion distribution across their events. + \item Average topic distribution across their events. + \item Comment-to-post ratio. + \item Vocabulary information such as top words used and lexical diversity. + \end{itemize} +\end{itemize} + +\subsubsection{Interactional Analysis} +Instead of per-user analysis, interactional analysis looks at the interactions between users, such as who replies to who and who is contributing the most to the conversations. + +In this system, interactional analysis will include: +\begin{itemize} + \item Average conversation thread depth. + \item Top interaction pairs between users. + \item An interaction graph based on user relationships. + \item Conversation concentration metrics such as who is contributing the most to the conversations and how much of the conversation is dominated by a small number of users. +\end{itemize} + +For simplicity, an interaction is defined as a reply from one user to another, which can be either a comment replying to a post or a comment replying to another comment. The system will not attempt to capture more complex interactions such as mentions or indirect references between users, as these would require more advanced NLP techniques. + +\subsubsection{Emotional Analysis} +Emotional analysis allows researchers to understand the emotional tone of a community, and how it varies across different topics and users. + +In this system, emotional analysis will include: +\begin{itemize} + \item Average emotional by topic. + \item Overall average emotional distribution across the dataset. + \item Dominant emotion distributions, which are the most common overall +\end{itemize} \subsection{Data Pipeline} As this project is focused on the collection and analysis of online community data, the primary component that must be well-designed is the data pipeline, which encompasses the processes of data ingestion, normalisation, enrichment, storage, and retrieval for analysis. @@ -533,20 +618,6 @@ Creating a base interface for what a connector should look like allows for the e The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. -\subsection{Client-Server Architecture} -The system will follow a client-server architecture, with a Flask-based backend API and a React-based frontend interface. The backend will handle data processing, NLP analysis, and database interactions, while the frontend will provide an interactive user interface for data exploration and visualization. - -The reasoning behind this architecture is that it allows the analytics to be aggregated and computed on the server side using Pandas which is much faster than doing it on the client frontend. The frontend will focus on rendering and visualising the data. - -\subsubsection{Flask API} -The Flask backend will expose a RESTful API with endpoints for dataset management, authentication and user management, and analytical queries. Flask will call on backend components for data parsing, normalisation, NLP processing and database interfacing. - -Flask was chosen for its simplicity, familiarity and speed of development. It also has many extensions that can be used for authentication (Flask-Bcrypt, Flask-Login). - -\subsubsection{React Frontend} -React was chosen for the frontend due to its massive library of pre-built components with efficient rendering capabilities and ability to display many different types of data. The frontend will be structured around a tabbed interface, with each tab corresponding to a different analytical endpoint (e.g., temporal analysis, linguistic analysis, emotional analysis). Each tab will fetch data from the backend API and render it using appropriate visualisation libraries (react-wordcloud for word clouds, react-chartjs-2 for charts, etc). The frontend will also include controls for filtering the dataset based on keywords, date ranges, and data sources. - - \subsection{Database vs On-Disk Storage} Originally, the system was designed to store \texttt{json} datasets on disk and load them into memory for processing. This was simple and time-efficient for early development and testing. However, as the functionality of the system expanded, it become clear that a more persistent and scalable storage solution was needed. From addc1d40876451d8cd695fd05491feb1e418b542 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 12:17:02 +0100 Subject: [PATCH 20/30] docs(report): add justification at each stage --- report/img/reddit_bot.png | Bin 0 -> 237057 bytes report/main.tex | 31 ++++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 report/img/reddit_bot.png diff --git a/report/img/reddit_bot.png b/report/img/reddit_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..a895e63d0c1d363e751d08410b0b458aa5c0dc5f GIT binary patch literal 237057 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

)2yRjq-gf$gpo2bn_eOTCKYc%Ia8iq6D6fn+saJ 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

~sq^&*k!NRIRlk1tB%YFs-GU!Z5^FZSp z=Hf#LcU4`upr~+H`ZpGo14Xa^(e(W%WO=rEu0c{4d&-4)Ekf+o>yP2&qiv|>yDd8Y zRuK9f3qVOczLi`oylU@=d6a6l;I+!Ji&yN?3DLk+gIkPc|S-nv~SEnNs~ zOBy)9et=0(LABIs@Hk}e)_EcJd6u?lJ8dk(jhAFv)UFp4+34-KTVK3R!ha$C5{i?! z`5}jgwPdZtuTXbmHxJ+(nMes+liPz=vTr!IhV zw`zGv8heUGyeJWIl-P(7fyOuzW=% z+?O(mkFCX%FWDr-l%l8x?(n+Hu$XZscFmzS-pKb`i4q!9OY^VzN^OVQt>bP zgMw_J813i^kY~yef8lwMYX+WYsw?VU{wqE`{v6fRd1&48{Te%#foZ4LpVT5d)j5+q ztROkl@Hp?~VyA_pwEHfP%9i2w>mC=}i$R^|F&AC!&qNGjLIVXLmX}TirC{4-m#U6( zOh8N@Xy5B-epPyFhda)!QomgH6b}x^klfhEz-McU_&& z$=VHOooET7QdGF;1h4nBg{D=Vw-C?W0=)59z&fg;f6IkUw=ZMlo?_bs|BYdcHU{*# zSG2&37^CUh#mIJ$qw(Nus7Nb{6j19y7^xX$SE?%Yh?|1d5n;q1~ zCr~?YJ!-Mr(iorOekHsHR@(uPY;+KVTDf*J5tOl@=2HLV2dH^6M; zG9p?HvjLqIp;?(<6JN4{yg#UY;(~p9vEP}Tz3dBhRr`ke@uv$u4$_Qr=P|a?Vds|n zUdD=I)NNqTVH`9lbo$^{{Yf0N47j*p?qvD&=Gx_K<?ekW{mdizX6pxSlp z;S6R{&!io1qjq9MtR0Ur#RzFrRm0$Y8g{}+CctOyO#@Yqg%f5qQ4np`^fSNq{kb`e zoQ2eVe;C!fJlTRyh)kq@iO*CPc6ydWFZE@*Qe1?1VF35VJ46}uBoYXswBCN`f^Y~M z^As>dh;2bLGSklMcb!R!=s~u#RM$Eq*z+JWo7j3Einq_CU`t{!s|h|@fH^5k&9bW) z9lbPJT78>&cBXnMdtDYnU$6%m4x9e5U=K;Ru`Lm?0ltQg?JuQY1z&4CA+85bIf=B@ zkE9D-$q#b48u~WVh2Mj}l!ArHHC{#U9IHb$Ju}JAp^1RHT_5ELkON^n3^dd%v+|+i zp`in+_;nIx3q_n9-?lxaKYV-KQs=7bJ4ZOk6fqq@tNR0?Et`;xJlsz9CP;0*ML5)*weX{>a!)r6xQK|#9LC0jy#%i#%pXcgr6)h#aQI;PM#>cvt?1npe7vSQ_*?W zhAy`85g-Gu%zOqK(wkY5qm_C8=p;YmHW~n+5v(}E2s-z+r-o3?d3QBetUAJEB}Wn1 zg5DoJs&rezAW(0KV3D%@tOgVF7|XmT3*jv5G}MES<#7IH_;l9dX6DsM^*r98Id`7+ z=COq|2d~;lxyLr-9CHJq+i$)2&)!MW>DV2*P_E8W!IucYQ7@Zka{w188Q~*!7wCaz zz>ud;r^@zY52jJLcropd%a=jKbG&$TLD$!gg}g&o*l}MBx(dqSJK<#mcoufrEbmqW zi$VXVQ;*L#?xmJ7(}<{VvO66iry*?5Lp?4L^goxT#fr}8xIvP^)KZ4wjL-MU+tuLtp|h^kID(2*9+@J;zCpJxi=-g6k& zs5jmmp70wC(sx(`(kXTCw~Lmpp!oVmqvyVyR*^luFniTDo-5lld!VT_j`Q@5nqw_l3!YqG4l0_R4-FtI=ImL=yVNCIa zsSGdm97Q796-~4@>3!iefrc?47#xUX9FNYw)25EN^BR`UrA?f=vw+!*#KZQil*0^) z-lo*vf6C|8PJ)Ir0KU10F8kuY#(|JP?oRo?jKk9@`2v0gpGR`AZ5Ja9dV(bC)awO& zBM;O_*olKN`qME5g2lff2d2KsiV=J^(k2sfYsSX;xq3+pw81ttUat!NaDVh6qCaTI zKmezuzvuQO$-dk?S~nok4QD;9zm{E0YXi#yw)(>{0BLj2z9t)z$C$QO>+8gMXR9mq z;)G@za0dfJDu%@$d_eW7Efa~{x_mOAIZL*MvYQDEg_U6x;su%#|0Ol8fR%#Y3Vdl6FNk-uNGwh8WD~# zt$Z)qe!fg%ZkPbgaB@V+gm>^r8vReVbrH}8`? z^dyNEv*4K%Y6QnF97KW8!m6(+!x-7jg}hanOL5$Lm~jpcyc<)d7T1k;>7xga z^T(%5+W`P!uAW-ssm-vqsapyAO9HZB3?sRig>g!Aw1DYK!~W5?MBNe0KWi_3PGzL1 zokiMU40_%nSqAXu4Uh!X`63=Kn#dC+A;|hY%>ms`;@99wR>X0gE>PS+?+0K}{e{`| z-~H6-lkFu6UuqmbmL;qAyb38=OGtDQY81|hVBV}SQW9*z=r}gBK zK6kEC*Ir=J)-Be*U~eU^INHsQaSNWm&icRn&R8$4@EpuAG(!sE|9UV4eYfWuwFlfT zL|`p`TgxVwF{bpeOro)Dj%?`Lg1!UqlJN6iWmR(WfRMbwizc=LyU~ za71@@iz4sbU#bkLoV#p6ff^E~L@?s^ufl|uUb2jSjE#1=1sq|dkEb-alex}G?{bc4h1pm2Gp{{z#p zqZ1{h(KopbMJlji81cMIcf53_YhZm6Y}e2aT7x#Tp@DWY_ns^Rnb1E==@jXrSIa(N z;dXiUQju5MdT#z+m^oYb*of92L!M9G@#zk7!$97a(1O_`-Ov?cb}I(_lJ#rk;OACj z8HA-#>ehPal(00QpRh;dd$(%xQKp#(*O*@5#d<}p#I|;XRH#U@7?Z*!B_~YL+d&mJgTK!68@HLf}lkIsCtm5TB~wBauwH)*dI<2(=Qzf z&^qNn^b>Up;;yGqHHoCb0DT=1eV7p3N<(tLZ#&ten~nN}z1?zJ?4W4W5Syi0qRX`L z?M74Jwd#Y58}$uP3G|ECV8Rz0ZrRJ@Zuy*Vfda@QdzF;f%Dw-Qubpygddh9XXFpTw z`*$igYC2Wq4*GDSgnTCJQL{L|*^Ro4`;(y2RSoJIKz?k$?rRm!*g8U4hs;VdAquD7q(%UyS>LYkOZT?t*jZ#J;b~lB{%) zri5oF?;E$q*ysG#?07XteWxxoi&7}-E&v3-&O%_<`*Ocw3TT-EFvo;>7oL$|z(U;a z!of-VfA6~i?}f1=pv3)8GtR)5-HP%YlA#X~1V>BlD^-3NcJcuWi-6By^dTRpP+|g` zp`_$-*N>|Xtp3aQK{xT;M;C)wS^4T=4qP?Fe~KSHtZ7*%xv5LjMRef}`(&P~Nx8U0 zE3=HQw99qcyF-QKo-w_CwidPrZ;&Wc-6}E147w|3@=9b@B#Mrwzd{Jw!mVYm`oC&MvWCexJIJp*?;TgA8pC_95)p)x zQm~}l35#KjX?v9|+b^zDYf9GDioQ|SXO59{wILSz1r^K}=4$WXg3T@et$XqExq9_7 zOvCq5sX_ulkgSJwKSHX9$#NOB)Wx{J?{@}1IONM|IqqI&(*|2F;_bu})p=k$BABF@ zUErJ8Hl=(-Be8rhJUV^AmLby8>q=QwN>}@Rko>itgPbo304i^|3toC?6nd=}dsck# zJTyrmi!ic~8aPI%!yr)Y0(lI5GerpW8Hj9dRxI_|1ACS_td_FC9RM3nELI1+RB6)& zNxZDe92_^A|33Dgooq*JOeDE~g@J*2eRW0F`1vmu_mg#m44hrU?#r+nb=k>hn{p&~RtuZx>f8FDUD%r=tmoHH%u>bnc zzi<7ohXhhF2xkiolMv8{!oVSs1^iDx!fSAE9=Ewn(EmfUe_j9IH;yld34EdQu`0&@ zf87KI&IuLsAZGOk&;N1hfBY#`3w=<+NluQ*|3ea}bkM;x*+LGKd;ix;{=G!9VHC^* z#oDmYpXC4Ja{ew6vk5A1b5siazpwh&JO7tB|G&N%DuF;K^{Y&W1=CKGA=hyGp(;yh zP?WA9^G7zbUv7q#aW}`Et;KHDm~cp9S>5VhV3`M92B{p1ek#*F#@fB@#M;Na#PC|m zWtW{_d-i-I%XOCKd%wcLi_?_hwZs}}^>5;-6`7mV%Beyk5@UT4P)1T`i+1~2dw1)- z=Hu}fN!R!C?6W?vwkhmQrqFcRZ~UrPDn|RyUDsoU?qXGn=y)^*W^4DPuUp8M-6yDw?ARxh@-f5L9g=sB`=i;S_Kvd#&T zcWX(e0({z-JMx_yp8Rg>)H?{klQpL9dM0}Q4$X%ehwOIs`mY$E$^>J-)(1PGPDkgx zPMH<=GiyBE4x13)TChNgdR5#nCjW?`uGf)+-+sH-C90SDOjnfu@jZ2aAQR4hMfoyx zVzPs*r25GgF%jmA3j0co$fnVtRHGE%-Q@aqw$weg+hjU?&Nf?-pzJ%~mQNUOQqG61l& zVtBc+?TUx^zmWU5pCPp>P>=rlJECz!vrH(?NfcN!dPBq^;?R2Pez;na`TRI4;h~>c zs+JHf@U(oFhj?3~h}nYuQA!04*{!2(JIiNxn8fe26H@=8`|zBgUh8=7uzWp>aXXBj z8H>LN)YH^w!ZygH9ag1E-i_GcP>gNIjIYX?^fs`aPJiotWwdz^t^$6ntvzjGnkf@K zj$N4S`A?<&_5fAFF5eg?AKc$?iD#Ac#6CAoK2w#_`aHfD!tqP#JB9r_Xxt!rKESIy zI>{1gg~DV9za)5Pl$Nx!O{`E*h-Sr=I1WEBDS*% zOC{gxI#cW5#`6+$jy9c3Et3j!o?5-J*_;AtpGlG~KGq+-&D?oGBu(mi<)x3|E~VU` z1jb0DYAuqY-R_SY3U|J`S3DCMwN2Awjs8e;Ba~rJKslHjRt0N8(wz6ktW$X%Ys`j| z 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⁡OO=ufkm#KasZJHwi$E;rz!JK>9Xkp;$kr)9 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 Date: Tue, 7 Apr 2026 12:49:18 +0100 Subject: [PATCH 21/30] feat(analysis): add emotional averages to stance markers --- frontend/src/components/CulturalStats.tsx | 51 ++++++++++++++--------- frontend/src/types/ApiTypes.ts | 4 ++ server/analysis/cultural.py | 34 ++++++++++++++- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/CulturalStats.tsx b/frontend/src/components/CulturalStats.tsx index e62b956..430937a 100644 --- a/frontend/src/components/CulturalStats.tsx +++ b/frontend/src/components/CulturalStats.tsx @@ -39,6 +39,21 @@ const CulturalStats = ({ data }: CulturalStatsProps) => { return `${dominantLabel} (${(dominant[1] * 100).toFixed(1)}%)`; }; + const stanceSublabel = ( + per1kTokens: number | undefined, + emotionAvg: Record | undefined, + ) => { + const rateLabel = + typeof per1kTokens === "number" + ? `${per1kTokens.toFixed(1)} per 1k words` + : "Word frequency"; + const emotionLabel = topEmotion(emotionAvg); + + return emotionLabel === "—" + ? rateLabel + : `${rateLabel} • Avg mood: ${emotionLabel}`; + }; + return (

@@ -107,41 +122,37 @@ const CulturalStats = ({ data }: CulturalStatsProps) => { diff --git a/frontend/src/types/ApiTypes.ts b/frontend/src/types/ApiTypes.ts index 3143c32..dcd5969 100644 --- a/frontend/src/types/ApiTypes.ts +++ b/frontend/src/types/ApiTypes.ts @@ -168,6 +168,10 @@ type StanceMarkers = { certainty_per_1k_tokens: number; deontic_per_1k_tokens: number; permission_per_1k_tokens: number; + hedge_emotion_avg?: Record; + certainty_emotion_avg?: Record; + deontic_emotion_avg?: Record; + permission_emotion_avg?: Record; }; type EntityEmotionAggregate = { diff --git a/server/analysis/cultural.py b/server/analysis/cultural.py index af64091..47e8e4f 100644 --- a/server/analysis/cultural.py +++ b/server/analysis/cultural.py @@ -67,6 +67,12 @@ class CulturalAnalysis: def get_stance_markers(self, df: pd.DataFrame) -> dict[str, Any]: s = df[self.content_col].fillna("").astype(str) + emotion_exclusions = {"emotion_neutral", "emotion_surprise"} + emotion_cols = [ + c + for c in df.columns + if c.startswith("emotion_") and c not in emotion_exclusions + ] hedge_pattern = re.compile( r"\b(maybe|perhaps|possibly|probably|likely|seems|seem|i think|i feel|i guess|kind of|sort of|somewhat)\b" @@ -88,7 +94,7 @@ class CulturalAnalysis: 0, 1 ) - return { + result = { "hedge_total": int(hedge_counts.sum()), "certainty_total": int(certainty_counts.sum()), "deontic_total": int(deontic_counts.sum()), @@ -107,6 +113,32 @@ class CulturalAnalysis: ), } + if emotion_cols: + emo = df[emotion_cols].apply(pd.to_numeric, errors="coerce").fillna(0.0) + + result["hedge_emotion_avg"] = ( + emo.loc[hedge_counts > 0].mean() + if (hedge_counts > 0).any() + else pd.Series(0.0, index=emotion_cols) + ).to_dict() + result["certainty_emotion_avg"] = ( + emo.loc[certainty_counts > 0].mean() + if (certainty_counts > 0).any() + else pd.Series(0.0, index=emotion_cols) + ).to_dict() + result["deontic_emotion_avg"] = ( + emo.loc[deontic_counts > 0].mean() + if (deontic_counts > 0).any() + else pd.Series(0.0, index=emotion_cols) + ).to_dict() + result["permission_emotion_avg"] = ( + emo.loc[perm_counts > 0].mean() + if (perm_counts > 0).any() + else pd.Series(0.0, index=emotion_cols) + ).to_dict() + + return result + def get_avg_emotions_per_entity( self, df: pd.DataFrame, top_n: int = 25, min_posts: int = 10 ) -> dict[str, Any]: From 8fa4f3fbdfb20a84c378501c96e11af05a431dac Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 12:52:48 +0100 Subject: [PATCH 22/30] refactor(report): move data pipeline above ethnographic analysis --- report/main.tex | 231 ++++++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 106 deletions(-) diff --git a/report/main.tex b/report/main.tex index 581602e..3f49631 100644 --- a/report/main.tex +++ b/report/main.tex @@ -111,6 +111,19 @@ Looking at when a community is active can reveal quite a lot about its nature an \subsubsection{Cultural Markers} Cultural markers are the words, phrases, memes, and behaviours that are specific to a particular community and signal that someone is a member of it. These might include in-jokes, niche slang, recurring references, or even particular ways of formatting posts. In the context of digital ethnography, identifying these markers is useful because they reveal how communities build a shared identity and distinguish themselves from outsiders. +Some patterns, such as usage of words like "we, us, our, ourselves", where posts are referring to themselves as a community might have different sentiment to posts where words like "they, them, their, themselves" are used. These are known as "identity markers" and they can be used to identify how welcoming a community might be to outsiders. + +\subsubsection{Stance Markers} +Stance Markers refer to the usage of different phrasing patterns which can reveal the speakers attitude towards topics. There are different kinds of these phrasings, such as hedge, certainty, deontic and permission patterns. + +\textbf{Hedge Patterns} are usually phrases that contain words like "maybe, possibly, probably, i think, i feel" and generally mean that someone is unsure or suspicious about something. + +\textbf{Certainty Patterns} contain phrases like "definitely, certainly, clearly, obviously" and as the name suggests, imply certainty or assuredness. + +\textbf{Deontic Patterns} contains phrases that imply obligation, such as "must, should, need, have to". In the context of online communities, these patterns are often used to assert authority or to reinforce communal norms and "unwritten rules." + +\textbf{Permission Patterns} refer to phrases where someone is asking permision, like "can, allowed, ok, permitted". These patterns could serve as an indicator of a user's status within an online community. + \subsection{Natural Language Processing} \textbf{Natural Language Processing} is a branch of artificial intelligence that allows machines to interpret, analyse and generate human language. The aim of NLP models is not only to understand single words individually, but to be able to understand the context of those words in a broader paragraph or story. @@ -163,7 +176,7 @@ The dataset is drawn from four distinct online platforms, each of which represen Reddit's hierarchical comment threading enables deep conversational analysis and reply-chain metrics, whereas YouTube comments are largely flat and unthreaded. Boards.ie occupies a middle ground, with linear threads but a more intimate community character. Taken together, the four sources offer variation in interaction structure, community age, demographic composition, and linguistic register, all of which are factors that the system's analytical modules are designed to detect and compare. -Collecting data across multiple platforms also introduces the challenge of normalisation. Posts, comments, and metadata fields differ in schema and semantics across sources. A core design requirement of the system is the normalisation of these inputs into a unified event-based internal representation, allowing the same analytical pipeline to operate uniformly regardless of the source. +Due to data being collected across multiple platforms, they must be normalised into a single data model. Posts, comments, and metadata fields differ in schema and semantics across sources. A core design requirement of the system is the normalisation of these inputs into a unified event-based internal representation, allowing the same analytical pipeline to operate uniformly regardless of the source. \newpage \section{Analysis} @@ -427,111 +440,6 @@ Flask was chosen for its simplicity, familiarity and speed of development. It al \subsubsection{React Frontend} React was chosen for the frontend due to its massive library of pre-built components with efficient rendering capabilities and ability to display many different types of data. The frontend will be structured around a tabbed interface, with each tab corresponding to a different analytical endpoint (e.g., temporal analysis, linguistic analysis, emotional analysis). Each tab will fetch data from the backend API and render it using appropriate visualisation libraries (react-wordcloud for word clouds, react-chartjs-2 for charts, etc). The frontend will also include controls for filtering the dataset based on keywords, date ranges, and data sources. - -\subsection{Ethnographic Analysis} -The main goal of this project is to provide a tool that can assist researchers with ethnographic analysis of online communities. Therefore, ethnographic analysis will be a core component of the system. - -Ethnographic analysis can be carried out from many different perspectives, such as the perspective of a single user or the community as a whole. The system is designed to support both of these perspectives, as well as the ability to zoom in and out between them. For example, a researcher might want to look at the overall emotional tone of a community, but then zoom in to see how a specific user contributes to that tone. - -The system is designed to support multiple types of analysis, such as: -\begin{itemize} - \item \textbf{Temporal Analysis}: looking at when a community is active and how that activity changes over time. - \item \textbf{Linguistic Analysis}: looking at the words and phrases that are commonly used in a community, and how they relate to identity and culture. - \item \textbf{Emotional Analysis}: looking at the emotional tone of a community, and how it varies across different topics or users. - \item \textbf{User Analysis}: looking at the behaviour and activity of individual users, and how they contribute to the community. - \item \textbf{Interaction Analysis}: looking at how users interact with each other, such as who replies to whom and how conversations develop. - \item \textbf{Cultural Analysis}: looking at the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. -\end{itemize} - -Each of these types of analysis are available at different API endpoints for any given dataset, and the frontend is designed to allow users to easily switch between them and explore the data from different angles. - -For each type of analysis that involves analysing the content of the posts themselves, they will be split into tokens and stop words will be stripped from them, which makes analysis easier. - -\subsubsection{Temporal Analysis} -Temporal analysis allows researchers to understand what a community is talking about over time, and how the emotional tone of the community changes over time. For example, a researcher might want to see how discussions around a specific topic evolve over time, or how the emotional tone of a community changes in response to external events. - -However a major limitation of the data captured for this system, whether it's the Cork dataset, or any automatically fetched dataset, it will only stretch at most a few weeks back in time. This is because the system is designed to fetch only the most recent posts and comments from social media platforms, which means that it will not capture historical data beyond a certain point. Therefore, while temporal analysis can still be carried out on the dataset, it will be limited to a relatively short timeframe. - -In this system, temporal analysis will be limited to: -\begin{itemize} - \item Event frequency per day. - \item Weekday--hour heatmap data representing activity distribution. -\end{itemize} - -\textbf{Average reply time per emotion} was considered as a potential temporal analysis metric, but was eventually excluded due to inconsistent and statistically insignificant results that yielded no meaningful analytical insight. - -\subsubsection{Linguistic Analysis} -Linguistic analysis allows researchers to understand the language and words used in a community. For example, a researcher might want to see what words are most commonly used in a community, or how the language used in a community relates to identity and culture. - -Splitting each - -In this system, linguistic analysis will include: -\begin{itemize} - \item Word frequency statistics excluding standard and domain-specific stopwords. - \item Common bi-grams and tri-grams from textual content. - \item Lexical diversity metrics for the dataset. -\end{itemize} - -The word frequencies and n-gram metrics were chosen because they can provide insights into the language and phrases used commonly in an online community, which is important for ethnographic analysis and understanding a community fully. Lexical diversity metrics such as the total number of unique tokens versus the total number of tokens can show if a specific culture often repeats phrases (like memes, slang etc.) or if they often have structured, serious discussion without repeating themeselves. - -Outlining a list of stopwords is essential for linguistic analysis, as it filters out common words that wouldn't be useful for linguistic analysis. Stop Word lists can be provided by a Python library such as NLTK. - -In addition to standard stop words, the system also excludes link tokens such as "www", "http", and "https" from the word frequency analysis, as social media users will often include links in their posts and comments, and these tokens can become quite common and skew the word frequency results without adding meaningful insight. - -\subsubsection{User Analysis} -User analysis allows researchers to understand the behaviour and activity of individual users within a community. For example, a researcher might want to see who the most active users are in a community, or how different users contribute to the overall emotional tone of the community. - -In this system, user analysis will include: -\begin{itemize} - \item Identification of top users based on activity. - \item Per-user activity such as: - \begin{itemize} - \item Total number of events (posts and comments). - \item Average emotion distribution across their events. - \item Average topic distribution across their events. - \item Comment-to-post ratio. - \item Vocabulary information such as top words used and lexical diversity. - \end{itemize} -\end{itemize} - -Identifying top users allows us to see the most active and prolific posters in a community, which might often be site-specific bots that comment on every post or deleted users, which often show up as simply "[Deleted User]" and can aggregate together in statistics . An example might be a User Moderator bot on Reddit, seen below. - -\begin{figure}[h] - \centering - \includegraphics[width=0.75\textwidth]{img/reddit_bot.png} - \caption{An AutoModerator Bot on r/politics} - \label{fig:bot} -\end{figure} - -While it's impossible to filter out all of these bots, deleted users can simply be filtered out using an exclusion list. - -\subsubsection{Interactional Analysis} -Instead of per-user analysis, interactional analysis looks at the interactions between users, such as who replies to who and who is contributing the most to the conversations. - -In this system, interactional analysis will include: -\begin{itemize} - \item Average conversation thread depth. - \item Top interaction pairs between users. - \item An interaction graph based on user relationships. - \item Conversation concentration metrics such as who is contributing the most to the conversations and how much of the conversation is dominated by a small number of users. -\end{itemize} - -For simplicity, an interaction is defined as a reply from one user to another, which can be either a comment replying to a post or a comment replying to another comment. The system will not attempt to capture more complex interactions such as mentions or indirect references between users, as these would require more advanced NLP techniques. - -\subsubsection{Emotional Analysis} -Emotional analysis allows researchers to understand the emotional tone of a community, and how it varies across different topics and users. - -In this system, emotional analysis will include: -\begin{itemize} - \item Average emotional by topic. - \item Overall average emotional distribution across the dataset. - \item Dominant emotion distributions for each event - \item Average emotion by data source -\end{itemize} - -\subsubsection{Cultural Analysis} -Cultural analysis allows researchers to understand the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. While some of this is covered in the linguistic analysis, cultural analysis will focus more on the identity and stance-related markers that are present in the language of the community. - \subsection{Data Pipeline} As this project is focused on the collection and analysis of online community data, the primary component that must be well-designed is the data pipeline, which encompasses the processes of data ingestion, normalisation, enrichment, storage, and retrieval for analysis. @@ -618,6 +526,117 @@ The \texttt{events} table in PostgreSQL contains the following fields: \subsubsection{Data Retrieval} The stored dataset can then be retrieved through the Flask API endpoints for analysis. The API supports filtering by keywords and date ranges, as well as grouping and aggregation for various analytical outputs. +\subsection{Ethnographic Analysis} +The main goal of this project is to provide a tool that can assist researchers with ethnographic analysis of online communities. Therefore, ethnographic analysis will be a core component of the system. + +Ethnographic analysis can be carried out from many different perspectives, such as the perspective of a single user or the community as a whole. The system is designed to support both of these perspectives, as well as the ability to zoom in and out between them. For example, a researcher might want to look at the overall emotional tone of a community, but then zoom in to see how a specific user contributes to that tone. + +The system is designed to support multiple types of analysis, such as: +\begin{itemize} + \item \textbf{Temporal Analysis}: looking at when a community is active and how that activity changes over time. + \item \textbf{Linguistic Analysis}: looking at the words and phrases that are commonly used in a community, and how they relate to identity and culture. + \item \textbf{Emotional Analysis}: looking at the emotional tone of a community, and how it varies across different topics or users. + \item \textbf{User Analysis}: looking at the behaviour and activity of individual users, and how they contribute to the community. + \item \textbf{Interaction Analysis}: looking at how users interact with each other, such as who replies to whom and how conversations develop. + \item \textbf{Cultural Analysis}: looking at the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. +\end{itemize} + +Each of these types of analysis are available at different API endpoints for any given dataset, and the frontend is designed to allow users to easily switch between them and explore the data from different angles. + +For each type of analysis that involves analysing the content of the posts themselves, they will be split into tokens and stop words will be stripped from them, which makes analysis easier. + +\subsubsection{Temporal Analysis} +Temporal analysis allows researchers to understand what a community is talking about over time, and how the emotional tone of the community changes over time. For example, a researcher might want to see how discussions around a specific topic evolve over time, or how the emotional tone of a community changes in response to external events. + +However a major limitation of the data captured for this system, whether it's the Cork dataset, or any automatically fetched dataset, it will only stretch at most a few weeks back in time. This is because the system is designed to fetch only the most recent posts and comments from social media platforms, which means that it will not capture historical data beyond a certain point. Therefore, while temporal analysis can still be carried out on the dataset, it will be limited to a relatively short timeframe. + +In this system, temporal analysis will be limited to: +\begin{itemize} + \item Event frequency per day. + \item Weekday--hour heatmap data representing activity distribution. +\end{itemize} + +\textbf{Average reply time per emotion} was considered as a potential temporal analysis metric, but was eventually excluded due to inconsistent and statistically insignificant results that yielded no meaningful analytical insight. + +\subsubsection{Linguistic Analysis} +Linguistic analysis allows researchers to understand the language and words used in a community. For example, a researcher might want to see what words are most commonly used in a community, or how the language used in a community relates to identity and culture. + +In this system, linguistic analysis will include: +\begin{itemize} + \item Word frequency statistics excluding standard and domain-specific stopwords. + \item Common bi-grams and tri-grams from textual content. + \item Lexical diversity metrics for the dataset. +\end{itemize} + +The word frequencies and n-gram metrics were chosen because they can provide insights into the language and phrases used commonly in an online community, which is important for ethnographic analysis and understanding a community fully. Lexical diversity metrics such as the total number of unique tokens versus the total number of tokens can show if a specific culture often repeats phrases (like memes, slang etc.) or if they often have structured, serious discussion without repeating themeselves. + +Outlining a list of stopwords is essential for linguistic analysis, as it filters out common words that wouldn't be useful for linguistic analysis. Stop Word lists can be provided by a Python library such as NLTK. + +In addition to standard stop words, the system also excludes link tokens such as "www", "http", and "https" from the word frequency analysis, as social media users will often include links in their posts and comments, and these tokens can become quite common and skew the word frequency results without adding meaningful insight. + +\subsubsection{User Analysis} +User analysis allows researchers to understand the behaviour and activity of individual users within a community. For example, a researcher might want to see who the most active users are in a community, or how different users contribute to the overall emotional tone of the community. + +In this system, user analysis will include: +\begin{itemize} + \item Identification of top users based on activity. + \item Per-user activity such as: + \begin{itemize} + \item Total number of events (posts and comments). + \item Average emotion distribution across their events. + \item Average topic distribution across their events. + \item Comment-to-post ratio. + \item Vocabulary information such as top words used and lexical diversity. + \end{itemize} +\end{itemize} + +Identifying top users allows us to see the most active and prolific posters in a community, which might often be site-specific bots that comment on every post or deleted users, which often show up as simply "[Deleted User]" and can aggregate together in statistics . An example might be a User Moderator bot on Reddit, seen below. + +\begin{figure}[h] + \centering + \includegraphics[width=0.75\textwidth]{img/reddit_bot.png} + \caption{An AutoModerator Bot on r/politics} + \label{fig:bot} +\end{figure} + +While it's impossible to filter out all of these bots, deleted users can simply be filtered out using an exclusion list. + +\subsubsection{Interactional Analysis} +Instead of per-user analysis, interactional analysis looks at the interactions between users, such as who replies to who and who is contributing the most to the conversations. + +In this system, interactional analysis will include: +\begin{itemize} + \item Average conversation thread depth. + \item Top interaction pairs between users. + \item An interaction graph based on user relationships. + \item Conversation concentration metrics such as who is contributing the most to the conversations and how much of the conversation is dominated by a small number of users. +\end{itemize} + +For simplicity, an interaction is defined as a reply from one user to another, which can be either a comment replying to a post or a comment replying to another comment. The system will not attempt to capture more complex interactions such as mentions or indirect references between users, as these would require more advanced NLP techniques. + +\subsubsection{Emotional Analysis} +Emotional analysis allows researchers to understand the emotional tone of a community, and how it varies across different topics and users. + +In this system, emotional analysis will include: +\begin{itemize} + \item Average emotional by topic. + \item Overall average emotional distribution across the dataset. + \item Dominant emotion distributions for each event + \item Average emotion by data source +\end{itemize} + +\subsubsection{Cultural Analysis} +Cultural analysis allows researchers to understand the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. While some of this is covered in the linguistic analysis, cultural analysis will focus more on the identity and stance-related markers that are present in the language of the community. + +In this system, cultural analysis will include: +\begin{itemize} + \item In-Group vs Out-Group phrasing + \item Average emotion for in-group vs out-group phrasing + \item Stance Markers + \item Average emotions per stance marker type + \item Average emotions per entity +\end{itemize} + \subsection{Automatic Data Collection} Originally, the system was designed to only support manual dataset uploads, where users would collect their own data from social media platforms and format it into the required \texttt{.jsonl} format. From 8b4e13702ecf8e475155428743223ae4c65a3743 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 12:55:01 +0100 Subject: [PATCH 23/30] docs(report): add ucc crest to title page --- report/img/ucc_crest.png | Bin 0 -> 27877 bytes report/main.tex | 24 ++++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 report/img/ucc_crest.png diff --git a/report/img/ucc_crest.png b/report/img/ucc_crest.png new file mode 100644 index 0000000000000000000000000000000000000000..8e65177eb86c47a65c34725450aa2dbbc297f1b1 GIT binary patch literal 27877 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 Hunhe_#_T!2 literal 0 HcmV?d00001 diff --git a/report/main.tex b/report/main.tex index 3f49631..5c0b757 100644 --- a/report/main.tex +++ b/report/main.tex @@ -8,27 +8,39 @@ \begin{titlepage} \centering - \vspace*{3cm} - - {\Huge \textbf{Web-Based Tool for Observing and Analysing Online Communities} \par} + + % UCC Crest (clickable link) + \vspace*{1.5cm} + \href{https://www.ucc.ie/en/}{% + \includegraphics[width=0.25\textwidth]{img/ucc_crest.png} + } \vspace{2cm} + + % Title + {\Huge\bfseries Web-Based Tool for Observing\\[0.3cm] + and Analysing Online Communities \par} + \vspace{2.5cm} + + % Author {\Large Dylan De Faoite \par} \vspace{0.5cm} + % Date {\large April 2026 \par} \vfill + % Degree + Institution {\large - Bachelor of Science in Computer Science \\ - University College Cork \\ + Bachelor of Science in Computer Science \\[0.2cm] + University College Cork \\[0.2cm] Supervisor: Paolo Palmeiri \par} - \vspace{2cm} + \vspace{1.5cm} \end{titlepage} From a34786935360637e05eb60dcd6de0efbace9496a Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 15:22:47 +0100 Subject: [PATCH 24/30] docs(report): add more justification for ethnographic endpoints --- report/main.tex | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/report/main.tex b/report/main.tex index 5c0b757..1f148b0 100644 --- a/report/main.tex +++ b/report/main.tex @@ -602,6 +602,8 @@ In this system, user analysis will include: \end{itemize} \end{itemize} +Initially the user endpoint contained the interactional statistics as well, as a case could be made for the user analysis and interaction analysis being combined, however a distinction can be made between individual user analysis and user analysis on a larger, community-level scale focused on interactions. This allows the user endpoint to stay focused on singular user analysis while still using NLP outputs like emotions and topics. + Identifying top users allows us to see the most active and prolific posters in a community, which might often be site-specific bots that comment on every post or deleted users, which often show up as simply "[Deleted User]" and can aggregate together in statistics . An example might be a User Moderator bot on Reddit, seen below. \begin{figure}[h] @@ -618,7 +620,6 @@ Instead of per-user analysis, interactional analysis looks at the interactions b In this system, interactional analysis will include: \begin{itemize} - \item Average conversation thread depth. \item Top interaction pairs between users. \item An interaction graph based on user relationships. \item Conversation concentration metrics such as who is contributing the most to the conversations and how much of the conversation is dominated by a small number of users. @@ -626,6 +627,8 @@ In this system, interactional analysis will include: For simplicity, an interaction is defined as a reply from one user to another, which can be either a comment replying to a post or a comment replying to another comment. The system will not attempt to capture more complex interactions such as mentions or indirect references between users, as these would require more advanced NLP techniques. +\textbf{Average reply chain depth} was considered as a metric, however forum-based social media sites, such as boards.ie, do not have a way to reply to comments in the same way that Reddit does, therefore the concept of "reply chains" doesn't apply cleanly in the same way. One possible solution is to infer reply relationships from explicit user mentions embedded in content of the post, but this is not a reliable method. + \subsubsection{Emotional Analysis} Emotional analysis allows researchers to understand the emotional tone of a community, and how it varies across different topics and users. @@ -637,6 +640,10 @@ In this system, emotional analysis will include: \item Average emotion by data source \end{itemize} +It is emphasised that emotional analysis is inaccurate on an individual post level as the models cannot fully capture the nuance of human interaction and slang. Warnings will be presented to the user in the frontend that AI outputs can possible be misleading on an individual scale, and accuracy only increases with more posts. Even then it will not be perfect. + +In an ideal world, the models are accurate enough to capture general emotions on a macro-scale. + \subsubsection{Cultural Analysis} Cultural analysis allows researchers to understand the cultural markers and identity signals that are present in a community, such as slang, memes, and recurring references. While some of this is covered in the linguistic analysis, cultural analysis will focus more on the identity and stance-related markers that are present in the language of the community. @@ -670,7 +677,15 @@ Creating a base interface for what a connector should look like allows for the e The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. -\subsection{Database vs On-Disk Storage} +\subsection{Asynchronous Processing} +The usage of NLP models for tasks such as sentiment analysis, topic classification, and entity recognition can be computationally intensive, especially for large datasets. To prevent the Flask API from blocking while these tasks are being processed, an asynchronous processing queue will be implemented using \textbf{Redis} and \textbf{Celery}. + +When NLP processing is triggered or data is being fetched from social media APIs, a task will be added to the Redis queue. Celery workers will then pop tasks off the Redis queue and process these tasks in the background, which ensures the API to remain responsive to user requests. This approach also allows for better scalability, as additional workers can be added to handle increased load. + +Some of the these tasks, like fetching data from social media APIs are very long-running tasks that can take hours to complete. By using asynchronous processing that updates the database with progress updates, users can see the status of their data fetching through the frontend. + +\subsection{Design Tradeoffs} +\subsubsection{Database vs On-Disk Storage} Originally, the system was designed to store \texttt{json} datasets on disk and load them into memory for processing. This was simple and time-efficient for early development and testing. However, as the functionality of the system expanded, it become clear that a more persistent and scalable storage solution was needed. Storing datasets in a database allows for more efficient querying, filtering, and updating of data without needing to reload entire datasets into memory. However the priamry benefit of using a database is support for \textbf{ multiple users and multiple datasets per user}. @@ -679,27 +694,21 @@ An additional benefit of using a database was that it allowed the NLP processing \texttt{PostgreSQL} was chosen as the database solution due to its robustness, support for complex queries, and compatibility with Python through \texttt{psycopg2}. PostgreSQL's support for JSONB fields allows for storage of unstructured NLP outputs, which alternatives like SQLite does not support. -\subsection{Asynchronous Processing} -The usage of NLP models for tasks such as sentiment analysis, topic classification, and entity recognition can be computationally intensive, especially for large datasets. To prevent the Flask API from blocking while these tasks are being processed, an asynchronous processing queue will be implemented using \textbf{Redis} and \textbf{Celery}. +\subsubsection{Unified Data Model vs Split Data Model} -When NLP processing is triggered or data is being fetched from social media APIs, a task will be added to the Redis queue. Celery workers will then pop tasks off the Redis queue and process these tasks in the background, which ensures the API to remain responsive to user requests. This approach also allows for better scalability, as additional workers can be added to handle increased load. - -Some of the these tasks, like fetching data from social media APIs are very long-running tasks that can take hours to complete. By using asynchronous processing that updates the database with progress updates, users can see the status of their data fetching through the frontend. - -\subsection{Docker Deployment} -Docker Compose will be used to containerise the entire application, including: +\subsection{Deployment} +Docker Compose is used to containerise the entire application, including: \begin{itemize} \item The Flask backend API \item The React frontend interface \item The PostgreSQL database \item The Redis server for task queuing \item Celery workers for asynchronous processing - \item NLP model caching and management \end{itemize} -In addition, the source code for the backend and frontend will be mounted as volumes within the containers to allow for live code updates during development, which will speed up the process. +During development, the source code for the backend and frontend will be mounted as volumes within the containers to allow for live code updates during development, which will speed up the process. -Enviornment variables, such as database credentials and social media API keys, will be managed through an \texttt{.env} file that is passed into the Docker containers through \texttt{docker-compose.yml}. +Enviornment variables, such as database credentials and social media API keys, will be managed through an \texttt{.env} file that is passed into the Docker containers through \texttt{docker-compose.yaml}. \newpage From 3df6776111c1bace9970e9d259b3ba97f6cac37c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Tue, 7 Apr 2026 18:04:16 +0100 Subject: [PATCH 25/30] docs(report): add decision tradeoff decisions --- report/main.tex | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/report/main.tex b/report/main.tex index 1f148b0..eb8c2fe 100644 --- a/report/main.tex +++ b/report/main.tex @@ -444,11 +444,13 @@ The system will follow a client-server architecture, with a Flask-based backend The reasoning behind this architecture is that it allows the analytics to be aggregated and computed on the server side using Pandas which is much faster than doing it on the client frontend. The frontend will focus on rendering and visualising the data. -\subsubsection{Flask API} +\subsubsection{API Design} The Flask backend will expose a RESTful API with endpoints for dataset management, authentication and user management, and analytical queries. Flask will call on backend components for data parsing, normalisation, NLP processing and database interfacing. Flask was chosen for its simplicity, familiarity and speed of development. It also has many extensions that can be used for authentication (Flask-Bcrypt, Flask-Login). +The API is separated into three separate groups, \textbf{authentication}, \textbf{dataset management} and \textbf{analysis}. + \subsubsection{React Frontend} React was chosen for the frontend due to its massive library of pre-built components with efficient rendering capabilities and ability to display many different types of data. The frontend will be structured around a tabbed interface, with each tab corresponding to a different analytical endpoint (e.g., temporal analysis, linguistic analysis, emotional analysis). Each tab will fetch data from the backend API and render it using appropriate visualisation libraries (react-wordcloud for word clouds, react-chartjs-2 for charts, etc). The frontend will also include controls for filtering the dataset based on keywords, date ranges, and data sources. @@ -678,11 +680,21 @@ Creating a base interface for what a connector should look like allows for the e The connector registry is designed so that any new connector implementing \texttt{BaseConnector} is automatically discovered and registered at runtime, without requiring changes to any existing code. This allows for a modular and extensible architecture where new data sources can be integrated with minimal effort. \subsection{Asynchronous Processing} -The usage of NLP models for tasks such as sentiment analysis, topic classification, and entity recognition can be computationally intensive, especially for large datasets. To prevent the Flask API from blocking while these tasks are being processed, an asynchronous processing queue will be implemented using \textbf{Redis} and \textbf{Celery}. +The usage of NLP models for tasks such as sentiment analysis, topic classification, and entity recognition can be computationally intensive, especially for large datasets. In addition, fetching large datasets from sites like Reddit and YouTube takes a lot of time, due to the sequential nature of data fetching and severe rate limits on even authenticated Reddit accounts. To prevent the Flask API from blocking while these tasks are being processed, an asynchronous processing queue will be implemented using \textbf{Redis} and \textbf{Celery}. -When NLP processing is triggered or data is being fetched from social media APIs, a task will be added to the Redis queue. Celery workers will then pop tasks off the Redis queue and process these tasks in the background, which ensures the API to remain responsive to user requests. This approach also allows for better scalability, as additional workers can be added to handle increased load. +\subsubsection{Dataset Enrichment} +A non-normalised dataset will be passed into Celery along with the dataset id and the user id of the dataset owner. At this point, the program is running separately to the main Flask thread. The program then calls on the \textbf{Normalisation \& Enrichment Module} to: +\begin{itemize} + \item Flatten the dataset from posts with nested comments to unified event data model. + \item Add derived timestamp columns to aid with temporal analysis + \item Add topic, emotional and entity NLP analysis as columns +\end{itemize} + +\subsubsection{Data Fetching} +If the user triggers a data auto-fetch from any given social media site, a task will be added to the Redis queue. Celery workers will then pop tasks off the Redis queue and process these tasks in the background, which ensures the API to remain responsive to user requests. The specific data connectors are called and the data fetching begins. Once the data has been fetched from all social media sites, NLP processing begins and we are at the same stage as before. + +Asynchronous processing is especially important for automatic data-fetching, as particularly large datasets can take hours to fetch. -Some of the these tasks, like fetching data from social media APIs are very long-running tasks that can take hours to complete. By using asynchronous processing that updates the database with progress updates, users can see the status of their data fetching through the frontend. \subsection{Design Tradeoffs} \subsubsection{Database vs On-Disk Storage} @@ -695,6 +707,26 @@ An additional benefit of using a database was that it allowed the NLP processing \texttt{PostgreSQL} was chosen as the database solution due to its robustness, support for complex queries, and compatibility with Python through \texttt{psycopg2}. PostgreSQL's support for JSONB fields allows for storage of unstructured NLP outputs, which alternatives like SQLite does not support. \subsubsection{Unified Data Model vs Split Data Model} +The choice between a \textbf{Unified Data Model} and a \textbf{Split Data Model} led to many swaps in design for the API. + +\paragraph{The Case for a Unified Data Model} +\begin{itemize} + \item \textbf{Simpler Schema}: One \texttt{events} table rather than split comments and posts tables + \item \textbf{Simpler Pipeline}: The same pipeline works for both types + \item \textbf{Differentiation Possible}: Through the \texttt{type} column, we can still differentiate between a post and a comment, though more awkwardly. +\end{itemize} + +But it led to a simplification of some of the content, for example a post title is very different from the comment content. Reply chains must be reconstructed using the \texttt{reply\_to} and \texttt{parent\_id} fields and some fields, like \texttt{reply\_to} will be null depending on the data source. For example, boards.ie does not support nested replies. + +\paragraph{The Case for a Split Data Model} +\begin{itemize} + \item \textbf{Per-Type Analysis}: A post has different attributes to a comment, extending the analysis for post-specific metrics (like title sentiment, title-to-post length ratio) is easier later down the line. + \item \textbf{Accurate Reply Relationship}: Reply relationships are naturally represented, comments have a foreign key to posts, no reconstruction needed. +\end{itemize} + +However each analytical query would either need to be post or comment specific, or require a table merge later in the pipeline. For ethnographic analysis, the distinction between a post and a comment is minimal. From a research point of view a post and a comment are both just a user saying something at a point in time, and treating them uniformly reflects that. + +The decision to \textbf{stick with a unified data model was made} since the downsides of a Unified Model could be mitigated through reconstruction of reply chains using specific fields, and being able to differentiate between a post and a comment using a type field. Largely, in ethnography, a post and a comment are both just a user saying something at a point in time, and even in cases where they might need to be treated differently (reply-chains, interactions graphs), that distinction can still be made. \subsection{Deployment} Docker Compose is used to containerise the entire application, including: @@ -713,6 +745,7 @@ Enviornment variables, such as database credentials and social media API keys, w \newpage \section{Implementation} +\subsection{} \newpage \section{Evaluation} From e274b8295ae6982495ca1280c66ea5cc02c84e20 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Wed, 8 Apr 2026 17:28:41 +0100 Subject: [PATCH 26/30] docs(report): add citations and start implementation section --- report/main.tex | 51 +++++++++++++++++++++++++++++++++++++++++-- report/references.bib | 7 ++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 report/references.bib diff --git a/report/main.tex b/report/main.tex index eb8c2fe..4e15da8 100644 --- a/report/main.tex +++ b/report/main.tex @@ -1,4 +1,4 @@ -\documentclass{article}[12pt] +\documentclass{article} \usepackage{graphicx} \usepackage{setspace} \usepackage{hyperref} @@ -6,6 +6,8 @@ \begin{document} +\bibliographystyle{plain} + \begin{titlepage} \centering @@ -658,6 +660,12 @@ In this system, cultural analysis will include: \item Average emotions per entity \end{itemize} +\subsection{Frontend Design} +The frontend is built with React and TypeScript, and the analysis sections are structured around a tabbed dashboard interface where each tab corresponds to a distinct analytical perspective: temporal, linguistic, emotional, user, and interaction analysis. This organisation mirrors the shape of the backend API and makes it straightforward for a researcher to navigate between different lenses on the same dataset without losing context. + +React was chosen for its efficient rendering model and the breadth of its visualisation ecosystem + + \subsection{Automatic Data Collection} Originally, the system was designed to only support manual dataset uploads, where users would collect their own data from social media platforms and format it into the required \texttt{.jsonl} format. @@ -745,7 +753,44 @@ Enviornment variables, such as database credentials and social media API keys, w \newpage \section{Implementation} -\subsection{} +In the previous chapter, the architecture of the web-based ethnography tool was +outlined. In this chapter, the details on how this was implemented will be +discussed. + +\subsection{Overview} +In the initial stages, the project was a small Python script that would fetch data from Reddit and aggregate simple statistics such as number of posts and a number of comments. Some early features like search and subreddit specific searches were added through hard-coded variables. The Reddit Connector code was extracted into it's own \texttt{RedditConnector} module, though the connector abstraction had not yet been formalised. + +As this was going to be a web-based tool, the Flask server was then setup. A rudimentary sentiment analysis endpoint was added as an initial test using the VADER Sentiment Python module. An endpoint to fetch from Reddit was added but temporarily scratched. Eventually more analysis endpoints were added, creating the many different analytical perspectives that are available in the final system, such as linguistic analysis and user analysis. + +At this stage, datasets were simply files stored on the machine and loaded into memory globally, which made early development and testing easier, but as the project progressed, the database was added to allow multiple datasets and users. While this was happening, further infrastructure was added to support multiple users, and to fix long-standing issues such as the blocking nature of NLP and data fetching, which was solved through the addition of Redis and Celery for asynchronous processing. Multiple user support was added through the addition of user accounts, with authentication and dataset ownership endpoints. + +A very basic frontend was created with React, which was just a simple interface to call the API endpoints and display some basic summary stats such as number of posts, number of comments, and average sentiment. After the initial analysis endpoints were created and the API was fully functional, the frontend was expanded to include the full tabbed interface with visualisations for each analytical perspective. + +\subsection{Project Tooling} +The project was developed using the following tools and libraries: +\begin{itemize} + \item \textbf{Python 3.13} for the backend API and data processing. + \item \textbf{Flask} for the web server and API development. + \item \textbf{BeautifulSoup} and \textbf{Requests} for web scraping (used in the Boards.ie connector). + \item \textbf{google-api-python-client} for interacting with the YouTube Data API. + \item \textbf{PostgreSQL} for the database. + \item \textbf{Redis} and \textbf{Celery} for asynchronous task processing. + \item \textbf{React} and \textbf{TypeScript} for the frontend interface. + \item \textbf{Docker} and \textbf{Docker Compose} for containerisation and deployment. + \item \textbf{Pandas} for data manipulation and analysis. + \item \textbf{NLTK} for basic stop word lists and tokenisation. + \item \textbf{Transformers} for NLP models used in emotion classification, topic classification, and named entity recognition. + \item \textbf{react-chartjs-2} and \textbf{react-wordcloud} for data visualisation in the frontend. +\end{itemize} + +The project was developed using Git for version control, with a branching strategy that included feature branches for new functionality and a main branch for stable code. Regular commits were made to document the development process and conventional commit messages were used to indicate the type of changes made. Occasionally, text bodies were included in commit messages to provide justification for design decisions or to explain changes that couldn't be easily understood from the diff alone. + +\subsection{Social Media Connectors} +The first connectors implemented were the Reddit and Boards.ie connectors, as these were the original data sources for the Cork dataset. The YouTube connector was added later to improve diversity of data sources. In addition, the decision was made to only fetch new posts and fetch a fixed number of posts, rather than fetching the top posts of all time, which are usually full of memes and jokes that would skew the dataset and not be relevant for ethnographic analysis. In addition the temporal analysis would be skewed if we fetched top posts of all time, as the most popular posts are often from years ago, which would not be relevant for understanding the current state of the community. + +\subsubsection{Reddit Connector} +The initial implementation of the Reddit connector was a simple class that simply used the \texttt{requests} library to fetch data directly from the Reddit API. The online Reddit API documentation was used as a reference for the implementation of the connector \cite{reddit_api} + \newpage \section{Evaluation} @@ -753,4 +798,6 @@ Enviornment variables, such as database credentials and social media API keys, w \newpage \section{Conclusions} +\bibliography{references} + \end{document} diff --git a/report/references.bib b/report/references.bib new file mode 100644 index 0000000..eeae06a --- /dev/null +++ b/report/references.bib @@ -0,0 +1,7 @@ +@online{reddit_api, + author = {{Reddit Inc.}}, + title = {Reddit API Documentation}, + year = {2025}, + url = {https://www.reddit.com/dev/api/}, + urldate = {2026-04-08} +} \ No newline at end of file From ec645518812db8d9b131bf34ea74447fa27b14fb Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Wed, 8 Apr 2026 19:34:30 +0100 Subject: [PATCH 27/30] fix(connectors): update User-Agent header for BoardsAPI --- server/connectors/boards_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/connectors/boards_api.py b/server/connectors/boards_api.py index a2c64ef..86e4956 100644 --- a/server/connectors/boards_api.py +++ b/server/connectors/boards_api.py @@ -11,8 +11,7 @@ from server.connectors.base import BaseConnector logger = logging.getLogger(__name__) -HEADERS = {"User-Agent": "Mozilla/5.0 (compatible; ForumScraper/1.0)"} - +HEADERS = {"User-Agent": "Mozilla/5.0 (compatible; Digital-Ethnography-Aid/1.0)"} class BoardsAPI(BaseConnector): source_name: str = "boards.ie" From 42905cc5471f9f4df289fb7ed485ecf83bad997e Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Wed, 8 Apr 2026 20:39:44 +0100 Subject: [PATCH 28/30] docs(report): add connector implementation & design NLP docs --- report/main.tex | 76 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/report/main.tex b/report/main.tex index 4e15da8..d28f622 100644 --- a/report/main.tex +++ b/report/main.tex @@ -542,6 +542,23 @@ The \texttt{events} table in PostgreSQL contains the following fields: \subsubsection{Data Retrieval} The stored dataset can then be retrieved through the Flask API endpoints for analysis. The API supports filtering by keywords and date ranges, as well as grouping and aggregation for various analytical outputs. +\subsection{Natural Language Processing} +The system will utilise pre-trained NLP models to perform emotion classification, topic classification, and named entity recognition on the text content of each event. These NLP outputs will be stored in the database alongside the raw content, allowing for efficient retrieval and analysis without needing to re-run the models on every query. + +These will be implemented in a separate module that will be called during the data enrichment phase of the pipeline. The specific models used for each task will be selected based on their performance and suitability for the type of text data being analysed. This module will be called by the Celery worker during the data enrichment phase, and the outputs will be stored in the database for later retrieval. + +\subsubsection{Emotional Classification} +Emotional Classification will be the bedrock of the ethnographic analysis, as it provides insight into the emotions of a community and how they relate to different topics and users. As mentioned in the feasibility analysis, the outputs of the emotion classification model should be interpreted as indicative patterns rather than definitive representations of user meaning, due to the limitations of NLP models. + +Usage of simple VADER-based models is usually too-simplistic for the type of text data being analysed. Classifying posts into positive, negative and neutral categories is not nuanced enough to truly capture the emotional tone of a community. Therefore, the system will use a more complex model that can classify text into a wider range of emotions, which will allow for richer analysis of the emotions of the community. + +\subsubsection{Topic Classification} + + +\subsubsection{Named Entity Recognition} + + + \subsection{Ethnographic Analysis} The main goal of this project is to provide a tool that can assist researchers with ethnographic analysis of online communities. Therefore, ethnographic analysis will be a core component of the system. @@ -771,7 +788,7 @@ The project was developed using the following tools and libraries: \begin{itemize} \item \textbf{Python 3.13} for the backend API and data processing. \item \textbf{Flask} for the web server and API development. - \item \textbf{BeautifulSoup} and \textbf{Requests} for web scraping (used in the Boards.ie connector). + \item \textbf{BeautifulSoup} and \textbf{Requests} for web scraping and HTTP requests. \item \textbf{google-api-python-client} for interacting with the YouTube Data API. \item \textbf{PostgreSQL} for the database. \item \textbf{Redis} and \textbf{Celery} for asynchronous task processing. @@ -788,9 +805,62 @@ The project was developed using Git for version control, with a branching strate \subsection{Social Media Connectors} The first connectors implemented were the Reddit and Boards.ie connectors, as these were the original data sources for the Cork dataset. The YouTube connector was added later to improve diversity of data sources. In addition, the decision was made to only fetch new posts and fetch a fixed number of posts, rather than fetching the top posts of all time, which are usually full of memes and jokes that would skew the dataset and not be relevant for ethnographic analysis. In addition the temporal analysis would be skewed if we fetched top posts of all time, as the most popular posts are often from years ago, which would not be relevant for understanding the current state of the community. -\subsubsection{Reddit Connector} -The initial implementation of the Reddit connector was a simple class that simply used the \texttt{requests} library to fetch data directly from the Reddit API. The online Reddit API documentation was used as a reference for the implementation of the connector \cite{reddit_api} +\subsubsection{Data Transfer Objects} +Data Transfers Objects are simple classes that represent the data structure of a post or comment as it is retrieved from the source platform. They are used to encapsulate the raw data and provide a consistent interface for the rest of the system to interact with, regardless of the source platform. +These are later replaced by the unified "event" data model during the normalisation process, but they are a useful abstraction for the connectors to work with. Two DTOs are defined: \texttt{PostDTO} and \texttt{CommentDTO}, which represent the structure of a post and a comment respectively as they are retrieved from the source platform. The \texttt{PostDTO} will contain a list of \texttt{CommentDTO} objects. + +\subsubsection{Reddit Connector} +The initial implementation of the Reddit connector was a simple class that simply used the \texttt{requests} library to fetch data directly from the Reddit API. The online Reddit API documentation was used as a reference for the implementation of the connector \cite{reddit_api}. It uses the \texttt{reddit.com/r/\{subreddit\}/new} endpoint to fetch the most recent posts from a specified subreddit, and the \texttt{reddit.com/r/\{subreddit\}/{post\_id}/comments} endpoint to fetch comments for each post. + +It primary method implemented is of this signature: +\begin{Verbatim}[breaklines=true] +def get_new_posts_by_search(self, search: str, category: str, limit: int) -> list[Post]: +\end{Verbatim} + +The \texttt{reddit.com/r/\{subreddit\}/new} has a default limit of 100 posts per request, therefore \textbf{pagination} was implemented to allow fetching of more than 100 posts, which is necessary for Reddit datasets of larger than 100 posts. The connector will keep fetching posts until it reaches the specified number of posts to fetch, or until there are no more posts available. + +The "after" parameter is a post id and tells the API to fetch posts that come after that specific post id in the subreddit, which allows for pagination through the posts. The connector keeps track of the last post id fetched and uses it to fetch the next batch of posts until the desired number of posts is reached or there are no more posts available. + +It became apparent that when unauthenticated, the Reddit API has severe rate limits that make fetching large datasets take hours, therefore the connector was updated to support authentication using Reddit API client credentials, which are provided through environment variables. This was done using the \texttt{requests\_oauthlib} library, which provides a convenient way to handle OAuth2 authentication with the Reddit API. With authentication, the rate limits are increased, allowing for faster data fetching. + +\subsubsection{YouTube Connector} +The YouTube connector was the simplest out of the three initial connectors, as YouTube provides an official API that is well-documented compared to the Reddit API. The Python library \texttt{google-api-python-client} was used to interact with the YouTube Data API. It provides simple methods like \texttt{youtube.search().list()} to search for videos based on keywords, and \texttt{youtube.commentThreads().list()} to fetch comments for a specific video. + +Like the Reddit Connector, it implements the \texttt{get\_new\_posts\_by\_search} method, which searches for videos based on a query and then fetches comments for those videos. As the Google API library handles comment fetching and pagination internally, the implementation was straightforward and did not require manual handling of pagination or rate limits. + +\subsubsection{Boards.ie Connector} +The Boards.ie connector was the most complex connector to implement, as Boards.ie does not provide an official API for data retrieval, which meant web scraping techniques were utilised to fetch data from the site. The \texttt{requests} library was used to make HTTP requests to the Boards.ie website, and the \texttt{BeautifulSoup} library was used to parse the HTML content and extract the relevant data. + +Inspect element was used to poke around the structure of the Boards.ie website and find the relevant HTML elements that contain the post and comment data. \texttt{BeautifulSoup} was then used to extract the correct data from the \texttt{.Message.userContent} tag and the \texttt{.PageTitle} tag, which contain the content and title of the posts. Each comment lived in an \texttt{ItemComment} class. Each of these were collected and iterated through to create the list of \texttt{PostDTO} and \texttt{CommentDTO} objects that represent the data retrieved from the site. + +As not all comments on a thread are on one page, pagination was implemented by looking for the "Next" button on the page and following the link to the next page of comments until there are no more pages left. This allows for fetching of all comments for a given post, even if they span multiple pages. + +A \texttt{ThreadPoolExecutor} was used to fetch posts in parallel, which improved the performance of the connector significantly, as fetching posts sequentially was very slow due to the need to fetch comments for each post, which often spanned multiple pages. Though there was diminishing returns after a certain number of threads, possibly due to site blocking or internet connection limits. Initially 20 threads were used, but this was later reduced to 10 threads to avoid potential issues with site blocking and to improve ethical considerations around web scraping. + +\subsubsection{Connecter Plugin System} +The connector plugin system was implemented to allow for easy addition of new data sources in the future. This would require simply implemented a new connector class and dropping it into the connectors directory, without needing to modify any existing code. This was achieved through the use of Python's \texttt{importlib} library, which allows for dynamic importing of modules at runtime. + +To achieve this, the base class \texttt{BaseConnector} was defined, which allows a standard interface for all connectors to implement. Each connector implements the \texttt{get\_new\_posts\_by\_search} method, which takes in a search query, a category (which is the subreddit for Reddit, or the category for Boards.ie), and a limit on the number of posts to fetch. The method returns a list of \texttt{PostDTO} objects that represent the data retrieved from the source platform. + +In addition, some metadata is required for each connector, such as the source name, search support and category support, which are defined as class variables in each connector. This is required as some connectors may not support search or categories, for example YouTube does not support categories in the same sense that Reddit might. + +\subsection{Data Pipeline} + +\subsubsection{Data Enrichment} +The data enrichment process is responsible for taking the raw data retrieved from the connectors and transforming it into a format that is suitable for analysis. This involves several steps, including normalisation, NLP processing, and storage in the database. + +Initially enrichment was done synchronously in the main Flask thread, and was alongside the ethnographic analysis upon every request rather than being done once at the point of data ingestion. However once NLP processing was added, it was no longer feasible to do this synchronously in the main thread. + +\subsection{Ethnographic Statistics} +This section will discuss the implementation of the various ethnographic statistics that are available through the API endpoints, such as temporal analysis, linguistic analysis, emotional analysis, user analysis, interactional analysis, and cultural analysis. Each of these are available through the API and visualised in the frontend. + + + + +\subsection{Flask API} + +\subsection{React Frontend} \newpage \section{Evaluation} From 8c44df94c0e7cc8da3e484418e1c11ac3498dc83 Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Thu, 9 Apr 2026 19:01:21 +0100 Subject: [PATCH 29/30] docs(report): update references for emotion classification models and NLP techniques --- report/main.tex | 116 ++++++++++++++++++++++++++++++++++++++---- report/references.bib | 14 +++++ 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/report/main.tex b/report/main.tex index d28f622..0a44939 100644 --- a/report/main.tex +++ b/report/main.tex @@ -505,14 +505,11 @@ As part of this normalisation process, the dataset is also \textbf{flattened}, s Overall, the data normalisation process unifies the structure of the dataset, and flattens the data into a format that makes analysis more efficient and easier. - \subsubsection{Data Enrichment} After normalisation, the dataset is enriched with additional derived fields and NLP outputs. This includes: \begin{itemize} \item \textbf{Datetime Derivations}: Fields such as day of week, hour of day, and week of year are derived from the raw timestamp and stored alongside the event, so they do not need to be recomputed on every query. - \item \textbf{Emotion Classification}: Each event is run through an NLP model that assigns an emotional label to the text content, such as joy, anger, or sadness. - \item \textbf{Topic Classification}: Each event is classified into its most relevant topic using an NLP model, based on either the user-provided topic list or the system default. - \item \textbf{Named Entity Recognition}: Each event is processed to identify any named entities mentioned in the text, such as people, places, or organisations, which are stored as a list associated with the event. + \item \textbf{NLP Analysis}: The text content of each event is processed through NLP models to generate outputs such as emotion classification, topic classification, and named entity recognition. \end{itemize} NLP processing lets us perform much richer analysis of the dataset, as it provides additional layers of information beyond just the raw text content. After enrichment, the dataset is ready to be stored in the database and made available for analysis through the API endpoints. @@ -535,7 +532,7 @@ The \texttt{events} table in PostgreSQL contains the following fields: \item \texttt{reply\_to}: for comments, the identifier of the comment it directly replies to. Null if the comment is a direct reply to a post. \item \texttt{source}: the platform from which the content was retrieved. \item \texttt{topic}, \texttt{topic\_confidence}: the topic assigned to the event by the NLP model, along with a confidence score. - \item \texttt{ner\_entities}: a list of named entities identified in the content, stored as a \texttt{JSONB} field. + \item \texttt{ner\_entities}: a list of named entities identified in the content. \item \texttt{emotion\_anger}, \texttt{emotion\_disgust}, \texttt{emotion\_fear}, \texttt{emotion\_joy}, \texttt{emotion\_sadness}: emotion scores assigned to the event by the NLP model. \end{itemize} @@ -553,11 +550,12 @@ Emotional Classification will be the bedrock of the ethnographic analysis, as it Usage of simple VADER-based models is usually too-simplistic for the type of text data being analysed. Classifying posts into positive, negative and neutral categories is not nuanced enough to truly capture the emotional tone of a community. Therefore, the system will use a more complex model that can classify text into a wider range of emotions, which will allow for richer analysis of the emotions of the community. \subsubsection{Topic Classification} +Topic classification will allow the system to classify specific posts into specific topics, which can be used to understand what a community is talking about, and in conjunction with emotional classification, how they feel about these topics as well. The system will support both a generalised topic classification model that can classify posts into a set of pre-defined general topics, as well as a custom topic classification model that can classify posts into user-defined topics based on a list of topics and descriptions provided by the user. +Initially, the system would have extract common themes and topics from the dataset by extracting common keywords and phrases, and then use these to generate a topic list. However, this approach was noisy and topics were often singular random words that did not have any overlap with each other, making topic classification less insightful. Therefore, specified or pre-defined topic lists will instead be used. \subsubsection{Named Entity Recognition} - - +Named Entity Recognition allows the system to identify specific entities mentioned in the text, like people, places and organisations. In combination with emotional classification, we can see the general sentiment around specific places and people in a community, which can be very insightful for ethnographic analysis. For example, in a Cork-specific dataset, we might see that the city centre is often mentioned with negative emotions due to traffic and parking issues, while local parks are mentioned with positive emotions. \subsection{Ethnographic Analysis} The main goal of this project is to provide a tool that can assist researchers with ethnographic analysis of online communities. Therefore, ethnographic analysis will be a core component of the system. @@ -845,12 +843,112 @@ To achieve this, the base class \texttt{BaseConnector} was defined, which allows In addition, some metadata is required for each connector, such as the source name, search support and category support, which are defined as class variables in each connector. This is required as some connectors may not support search or categories, for example YouTube does not support categories in the same sense that Reddit might. +\subsection{Database Configuration} +A PostgreSQL Docker container was set up to serve as the database for the system. This allows for persistent storage of datasets, as well as support for multiple users and multiple datasets per user. The implemented schema passed into the Docker container by mounting the \texttt{schema.sql} file as a volume, which allows for easy updates to the database schema during development. The database contains three main tables: +\begin{itemize} + \item \textbf{users}: contains user information such as username, email and password hash. + \item \textbf{datasets}: contains dataset information such as dataset name, description and owner (foreign key to users table). + \item \textbf{events}: contains the main data for the posts and comments. +\end{itemize} + +\subsubsection{Low-Level Connector} +A low-level \texttt{PostgreConnector} module was implemented to handle the raw SQL queries for interacting with the database. It connects to the Docker container using environment variables for the database credentials, which are passed into the container through the \texttt{docker-compose.yaml} file. The connector provides methods for executing queries with parameters and supports rollback in the case of errors. + + Two main methods of the connector are: +\begin{itemize} + \item \texttt{def execute(self, query, params=None, fetch=False) -> list} + \item \texttt{def execute\_batch(self, query, values) -> list} +\end{itemize} + +This module provides a simple interface for executing SQL queries. It's used by higher level modules to interact with the database without needing to worry about the details of database connections and query execution. + +\subsubsection{Dataset Manager} +The dataset manager is a higher-level module that provides an interface for managing datasets in the database. It uses the low-level \texttt{PostgreConnector} to execute SQL queries, but provides more specific methods for dataset management, such as creating a new dataset, fetching a dataset by id, and updating a dataset metadata. Dependency injection is used to pass an instance of the \texttt{PostgreConnector}. + +The \texttt{DatasetManager} class is responsible for all database interactions relating to datasets, and draws a deliberate distinction between two categories of data: +\begin{itemize} + \item \textbf{Dataset metadata} (the \texttt{datasets} table) refers to the metadata about a dataset like its name, owner, topic configuration, and processing status. Methods such as \texttt{save\_dataset\_info()}, \texttt{get\_dataset\_info()}, and \texttt{set\_dataset\_status()} operate on this layer. + \item \textbf{Dataset content} (the \texttt{events} table) refers to the enriched event rows produced by the pipeline. \texttt{save\_dataset\_content()} performs a batch insert of the full enriched DataFrame, with NER entities serialised to JSONB via \texttt{psycopg2}'s \texttt{Json} wrapper, and emotion scores stored as flat numeric columns to allow direct SQL aggregation without requiring JSON parsing at query time. +\end{itemize} + +\texttt{authorize\_user\_dataset()} enforces ownership by comparing the dataset's \texttt{user\_id} against the requesting user before any operation is performed, returning \texttt{False} rather than raising an exception so that the calling route handler can respond with an appropriate HTTP error. + +NER output is stored as JSONB rather than in relational columns, as the number of extracted entities per post is arbitrary and varies between posts. Storing this into a fixed column structure would have been awkward and required a schema redesign. + +This module is a simple interface to deal with datasets in the database, and abstracts away the details of SQL queries and database interactions from the rest of the application. It is used by the API endpoints to manage datasets and their content. + +\subsubsection{Authentication Manager} +The authentication manager is another higher-level module that provides an interface for managing user authentication in the database. It also uses the low-level \texttt{PostgreConnector} to execute SQL queries, but provides more specific methods for authentication management, such as creating a new user, fetching a user by id, and authenticating a user. It handles password hashing using the \texttt{bcrypt} library, which provides a secure way to hash and verify passwords. Similar to the dataset manager, dependency injection is used to pass an instance of the \texttt{PostgreConnector}. + +The most important authentication methods implemented are as follows: +\begin{itemize} + \item \texttt{register\_user(username: str, email: str, password: str) -> None}: Registers a new user, hashes their password, checks for duplicate usernames or emails, and stores the user in the database. + \item \texttt{authenticate\_user(username: str, password: str) -> None | dict}: Authenticates a user by verifying the provided password against the stored hash, returning user information if successful or \texttt{None} if authentication fails. + \item \texttt{get\_user\_by\_id(user\_id: int) -> None | dict}: Fetches a user's information from the database based on their user ID, returning a dictionary of user details if found or \texttt{None} if no such user exists. +\end{itemize} + +Defensive programming is used in the authentication manager to handle edge cases like duplicate usernames or emails, an example of this is in the \texttt{register\_user()} method, shown below: + +\begin{Verbatim}[breaklines=true] +def register_user(self, username, email, password): + hashed_password = self.bcrypt.generate_password_hash(password).decode("utf-8") + + if len(username) < 3: + raise ValueError("Username must be longer than 3 characters") + + if not EMAIL_REGEX.match(email): + raise ValueError("Please enter a valid email address") + + if self.get_user_by_email(email): + raise ValueError("Email already registered") + + if self.get_user_by_username(username): + raise ValueError("Username already taken") + + self._save_user(username, email, hashed_password) +\end{Verbatim} + +This module is a simple interface that the higher level Flask API can call for easy management of user authentication and registration. + \subsection{Data Pipeline} +The data pipeline began with the data connectors mentioned in the previous section, which are responsible for fetching raw data from the source platforms. However they were not initially included as part of the data pipeline, as the initial system was designed to only support manual dataset uploads. The data connectors were used to fetch data for the Cork dataset, which was then uploaded automatically through the API. Once the automatic data fetching functionality was added, the connectors were integrated into the data pipeline. \subsubsection{Data Enrichment} The data enrichment process is responsible for taking the raw data retrieved from the connectors and transforming it into a format that is suitable for analysis. This involves several steps, including normalisation, NLP processing, and storage in the database. - -Initially enrichment was done synchronously in the main Flask thread, and was alongside the ethnographic analysis upon every request rather than being done once at the point of data ingestion. However once NLP processing was added, it was no longer feasible to do this synchronously in the main thread. + +Data Normalisation was intended to be a separate step in the data pipeline, but it was later combined with the enrichment processe as normalisation is a very small part of the process and can be done in a few lines of code, therefore it was combined with data enrichment. In normalisation, the list of \texttt{Post} objects retrieved from the connectors is flattened into a unified list of "events", which is a Pandas DataFrame that contains both posts and comments in a single table. The structure of the comments expansion method is as follows: +\begin{itemize} + \item The method receives a DataFrame \texttt{df} where each row represents a post, and the \texttt{comments} column contains a list of comment dictionaries. + \item The \texttt{comments} column is exploded using \texttt{pandas.DataFrame.explode()}, so that each comment occupies its own row, paired with the \texttt{id} of its parent post. + \item Rows where the comment value is not a dictionary are filtered out, discarding any \texttt{None} or malformed entries that may have resulted from posts with no comments. + \item \texttt{pd.json\_normalize()} is applied to the remaining comment dictionaries, flattening them into a structured DataFrame with one column per field. + \item The original DataFrame is stripped of its \texttt{comments} column to form \texttt{posts\_df}, and a \texttt{type} column is added with the value \texttt{"post"}, along with a \texttt{parent\_id} column set to \texttt{None}, as posts have no parent. + \item The comments DataFrame is similarly tagged with \texttt{type = "comment"}, and its \texttt{parent\_id} is populated from the \texttt{post\_id} field, establishing the relationship back to the originating post. + \item Both DataFrames are concatenated using \texttt{pd.concat()}, and the now-redundant \texttt{post\_id} column is dropped, yielding a single unified events table containing both posts and comments with a consistent schema. +\end{itemize} + +The \texttt{enrich()} method is the primary method for dataset enrichment in the module, and provides two main functionalities: +\begin{itemize} + \item \textbf{Column Derivation}: This involves adding new columns to the dataset that are derived from existing data, such as timestamp parsing to extract date and time components. + \item \textbf{NLP Analysis}: NLP analysis is performed on the dataset to add new columns that contains NLP outputs. The NLP performed includes emotion classification, topic classification, and named entity recognition. +\end{itemize} + +Column derivation is a process of combining or altering existing columns to create new columns useful to analysis. The original dataset contains a timestamp column that might need to be parsed into a datetime format, and then new columns can be derived from this, such as the date, time, weekday, hour of the event, which is needed for temporal analysis like heatmaps. Datetime parsing on it's own is not usually intensive, but multiplied across thousands of posts and comments, it can add up, therefore it's calculated before analysis. + +\subsubsection{Data Storage} +Once the dataset is enriched, it is ready for storage. Datasets are stored in a PostgreSQL database. The dataset manager is used to handle the storage of datasets in the database, and it provides a simple interface for saving the enriched dataset content. The enriched dataset is stored in the \texttt{events} table, with each row representing an event (either a post or a comment). + +One issue arose using dependency injection for the dataset manager. Since from the data enrichment stage onwards, the data pipeline runs on a separate Celery worker process, therefore dependency injection of non-serialisable objects like \texttt{PostgresConnector} or \texttt{DatasetManager} does not work, as these objects cannot be passed through the Redis queue. To solve this, the \texttt{PostgresConnector} and \texttt{DatasetManager} are instantiated within the Celery worker process itself, rather than being passed in from the Flask API. While this introduces some tight coupling and possible synchronisation issues, these are not issues at this scale of project since both the Celery worker and database module use single-threaded connections to the database, but it's worth noting that this could be an issue if the project scaled up and had multiple Celery workers in parallel. + +\subsection{NLP Module} +The NLP module is responsible for adding new columns to the dataset that contain the NLP outputs, three types of NLP analysis are performed: emotion classification, topic classification, and named entity recognition. It is instantiated once per dataset during the enrichment phase and runs on the provided Pandas DataFrame. + +\subsubsection{Emotion Classification} +For emotional classification, initially a pre-trained VADER sentiment analysis model was used, which provides a very simple way to classify text into positive, negative, and neutral emotions. Though for ethnographic analysis, a more complex emotional model that can capture more nuance is needed, therefore the VADER model was later replaced with a fine-tuned transformer-based model that can classify text into a wider range of emotions. + +GoEMOTION \cite{demszky2020goemotions} was considered as a potential model for emotional classification, as it is extremely nuanced and can capture a wide range of emotions, however it had over 27 emotion classes, which was too many for the purposes of this project, as it would have been difficult to visualise and analyse such a large number of emotion classes. + +A middle ground was found with the "Emotion English DistilRoBERTa-base" model from HuggingFace \cite{hartmann2022emotionenglish}, which is a fine-tuned transformer-based model that can classify text into 6 emotion classes: anger, disgust, fear, joy, sadness, and surprise. This model provides a good balance between nuance and simplicity for the purposes of ethnographic analysis. \subsection{Ethnographic Statistics} This section will discuss the implementation of the various ethnographic statistics that are available through the API endpoints, such as temporal analysis, linguistic analysis, emotional analysis, user analysis, interactional analysis, and cultural analysis. Each of these are available through the API and visualised in the frontend. diff --git a/report/references.bib b/report/references.bib index eeae06a..519d062 100644 --- a/report/references.bib +++ b/report/references.bib @@ -4,4 +4,18 @@ year = {2025}, url = {https://www.reddit.com/dev/api/}, urldate = {2026-04-08} +} + +@misc{hartmann2022emotionenglish, + author={Hartmann, Jochen}, + title={Emotion English DistilRoBERTa-base}, + year={2022}, + howpublished = {\url{https://huggingface.co/j-hartmann/emotion-english-distilroberta-base/}}, +} + +@inproceedings{demszky2020goemotions, + author = {Demszky, Dorottya and Movshovitz-Attias, Dana and Ko, Jeongwoo and Cowen, Alan and Nemade, Gaurav and Ravi, Sujith}, + booktitle = {58th Annual Meeting of the Association for Computational Linguistics (ACL)}, + title = {{GoEmotions: A Dataset of Fine-Grained Emotions}}, + year = {2020} } \ No newline at end of file From 99afe824648093170e467307fdbd48ee80fc037c Mon Sep 17 00:00:00 2001 From: Dylan De Faoite Date: Fri, 10 Apr 2026 13:17:11 +0100 Subject: [PATCH 30/30] docs(report): refine emotional classification model details --- report/main.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/report/main.tex b/report/main.tex index 0a44939..e3847d3 100644 --- a/report/main.tex +++ b/report/main.tex @@ -948,7 +948,9 @@ For emotional classification, initially a pre-trained VADER sentiment analysis m GoEMOTION \cite{demszky2020goemotions} was considered as a potential model for emotional classification, as it is extremely nuanced and can capture a wide range of emotions, however it had over 27 emotion classes, which was too many for the purposes of this project, as it would have been difficult to visualise and analyse such a large number of emotion classes. -A middle ground was found with the "Emotion English DistilRoBERTa-base" model from HuggingFace \cite{hartmann2022emotionenglish}, which is a fine-tuned transformer-based model that can classify text into 6 emotion classes: anger, disgust, fear, joy, sadness, and surprise. This model provides a good balance between nuance and simplicity for the purposes of ethnographic analysis. +A middle ground was found with the "Emotion English DistilRoBERTa-base" model from HuggingFace \cite{hartmann2022emotionenglish}, which is a fine-tuned transformer-based model that can classify text into 6 emotion classes: anger, disgust, fear, joy, sadness, neutral and surprise. + +As the project progressed and more posts were classified, the "surprise" and "neutral" emotions were found to be dominating the dataset, which made it difficult to analyse the other emotions. This could possible be because the model is not fine-tuned for internet slang, and usage of exclamation marks and emojis, which are common in social media posts, may be classified as "surprise" or "neutral" rather than the intended emotion. Therefore, the "surprise" and "neutral" emotion classes were removed from the dataset, and the confidence numbers were re-normalised to the remaining 5 emotions. \subsection{Ethnographic Statistics} This section will discuss the implementation of the various ethnographic statistics that are available through the API endpoints, such as temporal analysis, linguistic analysis, emotional analysis, user analysis, interactional analysis, and cultural analysis. Each of these are available through the API and visualised in the frontend.