Skip to content
Open
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
5 changes: 5 additions & 0 deletions app/src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { SimulationCreationFlow } from './flows/simulationCreationFlow';
import DashboardPage from './pages/Dashboard.page';
import DonatePage from './pages/Donate.page';
import HomePage from './pages/Home.page';
import AIMLPage from './pages/ML.page';
import PoliciesPage from './pages/Policies.page';
import PopulationsPage from './pages/Populations.page';
import PrivacyPage from './pages/Privacy.page';
Expand Down Expand Up @@ -142,6 +143,10 @@ const router = createBrowserRouter(
path: 'terms',
element: <TermsPage />,
},
{
path: 'ai-ml',
element: <AIMLPage />,
},
{
path: 'methodology',
element: <div>Methodology page</div>,
Expand Down
Binary file added app/src/assets/ai-analysis.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/assets/us-household-ai.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 25 additions & 23 deletions app/src/components/TwoColumnView.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Grid, Paper, Title } from '@mantine/core';
import { Box, Grid, Paper, Title } from '@mantine/core';
import { colors, spacing, typography } from '@/designTokens';

interface TwoColumnViewProps {
Expand All @@ -20,29 +20,31 @@ const TwoColumnView = ({ title, leftColumn, rightColumn, backgroundColor }: TwoC
};

return (
<Paper
bg={getBackgroundColor()}
p={spacing.container.lg}
radius={spacing.radius.lg}
style={{ minHeight: '400px' }}
<Box
style={{
maxWidth: 1300,
margin: '0 auto',
}}
>
<Title
order={2}
variant="colored"
ff={typography.fontFamily.primary}
size={typography.fontSize['3xl']}
fw={typography.fontWeight.bold}
c={colors.text.title}
mb={spacing['3xl']}
ta="left"
>
{title}
</Title>
<Grid gutter={spacing['3xl']} align="center">
<Grid.Col span={{ base: 12, sm: 6 }}>{leftColumn}</Grid.Col>
<Grid.Col span={{ base: 12, sm: 6 }}>{rightColumn}</Grid.Col>
</Grid>
</Paper>
<Paper bg={getBackgroundColor()} radius={spacing.radius.lg} style={{ minHeight: '400px' }}>
<Title
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Here, too, this impacts others' pages; what's the reasoning behind it?

order={2}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Having just said that, please increase the size of this title

variant="colored"
ff={typography.fontFamily.primary}
size={typography.fontSize['3xl']}
fw={typography.fontWeight.bold}
c={colors.text.title}
mb={spacing['3xl']}
ta="left"
>
{title}
</Title>
<Grid gutter={spacing['3xl']} align="center">
<Grid.Col span={{ base: 12, sm: 6 }}>{leftColumn}</Grid.Col>
<Grid.Col span={{ base: 12, sm: 6 }}>{rightColumn}</Grid.Col>
</Grid>
</Paper>
</Box>
);
};

Expand Down
2 changes: 0 additions & 2 deletions app/src/components/shared/static/CardsWithHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ export function CardsWithHeader({ containerTitle, cards }: CardsContainerProps)
return (
<Box
style={{
paddingLeft: spacing.container.xl,
paddingRight: spacing.container.xl,
paddingTop: spacing['2xl'],
paddingBottom: spacing['2xl'],
}}
Expand Down
72 changes: 40 additions & 32 deletions app/src/components/shared/static/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,50 @@ export default function PageHeader({ title, description }: PageHeaderProps) {
borderBottom: `1px solid ${colors.border.dark}`,
}}
>
<Flex
direction={{ base: 'column', md: 'row' }}
align={{ base: 'stretch', md: 'center' }}
gap={{ base: 'md', md: 'xl' }}
<Box
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Is this a change you're making now, or did you incorporate changes from a rebase and they're being improperly displayed as part of your PR?

second question: If you are making this change, why? This would modify all pages using this component.

px={spacing.xl}
style={{
maxWidth: 1300,
margin: '0 auto',
}}
>
<Box w={{ base: '100%', md: 300 }}>
<Title
variant="colored"
style={{
fontSize: typography.fontSize['4xl'],
fontWeight: typography.fontWeight.semibold,
fontFamily: typography.fontFamily.primary,
}}
>
{title}
</Title>
</Box>
<Flex
direction={{ base: 'column', md: 'row' }}
align={{ base: 'stretch', md: 'center' }}
gap={{ base: 'md', md: 'xl' }}
>
<Box w={{ base: '100%', md: 300 }}>
<Title
variant="colored"
style={{
fontSize: typography.fontSize['4xl'],
fontWeight: typography.fontWeight.semibold,
fontFamily: typography.fontFamily.primary,
}}
>
{title}
</Title>
</Box>

<Divider orientation="horizontal" size="xs" color={colors.border.light} hiddenFrom="md" />
<Divider orientation="horizontal" size="xs" color={colors.border.light} hiddenFrom="md" />

<Divider orientation="vertical" size="xs" color={colors.border.light} visibleFrom="md" />
<Divider orientation="vertical" size="xs" color={colors.border.light} visibleFrom="md" />

<Box w={{ base: '100%', md: 'auto' }}>
<Text
style={{
color: colors.text.primary,
fontSize: typography.fontSize.lg,
lineHeight: typography.lineHeight.relaxed,
fontFamily: typography.fontFamily.body,
}}
ta={{ base: 'left', md: 'center' }}
>
{description}
</Text>
</Box>
</Flex>
<Box w={{ base: '100%', md: 'auto' }}>
<Text
style={{
color: colors.text.primary,
fontSize: typography.fontSize.lg,
lineHeight: typography.lineHeight.relaxed,
fontFamily: typography.fontFamily.body,
}}
ta={{ base: 'left', md: 'center' }}
>
{description}
</Text>
</Box>
</Flex>
</Box>
</Box>
);
}
4 changes: 2 additions & 2 deletions app/src/components/shared/static/TextCardWithHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const TitleCardWithHeader: React.FC<TitleCardWithHeaderProps> = ({
textColor = colors.text.inverse;
break;
case 'gray':
resolvedBackgroundColor = colors.gray[200];
resolvedBackgroundColor = colors.gray[100];
textColor = colors.text.primary;
break;
case 'white':
Expand All @@ -47,7 +47,7 @@ export const TitleCardWithHeader: React.FC<TitleCardWithHeaderProps> = ({
</Title>

{/* Card with content */}
<Card radius="lg" p="xl" bg={resolvedBackgroundColor}>
<Card radius="lg" p="xl" mt="md" bg={resolvedBackgroundColor}>
<Stack gap="md">
{sections.map((section, idx) => (
<>
Expand Down
137 changes: 137 additions & 0 deletions app/src/pages/ML.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { Box } from '@mantine/core';
import aiAnalysisImg from '@/assets/ai-analysis.png';
import usHouseholdAiImg from '@/assets/us-household-ai.png';
import CalloutWithImage from '@/components/shared/static/CalloutWithImage';
import { CardsWithHeader } from '@/components/shared/static/CardsWithHeader';
import PageHeader from '@/components/shared/static/PageHeader';
import { TitleCardWithHeader } from '@/components/shared/static/TextCardWithHeader';
import TwoColumnView from '@/components/TwoColumnView';
import { spacing } from '@/designTokens';

export default function AIMLPage() {
const leftColumnContent = (
<>
PolicyEngine integrates large language models with our computational tax-benefit engine to
transform complex calculations into clear explanations.
<br />
<br />
For household calculations, we process thousands of intermediate values across tax and benefit
programs, then use Anthropic's Claude API to generate plain-language explanations of
eligibility, amounts, and potential changes.
<br />
<br />
For policy analysis, we leverage GPT-4 to weave narratives from our computational results,
explaining reforms in terms anyone can understand - from simplified `ELI5` explanations to
detailed technical analyses for policy experts.
</>
);

const rightColumnContent = (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Please round the edges on the image

<img
src={aiAnalysisImg}
alt="Diagram illustrating AI analysis"
style={{ maxWidth: '100%', height: 'auto' }}
/>
);

return (
<Box>
<PageHeader
title="AI & Machine Learning"
description="PolicyEngine uses artificial intelligence and machine learning to make policy analysis more accurate and accessible."
/>
<Box
px={spacing.xl}
py={spacing['3xl']}
style={{
maxWidth: 1300,
margin: '0 auto',
display: 'flex',
flexDirection: 'column',
gap: spacing['3xl'],
}}
>
<CalloutWithImage
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Shoot, CalloutWithImage actually does have something we'd want to change app-wide. As part of this PR, could you modify the button to look the same as (but have larger font size than) the button we have in the calculator pages to create a new report? It has rounded edges, unlike this one, and is a darker green.

title="Making Policy Accessible With AI"
description="PolicyEngine combines tax-benefit microsimulation with cutting-edge AI to democratize policy understanding"
buttonLabel="Learn about our AI explanations tool"
// TODO: update button click event once page link is available
// onButtonClick={() => console.log('clicked')}
imageSrc={usHouseholdAiImg}
imageAlt="AI Explanations Tool Preview"
/>
<CardsWithHeader
containerTitle="AI/ML Resources"
cards={[
{
title: 'Instant analysis',
description:
'Generate comprehensive policy analysis with natural language, tailored to different knowledge levels',
icon: '✨',
background: 'gray',
},
{
title: 'Plain language explanations',
description:
"Understand complex tax and benefit calculations through clear, accessible explanations of your household's finances",
icon: '🧠',
background: 'gray',
},
{
title: 'Data-driven insights',
description:
'Combine computational precision with narrative insights to tell the complete story of policy impacts',
icon: '📊',
background: 'gray',
},
]}
/>

<TitleCardWithHeader
title="Our AI Journey"
sections={[
{
heading: 'Machine learning foundations: 2021-2022',
body: 'PolicyEngine has leveraged artificial intelligence since our inception. In 2021, we pioneered the use of machine learning to enhance our microsimulation models, applying gradient descent to optimized survey weights and match administrative totals with unprecedented accuracy.',
},
{
body: 'By 2022, our UK model had achieved up to 80% lower aggregate errors compared to other microsimulation models. This foundation of AI-enhanced accuracy has been central to our mission of providing reliable policy analysis.',
},
{
heading: 'Data science innovation: 2023',
body: 'We expanded our AI capabilities in 2023 with our Enhanced Current Population Survey (ECPS) for the US model, using quantile regression forests to integrate tax record information with survey data, creating the first open alternative to restricted tax microdata for policy microsimulation.',
},
{
heading: 'AI-Powered Analysis: 2023-Present',
body: 'When OpenAI released GPT-4 in March 2023, we immediately recognized its potential to democratize policy understanding. Within just one month, we launched our AI-powered Analysis tool that translates complex computational results into accessible narratives.',
},
{
body: "In 2024, we extended this capability to household-level calculations with Anthropic's Claude API, enabling users to understand exactly how their taxes and benefits are calculated through plain-language explanations.",
},
]}
backgroundColor="gray"
/>

<TwoColumnView
title="How it works"
leftColumn={leftColumnContent}
rightColumn={rightColumnContent}
/>

<Box>
<h1>Watch our AI Demo</h1>
<iframe
width="900"
height="550"
src="https://www.youtube.com/embed/fnuDyLKpt90?si=kIOaT5HbJzRRV0Fj"
title="YouTube video player"
style={{ border: 'none' }}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
/>
</Box>
</Box>
</Box>
);
}
2 changes: 1 addition & 1 deletion app/src/styles/stylesheets/RichTextBlock.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
provides no way to provide styling to child components natively */

.rich-text-block p {
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.625;
margin-bottom: 16px;
Expand Down
Loading