From 5e2a3a20d0b37001331aeb71abc62842ceef3da1 Mon Sep 17 00:00:00 2001 From: Ikeoluwa Oladele Date: Sun, 23 Mar 2025 15:10:23 -0400 Subject: [PATCH 1/5] updated readme --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 284ce97..98b621e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ CiteMe is a modern, full-stack application designed to help researchers and academics manage their citations and references efficiently. The system provides intelligent citation suggestions, reference management, and seamless integration with academic databases. +๐ŸŒ **Live Demo**: [CiteMe Editor](https://cite-me-wpre.vercel.app/editor) + ## ๐Ÿš€ Features - **Smart Citation Suggestions**: AI-powered citation recommendations based on your research context @@ -11,6 +13,23 @@ CiteMe is a modern, full-stack application designed to help researchers and acad - **Modern UI**: Responsive and intuitive user interface - **API Integration**: Seamless integration with academic databases and search engines +## ๐Ÿ“ Project Structure + +``` +CiteMe/ +โ”œโ”€โ”€ frontend/ # Vue.js 3 frontend application +โ”‚ โ”œโ”€โ”€ src/ # Source code +โ”‚ โ”œโ”€โ”€ public/ # Static assets +โ”‚ โ”œโ”€โ”€ e2e/ # End-to-end tests +โ”‚ โ””โ”€โ”€ dist/ # Production build +โ”œโ”€โ”€ backend/ +โ”‚ โ”œโ”€โ”€ mainService/ # Core citation service +โ”‚ โ””โ”€โ”€ metricsService/ # Analytics and metrics service +โ”œโ”€โ”€ .github/ # GitHub workflows and templates +โ”œโ”€โ”€ docker-compose.yml # Docker services configuration +โ””โ”€โ”€ README.md # Project documentation +``` + ## ๐Ÿ—๏ธ Architecture The application is built using a microservices architecture with three main components: From 8b36fdd2032217debe86c36aa5f7306bef80945e Mon Sep 17 00:00:00 2001 From: Ikeoluwa Oladele Date: Sun, 23 Mar 2025 18:31:51 -0400 Subject: [PATCH 2/5] Updates dockerfiles. Updates readme. removes hardcoded metric-api-url --- backend/mainService/.env.example | 44 ++++++++++++++++++- backend/mainService/Dockerfile | 21 +++++++-- backend/mainService/requirements.txt | 1 + .../src/scraper/async_content_scraper.py | 2 +- .../source_credibility_metric_service.py | 5 ++- 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/backend/mainService/.env.example b/backend/mainService/.env.example index 55d82ce..9b500c3 100644 --- a/backend/mainService/.env.example +++ b/backend/mainService/.env.example @@ -4,4 +4,46 @@ GROQ_API_KEY= # your groq api key GOOGLE_API_KEY= # your gemini google api key MIXBREAD_API_KEY= # your mixbread api key PINECONE_API_KEY= # your pinecone api key -AZURE_MODELS_ENDPOINT = # your azure model endpoint for citation generation \ No newline at end of file +AZURE_MODELS_ENDPOINT = # your azure model endpoint for citation generation +CREDIBILITY_API_URL = # your credibility api url + + +#NOTE: +# CREDIBILITY_API_URL is the url of the credibility api that is used to get the credibility metrics for the sources +# CREDIBILITY_API_URL is optional and is only used if the CREDIBILITY_API_URL environment variable is set +# If the CREDIBILITY_API_URL environment variable is not set, the credibility metrics will not be fetched + + +#AZURE_MODELS_ENDPOINT is the endpoint of the azure model that is used for citation generation +#AZURE_MODELS_ENDPOINT is required and is used to generate the citations for the sources + + +#MIXBREAD_API_KEY is the api key of the mixbread api that is used to rerank the sources +#MIXBREAD_API_KEY is required and is used to rerank the sources + + +#PINECONE_API_KEY is the api key of the pinecone api that is used to store the embeddings of the sources +#PINECONE_API_KEY is required and is used to store the embeddings of the sources + + +#GPSE_API_KEY is the api key of the google programmable search engine api that is used to search the web +#GPSE_API_KEY is required and is used to search the web + + +#GOOGLE_API_KEY is the api key for gemini google api +#GOOGLE_API_KEY it is required and is used to merge the chunk of cited citations returned by the azure model + +#CX is the custom search engine id for google programmable search engine + +#All the above can be replaced by writing your own functions for the respective services +#for instance, one could decide to use gemini to generate the intext citation and references rather than using an azure +#hosted model. Hence all you need to do is write your own cite function/module and replace the azure cite function in the citation service file + + + + + + + + + diff --git a/backend/mainService/Dockerfile b/backend/mainService/Dockerfile index 0e34659..08ab309 100644 --- a/backend/mainService/Dockerfile +++ b/backend/mainService/Dockerfile @@ -3,21 +3,36 @@ FROM python:3.11-slim WORKDIR /app # Install system dependencies +# Installs essential tools for compiling software from source, often needed for Python package dependencies.(build-essential) +# Removes the package lists downloaded during the update to reduce the image size. RUN apt-get update && apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/* +# Set the PATH environment variable to include /app +ENV PATH="/app:${PATH}" + # Copy requirements first to leverage Docker cache COPY requirements.txt . # Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt -# Copy the rest of the application -COPY . . +# Copy the source code +COPY ./scripts/ /app/scripts/ +COPY ./src/ /app/src/ +COPY ./app.py /app/app.py +COPY ./__init__.py /app/__init__.py + +# Create a directory for runtime configuration +RUN mkdir -p /app/config + +# Install playwright +RUN playwright install && playwright install-deps # Expose the port the app runs on EXPOSE 8000 + # Command to run the application -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/backend/mainService/requirements.txt b/backend/mainService/requirements.txt index 261afd3..a39a8eb 100644 --- a/backend/mainService/requirements.txt +++ b/backend/mainService/requirements.txt @@ -23,4 +23,5 @@ urllib3==2.3.0 lxml==5.3.0 google-genai redis>=4.2.0 +uvicorn diff --git a/backend/mainService/src/scraper/async_content_scraper.py b/backend/mainService/src/scraper/async_content_scraper.py index 22dbc38..1f63f6a 100644 --- a/backend/mainService/src/scraper/async_content_scraper.py +++ b/backend/mainService/src/scraper/async_content_scraper.py @@ -99,7 +99,7 @@ async def __aenter__(self): async def __aexit__(self, exc_type, exc_val, exc_tb): try: if self._context: - self.scraper_driver.quit() + await self.scraper_driver.quit() await self._context.close() except Exception as e: # Log the exception even if it occurred during cleanup diff --git a/backend/mainService/src/services/source_credibility_metric_service.py b/backend/mainService/src/services/source_credibility_metric_service.py index 3b2a138..649a8f1 100644 --- a/backend/mainService/src/services/source_credibility_metric_service.py +++ b/backend/mainService/src/services/source_credibility_metric_service.py @@ -17,7 +17,10 @@ async def get_credibility_metrics(sources: List[Dict]) -> List[Dict]: Returns: List[Dict]: Credibility metrics for each source """ - credibility_metrics_api = 'http://localhost:9050/api/v1/credibility/batch' + credibility_metrics_api = os.getenv('CREDIBILITY_API_URL','') + if not credibility_metrics_api: + logger.error("CREDIBILITY_API_URL is not set") + return [] try: async with aiohttp.ClientSession() as session: async with session.post( From 2ccb371b472560f675b608289ebacf70749484e3 Mon Sep 17 00:00:00 2001 From: Ikeoluwa Oladele Date: Sun, 23 Mar 2025 18:32:48 -0400 Subject: [PATCH 3/5] Updates dockerfiles. Updates readme. removes hardcoded metric-api-url --- README.md | 59 +++++++++++++++++++------ backend/metricsService/Dockerfile | 15 +++++-- backend/metricsService/requirements.txt | 1 + backend/metricsService/src/__init__.py | 0 docker-compose.yml | 24 +++++----- 5 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 backend/metricsService/src/__init__.py diff --git a/README.md b/README.md index 98b621e..b27813b 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ The application is built using a microservices architecture with three main comp - Node.js 20+ (for local frontend development) - Python 3.11+ (for local backend development) -### Running with Docker +### Running with Docker Compose (Recommended for Local Development) 1. Clone the repository: ```bash @@ -73,21 +73,52 @@ git clone https://github.com/yourusername/citeme.git cd citeme ``` -2. Create a `.env` file in the root directory with necessary environment variables: -```env -# Add your environment variables here -``` +2. Create `.env` files in both service directories: + - `backend/mainService/.env` + - `backend/metricsService/.env` -3. Build and run the backend services using Docker Compose: +3. Build and run the services using Docker Compose: ```bash docker-compose up --build ``` -The backend services will be available at: -- Main Service: http://localhost:8000 -- Metrics Service: http://localhost:8001 +The services will be available at: +- Main Service: http://localhost:9020 +- Metrics Service: http://localhost:9050 + +### Running Services Individually + +If you need to run services separately: + +1. Create the Docker network: +```bash +docker network create cite_me +``` + +2. Run the Metrics Service: +```bash +cd backend/metricsService +docker build -t metrics_service . +docker run -p 9050:8000 \ + --name ms \ + --network cite_me \ + --env-file .env \ + metrics_service +``` + +3. Run the Main Service: +```bash +cd backend/mainService +docker build -t main_service . +docker run -p 9020:8000 \ + --name mbs \ + --network cite_me \ + --env-file .env \ + -e CREDIBILITY_API_URL=http://ms:8000/api/v1/credibility/batch \ + main_service +``` -### Local Development +### Local Development Without Docker #### Frontend ```bash @@ -102,7 +133,7 @@ cd backend/mainService python -m venv venv source venv/bin/activate # On Windows: .\venv\Scripts\activate pip install -r requirements.txt -uvicorn main:app --reload +uvicorn app:app --reload --port 9020 ``` #### Metrics Service @@ -111,14 +142,14 @@ cd backend/metricsService python -m venv venv source venv/bin/activate # On Windows: .\venv\Scripts\activate pip install -r requirements.txt -uvicorn main:app --reload +uvicorn src.main:app --reload --port 9050 ``` ## ๐Ÿ“š API Documentation Once the services are running, you can access the API documentation at: -- Main Service: http://localhost:8000/docs -- Metrics Service: http://localhost:8001/docs +- Main Service: http://localhost:9020/docs +- Metrics Service: http://localhost:9050/docs ## ๐Ÿงช Testing diff --git a/backend/metricsService/Dockerfile b/backend/metricsService/Dockerfile index b985497..5cf1198 100644 --- a/backend/metricsService/Dockerfile +++ b/backend/metricsService/Dockerfile @@ -3,21 +3,28 @@ FROM python:3.11-slim WORKDIR /app # Install system dependencies +# Installs essential tools for compiling software from source, often needed for Python package dependencies.(build-essential) +# Removes the package lists downloaded during the update to reduce the image size. RUN apt-get update && apt-get install -y \ build-essential \ && rm -rf /var/lib/apt/lists/* +# Set the PATH environment variable to include /app +ENV PATH="/app:${PATH}" + # Copy requirements first to leverage Docker cache COPY requirements.txt . # Install Python dependencies -RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir -r requirements.txt # Copy the rest of the application -COPY . . +COPY ./src/ /app/src/ + +RUN cd /app/src # Expose the port the app runs on -EXPOSE 8001 +EXPOSE 8000 # Command to run the application -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"] \ No newline at end of file +CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/backend/metricsService/requirements.txt b/backend/metricsService/requirements.txt index 0c38bee..183bb12 100644 --- a/backend/metricsService/requirements.txt +++ b/backend/metricsService/requirements.txt @@ -6,3 +6,4 @@ pytest==8.3.4 python-dotenv==1.0.1 Requests==2.32.3 scholarly==1.7.11 +uvicorn diff --git a/backend/metricsService/src/__init__.py b/backend/metricsService/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index 704a54d..fd369d7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,32 +1,36 @@ version: '3.8' services: - main-service: + main_service: build: context: ./backend/mainService dockerfile: Dockerfile ports: - - "8000:8000" + - "9020:8000" + env_file: + - ./backend/mainService/.env environment: - - ENVIRONMENT=production + - CREDIBILITY_API_URL=http://metrics_service:8000/api/v1/credibility/batch volumes: - ./backend/mainService:/app networks: - - citeme-network + - cite_me + depends_on: + - metrics_service - metrics-service: + metrics_service: build: context: ./backend/metricsService dockerfile: Dockerfile ports: - - "8001:8001" - environment: - - ENVIRONMENT=production + - "9050:8000" + env_file: + - ./backend/metricsService/.env volumes: - ./backend/metricsService:/app networks: - - citeme-network + - cite_me networks: - citeme-network: + cite_me: driver: bridge \ No newline at end of file From 7c5d4f468fcaf0ac7cdb3fb5a089a1aac037b84f Mon Sep 17 00:00:00 2001 From: Ikeoluwa Oladele Date: Sun, 23 Mar 2025 22:04:51 -0400 Subject: [PATCH 4/5] update the metrics to use a 60-0 weighted average of the rerank score and the the credibility. Updated citation service to start calculating score without waiting for citation task to be completed. fixed the caching error in metric service that caused it to return 0 for the overall score when re queried after caching --- backend/mainService/app.py | 4 + backend/mainService/src/config/config.py | 15 +-- .../src/services/citation_service.py | 92 ++++++-------- .../source_credibility_metric_service.py | 120 ++++++++++++++---- .../src/utils/concurrent_resources.py | 15 +++ .../src/utils/format_rerank_result.py | 2 + backend/metricsService/src/api/endpoints.py | 19 ++- .../src/services/credibility_service.py | 4 + 8 files changed, 179 insertions(+), 92 deletions(-) create mode 100644 backend/mainService/src/utils/concurrent_resources.py diff --git a/backend/mainService/app.py b/backend/mainService/app.py index 7b4f7bd..4c965bb 100644 --- a/backend/mainService/app.py +++ b/backend/mainService/app.py @@ -12,6 +12,9 @@ from src.scraper.async_content_scraper import AsyncContentScraper from fastapi.middleware.cors import CORSMiddleware import nltk +from src.utils.concurrent_resources import cleanup_resources + + origins = [ "http://localhost:5173", # Frontend running on localhost (React, Vue, etc.) @@ -37,6 +40,7 @@ async def startup_event(app: FastAPI): await app.state.playwright_driver.quit() await app.state.pc.cleanup() await AsyncHTTPClient.close_session() + cleanup_resources() # Clean up thread pool and other concurrent resources app = FastAPI(lifespan=startup_event) diff --git a/backend/mainService/src/config/config.py b/backend/mainService/src/config/config.py index d8fcfbd..c70b91d 100644 --- a/backend/mainService/src/config/config.py +++ b/backend/mainService/src/config/config.py @@ -98,18 +98,17 @@ class LlmConfig: # Concurrency and Performance @dataclass class ConcurrencyConfig: - """Configuration class for concurrency settings. + """Configuration class for concurrency settings.""" - Contains settings that control parallel processing and thread management.""" - """Configuration for concurrency and performance settings.""" - - """ - This is the number of concurrent workers that will be used for parallel and concurrent operations. - """ + # General concurrency settings DEFAULT_CONCURRENT_WORKERS: int = (os.cpu_count() // 2) + 1 - HANDLE_INDEX_DELETE_WORKERS: int = 2 + # Credibility service specific settings + CREDIBILITY_MAX_THREADS: int = 4 # Maximum threads for credibility calculations + CREDIBILITY_MAX_CONCURRENT: int = 8 # Maximum concurrent operations + CREDIBILITY_BATCH_SIZE: int = 4 # Size of processing batches + @dataclass class ModelConfig: diff --git a/backend/mainService/src/services/citation_service.py b/backend/mainService/src/services/citation_service.py index 1d2e0f0..c7a79c7 100644 --- a/backend/mainService/src/services/citation_service.py +++ b/backend/mainService/src/services/citation_service.py @@ -368,64 +368,58 @@ async def _generate_citations( max_tokens=LLMEC.QUERY_TOKEN_SIZE, overlap_percent=5 ) - # RAG + Rerank + # RAG + Rerank results = await self.process_queries(queries) - logger.info(f"size of reranked results:{len(results)}\n\n") filtered_results = filter_mixbread_results(results) - logger.info(f"size of filtered results:{len(filtered_results)}\n\n") - # Generrate citation + + sources_with_scores = [ + { + "title": result.get("title", ""), + "link": result.get("link", "") or result.get("url", ""), + "domain": result.get("domain", ""), + "journal": result.get("journal_title", ""), + "citation_doi": result.get("citation_doi", ""), + "citation_references": result.get("references", [""]), + "publication_date": result.get("publication_date", ""), + "author_name": result.get("author_name", "") or result.get("author", "") or result.get("authors", ""), + "abstract": result.get("abstract", ""), + "issn": result.get("issn", ""), + "type": result.get("type", ""), + "rerank_score": result.get("score", 0) + } for result in filtered_results + ] + + credibility_task = get_credibility_metrics(sources_with_scores) citation_task = Citation(source=filtered_results).cite( text=queries, citation_style=style ) - sources_for_credibility = [ - { - "title": result.get( - "title", ""), "link": result.get( - "link", "") or result.get( - "url", ""), "domain": result.get( - "domain", ""), "journal": result.get( - "journal_title", ""), "citation_doi": result.get( - "citation_doi", ""), "citation_references": result.get( - "references", [""]), "publication_date": result.get( - "publication_date", ""), "author_name": result.get( - "author_name", "") or result.get( - "author", "") or result.get( - "authors", ""), "abstract": result.get( - "abstract", ""), "issn": result.get( - "issn", ""), "type": result.get( - "type", "")} for result in filtered_results] - credibility_task = get_credibility_metrics(sources_for_credibility) - - # Wait for both tasks to complete - citation_result, credibility_metrics = await asyncio.gather( - citation_task, - credibility_task, - return_exceptions=True - ) + # Start both tasks but handle credibility metrics first + credibility_metrics = await asyncio.gather(credibility_task, return_exceptions=True) + + if isinstance(credibility_metrics[0], Exception): + logger.exception(f"Credibility metrics failed: {str(credibility_metrics[0])}") + credibility_metrics = [] + else: + credibility_metrics = credibility_metrics[0] + + # Calculate scores immediately after getting credibility metrics + scores = await calculate_overall_score(credibility_metrics, sources_with_scores, + rerank_weight=0.6, credibility_weight=0.4) + sources = [ + item["data"] for item in credibility_metrics if item["status"] == "success" + ] if credibility_metrics else [] + + citation_result = await citation_task if isinstance(citation_result, Exception): logger.exception(f"Citation generation failed: {str(citation_result)}") raise CitationGenerationError("Failed to generate citations") - if isinstance(credibility_metrics, Exception): - logger.exception(f"Credibility metrics failed: {str(credibility_metrics)}") - credibility_metrics = [] - - # Calculate overall credibility score - overall_score = calculate_overall_score(credibility_metrics) - - # Extract source details from credibility metrics - sources = [] - if credibility_metrics: - sources = [ - item["data"] for item in credibility_metrics if item["status"] == "success"] - - # Structure the final response return { "result": citation_result, - "overall_score": overall_score, + "overall_score": scores["overall_score"], "sources": sources } @@ -436,13 +430,3 @@ async def _generate_citations( logger.exception(f"Unexpected error in citation generation: {str(e)}") return False - -# TODO: store unique top 2 reranked results in a set -# TODO: feed the above to an llm as context to generate a citation -# TODO: Break the user content into large batches and ask the llm to generate a citation for each sentence/paragraph in a batch in the requested format -# TODO: store the citation in a database -# TODO: return the content with intext citations and reference list in json format -# TODO: annotate code -# TODO: clean up code: Get rid of code smells,magic numbers and bottlenecks -# TODO: add tests -# TODO: add more error handling diff --git a/backend/mainService/src/services/source_credibility_metric_service.py b/backend/mainService/src/services/source_credibility_metric_service.py index 649a8f1..012b0f5 100644 --- a/backend/mainService/src/services/source_credibility_metric_service.py +++ b/backend/mainService/src/services/source_credibility_metric_service.py @@ -1,15 +1,52 @@ -from typing import List, Dict +from typing import List, Dict, Any import aiohttp from src.config.log_config import setup_logging import os +from functools import partial +import asyncio +from src.config.config import concurrency_config +from src.utils.concurrent_resources import credibility_executor, credibility_semaphore filename = os.path.basename(__file__) logger = setup_logging(filename=filename) +def _calculate_source_score(metric: Dict, source: Dict, + rerank_weight: float, credibility_weight: float) -> tuple[float, Dict]: + """ + Calculate weighted score for a single source in a separate thread. + Uses semaphore to limit concurrent calculations. + + Args: + metric (Dict): Credibility metric for the source + source (Dict): Source with rerank score + rerank_weight (float): Weight for rerank score + credibility_weight (float): Weight for credibility score + + Returns: + tuple[float, Dict]: Tuple of (weighted_score, updated_metric) + """ + with credibility_semaphore: + if metric["status"] != "success": + return 0.00, metric + + credibility_score = metric["data"]["credibility_score"] + rerank_score = source["rerank_score"] + + # Normalize rerank score to 0-1 range + normalized_rerank = min(max(rerank_score, 0), 1) + + # Calculate weighted score and normalize to 0-100 range + weighted_score = round((normalized_rerank * rerank_weight + + credibility_score * credibility_weight) * 100, 2) + + # Update the credibility score in the metric data + metric["data"]["credibility_score"] = weighted_score + return weighted_score, metric async def get_credibility_metrics(sources: List[Dict]) -> List[Dict]: """ Call the credibility API to get metrics for sources. + Uses connection pooling and timeout handling for better performance. Args: sources (List[Dict]): List of source metadata @@ -21,8 +58,13 @@ async def get_credibility_metrics(sources: List[Dict]) -> List[Dict]: if not credibility_metrics_api: logger.error("CREDIBILITY_API_URL is not set") return [] + + # Configure timeout and connection settings + timeout = aiohttp.ClientTimeout(total=10) # 10 seconds total timeout + connector = aiohttp.TCPConnector(limit=10) # Limit concurrent connections + try: - async with aiohttp.ClientSession() as session: + async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: async with session.post( credibility_metrics_api, json={'sources': sources}, @@ -33,37 +75,61 @@ async def get_credibility_metrics(sources: List[Dict]) -> List[Dict]: else: logger.error(f"Credibility API error: {response.status}") return [] + except asyncio.TimeoutError: + logger.error("Credibility API request timed out") + return [] except Exception: logger.exception("Error calling credibility API") return [] + finally: + connector.close() - -def calculate_overall_score(credibility_metrics: List[Dict]) -> float: +async def calculate_overall_score(credibility_metrics: List[Dict], sources_with_scores: List[Dict], + rerank_weight: float = 0.6, credibility_weight: float = 0.4) -> Dict[str, Any]: """ - Calculate the weighted average of credibility scores. - + Calculate weighted scores for each source and overall mean score using parallel processing. + Uses configured thread pool and semaphore for concurrent calculations. + Args: - credibility_metrics (List[Dict]): List of credibility metric responses - + credibility_metrics (List[Dict]): List of credibility metrics for each source + sources_with_scores (List[Dict]): List of sources with their rerank scores + rerank_weight (float): Weight for rerank score (default 0.6) + credibility_weight (float): Weight for credibility score (default 0.4) + Returns: - float: Weighted average score rounded to 2 decimal places + Dict[str, Any]: Dictionary containing source scores and overall mean score """ - try: - # Filter successful responses and extract scores - valid_scores = [ - item["data"]["credibility_score"] - for item in credibility_metrics - if item["status"] == "success" and "data" in item - ] - - if not valid_scores: - return 0.0 - - # Calculate simple average (can be modified to use weights if needed) - average_score = sum(valid_scores) / len(valid_scores) + if not credibility_metrics or not sources_with_scores: + return {"overall_score": 0.00, "source_scores": []} - return round(average_score, 2) - - except Exception: - logger.exception("Error calculating overall score") - return 0.0 + try: + calculate_score = partial(_calculate_source_score, + rerank_weight=rerank_weight, + credibility_weight=credibility_weight) + + # Process in batches using configured size + source_scores = [] + for i in range(0, len(sources_with_scores), concurrency_config.CREDIBILITY_BATCH_SIZE): + batch_metrics = credibility_metrics[i:i + concurrency_config.CREDIBILITY_BATCH_SIZE] + batch_sources = sources_with_scores[i:i + concurrency_config.CREDIBILITY_BATCH_SIZE] + + # Calculate batch scores + batch_results = list(credibility_executor.map( + lambda x: calculate_score(x[0], x[1]), + zip(batch_metrics, batch_sources) + )) + + scores, updated_metrics = zip(*batch_results) if batch_results else ([], []) + source_scores.extend(scores) + credibility_metrics[i:i + concurrency_config.CREDIBILITY_BATCH_SIZE] = updated_metrics + + overall_mean = round(sum(source_scores) / len(source_scores), 2) if source_scores else 0.00 + + return { + "overall_score": overall_mean, + "source_scores": source_scores + } + + except Exception as e: + logger.exception(f"Error in score calculation: {str(e)}") + return {"overall_score": 0.00, "source_scores": []} diff --git a/backend/mainService/src/utils/concurrent_resources.py b/backend/mainService/src/utils/concurrent_resources.py new file mode 100644 index 0000000..0d33028 --- /dev/null +++ b/backend/mainService/src/utils/concurrent_resources.py @@ -0,0 +1,15 @@ +from concurrent.futures import ThreadPoolExecutor +from threading import Semaphore +from src.config.config import concurrency_config + +# Create thread pool for credibility calculations +credibility_executor = ThreadPoolExecutor( + max_workers=concurrency_config.CREDIBILITY_MAX_THREADS +) + +# Create semaphore for limiting concurrent operations +credibility_semaphore = Semaphore(concurrency_config.CREDIBILITY_MAX_CONCURRENT) + +def cleanup_resources(): + """Cleanup all concurrent resources""" + credibility_executor.shutdown(wait=True) diff --git a/backend/mainService/src/utils/format_rerank_result.py b/backend/mainService/src/utils/format_rerank_result.py index 0056a00..a70e3f5 100644 --- a/backend/mainService/src/utils/format_rerank_result.py +++ b/backend/mainService/src/utils/format_rerank_result.py @@ -111,6 +111,8 @@ def filter_mixbread_results( doc: dict = result.input.get("metadata") if doc.get("id") not in seen_ids and result.score >= benchmark: seen_ids.add(doc.pop("id")) + doc["score"] = result.score + print(f"doc: {doc}") unique_results.append(doc) # with open("sample_output\\rerank_result_mixbread.json", "a") as f: # json.dump(unique_results, f, indent=4) diff --git a/backend/metricsService/src/api/endpoints.py b/backend/metricsService/src/api/endpoints.py index f9bd46d..ecdf15a 100644 --- a/backend/metricsService/src/api/endpoints.py +++ b/backend/metricsService/src/api/endpoints.py @@ -44,14 +44,27 @@ async def compute_credibility( """Calculate credibility score for a single source""" try: result = await calculate_credibility(request) + # Store the total score before modifying the result + total_score = result.get("total_score", 0) + if detailed: - credibility_score = result.pop("total_score", 0) - return {"status": "success", "data": {"credibility_score": credibility_score,"component": result, "url": request.domain, "title": request.title, "type": request.type}} + # Don't pop the total_score, just create a new dict without it for components + components = {k: v for k, v in result.items() if k != "total_score"} + return { + "status": "success", + "data": { + "credibility_score": total_score, + "component": components, + "url": request.domain, + "title": request.title, + "type": request.type + } + } else: return { "status": "success", "data": { - "credibility_score": result["total_score"], + "credibility_score": total_score, "url": request.domain, "title": request.title, "type": request.type diff --git a/backend/metricsService/src/services/credibility_service.py b/backend/metricsService/src/services/credibility_service.py index a85dd7e..6edc27b 100644 --- a/backend/metricsService/src/services/credibility_service.py +++ b/backend/metricsService/src/services/credibility_service.py @@ -106,6 +106,10 @@ async def calculate_credibility(request: CredibilityRequest) -> Dict[str, Any]: "authorship_reputation": results.get('author', 0) } + # Debug logging + logger.info(f"Final result before caching: {result}") + logger.info(f"Total score calculation: {total_score} (total_weight: {total_weight})") + # Cache the result await set_cache(cache_key, result) From eb43232a613955783fd5d986811167ec42b8a029 Mon Sep 17 00:00:00 2001 From: Ikeoluwa Oladele Date: Mon, 24 Mar 2025 12:06:56 -0400 Subject: [PATCH 5/5] update the favicon --- frontend/index.html | 2 +- frontend/package-lock.json | 982 ++++++++++++++++++ frontend/public/favicon.ico | Bin 4286 -> 0 bytes frontend/public/favicon.svg | 16 + frontend/src/components/CiteMeLogo.vue | 139 +++ .../Editor/WordAndCharacterCount.vue | 2 +- frontend/src/components/MainPageHeader.vue | 53 +- frontend/src/layouts/MainLayout.vue | 34 +- 8 files changed, 1211 insertions(+), 17 deletions(-) delete mode 100644 frontend/public/favicon.ico create mode 100644 frontend/public/favicon.svg create mode 100644 frontend/src/components/CiteMeLogo.vue diff --git a/frontend/index.html b/frontend/index.html index f365e77..0c9c565 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,7 +2,7 @@ - + Cite Me diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f4ebc69..a1ea400 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -42,6 +42,7 @@ "globals": "^16.0.0", "jsdom": "^26.0.0", "prettier": "3.5.3", + "puppeteer": "^22.4.1", "vite": "^6.2.1", "vite-plugin-vue-devtools": "^7.7.2", "vitest": "^3.0.8" @@ -1544,6 +1545,29 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@puppeteer/browsers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.0.tgz", + "integrity": "sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.3.5", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@remirror/core-constants": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", @@ -2571,6 +2595,13 @@ "vue": "^3.0.0" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -2616,6 +2647,17 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.26.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", @@ -3248,6 +3290,19 @@ "node": ">=12" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3265,6 +3320,13 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3272,6 +3334,106 @@ "dev": true, "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.1.tgz", + "integrity": "sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^3.0.0", + "bare-stream": "^2.0.0" + }, + "engines": { + "bare": ">=1.7.0" + } + }, + "node_modules/bare-os": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.0.tgz", + "integrity": "sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/birpc": { "version": "0.2.19", "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", @@ -3345,6 +3507,41 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -3459,6 +3656,99 @@ "node": ">= 16" } }, + "node_modules/chromium-bidi": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.3.tgz", + "integrity": "sha512-qXlsCmpCZJAnoTYI83Iu6EdYQpMYdVkCfq08KDh2pmlVqK5t5IA9mGs4/LwCwp4fqisSOMXZxP3HIh8w8aRn0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3547,6 +3837,33 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -3601,6 +3918,16 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -3700,6 +4027,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3719,6 +4061,13 @@ "node": ">=8" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/docx": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/docx/-/docx-9.3.0.tgz", @@ -3806,6 +4155,16 @@ "dev": true, "license": "MIT" }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -3832,6 +4191,26 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/error-stack-parser-es": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", @@ -3957,6 +4336,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/eslint": { "version": "9.22.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", @@ -4217,6 +4618,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -4306,6 +4721,43 @@ "node": ">=12.0.0" } }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4320,6 +4772,13 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4377,6 +4836,16 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/figures": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", @@ -4565,6 +5034,16 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -4619,6 +5098,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -4814,6 +5308,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4870,6 +5385,27 @@ "dev": true, "license": "ISC" }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", @@ -5114,6 +5650,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true, + "license": "MIT" + }, "node_modules/jsdom": { "version": "26.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", @@ -5185,6 +5728,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5516,6 +6066,13 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -5760,6 +6317,16 @@ "dev": true, "license": "MIT" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -5833,6 +6400,16 @@ "dev": true, "license": "MIT" }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/open": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", @@ -5908,6 +6485,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -5934,6 +6545,25 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-ms": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", @@ -6021,6 +6651,13 @@ "node": ">= 14.16" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -6221,6 +6858,16 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prosemirror-changeset": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz", @@ -6423,12 +7070,53 @@ "dev": true, "license": "ISC" }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6448,6 +7136,43 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "22.15.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.15.0.tgz", + "integrity": "sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.3.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1312386", + "puppeteer-core": "22.15.0" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "22.15.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.15.0.tgz", + "integrity": "sha512-cHArnywCiAAVXa3t4GGL2vttNxh7GqXtIYGym99egkNJ3oG//wL9LkvO4WE8W1TJe95t1F1ocu9X4xWaGsOKOA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.3.0", + "chromium-bidi": "0.6.3", + "debug": "^4.3.6", + "devtools-protocol": "0.0.1312386", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6485,6 +7210,16 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -6712,6 +7447,58 @@ "node": ">=18" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -6730,6 +7517,13 @@ "node": ">=0.10.0" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -6744,6 +7538,20 @@ "dev": true, "license": "MIT" }, + "node_modules/streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6948,6 +7756,50 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -7139,6 +7991,17 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -7209,6 +8072,13 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true, + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7795,6 +8665,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", @@ -7852,6 +8729,16 @@ "dev": true, "license": "MIT" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -7859,6 +8746,91 @@ "dev": true, "license": "ISC" }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7884,6 +8856,16 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index df36fcfb72584e00488330b560ebcf34a41c64c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S diff --git a/frontend/public/favicon.svg b/frontend/public/favicon.svg new file mode 100644 index 0000000..806c4a2 --- /dev/null +++ b/frontend/public/favicon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + " + \ No newline at end of file diff --git a/frontend/src/components/CiteMeLogo.vue b/frontend/src/components/CiteMeLogo.vue new file mode 100644 index 0000000..586dda3 --- /dev/null +++ b/frontend/src/components/CiteMeLogo.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/frontend/src/components/Editor/WordAndCharacterCount.vue b/frontend/src/components/Editor/WordAndCharacterCount.vue index e40b04e..0a5bef1 100644 --- a/frontend/src/components/Editor/WordAndCharacterCount.vue +++ b/frontend/src/components/Editor/WordAndCharacterCount.vue @@ -59,4 +59,4 @@ const props = defineProps({ const greenRegion = computed(() => props.characterLimit * 0.6); const yellowRegion = computed(() => props.characterLimit * 0.75); - \ No newline at end of file + diff --git a/frontend/src/components/MainPageHeader.vue b/frontend/src/components/MainPageHeader.vue index 93156d2..f2d985c 100644 --- a/frontend/src/components/MainPageHeader.vue +++ b/frontend/src/components/MainPageHeader.vue @@ -6,6 +6,7 @@ import { PlayIcon, } from 'lucide-vue-next'; import { useCitationStore } from '@/stores/citationStore'; +import CiteMeLogo from '@/components/CiteMeLogo.vue'; // import { useRouter } from 'vue-router'; // const router = useRouter(); @@ -64,6 +65,7 @@ const toggleView = () => {
+
+ +
+ +
+ { maxlength="50" />
+ + + + +
- + diff --git a/frontend/src/layouts/MainLayout.vue b/frontend/src/layouts/MainLayout.vue index a523157..f52f5e6 100644 --- a/frontend/src/layouts/MainLayout.vue +++ b/frontend/src/layouts/MainLayout.vue @@ -7,6 +7,7 @@ import RightSidebar from '@/components/SideBar/RightSidebar.vue' import CitationSourceSelector from '@/components/CitationSourceSelector.vue' import CitationStyleSelector from '@/components/CitationStyleSelector.vue' import { provide, computed } from 'vue' +import CiteMeLogo from '@/components/CiteMeLogo.vue'; const store = useCitationStore() @@ -57,22 +58,27 @@ const citationStyle = defineModel('citationStyle') - -
- -
- -
+
+ +
+ +
+ +
+ - - + + +
+ +