Skip to content
Open
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
51 changes: 46 additions & 5 deletions frontend/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,35 @@ const inter = Inter({ subsets: ["latin"] })

export const metadata: Metadata = {
title: "Perspective - AI-Powered Bias Detection",
description: "Combat bias and one-sided narratives with AI-generated alternative perspectives.",
description:
"Combat bias and one-sided narratives with AI-generated alternative perspectives. Perspective analyzes text and provides balanced viewpoints using AI.",
keywords: [
"AI bias detection",
"AI perspective analysis",
"bias detection tool",
"AI content evaluation",
"alternative narrative generation",
],
openGraph: {
title: "Perspective - AI-Powered Bias Detection",
description:
"Analyze content for bias and generate alternative AI-driven perspectives.",
url: "https://perspective-aossie.vercel.app/",
siteName: "Perspective",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "Perspective - AI-Powered Bias Detection",
description:
"AI-powered tool to analyze bias and generate alternative perspectives.",
},
Comment on lines +20 to +33
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

summary_large_image card type without an images property will render poorly on social platforms.

Both openGraph and twitter metadata are missing images. The summary_large_image card type features a large, full-width prominent image alongside a tweet and is designed to give the reader a rich photo experience. Without providing twitter:image, "Twitter says that the image should be unique to the page, but if you don't include an image, the card they produce has a silly-looking icon on it (of a scroll or document)." Similarly, OG shares on LinkedIn, Slack, and other platforms will display no visual thumbnail.

The suggested minimum properties for the Summary Card with Large Image include title, description, and image.

Either add images arrays to both openGraph and twitter, or downgrade the Twitter card to "summary" if no image is available yet.

🖼️ Proposed fix — add images or downgrade Twitter card type
  openGraph: {
    title: "Perspective - AI-Powered Bias Detection",
    description:
      "Analyze content for bias and generate alternative AI-driven perspectives.",
    url: "https://perspective-aossie.vercel.app/",
    siteName: "Perspective",
    type: "website",
+   images: [
+     {
+       url: "https://perspective-aossie.vercel.app/og-image.png",
+       width: 1200,
+       height: 630,
+       alt: "Perspective - AI-Powered Bias Detection",
+     },
+   ],
  },
  twitter: {
-   card: "summary_large_image",
+   card: "summary",   // upgrade to "summary_large_image" once a twitter:image is available
    title: "Perspective - AI-Powered Bias Detection",
    description:
      "AI-powered tool to analyze bias and generate alternative perspectives.",
  },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
openGraph: {
title: "Perspective - AI-Powered Bias Detection",
description:
"Analyze content for bias and generate alternative AI-driven perspectives.",
url: "https://perspective-aossie.vercel.app/",
siteName: "Perspective",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "Perspective - AI-Powered Bias Detection",
description:
"AI-powered tool to analyze bias and generate alternative perspectives.",
},
openGraph: {
title: "Perspective - AI-Powered Bias Detection",
description:
"Analyze content for bias and generate alternative AI-driven perspectives.",
url: "https://perspective-aossie.vercel.app/",
siteName: "Perspective",
type: "website",
images: [
{
url: "https://perspective-aossie.vercel.app/og-image.png",
width: 1200,
height: 630,
alt: "Perspective - AI-Powered Bias Detection",
},
],
},
twitter: {
card: "summary",
title: "Perspective - AI-Powered Bias Detection",
description:
"AI-powered tool to analyze bias and generate alternative perspectives.",
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/layout.tsx` around lines 20 - 33, The openGraph and twitter
metadata objects (openGraph and twitter) are missing images while using the
"summary_large_image" card type; either add an images array to openGraph and a
twitter.images or twitter.image entry with a public image URL (and alt text
where supported) to provide the large thumbnail, or change twitter.card from
"summary_large_image" to "summary" if you cannot supply an image yet; update the
openGraph.images and twitter.image(s) references in layout.tsx accordingly so
social previews render correctly.

}

/**
* Root layout component that sets up global HTML structure, font, and theming for the application.
*
* Wraps all page content with the Inter font and a theme provider supporting system-based theming.
*
* @param children - The content to be rendered within the layout.
*/
export default function RootLayout({
children,
Expand All @@ -26,10 +46,31 @@ export default function RootLayout({
return (
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange={false}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange={false}
>
{/* Structured Data for AI & Search Engines */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "https://schema.org",
"@type": "SoftwareApplication",
name: "Perspective",
applicationCategory: "AIApplication",
description:
"Perspective is an AI-powered tool that detects bias in text and generates alternative perspectives.",
operatingSystem: "Web",
url: "https://perspective-aossie.vercel.app/",
}),
}}
/>
Comment on lines +56 to +70
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's confirm the file exists and view the actual code at lines 56-70
cat -n frontend/app/layout.tsx | sed -n '56,70p'

Repository: AOSSIE-Org/Perspective

Length of output: 793


🌐 Web query:

schema.org SoftwareApplication applicationCategory valid values

💡 Result:

SoftwareApplication.applicationCategory in schema.org does not have a fixed set of “valid values”. The property’s expected type is Text or URL, and schema.org only describes it as “Type of software application” (example: “Game, Multimedia”). So any reasonable free-text label (or a URL pointing to a category in some taxonomy you control/use) is valid from a schema.org perspective. [1]

If you care specifically about Google Software App rich results, Google says the value “must be a supported app type” and provides this supported list: GameApplication, SocialNetworkingApplication, TravelApplication, ShoppingApplication, SportsApplication, LifestyleApplication, BusinessApplication, DesignApplication, DeveloperApplication, DriverApplication, EducationalApplication, HealthApplication, FinanceApplication, SecurityApplication, BrowserApplication, CommunicationApplication, DesktopEnhancementApplication, EntertainmentApplication, MultimediaApplication, HomeApplication, UtilitiesApplication, ReferenceApplication. [2]

Sources:
[1] Schema.org – SoftwareApplication / applicationCategory definition: expected type Text or URL
[2] Google Search Central – Software app structured data (SoftwareApplication), supported applicationCategory values


🌐 Web query:

Google Rich Results SoftwareApplication requirements schema.org

💡 Result:

Google’s Software app rich result is based on Schema.org’s SoftwareApplication (and optionally MobileApplication / WebApplication). To be eligible, Google says your structured data must include:

Required (Google rich result eligibility)

  • @type: SoftwareApplication (Schema.org type) [2]
  • name [1]
  • offers.price (set to 0 if free) [1]
  • One of: aggregateRating or review (rating/review is required) [1]

Recommended (improves/clarifies results)

  • offers.priceCurrency when offers.price > 0 [1]
  • applicationCategory (must be one of Google’s supported categories) [1]
  • operatingSystem [1]

Notes

  • Google supports MobileApplication and WebApplication as subtypes; and if you use VideoGame, Google recommends co-typing it with another supported type (for eligibility). [1]

Sources: Google Search Central “Software app (SoftwareApplication) structured data” [1], Schema.org SoftwareApplication definition [2].


applicationCategory: "AIApplication" is not a Google-supported value; schema may not qualify for Google Rich Results.

dangerouslySetInnerHTML (Line 58): Safe here. The injected content is a static JSON.stringify() of a hardcoded literal with no user input. This is the recommended Next.js pattern for JSON-LD structured data.

applicationCategory: "AIApplication" (Line 63): Not a recognized value in Google's SoftwareApplication supported types. Google's supported categories include: GameApplication, BusinessApplication, DeveloperApplication, EducationApplication, UtilitiesApplication, ReferenceApplication, and others. "AIApplication" is absent. Use "UtilitiesApplication" or "DeveloperApplication" instead.

Google Rich Results eligibility: To qualify for Google's software app rich results, the schema must include offers.price (set to 0 if free) and either aggregateRating or review. The current implementation provides context to crawlers but won't display as a rich result. Add these properties for eligibility.

✏️ Suggested fix
-   applicationCategory: "AIApplication",
+   applicationCategory: "UtilitiesApplication",

Also add required properties for Google Rich Results:

  offers: {
+   price: "0",
+   priceCurrency: "USD"
  },

And one of:

+   aggregateRating: {
+     "@type": "AggregateRating",
+     ratingValue: "4.5",
+     ratingCount: "10"
+   }
🧰 Tools
🪛 ast-grep (0.40.5)

[warning] 57-57: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/layout.tsx` around lines 56 - 70, Update the JSON-LD object
passed to dangerouslySetInnerHTML: change applicationCategory from
"AIApplication" to a Google-supported value such as "UtilitiesApplication" (or
"DeveloperApplication"), and add the required rich result fields so Google can
surface a software rich result — e.g. include an "offers" object with "price": 0
and "priceCurrency": "USD" and add either an "aggregateRating" object (with
"ratingValue" and "reviewCount") or a "review" array with at least one review;
modify the literal inside the JSON.stringify in the <script
type="application/ld+json"> block so these properties are present and populated
appropriately.

{children}
</ThemeProvider>
</body>
</html>
)
}
}