Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 7 additions & 17 deletions src/api/endpoints/annotate/all/get/models/agency.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
from pydantic import BaseModel, Field


class AgencyAnnotationAutoSuggestion(BaseModel):
class AgencyAnnotationSuggestion(BaseModel):

Check warning on line 3 in src/api/endpoints/annotate/all/get/models/agency.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/all/get/models/agency.py#L3 <101>

Missing docstring in public class
Raw output
./src/api/endpoints/annotate/all/get/models/agency.py:3:1: D101 Missing docstring in public class
agency_id: int
agency_name: str
confidence: int = Field(
title="The confidence of the location",
user_count: int
robo_confidence: int | None = Field(
description="The robo labeler's given confidence for its suggestion. Null if no robo-label occurred.",
ge=0,
le=100,
)

class AgencyAnnotationUserSuggestion(BaseModel):
agency_id: int
agency_name: str
user_count: int

class AgencyAnnotationUserSuggestionOuterInfo(BaseModel):
suggestions: list[AgencyAnnotationUserSuggestion]
class AgencyAnnotationResponseOuterInfo(BaseModel):

Check warning on line 13 in src/api/endpoints/annotate/all/get/models/agency.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/all/get/models/agency.py#L13 <101>

Missing docstring in public class
Raw output
./src/api/endpoints/annotate/all/get/models/agency.py:13:1: D101 Missing docstring in public class
suggestions: list[AgencyAnnotationSuggestion]
not_found_count: int = Field(
title="How many users listed the agency as not found.",
ge=0,
description="How many users indicated the agency could not be found."
)

class AgencyAnnotationResponseOuterInfo(BaseModel):
user: AgencyAnnotationUserSuggestionOuterInfo
auto: list[AgencyAnnotationAutoSuggestion]
35 changes: 9 additions & 26 deletions src/api/endpoints/annotate/all/get/models/location.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
from pydantic import BaseModel, Field


class LocationAnnotationAutoSuggestion(BaseModel):
class LocationAnnotationSuggestion(BaseModel):

Check warning on line 4 in src/api/endpoints/annotate/all/get/models/location.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/all/get/models/location.py#L4 <101>

Missing docstring in public class
Raw output
./src/api/endpoints/annotate/all/get/models/location.py:4:1: D101 Missing docstring in public class
location_id: int
location_name: str = Field(
title="The full name of the location"
)
confidence: int = Field(
title="The confidence of the location",
location_name: str
user_count: int
robo_confidence: int | None = Field(
description="The robo labeler's given confidence for its suggestion. Null if no robo-label occurred.",
ge=0,
le=100,
)


class LocationAnnotationUserSuggestion(BaseModel):
location_id: int
location_name: str = Field(
title="The full name of the location"
)
user_count: int = Field(
title="The number of users who suggested this location",
ge=1,
)

class LocationAnnotationUserSuggestionOuterInfo(BaseModel):
suggestions: list[LocationAnnotationUserSuggestion]
not_found_count: int = Field(
title="How many users listed the location as not found.",
ge=0,
)

class LocationAnnotationResponseOuterInfo(BaseModel):
user: LocationAnnotationUserSuggestionOuterInfo
auto: list[LocationAnnotationAutoSuggestion]
suggestions: list[LocationAnnotationSuggestion]
not_found_count: int = Field(
description="How many users indicated the location could not be found."
)

Check warning on line 18 in src/api/endpoints/annotate/all/get/models/location.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/all/get/models/location.py#L18 <292>

no newline at end of file
Raw output
./src/api/endpoints/annotate/all/get/models/location.py:18:6: W292 no newline at end of file
23 changes: 6 additions & 17 deletions src/api/endpoints/annotate/all/get/queries/agency/core.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationResponseOuterInfo, \
AgencyAnnotationUserSuggestionOuterInfo, AgencyAnnotationUserSuggestion, AgencyAnnotationAutoSuggestion
from src.api.endpoints.annotate.all.get.queries.agency.requester import GetAgencySuggestionsRequester
from src.db.queries.base.builder import QueryBuilderBase
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationResponseOuterInfo, \
AgencyAnnotationUserSuggestionOuterInfo, AgencyAnnotationUserSuggestion, AgencyAnnotationAutoSuggestion
from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationResponseOuterInfo
from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationSuggestion
from src.api.endpoints.annotate.all.get.queries.agency.requester import GetAgencySuggestionsRequester
from src.db.queries.base.builder import QueryBuilderBase

Expand All @@ -30,18 +24,13 @@ async def run(self, session: AsyncSession) -> AgencyAnnotationResponseOuterInfo:
location_id=self.location_id
)

user_suggestions: list[AgencyAnnotationUserSuggestion] = \
await requester.get_user_agency_suggestions()
auto_suggestions: list[AgencyAnnotationAutoSuggestion] = \
await requester.get_auto_agency_suggestions()
suggestions: list[AgencyAnnotationSuggestion] = \
await requester.get_agency_suggestions()
not_found_count: int = \
await requester.get_not_found_count()
return AgencyAnnotationResponseOuterInfo(
user=AgencyAnnotationUserSuggestionOuterInfo(
suggestions=user_suggestions,
not_found_count=not_found_count
),
auto=auto_suggestions,
suggestions=suggestions,
not_found_count=not_found_count
)


148 changes: 71 additions & 77 deletions src/api/endpoints/annotate/all/get/queries/agency/requester.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
from typing import Sequence

from sqlalchemy import func, select, RowMapping
from sqlalchemy import func, select, RowMapping, or_, and_
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationAutoSuggestion, \
AgencyAnnotationUserSuggestion
from src.api.endpoints.annotate.all.get.queries.agency.suggestions_with_highest_confidence import \
SuggestionsWithHighestConfidenceCTE
from src.api.endpoints.annotate.all.get.models.agency import AgencyAnnotationSuggestion
from src.db.helpers.query import exists_url
from src.db.helpers.session import session_helper as sh
from src.db.models.impl.agency.sqlalchemy import Agency
from src.db.models.impl.link.agency_location.sqlalchemy import LinkAgencyLocation
from src.db.models.impl.link.user_suggestion_not_found.agency.sqlalchemy import LinkUserSuggestionAgencyNotFound
from src.db.models.impl.url.suggestion.agency.subtask.sqlalchemy import URLAutoAgencyIDSubtask
from src.db.models.impl.url.suggestion.agency.suggestion.sqlalchemy import AgencyIDSubtaskSuggestion
from src.db.models.impl.url.suggestion.agency.user import UserURLAgencySuggestion
from src.db.templates.requester import RequesterBase

Expand All @@ -27,102 +26,97 @@
self.url_id = url_id
self.location_id = location_id

async def get_user_agency_suggestions(self) -> list[AgencyAnnotationUserSuggestion]:
query = (
async def get_agency_suggestions(self) -> list[AgencyAnnotationSuggestion]:

Check warning on line 29 in src/api/endpoints/annotate/all/get/queries/agency/requester.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/all/get/queries/agency/requester.py#L29 <102>

Missing docstring in public method
Raw output
./src/api/endpoints/annotate/all/get/queries/agency/requester.py:29:1: D102 Missing docstring in public method
# All agencies with either a user or robo annotation
valid_agencies_cte = (
select(
UserURLAgencySuggestion.agency_id,
func.count(UserURLAgencySuggestion.user_id).label("count"),
Agency.name.label("agency_name"),
)
.join(
Agency,
Agency.id == UserURLAgencySuggestion.agency_id
Agency.id,
)

)

if self.location_id is not None:
query = (
query.join(
LinkAgencyLocation,
LinkAgencyLocation.agency_id == UserURLAgencySuggestion.agency_id
)
.where(
LinkAgencyLocation.location_id == self.location_id
.where(
or_(
exists_url(
UserURLAgencySuggestion
),
exists_url(
URLAutoAgencyIDSubtask
)
)
)
.cte("valid_agencies")
)

query = (
query.where(
UserURLAgencySuggestion.url_id == self.url_id
# Number of users who suggested each agency
user_suggestions_cte = (
select(
UserURLAgencySuggestion.url_id,
UserURLAgencySuggestion.agency_id,
func.count(UserURLAgencySuggestion.user_id).label('user_count')
)
.group_by(
UserURLAgencySuggestion.agency_id,
Agency.name
UserURLAgencySuggestion.url_id,
)
.order_by(
func.count(UserURLAgencySuggestion.user_id).desc()
)
.limit(3)
.cte("user_suggestions")
)

results: Sequence[RowMapping] = await sh.mappings(self.session, query=query)

return [
AgencyAnnotationUserSuggestion(
agency_id=autosuggestion["agency_id"],
user_count=autosuggestion["count"],
agency_name=autosuggestion["agency_name"],
# Maximum confidence of robo annotation, if any
robo_suggestions_cte = (
select(
URLAutoAgencyIDSubtask.url_id,
Agency.id.label("agency_id"),
func.max(AgencyIDSubtaskSuggestion.confidence).label('robo_confidence')
)
for autosuggestion in results
]


async def get_auto_agency_suggestions(self) -> list[AgencyAnnotationAutoSuggestion]:
cte = SuggestionsWithHighestConfidenceCTE()
query = (
.join(
AgencyIDSubtaskSuggestion,
AgencyIDSubtaskSuggestion.subtask_id == URLAutoAgencyIDSubtask.id
)
.join(
Agency,
Agency.id == AgencyIDSubtaskSuggestion.agency_id
)
.group_by(
URLAutoAgencyIDSubtask.url_id,
Agency.id
)
.cte("robo_suggestions")
)
# Join user and robo suggestions
joined_suggestions_query = (
select(
cte.agency_id,
cte.confidence,
valid_agencies_cte.c.id.label("agency_id"),
Agency.name.label("agency_name"),
func.coalesce(user_suggestions_cte.c.user_count, 0).label('user_count'),
func.coalesce(robo_suggestions_cte.c.robo_confidence, 0).label('robo_confidence'),
)
.join(
Agency,
Agency.id == cte.agency_id
Agency.id == valid_agencies_cte.c.id
)
)

if self.location_id is not None:
query = (
query.join(
LinkAgencyLocation,
LinkAgencyLocation.agency_id == cte.agency_id
)
.where(
LinkAgencyLocation.location_id == self.location_id
.outerjoin(
user_suggestions_cte,
and_(
user_suggestions_cte.c.url_id == self.url_id,
user_suggestions_cte.c.agency_id == Agency.id
)
)

query = (
query.where(
cte.url_id == self.url_id
)
.order_by(
cte.confidence.desc()
.outerjoin(
robo_suggestions_cte,
and_(
robo_suggestions_cte.c.url_id == self.url_id,
robo_suggestions_cte.c.agency_id == Agency.id
)
)
.limit(3)
)

results: Sequence[RowMapping] = await sh.mappings(self.session, query=query)

return [
AgencyAnnotationAutoSuggestion(
agency_id=autosuggestion["agency_id"],
confidence=autosuggestion["confidence"],
agency_name=autosuggestion["agency_name"],
# Return suggestions
mappings: Sequence[RowMapping] = await self.mappings(joined_suggestions_query)
suggestions: list[AgencyAnnotationSuggestion] = [
AgencyAnnotationSuggestion(
**mapping
)
for autosuggestion in results
for mapping in mappings
]
return suggestions

async def get_not_found_count(self) -> int:
query = (
Expand Down
26 changes: 8 additions & 18 deletions src/api/endpoints/annotate/all/get/queries/location_/core.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.get.models.location import LocationAnnotationResponseOuterInfo, \
LocationAnnotationUserSuggestion, LocationAnnotationAutoSuggestion, LocationAnnotationUserSuggestionOuterInfo
from src.api.endpoints.annotate.all.get.queries.location_.requester import GetLocationSuggestionsRequester
from src.db.queries.base.builder import QueryBuilderBase
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.get.models.location import LocationAnnotationResponseOuterInfo, \
LocationAnnotationUserSuggestion, LocationAnnotationAutoSuggestion
from src.api.endpoints.annotate.all.get.models.location import LocationAnnotationResponseOuterInfo
from src.api.endpoints.annotate.all.get.models.location import LocationAnnotationSuggestion
from src.api.endpoints.annotate.all.get.queries.location_.requester import GetLocationSuggestionsRequester
from src.db.queries.base.builder import QueryBuilderBase

Expand All @@ -21,21 +15,17 @@ def __init__(
super().__init__()
self.url_id = url_id


# TODO: Test
async def run(self, session: AsyncSession) -> LocationAnnotationResponseOuterInfo:
requester = GetLocationSuggestionsRequester(session)
user_suggestions: list[LocationAnnotationUserSuggestion] = \
await requester.get_user_location_suggestions(self.url_id)
auto_suggestions: list[LocationAnnotationAutoSuggestion] = \
await requester.get_auto_location_suggestions(self.url_id)

suggestions: list[LocationAnnotationSuggestion] = \
await requester.get_location_suggestions(self.url_id)
not_found_count: int = \
await requester.get_not_found_count(self.url_id)

return LocationAnnotationResponseOuterInfo(
user=LocationAnnotationUserSuggestionOuterInfo(
suggestions=user_suggestions,
not_found_count=not_found_count
),
auto=auto_suggestions
suggestions=suggestions,
not_found_count=not_found_count
)

Loading