diff --git a/README.md b/README.md index 284ce97..b27813b 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: @@ -46,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 @@ -54,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 @@ -83,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 @@ -92,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/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/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/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/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/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/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 3b2a138..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 @@ -17,9 +54,17 @@ 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 [] + + # 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}, @@ -30,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/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/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) 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 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 df36fcf..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ 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') - -
- -
- -
+
+ +
+ +
+ +
+ - - + + +
+ +