Skip to content

Commit

Permalink
comments_async: redesign ai report
Browse files Browse the repository at this point in the history
  • Loading branch information
goapunk committed Sep 19, 2024
1 parent e10457d commit 17b5513
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,45 @@ import { render, fireEvent, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import AiReport from '../ai_report'

test('Test render <AiReport> with Read More button', () => {
render(
<AiReport
Report={{ explanation: 'This is the ai report', show_in_discussion: true }}
/>
)
const comment = screen.getByText('Read more')
expect(comment).toBeTruthy()
})
describe('Test AiReport', () => {
test('renders with Read More button', () => {
render(
<AiReport
report={{ label: [['cattest', 'test label']], confidence: [['cattest', 0.65]], explanation: { cattest: [['word', 0.61]] }, show_in_discussion: true }}
/>
)
const comment = screen.getByText('Read more')
expect(comment).toBeInTheDocument()
})

test('functionality of Read More button', () => {
render(
<AiReport
report={{ label: [['cattest', 'test label']], confidence: [['cattest', 0.65]], explanation: { cattest: [['word', 0.61]] }, show_in_discussion: true }}
/>
)
const readMore = screen.getByText('Read more')
expect(readMore).toBeInTheDocument()
const button = screen.getByRole('button')
expect(button).toBeInTheDocument()
fireEvent.click(button)
const readLess = screen.getByText('Show less')
expect(readLess).toBeInTheDocument()
expect(readLess).toBeInTheDocument()
})

test('Test functionality of Read More <AiReport>', () => {
render(
<AiReport
Report={{ explanation: 'This is the ai report', show_in_discussion: true }}
/>
)
const readMore = screen.getByText('Read more')
expect(readMore).toBeTruthy()
const button = screen.getByRole('button')
expect(button).toBeTruthy()
fireEvent.click(button)
const readLess = screen.getByText('Show less')
expect(readLess).toBeTruthy()
test('shows percentage for each label', async () => {
render(
<AiReport
report={{ label: [['cattest', 'test label']], confidence: [0.65], explanation: { cattest: [['word', 0.61]] }, show_in_discussion: true }}
/>
)
const readMore = screen.getByText('Read more')
expect(readMore).toBeInTheDocument()
const button = screen.getByRole('button')
expect(button).toBeInTheDocument()
fireEvent.click(button)
const percent = screen.getByText(/65%/)
expect(percent).toBeInTheDocument()
})
})
76 changes: 65 additions & 11 deletions adhocracy4/comments_async/static/comments_async/ai_report.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import django from 'django'
import { SwitchButton } from '../../../static/SwitchButton'

const translated = {
intro: django.pgettext('defakts', 'This comment contains disinformation. Defakts uses an Artificial ' +
'Intelligence to scan content for disinformation. Disinformation often shows ' +
'certain characteristics that allow for a reliable identification.'),
expandableBar: django.pgettext('defakts', 'The defakt AI has found evidence of disinformation.'),
intro: django.pgettext('defakts', 'Defakts uses artificial intelligence to check content for disinformation based on certain linguistic characteristics.'),
confidenceScore: django.pgettext('defakts', 'The AI considers some of the characteristics of disinformation to be fulfilled based on the following words in the comment. The probability is given in % for each characteristic.'),
cta: django.pgettext('defakts', 'If you want to know more about what the characteristics mean, please visit our [FAQs]. Here you will also find advice on how to respond constructively to disinformation.'),
ariaReadMore: django.pgettext('defakts', 'Click to view the AI explanation for reporting this comment.'),
ariaReadLess: django.pgettext('defakts', 'Click to hide the AI explanation for reporting this comment.'),
readMore: django.pgettext('defakts', 'Read more'),
Expand All @@ -14,7 +15,7 @@ const translated = {
hideInfoSwitch: django.pgettext('defakts', 'Hide AI info from users')
}

export const AiReport = ({ Report, notificationPk, toggleShowAiReport }) => {
export const AiReport = ({ report, notificationPk, toggleShowAiReport }) => {
const [isExpanded, setIsExpanded] = useState()

const toggleExpand = () => {
Expand All @@ -32,31 +33,84 @@ export const AiReport = ({ Report, notificationPk, toggleShowAiReport }) => {
</button>
)

const confidenceToPercent = (confidence) => {
const percentFormat = new Intl.NumberFormat('default', {
style: 'percent',
minimumFractionDigits: 0,
maximumFractionDigits: 0
})
return percentFormat.format(confidence)
}

const extractLabelWords = (label) => {
const words = report.explanation[label]
let result = ''
const length = Math.min(words.length, 3)
for (let i = 0; i < length; i++) {
result += words[i][0]
if (i < length - 1) {
result += ', '
}
}
return result
}

const renderExplanation = (
<ul>
{report.label.map(([key, description], index) => (
<li key={key}>
<span>{description.charAt(0).toUpperCase() + description.slice(1)} </span>
<span>({confidenceToPercent(report.confidence[index])}): </span>
<span>{extractLabelWords(key)}</span>
</li>
))}
</ul>
)

const renderCTA = () => {
// replace "[FAQs]" with anchor
const [preText, placeholderText, postText] = translated.cta.split(/(\[.*?\])/)
// remove square brackets
const anchorText = placeholderText.replace(/\[|\]/g, '')
return (
<>
{preText} <a href={report.faq_url} target="_blank" rel="noreferrer">{anchorText}</a> {postText}
</>
)
}

return (
<div className="alert alert--danger mb-4">
<div className="d-flex text-start mb-4">
<div className="alert alert--danger mb-2 pb-0">
<div className="d-flex text-start">
<i
className="fas fa-exclamation-circle text-danger pt-1 pe-2"
aria-hidden="True"
/>

{!isExpanded
? (
<p className="pe-4">{translated.intro} {toggleReadMore}</p>
<p className="pe-4">{translated.expandableBar} {toggleReadMore}</p>
)
: (
<div className="pe-4">
<p>{translated.intro}</p>
<p>{Report.explanation} {toggleReadMore}</p>
<p>{translated.expandableBar}</p>
<p>
<span>{translated.intro} </span>
<span>{translated.confidenceScore}</span>
</p>
{renderExplanation}
<p>
{renderCTA()} {toggleReadMore}
</p>
</div>
)}
</div>
{toggleShowAiReport &&
<div className="d-flex text-start">
<div className="d-flex text-start mt-3 mb-3">
<SwitchButton
id={notificationPk}
onClickCallback={toggleShowAiReport}
isChecked={Report.show_in_discussion}
isChecked={report.show_in_discussion}
switchLabelOn={translated.hideInfoSwitch}
switchLabelOff={translated.showInfoSwitch}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ export default class Comment extends React.Component {

{this.props.aiReport && this.props.aiReport.show_in_discussion &&
<AiReport
Report={this.props.aiReport}
report={this.props.aiReport}
/>}

{this.state.showModStatement && this.state.moderatorFeedback &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ const CommentList = (props) => {
<ul className="u-list-reset a4-comments">
{
props.comments.map((comment, index) => {
// don't show ai report if there are no labels
let aiReport = null
if (comment.ai_report && comment.ai_report.label.length > 0) {
aiReport = comment.ai_report
}
return (
<Comment
comment_categories={comment.comment_categories}
Expand Down Expand Up @@ -60,7 +65,7 @@ const CommentList = (props) => {
wouldHaveCommentingPermission={props.wouldHaveCommentingPermission}
projectIsPublic={props.projectIsPublic}
moderatorFeedback={comment.moderator_feedback ? comment.moderator_feedback : null}
aiReport={comment.ai_report ? comment.ai_report : null}
aiReport={aiReport}
useTermsOfUse={props.useTermsOfUse}
agreedTermsOfUse={props.agreedTermsOfUse}
orgTermsUrl={props.orgTermsUrl}
Expand Down
5 changes: 5 additions & 0 deletions changelog/8372.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Changed

- redesign AI report to be readable
- only show AI report when there's a useful label (catnodecis and catneutral don't
count as labels)

0 comments on commit 17b5513

Please sign in to comment.