Skip to content

Commit

Permalink
Merge d39aa46 into 7886f6d
Browse files Browse the repository at this point in the history
  • Loading branch information
MrOrz committed Mar 30, 2023
2 parents 7886f6d + d39aa46 commit a6f542f
Show file tree
Hide file tree
Showing 18 changed files with 647 additions and 23 deletions.
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,9 @@ GCS_CREDENTIALS=
GCS_BUCKET_NAME=
GCS_MEDIA_FOLDER=media/

# Open AI API key for AI replies, etc.
#
OPENAI_API_KEY=

# When LOG_REQUESTS exists, it also shows incoming GraphQL request, variables, and resolved user info
LOG_REQUESTS=
111 changes: 90 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"koa-session2": "^2.2.9",
"koa-static": "^5.0.0",
"node-fetch": "^2.2.0",
"openai": "^3.2.1",
"passport-facebook": "^3.0.0",
"passport-github2": "^0.1.10",
"passport-google-oauth20": "^2.0.0",
Expand Down
88 changes: 88 additions & 0 deletions src/graphql/models/AIResponse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import {
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLString,
GraphQLNonNull,
GraphQLID,
GraphQLInt,
} from 'graphql';

import { createConnectionType } from 'graphql/util';
import Node from '../interfaces/Node';
import AIResponseTypeEnum from './AIResponseTypeEnum';
import AIResponseStatusEnum from './AIResponseStatusEnum';
import User, { userFieldResolver } from './User';

const commonAiResponseFields = {
id: { type: new GraphQLNonNull(GraphQLID) },

docId: {
description: 'The id for the document that this AI response is for.',
type: GraphQLID,
},

type: {
description: 'AI response type',
type: new GraphQLNonNull(AIResponseTypeEnum),
},

user: {
description: 'The user triggered this AI response',
type: User,
resolve: userFieldResolver,
},

status: {
description: 'Processing status of AI',
type: new GraphQLNonNull(AIResponseStatusEnum),
},

text: {
description: 'AI response text. Populated after status becomes SUCCESS.',
type: GraphQLString,
},

createdAt: { type: new GraphQLNonNull(GraphQLString) },
updatedAt: { type: GraphQLString },
};

const AIResponse = new GraphQLInterfaceType({
name: 'AIResponse',
description: 'Denotes an AI processed response and its processing status.',
interfaces: [Node],
fields: commonAiResponseFields,
resolveType(doc) {
switch (doc.type) {
case 'AI_REPLY':
return AIReply;
}
},
});

export const AIReply = new GraphQLObjectType({
name: 'AIReply',
description: 'A ChatGPT reply for an article with no human fact-checks yet',
interfaces: [Node, AIResponse],
fields: {
...commonAiResponseFields,
usage: {
description:
'The usage returned from OpenAI. Populated after status becomes SUCCESS.',
type: new GraphQLObjectType({
name: 'OpenAICompletionUsage',
fields: {
promptTokens: { type: new GraphQLNonNull(GraphQLInt) },
completionTokens: { type: new GraphQLNonNull(GraphQLInt) },
totalTokens: { type: new GraphQLNonNull(GraphQLInt) },
},
}),
},
},
});

export const AIResponseConnection = createConnectionType(
'AIResponseConnection',
AIResponse
);

export default AIResponse;
10 changes: 10 additions & 0 deletions src/graphql/models/AIResponseStatusEnum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { GraphQLEnumType } from 'graphql';

export default new GraphQLEnumType({
name: 'AIResponseStatusEnum',
values: {
LOADING: { value: 'LOADING' },
SUCCESS: { value: 'SUCCESS' },
ERROR: { value: 'ERROR' },
},
});
13 changes: 13 additions & 0 deletions src/graphql/models/AIResponseTypeEnum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GraphQLEnumType } from 'graphql';

export default new GraphQLEnumType({
name: 'AIResponseTypeEnum',
values: {
AI_REPLY: {
description:
'The AI Response is an automated analysis / reply of an article.',
value: 'AI_REPLY',
},
// TBA: speach-to-text result, OCR result, reply review response, etc
},
});
28 changes: 28 additions & 0 deletions src/graphql/models/Article.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import mediaManager, {
} from 'util/mediaManager';
import ArticleReplyStatusEnum from './ArticleReplyStatusEnum';
import ArticleReply from './ArticleReply';
import { AIReply } from './AIResponse';
import ArticleCategoryStatusEnum from './ArticleCategoryStatusEnum';
import ReplyRequestStatusEnum from './ReplyRequestStatusEnum';
import ArticleCategory from './ArticleCategory';
Expand Down Expand Up @@ -144,6 +145,33 @@ const Article = new GraphQLObjectType({
},
},

aiReplies: {
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(AIReply))),
description:
'Automated reply from AI before human fact checkers compose an fact check',
async resolve({ id }, _, { loaders }) {
return loaders.searchResultLoader.load({
index: 'airesponses',
type: 'doc',
body: {
query: {
bool: {
must: [
{ term: { type: 'AI_REPLY' } },
{ term: { docId: id } },
{ term: { status: 'SUCCESS' } },
],
},
},
sort: {
createdAt: 'desc',
},
size: 10,
},
});
},
},

articleCategories: {
type: new GraphQLList(ArticleCategory),
args: {
Expand Down
Loading

0 comments on commit a6f542f

Please sign in to comment.