Skip to content

Commit

Permalink
feat: Enhanced Political Career Analysis System (#6936)
Browse files Browse the repository at this point in the history
* feat: Enhanced Political Career Analysis System

Implements comprehensive political experience scoring framework with
weighted metrics
for Swedish parliamentary roles and policy domains.

Key analytical improvements:
- Hierarchical role weighting (50-1) prioritizing executive positions
- Policy domain importance scaling (5.0-0.5) emphasizing core state
functions
- Career phase classification based on cumulative weighted experience
- Detailed expertise mapping across parliamentary committees and
ministries
- Sophisticated political career trajectory analysis

Impact:
- More nuanced evaluation of political influence and expertise
- Better identification of policy domain specialists
- Improved tracking of career progression patterns
- Enhanced assessment of leadership experience

Supports deeper institutional analysis and career pattern recognition in
Swedish political system.

* cleanup

* fix

* fix

* update

* cleanup
  • Loading branch information
pethers authored Jan 5, 2025
1 parent f944800 commit 1529d24
Show file tree
Hide file tree
Showing 6 changed files with 2,983 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.util.Date;
import java.util.Locale;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.annotation.Secured;
Expand All @@ -28,6 +29,8 @@
import com.hack23.cia.model.external.riksdagen.person.impl.PersonData;
import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPolitician;
import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPoliticianBallotSummary;
import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPoliticianExperienceSummary;
import com.hack23.cia.model.internal.application.data.politician.impl.ViewRiksdagenPoliticianExperienceSummary.PoliticalRole;
import com.hack23.cia.model.internal.application.system.impl.ApplicationEventGroup;
import com.hack23.cia.web.impl.ui.application.action.ViewAction;
import com.hack23.cia.web.impl.ui.application.views.common.sizing.ContentRatio;
Expand Down Expand Up @@ -76,6 +79,8 @@ public Layout createContent(final String parameters, final MenuBar menuBar, fina
final ViewRiksdagenPolitician viewRiksdagenPolitician = getItem(parameters);
final ViewRiksdagenPoliticianBallotSummary viewRiksdagenPoliticianBallotSummary = getViewRiksdagenPoliticianBallotSummary(
parameters);
final ViewRiksdagenPoliticianExperienceSummary experienceSummary = getViewRiksdagenPoliticianExperienceSummary(parameters);


getPoliticianMenuItemFactory().createPoliticianMenuBar(menuBar, pageId);

Expand All @@ -87,9 +92,8 @@ public Layout createContent(final String parameters, final MenuBar menuBar, fina
final PersonData personData = getApplicationManager().getDataContainer(PersonData.class)
.load(viewRiksdagenPolitician.getPersonId());

createOverviewContent(panelContent, personData, viewRiksdagenPolitician, viewRiksdagenPoliticianBallotSummary,
pageId);

createOverviewContent(panelContent, personData, viewRiksdagenPolitician,
viewRiksdagenPoliticianBallotSummary, experienceSummary, pageId);
getPageActionEventHelper().createPageEvent(ViewAction.VISIT_POLITICIAN_VIEW, ApplicationEventGroup.USER,
UserViews.POLITICIAN_VIEW_NAME, parameters, pageId);

Expand All @@ -112,6 +116,11 @@ protected ViewRiksdagenPoliticianBallotSummary getViewRiksdagenPoliticianBallotS
return null;
}
}

protected ViewRiksdagenPoliticianExperienceSummary getViewRiksdagenPoliticianExperienceSummary(final String parameters) {
final String pageId = getPageId(parameters);
return getApplicationManager().getDataContainer(ViewRiksdagenPoliticianExperienceSummary.class).load(pageId);
}

/**
* Creates the overview content in a card style similar to the scoreboard
Expand All @@ -125,9 +134,11 @@ protected ViewRiksdagenPoliticianBallotSummary getViewRiksdagenPoliticianBallotS
* @param pageId the page id
*/
private void createOverviewContent(final VerticalLayout panelContent, final PersonData personData,
final ViewRiksdagenPolitician viewRiksdagenPolitician,
final ViewRiksdagenPoliticianBallotSummary viewRiksdagenPoliticianBallotSummary, final String pageId) {

final ViewRiksdagenPolitician viewRiksdagenPolitician,
final ViewRiksdagenPoliticianBallotSummary viewRiksdagenPoliticianBallotSummary,
final ViewRiksdagenPoliticianExperienceSummary experienceSummary,
final String pageId) {

// Link to politician detail page
final Link createPoliticianPageLink = getPageLinkFactory().createPoliticianPageLink(personData);
createPoliticianPageLink.addStyleName("card-subtitle");
Expand Down Expand Up @@ -186,9 +197,14 @@ private void createOverviewContent(final VerticalLayout panelContent, final Pers

// 1. Political Role & Influence
final VerticalLayout politicalRoleLayout = createSectionLayout("Political Role & Influence");
addPoliticalRoleMetrics(politicalRoleLayout, viewRiksdagenPolitician, viewRiksdagenPoliticianBallotSummary);
addPoliticalRoleMetrics(politicalRoleLayout, viewRiksdagenPolitician, viewRiksdagenPoliticianBallotSummary,experienceSummary);
sectionsGrid.addComponent(politicalRoleLayout);
sectionsGrid.setExpandRatio(politicalRoleLayout, 1.0f);

final VerticalLayout experienceLayout = createSectionLayout("Experience & Expertise");
addExperienceMetrics(experienceLayout, experienceSummary);
sectionsGrid.addComponent(experienceLayout);
sectionsGrid.setExpandRatio(experienceLayout, 1.0f);

// 2. Parliamentary Performance
final VerticalLayout performanceLayout = createSectionLayout("Parliamentary Performance");
Expand Down Expand Up @@ -221,6 +237,44 @@ private void createOverviewContent(final VerticalLayout panelContent, final Pers
getPoliticianMenuItemFactory().createOverviewPage(overviewLayout, pageId);
}


private void addExperienceMetrics(VerticalLayout layout, ViewRiksdagenPoliticianExperienceSummary experienceSummary) {
if (experienceSummary != null) {
// Career Overview
layout.addComponent(createInfoRow("Career Phase:",
experienceSummary.getCareerPhase().toString().replace("_", " "),
VaadinIcons.CALENDAR_CLOCK,
"Current career stage"));

// Experience Level
layout.addComponent(createInfoRow("Experience Level:",
experienceSummary.getExperienceLevel().toString().replace("_", " "),
VaadinIcons.CHART_TIMELINE,
"Overall political experience classification"));

// Leadership Profile
layout.addComponent(createInfoRow("Leadership Role:",
experienceSummary.getLeadershipProfile().toString().replace("_", " "),
VaadinIcons.USER_STAR,
"Leadership experience level"));

// Specialization
layout.addComponent(createInfoRow("Expertise:",
experienceSummary.getSpecializationLevel().toString().replace("_", " "),
VaadinIcons.SPECIALIST,
"Area of specialization"));

// Political Analysis Comment
if (StringUtils.isNotBlank(experienceSummary.getPoliticalAnalysisComment())) {
layout.addComponent(createInfoRow("Analysis:",
experienceSummary.getPoliticalAnalysisComment(),
VaadinIcons.COMMENT,
"Political career analysis"));
}
}
}


/**
* Adds the political role metrics.
*
Expand All @@ -229,7 +283,7 @@ private void createOverviewContent(final VerticalLayout panelContent, final Pers
* @param ballotSummary the ballot summary
*/
private void addPoliticalRoleMetrics(VerticalLayout layout, ViewRiksdagenPolitician politician,
ViewRiksdagenPoliticianBallotSummary ballotSummary) {
ViewRiksdagenPoliticianBallotSummary ballotSummary, ViewRiksdagenPoliticianExperienceSummary experienceSummary) {

layout.addComponent(createInfoRow("Current Role:", ballotSummary.getStatus(), VaadinIcons.INSTITUTION,
"Current position in parliament"));
Expand All @@ -238,9 +292,43 @@ private void addPoliticalRoleMetrics(VerticalLayout layout, ViewRiksdagenPolitic
layout.addComponent(createInfoRow("Career Length:",
calculateServiceYears(politician.getFirstAssignmentDate(), politician.getLastAssignmentDate()),
VaadinIcons.TIMER, "Years in parliament"));
layout.addComponent(
createInfoRow("Influence Score:", String.format(Locale.ENGLISH,"%.1f", ballotSummary.getVotingConsistencyScore()),
VaadinIcons.CHART_GRID, "Overall parliamentary influence"));

// Top Knowledge Areas
if (experienceSummary.getKnowledgeAreas() != null && !experienceSummary.getKnowledgeAreas().isEmpty()) {
String topAreas = experienceSummary.getKnowledgeAreas().stream()
.filter(ka -> ka.getArea() != null && !ka.getArea().equals("Other"))
.sorted((ka1, ka2) -> ka2.getWeightedExp().compareTo(ka1.getWeightedExp()))
.limit(3)
.map(ka -> String.format(Locale.ENGLISH,"%s ",
ka.getArea()))
.collect(Collectors.joining(", "));

if (!topAreas.isEmpty()) {
layout.addComponent(createInfoRow("Key Policy Areas:",
topAreas,
VaadinIcons.CLIPBOARD_TEXT,
"Main areas of expertise with weighted importance"));
}
}

// Top Roles
if (experienceSummary.getRoles() != null && !experienceSummary.getRoles().isEmpty()) {
String topRoles = experienceSummary.getRoles().stream()
.filter(role -> role.getRole() != null && !role.getRole().equals("Other"))
.sorted((r1, r2) -> r2.getWeightedExp().compareTo(r1.getWeightedExp()))
.limit(3)
.map(role -> String.format(Locale.ENGLISH,"%s",
role.getRole()))
.collect(Collectors.joining(", "));

if (!topRoles.isEmpty()) {
layout.addComponent(createInfoRow("Key Political Roles:",
topRoles,
VaadinIcons.USERS,
"Most significant positions with weighted importance"));
}
}

}

/**
Expand All @@ -260,8 +348,6 @@ private void addParliamentaryPerformanceMetrics(VerticalLayout layout, ViewRiksd
VaadinIcons.TROPHY, "Votes on winning side"));
layout.addComponent(createInfoRow("Activity Level:", politician.getDocActivityLevel(), VaadinIcons.CHART_LINE,
"Overall engagement level"));
layout.addComponent(createInfoRow("Total Votes:", String.valueOf(ballotSummary.getTotalVotes()),
VaadinIcons.USER_CARD, "Total votes cast"));
}

/**
Expand All @@ -276,6 +362,10 @@ private void addLegislativeMetrics(VerticalLayout layout, ViewRiksdagenPoliticia
VaadinIcons.FILE_TEXT, "Average documents per year"));
layout.addComponent(createInfoRow("Individual Motions:", String.valueOf(politician.getIndividualMotions()),
VaadinIcons.USER, "Personal motions submitted"));

layout.addComponent(createInfoRow("Party Motions:", String.valueOf(politician.getPartyMotions()),
VaadinIcons.USER, "Party motions signed"));

layout.addComponent(createInfoRow("Committee Motions:", String.valueOf(politician.getCommitteeMotions()),
VaadinIcons.GROUP, "Committee-based motions"));
layout.addComponent(createInfoRow("Document Impact:", politician.getDocActivityProfile(), VaadinIcons.CHART_3D,
Expand Down
5 changes: 5 additions & 0 deletions model.internal.application.user.impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
<artifactId>model.common.impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
Expand Down
Loading

0 comments on commit 1529d24

Please sign in to comment.