Skip to content

Commit e70d579

Browse files
committed
feat: paysage optimizations
1 parent b97ce8b commit e70d579

File tree

9 files changed

+239
-76
lines changed

9 files changed

+239
-76
lines changed

notebooks/paysage_api_test.ipynb

+84-6
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,103 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 1,
5+
"execution_count": 30,
66
"metadata": {},
7-
"outputs": [],
7+
"outputs": [
8+
{
9+
"data": {
10+
"text/plain": [
11+
"True"
12+
]
13+
},
14+
"execution_count": 30,
15+
"metadata": {},
16+
"output_type": "execute_result"
17+
}
18+
],
819
"source": [
20+
"import os\n",
921
"import requests\n",
10-
"import pandas as pd"
22+
"\n",
23+
"import pandas as pd\n",
24+
"from dotenv import load_dotenv\n",
25+
"\n",
26+
"load_dotenv()"
27+
]
28+
},
29+
{
30+
"cell_type": "code",
31+
"execution_count": 2,
32+
"metadata": {},
33+
"outputs": [],
34+
"source": [
35+
"url = \"https://paysage-api.staging.dataesr.ovh/relations?limit=10000&filters[relationTag]=structure-categorie&filters[relatedObjectId]=mCpLW\"\n",
36+
"headers = {\"X-API-KEY\": os.getenv(\"PAYSAGE_API_KEY\")}\n",
37+
"\n",
38+
"response = requests.get(url, headers=headers)"
1139
]
1240
},
1341
{
1442
"cell_type": "code",
15-
"execution_count": 21,
43+
"execution_count": 9,
44+
"metadata": {},
45+
"outputs": [
46+
{
47+
"data": {
48+
"text/plain": [
49+
"'mCpLW'"
50+
]
51+
},
52+
"execution_count": 9,
53+
"metadata": {},
54+
"output_type": "execute_result"
55+
}
56+
],
57+
"source": [
58+
"response.json().get(\"data\")[0].get(\"relatedObjectId\")"
59+
]
60+
},
61+
{
62+
"cell_type": "code",
63+
"execution_count": 45,
1664
"metadata": {},
1765
"outputs": [],
1866
"source": [
19-
"url = \"https://paysage-api.staging.dataesr.ovh/relations?limit=10000&filters[relationTag]=structure-categorie&filters[relatedObjectId]=mCpLW&filters[relatedObjectId]=Eg7tX&filters[relatedObjectId]=93BR1&filters[relatedObjectId]=2ZdzP&filters[relatedObjectId]=MTFHZ&filters[relatedObjectId]=UfEnK&filters[relatedObjectId]=Sv5bb&filters[relatedObjectId]=mNJ1Z&filters[relatedObjectId]=WCat8&filters[relatedObjectId]=fQ6GL&filters[relatedObjectId]=WkSgR&filters[relatedObjectId]=YNqFb&filters[relatedObjectId]=iyn79&filters[relatedObjectId]=NsMkU\"\n",
20-
"headers = {\"X-API-KEY\": \"xkeypsg-72b39GvylkDPoEe6AwUz\"}\n",
67+
"id = \"m7K6T\"\n",
68+
"url = f\"https://paysage-api.staging.dataesr.ovh/structures/{id}\"\n",
69+
"url = f\"https://paysage-api.staging.dataesr.ovh/relations?limit=100&filters[relationTag]=structure-categorie&filters[resourceId]={id}\"\n",
70+
"headers = {\"X-API-KEY\": os.getenv(\"PAYSAGE_API_KEY\")}\n",
2171
"\n",
2272
"response = requests.get(url, headers=headers)"
2373
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": 62,
78+
"metadata": {},
79+
"outputs": [
80+
{
81+
"data": {
82+
"text/plain": [
83+
"{'usualNameFr': 'Université',\n",
84+
" 'priority': 1,\n",
85+
" 'id': 'mCpLW',\n",
86+
" 'displayName': 'Université',\n",
87+
" 'collection': 'categories',\n",
88+
" 'href': '/categories/mCpLW',\n",
89+
" 'usualNameEn': None,\n",
90+
" 'descriptionFr': None,\n",
91+
" 'descriptionEn': None}"
92+
]
93+
},
94+
"execution_count": 62,
95+
"metadata": {},
96+
"output_type": "execute_result"
97+
}
98+
],
99+
"source": [
100+
"response.json().get(\"data\")[16].get(\"relatedObject\")"
101+
]
24102
}
25103
],
26104
"metadata": {

project/client/dist/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
77
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
88
<title>Affiliation Matcher</title>
9-
<script type="module" crossorigin src="/static/index-78f5f2fe.js"></script>
9+
<script type="module" crossorigin src="/static/index-09aab7a4.js"></script>
1010
<link rel="stylesheet" href="/static/index-b7346e81.css">
1111
</head>
1212

project/client/dist/static/index-78f5f2fe.js project/client/dist/static/index-09aab7a4.js

+24-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

project/client/src/components/results/debug/index.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { MatchDebug } from "../../../types"
44

55
type ResultsDebugArgs = {
66
resultsDebug: MatchDebug
7+
resultsLogs: string
78
}
8-
export default function ResultsDebug({ resultsDebug }: ResultsDebugArgs) {
9+
export default function ResultsDebug({ resultsDebug, resultsLogs }: ResultsDebugArgs) {
910
const intl = useIntl()
1011
if (!resultsDebug) return null
1112

@@ -40,6 +41,9 @@ export default function ResultsDebug({ resultsDebug }: ResultsDebugArgs) {
4041
))}
4142
</Container>
4243
))}
44+
<Container>
45+
<div dangerouslySetInnerHTML={{ __html: resultsLogs }} />
46+
</Container>
4347
</Accordion>
4448
)
4549
}

project/client/src/components/results/index.tsx

+83-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect, useState } from "react"
22
import { useIntl } from "react-intl"
33
import { Container, Text, Badge } from "@dataesr/dsfr-plus"
4-
import { MatchResults } from "../../types"
4+
import { MatchIds, MatchResults } from "../../types"
55
import Error from "../error"
66
import Result from "./result"
77
import Fetching from "../fetching"
@@ -10,6 +10,81 @@ import useUrl from "../../hooks/useUrl"
1010
import Info from "../info"
1111
import useMatch from "../../hooks/useMatch"
1212

13+
type MatcherResultsArgs = {
14+
matchIds: MatchIds
15+
matchResults: MatchResults
16+
setTitle: any
17+
}
18+
19+
function MatcherResults({ matchIds, matchResults, setTitle }: MatcherResultsArgs) {
20+
const intl = useIntl()
21+
return (
22+
<Container fluid>
23+
<Container className="fr-mt-3w">
24+
<Text size="md">{intl.formatMessage({ id: "match.count" }, { count: matchIds.length })}</Text>
25+
</Container>
26+
<Container fluid className="fr-mt-3w">
27+
{matchIds.map((id, index) => {
28+
return <Result key={index} resultData={matchResults} resultId={id} setTitle={setTitle} />
29+
})}
30+
</Container>
31+
</Container>
32+
)
33+
}
34+
35+
function PaysageResults({ matchIds, matchResults, setTitle }: MatcherResultsArgs) {
36+
const intl = useIntl()
37+
38+
const DEFAULT_CATEGORY = "Others"
39+
const DEFAULT_PRIORITY = 99
40+
41+
const categories = matchResults?.enriched_results?.reduce((acc, res) => {
42+
if (res?.paysage_categories) {
43+
const lowestPriority = Math.min(...res.paysage_categories.map((category) => category?.priority || DEFAULT_PRIORITY))
44+
res.paysage_categories
45+
.filter((category) => (category?.priority || DEFAULT_PRIORITY) === lowestPriority)
46+
.forEach((category) => {
47+
const label = category?.label || DEFAULT_CATEGORY
48+
const priority = category?.priority || DEFAULT_PRIORITY
49+
acc[label] = acc?.[label]
50+
? { ...acc[label], ids: [...acc[label].ids, res.id] }
51+
: { ids: [res.id], priority: priority }
52+
})
53+
} else {
54+
acc[DEFAULT_CATEGORY] = acc?.[DEFAULT_CATEGORY]
55+
? { ...acc[DEFAULT_CATEGORY], ids: [...acc[DEFAULT_CATEGORY].ids, res.id] }
56+
: { ids: [res.id], priority: DEFAULT_PRIORITY }
57+
}
58+
return acc
59+
}, {} as Record<string, { ids: MatchIds; priority: number }>)
60+
61+
if (!categories || (Object.keys(categories)?.length === 1 && Object.keys(categories)[0] === DEFAULT_CATEGORY))
62+
return <MatcherResults matchIds={matchIds} matchResults={matchResults} setTitle={setTitle} />
63+
64+
return (
65+
<Container fluid>
66+
{Object.entries(categories)
67+
.sort((a, b) => a[1].priority - b[1].priority)
68+
.map(([key, values]) => (
69+
<Container fluid>
70+
<Container className="fr-mt-3w">
71+
<Text size="md">
72+
{key}
73+
{" : "}
74+
{intl.formatMessage({ id: "match.count" }, { count: values.ids.length })}
75+
</Text>
76+
</Container>
77+
<Container fluid className="fr-mt-3w">
78+
{values.ids.map((id, index) => {
79+
return <Result key={index} resultData={matchResults} resultId={id} setTitle={setTitle} />
80+
})}
81+
</Container>
82+
</Container>
83+
))}
84+
</Container>
85+
)
86+
}
87+
1388
export default function Results() {
1489
const intl = useIntl()
1590
const { currentQuery, currentMatcher, currentYear } = useUrl()
@@ -42,7 +117,7 @@ export default function Results() {
42117
<Container className="fr-mt-3w">
43118
<Badge color="error">{`${currentMatcher} : ${intl.formatMessage({ id: "match.count" }, { count: 0 })}`}</Badge>
44119
</Container>
45-
<ResultsDebug resultsDebug={matchResults?.debug} />
120+
<ResultsDebug resultsDebug={matchResults?.debug} resultsLogs={matchResults?.logs} />
46121
</Container>
47122
)
48123

@@ -51,16 +126,12 @@ export default function Results() {
51126
<Container className="sticky card">
52127
<Text size="lead">{currentTitle}</Text>
53128
</Container>
54-
<Container className="fr-mt-3w">
55-
<Text size="md">{intl.formatMessage({ id: "match.count" }, { count: matchIds.length })}</Text>
56-
</Container>
57-
<Container fluid className="fr-mt-3w">
58-
{matchIds.map((id, index) => {
59-
return <Result key={index} resultData={matchResults} resultId={id} setTitle={setTitle} />
60-
})}
61-
</Container>
62-
<ResultsDebug resultsDebug={matchResults?.debug} />
63-
{/* <div dangerouslySetInnerHTML={{ __html: matchResults?.logs }} /> */}
129+
{currentMatcher === "paysage" ? (
130+
<PaysageResults matchIds={matchIds} matchResults={matchResults} setTitle={setTitle} />
131+
) : (
132+
<MatcherResults matchIds={matchIds} matchResults={matchResults} setTitle={setTitle} />
133+
)}
134+
<ResultsDebug resultsDebug={matchResults?.debug} resultsLogs={matchResults?.logs} />
64135
</Container>
65136
)
66137
}

project/client/src/locales/en.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"info.missing.query": "Please enter a text affiliation",
33
"info.missing.matcher": "Please select a matcher",
4-
"debug.accordion.title": "Matching details",
4+
"debug.accordion.title": "Matching logs",
55
"match.count": "{count, plural, =0 {# matches} one {# match} other {# matches}}",
66
"possibility.count": "{count, plural, =0 {# possibilities} one {# possibility} other {# possibilities}}"
77
}

project/client/src/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type MatchEnrichedResult = {
77
acronym?: Array<string>
88
city?: Array<string>
99
country?: Array<string>
10+
paysage_categories?: Array<{ id: string; label?: string; priority?: number }>
1011
}
1112
export type MatchEnrichedResults = Array<MatchEnrichedResult>
1213

project/server/main/load_paysage.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def load_paysage(index_prefix: str = "matcher") -> dict:
127127
for criterion_value in criterion_values:
128128
if criterion_value not in es_data[criterion]:
129129
es_data[criterion][criterion_value] = []
130-
es_data[criterion][criterion_value].append({"id": data_point["id"], "categories": data_point["categories"]})
130+
es_data[criterion][criterion_value].append({"id": data_point["id"]})
131131

132132
# Bulk insert data into ES
133133
actions = []

0 commit comments

Comments
 (0)