Skip to content

Commit

Permalink
Merge pull request #6949 from ForumMagnum/modgpt
Browse files Browse the repository at this point in the history
[EA Forum only] ModGPT (GPT-4) checks comments on "Community" posts
  • Loading branch information
s-cheng committed Apr 12, 2023
2 parents 5394991 + 86b0a2d commit b9614d5
Show file tree
Hide file tree
Showing 18 changed files with 537 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
"mongodb": "^3.6.3",
"mz": "^2.7.0",
"nodemailer": "^6.6.1",
"openai": "^3.1.0",
"openai": "^3.2.0",
"papaparse": "^5.2.0",
"passport": "^0.5.2",
"passport-auth0": "^1.4.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/lesswrong/components/comments/CommentsNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const CommentsNode = ({
}: CommentsNodeProps) => {
const currentUser = useCurrentUser();
const scrollTargetRef = useRef<HTMLDivElement|null>(null);
const [collapsed, setCollapsed] = useState(comment.deleted || comment.baseScore < karmaCollapseThreshold);
const [collapsed, setCollapsed] = useState(comment.deleted || comment.baseScore < karmaCollapseThreshold || comment.modGPTRecommendation === 'Intervene');
const [truncatedState, setTruncated] = useState(!!startThreadTruncated);
const { lastCommentId, condensed, postPage, post, highlightDate, scrollOnExpand, forceSingleLine, forceNotSingleLine, noHash } = treeOptions;

Expand Down
131 changes: 131 additions & 0 deletions packages/lesswrong/components/sunshineDashboard/ModGPTDashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React from 'react';
import { Components, registerComponent, sanitizeAllowedTags } from '../../lib/vulcan-lib';
import { postGetPageUrl } from '../../lib/collections/posts/helpers';
import { Comments } from '../../lib/collections/comments'
import { Link } from '../../lib/reactRouterWrapper'
import { useCurrentUser } from '../common/withUser';
import type { Column } from '../vulcan-core/Datatable';
import { userIsAdminOrMod } from '../../lib/vulcan-users/permissions';
import sanitizeHtml from 'sanitize-html';
import { htmlToText } from 'html-to-text';

const styles = (theme: JssStyles) => ({
root: {
maxWidth: 1200,
fontFamily: theme.typography.fontFamily,
whiteSpace: 'pre-line',
margin: '0 auto',
'& tbody tr:nth-child(2n)': {
background: theme.palette.grey[30]
},
'& tbody tr:nth-child(2n-1)': {
background: theme.palette.grey[0]
},
'& th': {
padding: '14px 18px'
},
'& td': {
padding: '14px 18px'
}
},
})

const UserDisplay = ({column, document}: {
column: Column;
document: any;
}) => {
const user = document.user || document
return <div>
<Components.UsersName user={user} nofollow />
</div>
}

const PostDisplay = ({column, document}: {
column: Column;
document: any;
}) => {
const post = document.post || document
return <Link rel="nofollow" to={postGetPageUrl(post) + "#" + document._id }>{ post.title }</Link>
}

const CommentDisplay = ({column, document}: {
column: Column;
document: any;
}) => {
const mainTextHtml = sanitizeHtml(
document.contents.html, {
allowedTags: sanitizeAllowedTags.filter(tag => !['img', 'iframe'].includes(tag)),
nonTextTags: ['img', 'style']
}
)
return <div>{htmlToText(mainTextHtml)}</div>
}

const DateDisplay = ({column, document}: {
column: Column;
document: any;
}) => {
return <div>{document[column.name] && <Components.FormatDate date={document[column.name]}/>}</div>
}

const columns: Column[] = [
{
name: 'postedAt',
label: 'Posted',
component: DateDisplay,
},
{
name: 'post',
component: PostDisplay,
},
{
name: 'contents',
label: 'Comment',
component: CommentDisplay,
},
{
name: 'user',
label: 'Author',
component: UserDisplay,
},
{
name:'modGPTAnalysis',
label: 'Analysis'
},
]


const ModGPTDashboard = ({classes}: {
classes: ClassesType
}) => {
const currentUser = useCurrentUser()
if (!userIsAdminOrMod(currentUser)) {
return <Components.Error404 />
}

return (
<div className={classes.root}>
<Components.SectionTitle title="ModGPT Dashboard" noTopMargin />

<Components.Datatable
collection={Comments}
columns={columns}
options={{
fragmentName: 'CommentsListWithModGPTAnalysis',
terms: {view: "checkedByModGPT"},
limit: 10,
enableTotal: true
}}
showEdit={false}
/>
</div>
)
}

const ModGPTDashboardComponent = registerComponent('ModGPTDashboard', ModGPTDashboard, {styles});

declare global {
interface ComponentTypes {
ModGPTDashboard: typeof ModGPTDashboardComponent
}
}
11 changes: 11 additions & 0 deletions packages/lesswrong/lib/collections/comments/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ registerFragment(`
isPinnedOnProfile
debateResponse
rejected
modGPTRecommendation
}
`);

Expand Down Expand Up @@ -183,3 +184,13 @@ registerFragment(`
}
}
`);

registerFragment(`
fragment CommentsListWithModGPTAnalysis on Comment {
...CommentsList
post {
...PostsMinimumInfo
}
modGPTAnalysis
}
`);
21 changes: 21 additions & 0 deletions packages/lesswrong/lib/collections/comments/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,27 @@ const schema: SchemaType<DbComment> = {
hidden: true,
...schemaDefaultValue(false),
},

// How well does ModGPT (GPT-4) think this comment adheres to forum norms and rules? (currently EAF only)
modGPTAnalysis: {
type: String,
optional: true,
nullable: true,
canRead: ['sunshineRegiment', 'admins'],
canCreate: ['admins'],
canUpdate: ['admins'],
hidden: true
},
// This should be one of: Intervene, Consider reviewing, Don't intervene
modGPTRecommendation: {
type: String,
optional: true,
nullable: true,
canRead: ['sunshineRegiment', 'admins'],
canCreate: ['admins'],
canUpdate: ['admins'],
hidden: true
},

rejectedByUserId: {
...foreignKeyField({
Expand Down
9 changes: 9 additions & 0 deletions packages/lesswrong/lib/collections/comments/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ Comments.addView("allCommentsDeleted", (terms: CommentsViewTerms) => {
};
});

Comments.addView("checkedByModGPT", (terms: CommentsViewTerms) => {
return {
selector: {
modGPTAnalysis: {$exists: true}
},
options: {sort: {postedAt: -1}}
};
});

Comments.addView("postCommentsTop", (terms: CommentsViewTerms) => {
return {
selector: {
Expand Down
1 change: 1 addition & 0 deletions packages/lesswrong/lib/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ importComponent("AdminMetadata", () => require('../components/admin/AdminMetadat
importComponent("ModerationDashboard", () => require('../components/sunshineDashboard/ModerationDashboard'));
importComponent("ModerationTemplatesPage", () => require('../components/moderationTemplates/ModerationTemplatesPage'));
importComponent("ModerationTemplateItem", () => require('../components/moderationTemplates/ModerationTemplateItem'));
importComponent("ModGPTDashboard", () => require('../components/sunshineDashboard/ModGPTDashboard'));
importComponent("ModerationLog", () => require('../components/sunshineDashboard/ModerationLog'));
importComponent("ReportForm", () => require('../components/sunshineDashboard/ReportForm'));
importComponent("SunshineCommentsItemOverview", () => require('../components/sunshineDashboard/SunshineCommentsItemOverview'));
Expand Down
2 changes: 2 additions & 0 deletions packages/lesswrong/lib/generated/databaseTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ interface DbComment extends DbObject {
relevantTagIds: Array<string>
debateResponse: boolean | null
rejected: boolean
modGPTAnalysis: string | null
modGPTRecommendation: string | null
rejectedByUserId: string
af: boolean
suggestForAlignmentUserIds: Array<string>
Expand Down
10 changes: 10 additions & 0 deletions packages/lesswrong/lib/generated/fragmentTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ interface CommentsDefaultFragment { // fragment on Comments
readonly relevantTagIds: Array<string>,
readonly debateResponse: boolean | null,
readonly rejected: boolean,
readonly modGPTAnalysis: string | null,
readonly modGPTRecommendation: string | null,
readonly rejectedByUserId: string,
readonly af: boolean,
readonly suggestForAlignmentUserIds: Array<string>,
Expand Down Expand Up @@ -1336,6 +1338,7 @@ interface CommentsList { // fragment on Comments
readonly isPinnedOnProfile: boolean,
readonly debateResponse: boolean | null,
readonly rejected: boolean,
readonly modGPTRecommendation: string | null,
}

interface CommentsList_tag { // fragment on Tags
Expand Down Expand Up @@ -1421,6 +1424,11 @@ interface CommentsListWithModerationMetadata_allVotes { // fragment on Votes
readonly voteType: string,
}

interface CommentsListWithModGPTAnalysis extends CommentsList { // fragment on Comments
readonly post: PostsMinimumInfo|null,
readonly modGPTAnalysis: string | null,
}

interface RevisionDisplay { // fragment on Revisions
readonly _id: string,
readonly version: string,
Expand Down Expand Up @@ -3031,6 +3039,7 @@ interface FragmentTypes {
StickySubforumCommentFragment: StickySubforumCommentFragment
WithVoteComment: WithVoteComment
CommentsListWithModerationMetadata: CommentsListWithModerationMetadata
CommentsListWithModGPTAnalysis: CommentsListWithModGPTAnalysis
RevisionDisplay: RevisionDisplay
RevisionEdit: RevisionEdit
RevisionMetadata: RevisionMetadata
Expand Down Expand Up @@ -3215,6 +3224,7 @@ interface CollectionNamesByFragmentName {
StickySubforumCommentFragment: "Comments"
WithVoteComment: "Comments"
CommentsListWithModerationMetadata: "Comments"
CommentsListWithModGPTAnalysis: "Comments"
RevisionDisplay: "Revisions"
RevisionEdit: "Revisions"
RevisionMetadata: "Revisions"
Expand Down
2 changes: 1 addition & 1 deletion packages/lesswrong/lib/generated/viewTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type ChaptersViewName = "SequenceChapters";
type ClientIdsViewName = "getClientId";
type CollectionsViewName = never
type CommentModeratorActionsViewName = "activeCommentModeratorActions";
type CommentsViewName = "commentReplies"|"postCommentsDeleted"|"allCommentsDeleted"|"postCommentsTop"|"postCommentsMagic"|"afPostCommentsTop"|"postCommentsOld"|"postCommentsNew"|"postCommentsBest"|"postLWComments"|"profileRecentComments"|"allRecentComments"|"recentComments"|"afSubmissions"|"recentDiscussionThread"|"afRecentDiscussionThread"|"postsItemComments"|"sunshineNewCommentsList"|"questionAnswers"|"legacyIdComment"|"sunshineNewUsersComments"|"defaultModeratorResponses"|"repliesToAnswer"|"topShortform"|"shortform"|"shortformFrontpage"|"repliesToCommentThread"|"shortformLatestChildren"|"nominations2018"|"nominations2019"|"reviews2018"|"reviews2019"|"reviews"|"tagDiscussionComments"|"tagSubforumComments"|"latestSubforumDiscussion"|"moderatorComments"|"debateResponses"|"alignmentSuggestedComments"|"rss";
type CommentsViewName = "commentReplies"|"postCommentsDeleted"|"allCommentsDeleted"|"checkedByModGPT"|"postCommentsTop"|"postCommentsMagic"|"afPostCommentsTop"|"postCommentsOld"|"postCommentsNew"|"postCommentsBest"|"postLWComments"|"profileRecentComments"|"allRecentComments"|"recentComments"|"afSubmissions"|"recentDiscussionThread"|"afRecentDiscussionThread"|"postsItemComments"|"sunshineNewCommentsList"|"questionAnswers"|"legacyIdComment"|"sunshineNewUsersComments"|"defaultModeratorResponses"|"repliesToAnswer"|"topShortform"|"shortform"|"shortformFrontpage"|"repliesToCommentThread"|"shortformLatestChildren"|"nominations2018"|"nominations2019"|"reviews2018"|"reviews2019"|"reviews"|"tagDiscussionComments"|"tagSubforumComments"|"latestSubforumDiscussion"|"moderatorComments"|"debateResponses"|"alignmentSuggestedComments"|"rss";
type ConversationsViewName = "moderatorConversations"|"userConversations"|"userGroupUntitledConversations";
type CronHistoriesViewName = never
type DatabaseMetadataViewName = never
Expand Down
6 changes: 6 additions & 0 deletions packages/lesswrong/lib/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,12 @@ addRoute(
componentName: 'ModerationTemplatesPage',
title: "Moderation Message Templates"
},
{
name: 'ModGPTDashboard',
path: '/admin/modgpt',
componentName: 'ModGPTDashboard',
title: "ModGPT Dashboard"
},
{
name: 'moderation',
path: '/moderation',
Expand Down
1 change: 1 addition & 0 deletions packages/lesswrong/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import "./server/scripts/importEAGUserInterests";
import "./server/scripts/importLocalgroups";
import "./server/scripts/setUserTagFilters";
import "./server/scripts/languageModels/generateTaggingPostSets";
import "./server/scripts/languageModels/testModGPTOnComments";
import './server/manualMigrations';
import './server/manualMigrations/migrationsDashboardGraphql';

Expand Down

0 comments on commit b9614d5

Please sign in to comment.