Skip to content

Commit 28e503b

Browse files
authored
Merge pull request #6 from StephixOne/topic
Return likely predicted topics for posts.
2 parents a416acb + bcfd7fc commit 28e503b

File tree

4 files changed

+98
-26
lines changed

4 files changed

+98
-26
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"nodemon": "1.18.9",
2020
"npm-run-all": "4.1.5",
2121
"ts-node": "4.1.0",
22-
"typescript": "2.9.2"
22+
"typescript": "3.3"
2323
},
2424
"dependencies": {
2525
"apollo-errors": "1.9.0",

src/resolvers/index.ts

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as scuid from 'scuid';
22

3-
import { generateAuthToken, getUserId } from '../utils';
3+
import { generateAuthToken, getUserId, likelyTopics } from '../utils';
44

55
const DEFAULT_COUNT = 25;
66

@@ -66,37 +66,57 @@ export default {
6666
},
6767

6868
// refactor user relation into Class
69-
Post: (parent, { id }, { faker }) => ({
70-
id,
71-
title: faker.random.words(),
72-
body: faker.lorem.paragraphs(),
73-
published: faker.random.boolean(),
74-
createdAt: faker.date.past(),
75-
author: {
76-
id: scuid(),
77-
firstName: faker.name.firstName(),
78-
lastName: faker.name.lastName(),
79-
email: faker.internet.email(),
80-
avatar: faker.image.avatar()
81-
}
82-
}),
83-
84-
// refactor user relation into Class
85-
allPosts: (parent, { count }, { faker }) => {
86-
return new Array(count).fill(0).map(_ => ({
87-
id: scuid(),
88-
title: faker.random.words(),
89-
body: faker.lorem.sentences(),
69+
Post: (parent, { id }, { faker }) => {
70+
const title = faker.random.words();
71+
const body = faker.lorem.paragraphs();
72+
const firstName = faker.name.firstName();
73+
const lastName = faker.name.lastName();
74+
return {
75+
id,
76+
title,
77+
body,
9078
published: faker.random.boolean(),
9179
createdAt: faker.date.past(),
9280
author: {
9381
id: scuid(),
94-
firstName: faker.name.firstName(),
95-
lastName: faker.name.lastName(),
82+
firstName,
83+
lastName,
9684
email: faker.internet.email(),
9785
avatar: faker.image.avatar()
86+
},
87+
likelyTopics: likelyTopics(
88+
`${firstName} ${lastName}`,
89+
title, body
90+
)
91+
};
92+
},
93+
94+
// refactor user relation into Class
95+
allPosts: (parent, { count }, { faker }) => {
96+
return new Array(count).fill(0).map(_ => {
97+
const title = faker.random.words();
98+
const body = faker.lorem.paragraphs();
99+
const firstName = faker.name.firstName();
100+
const lastName = faker.name.lastName();
101+
return {
102+
id: scuid(),
103+
title,
104+
body,
105+
published: faker.random.boolean(),
106+
createdAt: faker.date.past(),
107+
author: {
108+
id: scuid(),
109+
firstName,
110+
lastName,
111+
email: faker.internet.email(),
112+
avatar: faker.image.avatar()
113+
},
114+
likelyTopics: likelyTopics(
115+
`${firstName} ${lastName}`,
116+
title, body
117+
)
98118
}
99-
}));
119+
});
100120
}
101121
},
102122

src/schema.graphql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ type Todo {
2222
completed: Boolean!
2323
}
2424

25+
type Topic {
26+
label: String!
27+
likelihood: Float
28+
}
29+
2530
type Post {
2631
id: ID!
2732
title: String!
2833
body: String!
2934
published: Boolean!
3035
createdAt: String!
3136
author: User!
37+
likelyTopics: [Topic]
3238
}
3339

3440
type Query {

src/utils.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,49 @@ export const getUserId = ctx => {
1616

1717
throw new Error('Not Authorized');
1818
};
19+
20+
// Ten randomly-chosen but consistent topic nouns.
21+
export const topicWords = [
22+
'wedding',
23+
'sport',
24+
'fishing',
25+
'shopping',
26+
'security',
27+
'management',
28+
'community',
29+
'celebrity',
30+
'birthday',
31+
'potato'
32+
];
33+
34+
export const likelyTopics = (user, title, body) => {
35+
// create a custom order over the topics, based on letters as they appear in
36+
// the user's name, post title, and post body, for variability
37+
const alphabet = `${title} ${user} ${body}`;
38+
const topicLabels = topicWords.sort((a, b) => {
39+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
40+
const aValue = alphabet.indexOf(a[i]);
41+
const bValue = alphabet.indexOf(b[i]);
42+
if (aValue !== bValue) {
43+
return bValue - aValue;
44+
}
45+
}
46+
return b.length - a.length;
47+
})
48+
// compute a biased probability distribution
49+
const likelihoods = [];
50+
let total = 0;
51+
for (let i = 0; i < topicLabels.length; i++) {
52+
const weight = Math.random() * Math.log(i + 2);
53+
total += weight;
54+
likelihoods.push(weight);
55+
}
56+
likelihoods.reverse();
57+
// and associate each likelihood with a probability
58+
return likelihoods.map((weight, i) => {
59+
return {
60+
likelihood: weight / total,
61+
label: topicLabels[i]
62+
}
63+
}).sort((a, b) => b.likelihood - a.likelihood);
64+
};

0 commit comments

Comments
 (0)