Skip to content

Commit

Permalink
feature: add google insight
Browse files Browse the repository at this point in the history
  • Loading branch information
DEMARES Timothee committed Oct 3, 2024
1 parent 6699fc2 commit cb2292e
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 68 deletions.
8 changes: 8 additions & 0 deletions app/adapter/exception/app_exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@ def __init__(self, message: str):

def __str__(self):
return self.message


class GoogleInsightError(AppError):
pass


class ParsingError(GoogleInsightError):
pass
47 changes: 7 additions & 40 deletions app/core/insight/google.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,11 @@
from functools import cached_property
from app.core.insight.interface import (
Insight,
)

import requests

from app.adapter.exception.app_exception import AppError
from app.core.insight.interface import Insight, InsightContent, endpoint
from app.core.settings import SETTINGS
class MobileInsight(Insight):
_STATEGY = "mobile"


class GoogleInsight(Insight):
"""
Attributes
----------
url : str
The URL to test
Methods
-------
load() -> dict:
Load the insights from the Google API
get_desktop_result() -> InsightContent:
Get the insights for the desktop version
get_mobile_result() -> InsightContent:
Get the insights for the mobile version
"""

def __init__(self, url: str, strategy: str) -> None:
self.url = url
self.strategy = strategy
self._api_key = SETTINGS.GOOGLE_INSIGHTS_API_KEY

@cached_property
def load(self) -> dict:
api_url = endpoint(self.url, self.api_key)

response = requests.get(api_url)

if response.status_code == 200:
return response.json()
else:
raise AppError(f"Erreur {response.status_code}: {response.text}")

def get_desktop_result(self) -> InsightContent:
pass
class DestopInsight(Insight):
_STATEGY = "desktop"
138 changes: 125 additions & 13 deletions app/core/insight/interface.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,51 @@
from abc import ABC, abstractmethod
from abc import ABC
from collections.abc import Iterable
from functools import cached_property
from typing import Literal

import requests
from pydantic import BaseModel

from app.adapter.exception.app_exception import GoogleInsightError, ParsingError
from app.core.settings import SETTINGS


class InsightContent(BaseModel):
"""
Attributes
----------
performance : int
Score 0-100
accessibility : int
Score 0-100
best_practices : int
Score 0-100
seo : int
first_contentful_paint : float
largest_contentful_paint : float
Score 0-100
first_contentful_paint : int
largest_contentful_paint : int
total_blocking_time : int
cumulative_layout_shift : float
speed_index : float
speed_index : int
"""

performance: int
accessibility: int
best_practices: int
seo: int
first_contentful_paint: float
largest_contentful_paint: float
first_contentful_paint: int
largest_contentful_paint: int
total_blocking_time: int
cumulative_layout_shift: float
speed_index: float
speed_index: int


Strategy = Literal["mobile", "desktop"]
Category = Literal["accessibility", "performance", "best_practices", "seo"]
Locale = Literal["fr", "en"]

ALL_CATEGORIES = "accessibility", "performance", "best_practices", "seo"


def endpoint(
*,
Expand All @@ -45,7 +56,7 @@ def endpoint(
locale: Locale = "fr",
) -> str:
# Default categories
categories = categories or ("accessibility", "performance", "best_practices", "seo")
categories = categories or ALL_CATEGORIES

# Base URL
base_url = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?"
Expand All @@ -69,11 +80,112 @@ def endpoint(
return base_url


def get_insight_or_raise(data: dict, key: str) -> dict | int | str | float:
result = data.get(key)

if result is None:
raise ParsingError(f"Cannot find {key} on insight result")

return result


class Insight(ABC):
@abstractmethod
def load(self, url: str, strategy: Strategy) -> dict:
pass
_STATEGY: Strategy

def __init__(self, url: str, *, locale: Locale = "fr") -> None:
self.url = url
self.locale = locale

@abstractmethod
def get_result(self) -> InsightContent:
pass
return InsightContent(
performance=int(self.performance["score"] * 100),
accessibility=int(self.accessibility["score"] * 100),
best_practices=int(self.best_practices["score"] * 100),
seo=int(self.seo["score"] * 100),
cumulative_layout_shift=self.cumulative_layout_shift,
first_contentful_paint=self.first_contentful_paint,
speed_index=self.speed_index,
largest_contentful_paint=self.largest_contentful_paint,
total_blocking_time=self.total_blocking_time,
)

@cached_property
def data(self) -> dict:
api_url = endpoint(
url=self.url,
api_key=SETTINGS.GOOGLE_INSIGHTS_API_KEY,
categories=ALL_CATEGORIES,
strategy=self._STATEGY,
locale=self.locale,
)

response = requests.get(api_url)

if response.status_code != 200:
raise GoogleInsightError(f"Erreur {response.status_code}: {response.text}")

return response.json()

@cached_property
def _light_result(self) -> dict:
return get_insight_or_raise(self.data, "lighthouseResult")

@cached_property
def _categories(self) -> dict:
return get_insight_or_raise(self._light_result, "categories")

@property
def performance(self) -> dict:
return get_insight_or_raise(self._categories, "performance")

@property
def accessibility(self) -> dict:
return get_insight_or_raise(self._categories, "accessibility")

@property
def best_practices(self) -> dict:
return get_insight_or_raise(self._categories, "best-practices")

@property
def seo(self) -> dict:
return get_insight_or_raise(self._categories, "seo")

@cached_property
def _audits(self) -> dict:
return get_insight_or_raise(self._light_result, "audits")

@cached_property
def _metrics(self) -> dict:
return get_insight_or_raise(self._audits, "metrics")

@cached_property
def _details(self) -> dict:
return get_insight_or_raise(self._metrics, "details")

@cached_property
def _details_items(self) -> dict:
return get_insight_or_raise(self._details, "items")[0]

@property
def cumulative_layout_shift(self) -> float:
return get_insight_or_raise(self._details_items, "cumulativeLayoutShift")

@property
def first_contentful_paint(self) -> int:
return get_insight_or_raise(self._details_items, "firstContentfulPaint")

@property
def speed_index(self) -> int:
return get_insight_or_raise(self._details_items, "speedIndex")

@property
def largest_contentful_paint(self) -> int:
return get_insight_or_raise(self._details_items, "largestContentfulPaint")

@property
def total_blocking_time(self) -> int:
return get_insight_or_raise(self._details_items, "totalBlockingTime")

@property
def time_to_first_byte(self) -> int:
return get_insight_or_raise(self._details_items, "timeToFirstByte")
18 changes: 3 additions & 15 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,17 @@
import logging
from atexit import register

import requests

from app.core.constants import LOGGER_NAME
from app.core.settings import SETTINGS
from app.core.insight.google import MobileInsight

logger = logging.getLogger(LOGGER_NAME)


def main():
"""Entry point for the application."""
API_KEY = SETTINGS.GOOGLE_INSIGHTS_API_KEY

url = "https://www.alextraveylan.fr"
api_url = f"https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={url}&key={API_KEY}"

response = requests.get(api_url)

# Vérifier si la requête s'est bien déroulée
if response.status_code == 200:
json_response = response.json()
print(json_response)
else:
print(f"Erreur {response.status_code}: {response.text}")
insight = MobileInsight(url)
print(insight.get_result())


@register
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pydantic-settings
requests
pydantic

0 comments on commit cb2292e

Please sign in to comment.