Spaces:
Running
Running
Commit
·
d0c63f4
1
Parent(s):
013e696
update
Browse files- package-lock.json +6 -0
- package.json +1 -0
- src/app/api/v1/create/generateRandomStory.ts +102 -0
- src/app/api/v1/create/generateStoryPrompt.txt +72 -0
- src/app/api/v1/create/index.ts +9 -5
- src/app/api/v1/create/{systemPrompt.ts → systemPromptCompleteStory.ts} +1 -1
- src/app/api/v1/create/systemPromptRandomStory.ts +13 -0
- src/lib/fun-words/declaration.d.ts +22 -0
- src/lib/fun-words/filterSensitiveContent.ts +81 -0
- src/lib/fun-words/index.ts +35 -0
- src/lib/utils/pick.ts +21 -1
package-lock.json
CHANGED
@@ -63,6 +63,7 @@
|
|
63 |
"eslint-config-next": "13.4.10",
|
64 |
"fastest-levenshtein": "^1.0.16",
|
65 |
"fluent-ffmpeg": "^2.1.2",
|
|
|
66 |
"gsplat": "^1.2.4",
|
67 |
"hash-wasm": "^4.11.0",
|
68 |
"jose": "^5.2.4",
|
@@ -5285,6 +5286,11 @@
|
|
5285 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
5286 |
}
|
5287 |
},
|
|
|
|
|
|
|
|
|
|
|
5288 |
"node_modules/function-bind": {
|
5289 |
"version": "1.1.2",
|
5290 |
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
|
|
63 |
"eslint-config-next": "13.4.10",
|
64 |
"fastest-levenshtein": "^1.0.16",
|
65 |
"fluent-ffmpeg": "^2.1.2",
|
66 |
+
"fun-word-list": "^1.0.1",
|
67 |
"gsplat": "^1.2.4",
|
68 |
"hash-wasm": "^4.11.0",
|
69 |
"jose": "^5.2.4",
|
|
|
5286 |
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
5287 |
}
|
5288 |
},
|
5289 |
+
"node_modules/fun-word-list": {
|
5290 |
+
"version": "1.0.1",
|
5291 |
+
"resolved": "https://registry.npmjs.org/fun-word-list/-/fun-word-list-1.0.1.tgz",
|
5292 |
+
"integrity": "sha512-WoUxTcjSPLSWhyMQaDiYgIWGOPHS7SnsZL8TVQrX8qdMyHXz8uPWnfMHq/Kx+kxQpQJ0GZkMjKgynv+INhbzBg=="
|
5293 |
+
},
|
5294 |
"node_modules/function-bind": {
|
5295 |
"version": "1.1.2",
|
5296 |
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
package.json
CHANGED
@@ -65,6 +65,7 @@
|
|
65 |
"eslint-config-next": "13.4.10",
|
66 |
"fastest-levenshtein": "^1.0.16",
|
67 |
"fluent-ffmpeg": "^2.1.2",
|
|
|
68 |
"gsplat": "^1.2.4",
|
69 |
"hash-wasm": "^4.11.0",
|
70 |
"jose": "^5.2.4",
|
|
|
65 |
"eslint-config-next": "13.4.10",
|
66 |
"fastest-levenshtein": "^1.0.16",
|
67 |
"fluent-ffmpeg": "^2.1.2",
|
68 |
+
"fun-word-list": "^1.0.1",
|
69 |
"gsplat": "^1.2.4",
|
70 |
"hash-wasm": "^4.11.0",
|
71 |
"jose": "^5.2.4",
|
src/app/api/v1/create/generateRandomStory.ts
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { pick } from "@/lib/utils/pick"
|
2 |
+
import {
|
3 |
+
addons, // Fragments to add to the end of sentences for different moods. Many include preceding commas or periods.
|
4 |
+
adjectives, // For use with `nouns` or `concepts`
|
5 |
+
concepts, // Complex nouns
|
6 |
+
descriptions, // For use with `locations`
|
7 |
+
gametypes, // Video game genres/playstyles/feels
|
8 |
+
locations, // Nouns that represent places
|
9 |
+
nouns, // Simple things that can act or be acted upon
|
10 |
+
superlatives, // Adjectives that express the extremes of something. For use with `nouns`, `concepts`, or `locations`
|
11 |
+
verbSecondPerson, // Verbs for use with "you" or "they" as in "you help the aardvark" or "they fight a bird"
|
12 |
+
verbSecondConcepts, // Verbs for use with "you" or "they" in combination with `concepts` as in "you are helped by the King" or "they fight against traditions"
|
13 |
+
verbThirdPerson, // Verbs for use with `nouns` as in "The aardvark anticipates rain"
|
14 |
+
} from "@/lib/fun-words"
|
15 |
+
|
16 |
+
|
17 |
+
const moodTypes = [
|
18 |
+
"A fantasy",
|
19 |
+
"An epic",
|
20 |
+
"A beautiful",
|
21 |
+
"A science-fiction",
|
22 |
+
"A boring",
|
23 |
+
"A sad",
|
24 |
+
"A cheerful",
|
25 |
+
"A funny",
|
26 |
+
"A funny",
|
27 |
+
"A trending",
|
28 |
+
"A cute",
|
29 |
+
"An interesting",
|
30 |
+
"An outrageous",
|
31 |
+
"A dark",
|
32 |
+
"A 3D-rendered",
|
33 |
+
"An animated",
|
34 |
+
"Burlesque",
|
35 |
+
"Short",
|
36 |
+
"Long",
|
37 |
+
"An inspiring",
|
38 |
+
"A marketing",
|
39 |
+
"A commercial",
|
40 |
+
"An internet",
|
41 |
+
"A stupid",
|
42 |
+
"A vintage",
|
43 |
+
]
|
44 |
+
|
45 |
+
const videoTypes = [
|
46 |
+
"fail compilation",
|
47 |
+
"influencer meltdown",
|
48 |
+
"breaking news",
|
49 |
+
"newscast",
|
50 |
+
"politician speech",
|
51 |
+
"found footage",
|
52 |
+
"meme video",
|
53 |
+
"rap video",
|
54 |
+
"animal documentary",
|
55 |
+
"music video",
|
56 |
+
"live video",
|
57 |
+
"advert",
|
58 |
+
"instagram video",
|
59 |
+
"short movie",
|
60 |
+
"documentary",
|
61 |
+
"movie trailer",
|
62 |
+
"TikTok video",
|
63 |
+
]
|
64 |
+
|
65 |
+
const locationTypes = [
|
66 |
+
"in some",
|
67 |
+
// "set somewhere in",
|
68 |
+
"near some",
|
69 |
+
]
|
70 |
+
|
71 |
+
export function generateRandomStory() {
|
72 |
+
|
73 |
+
let pickedWords: any[] = []
|
74 |
+
|
75 |
+
function randomize<T>(words: T[]): T {
|
76 |
+
const picked = pick(words, '' as T)
|
77 |
+
pickedWords.push(picked as any)
|
78 |
+
return picked
|
79 |
+
}
|
80 |
+
|
81 |
+
return `${
|
82 |
+
pick(moodTypes, '')
|
83 |
+
} ${
|
84 |
+
pick(videoTypes, '')
|
85 |
+
}${
|
86 |
+
Math.random() > 0.5 ? "," : ""
|
87 |
+
} ${
|
88 |
+
pick(locationTypes, '')
|
89 |
+
} ${
|
90 |
+
randomize(descriptions)
|
91 |
+
} and ${
|
92 |
+
randomize(descriptions)
|
93 |
+
} ${
|
94 |
+
randomize(locations)
|
95 |
+
}. It is about ${
|
96 |
+
randomize(nouns)[1]
|
97 |
+
}, ${
|
98 |
+
randomize(nouns)[0]
|
99 |
+
} ${
|
100 |
+
randomize(nouns)[1]
|
101 |
+
} and..`
|
102 |
+
}
|
src/app/api/v1/create/generateStoryPrompt.txt
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import YAML from "yaml"
|
3 |
+
|
4 |
+
import { predict } from "@/app/api/providers/huggingface/predictWithHuggingFace"
|
5 |
+
import { LatentStory } from "@/app/api/v1/types"
|
6 |
+
|
7 |
+
import { import { systemPrompt } from "./systemPromptRandomStory"
|
8 |
+
} from "./systemPromptRandomStory"
|
9 |
+
|
10 |
+
export async function generateStoryPrompt({
|
11 |
+
turbo = false,
|
12 |
+
}: {
|
13 |
+
turbo?: boolean
|
14 |
+
} = {
|
15 |
+
turbo: false
|
16 |
+
}): Promise<string[]> {
|
17 |
+
|
18 |
+
if (!prompt.length) { throw new Error(`please provide a prompt`) }
|
19 |
+
console.log("generateMusicPrompts(): prompt:", prompt)
|
20 |
+
|
21 |
+
|
22 |
+
if (!latentStory.length) { throw new Error(`please provide a story`) }
|
23 |
+
|
24 |
+
// console.log("generateMusicPrompts(): latentStory:", latentStory)
|
25 |
+
|
26 |
+
const userPrompt = `The input story is about: ${prompt}.
|
27 |
+
|
28 |
+
The input story is:
|
29 |
+
\`\`\`yaml
|
30 |
+
${YAML.stringify(
|
31 |
+
// we need to help the LLM by marking the shots with a simple numeric ID
|
32 |
+
latentStory.map((shot, i) => ({
|
33 |
+
shot: i,
|
34 |
+
...shot,
|
35 |
+
}))
|
36 |
+
)}
|
37 |
+
\`\`\`
|
38 |
+
|
39 |
+
# Output`
|
40 |
+
|
41 |
+
const prefix = "\""
|
42 |
+
|
43 |
+
// we don't need a lot here!
|
44 |
+
const nbMaxNewTokens = 120
|
45 |
+
|
46 |
+
// TODO use streaming for the Hugging Face prediction
|
47 |
+
//
|
48 |
+
// note that a Clap file is actually a YAML stream of documents
|
49 |
+
// so technically we could stream everything from end-to-end
|
50 |
+
// (but I haven't coded the helpers to do this yet)
|
51 |
+
let rawString = await predict({
|
52 |
+
systemPrompt,
|
53 |
+
userPrompt,
|
54 |
+
nbMaxNewTokens,
|
55 |
+
prefix,
|
56 |
+
turbo,
|
57 |
+
})
|
58 |
+
|
59 |
+
// console.log("generateEntityPrompts(): rawString: ", rawString)
|
60 |
+
|
61 |
+
let results: string[] = []
|
62 |
+
|
63 |
+
// we remove everything after the last ``` (or ``)
|
64 |
+
rawString = rawString.split(/```?/)[0].trim()
|
65 |
+
results.push(rawString)
|
66 |
+
|
67 |
+
if (!Array.isArray(results) || typeof results.at(0) !== "string" || !results) {
|
68 |
+
throw new Error(`failed to generate the output (rawString is: ${rawString})`)
|
69 |
+
}
|
70 |
+
|
71 |
+
return results
|
72 |
+
}
|
src/app/api/v1/create/index.ts
CHANGED
@@ -7,9 +7,10 @@ import { predict } from "@/app/api/providers/huggingface/predictWithHuggingFace"
|
|
7 |
import { parseRawStringToYAML } from "@/app/api/parsers/parseRawStringToYAML"
|
8 |
import { LatentStory } from "@/app/api/v1/types"
|
9 |
|
10 |
-
import {
|
11 |
import { generateMusicPrompts } from "../edit/music/generateMusicPrompt"
|
12 |
import { clapToLatentStory } from "../edit/entities/clapToLatentStory"
|
|
|
13 |
|
14 |
// a helper to generate Clap stories from a few sentences
|
15 |
// this is mostly used by external apps such as the Stories Factory
|
@@ -26,11 +27,14 @@ export async function create(request: {
|
|
26 |
}): Promise<ClapProject> {
|
27 |
|
28 |
// we limit to 512 characters
|
29 |
-
|
30 |
|
31 |
console.log("api/v1/create(): request:", request)
|
32 |
|
33 |
-
if (!prompt.length) {
|
|
|
|
|
|
|
34 |
|
35 |
const width = getValidNumber(request?.width, 256, 8192, 1024)
|
36 |
const height = getValidNumber(request?.height, 256, 8192, 576)
|
@@ -49,7 +53,7 @@ Output: `
|
|
49 |
// so technically we could stream everything from end-to-end
|
50 |
// (but I haven't coded the helpers to do this yet)
|
51 |
let rawString = await predict({
|
52 |
-
systemPrompt,
|
53 |
userPrompt,
|
54 |
nbMaxNewTokens,
|
55 |
prefix,
|
@@ -68,7 +72,7 @@ Output: `
|
|
68 |
await sleep(2000)
|
69 |
|
70 |
rawString = await predict({
|
71 |
-
systemPrompt,
|
72 |
userPrompt: userPrompt + ".", // we trick the Hugging Face cache
|
73 |
nbMaxNewTokens,
|
74 |
prefix,
|
|
|
7 |
import { parseRawStringToYAML } from "@/app/api/parsers/parseRawStringToYAML"
|
8 |
import { LatentStory } from "@/app/api/v1/types"
|
9 |
|
10 |
+
import { systemPromptCompleteStory } from "./systemPromptCompleteStory"
|
11 |
import { generateMusicPrompts } from "../edit/music/generateMusicPrompt"
|
12 |
import { clapToLatentStory } from "../edit/entities/clapToLatentStory"
|
13 |
+
import { generateRandomStory } from "./generateRandomStory"
|
14 |
|
15 |
// a helper to generate Clap stories from a few sentences
|
16 |
// this is mostly used by external apps such as the Stories Factory
|
|
|
27 |
}): Promise<ClapProject> {
|
28 |
|
29 |
// we limit to 512 characters
|
30 |
+
let prompt = `${request?.prompt || ""}`.trim().slice(0, 512)
|
31 |
|
32 |
console.log("api/v1/create(): request:", request)
|
33 |
|
34 |
+
if (!prompt.length) {
|
35 |
+
// throw new Error(`please provide a prompt`)
|
36 |
+
prompt = generateRandomStory()
|
37 |
+
}
|
38 |
|
39 |
const width = getValidNumber(request?.width, 256, 8192, 1024)
|
40 |
const height = getValidNumber(request?.height, 256, 8192, 576)
|
|
|
53 |
// so technically we could stream everything from end-to-end
|
54 |
// (but I haven't coded the helpers to do this yet)
|
55 |
let rawString = await predict({
|
56 |
+
systemPrompt: systemPromptCompleteStory,
|
57 |
userPrompt,
|
58 |
nbMaxNewTokens,
|
59 |
prefix,
|
|
|
72 |
await sleep(2000)
|
73 |
|
74 |
rawString = await predict({
|
75 |
+
systemPrompt: systemPromptCompleteStory,
|
76 |
userPrompt: userPrompt + ".", // we trick the Hugging Face cache
|
77 |
nbMaxNewTokens,
|
78 |
prefix,
|
src/app/api/v1/create/{systemPrompt.ts → systemPromptCompleteStory.ts}
RENAMED
@@ -1,4 +1,4 @@
|
|
1 |
-
export const
|
2 |
`# Context
|
3 |
You are a server-side function generating stories from a single synopsis/brief (a "prompt").
|
4 |
The videos are meant to be shared on social media platform (Instagram, TikTok, Snapchat, Twitter, YouTube Shorts etc).
|
|
|
1 |
+
export const systemPromptCompleteStory: string =
|
2 |
`# Context
|
3 |
You are a server-side function generating stories from a single synopsis/brief (a "prompt").
|
4 |
The videos are meant to be shared on social media platform (Instagram, TikTok, Snapchat, Twitter, YouTube Shorts etc).
|
src/app/api/v1/create/systemPromptRandomStory.ts
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const systemPromptRandomStory: string =
|
2 |
+
`# Context
|
3 |
+
You are a server-side function generating story ideas from a single synopsis/brief (a "prompt").
|
4 |
+
|
5 |
+
# Task
|
6 |
+
Your mission is to invent a RANDOM story, by taking inspiration from a set of keywords.
|
7 |
+
|
8 |
+
You only must generate a sommary and description of the story, not the whole thing.
|
9 |
+
|
10 |
+
# Expected output
|
11 |
+
|
12 |
+
Generate or or two sentences maximum. NEVER generate violent stories, or stories related to some religions or communities.
|
13 |
+
`
|
src/lib/fun-words/declaration.d.ts
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
declare module 'fun-word-list' {
|
2 |
+
import * as funWordList from 'fun-word-list';
|
3 |
+
|
4 |
+
type FunWordList = {
|
5 |
+
addons: string[] // Fragments to add to the end of sentences for different moods. Many include preceding commas or periods.
|
6 |
+
adjectives: string[] // For use with `nouns` or `concepts`
|
7 |
+
concepts: string[] // Complex nouns
|
8 |
+
descriptions: string[] // For use with `locations`
|
9 |
+
gametypes: string[] // Video game genres/playstyles/feels
|
10 |
+
locations: string[] // Nouns that represent places
|
11 |
+
nouns: string[][] // Simple things that can act or be acted upon
|
12 |
+
|
13 |
+
superlatives: string[] // Adjectives that express the extremes of something. For use with `nouns`, `concepts`, or `locations`
|
14 |
+
verbs: { // All verbs in this list are used for acting in relation to another thing.
|
15 |
+
secondPerson: string[] // Verbs for use with "you" or "they" as in "you help the aardvark" or "they fight a bird"
|
16 |
+
secondConcepts: string[] // Verbs for use with "you" or "they" in combination with `concepts` as in "you are helped by the King" or "they fight against traditions"
|
17 |
+
thirdPerson: string[] // Verbs for use with `nouns` as in "The aardvark anticipates rain"
|
18 |
+
}
|
19 |
+
}
|
20 |
+
|
21 |
+
export default funWordList as FunWordList
|
22 |
+
}
|
src/lib/fun-words/filterSensitiveContent.ts
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
// unfortunately the lib comes with some words
|
3 |
+
// that, when combined, could create some bad buzz
|
4 |
+
export const sensitiveTopics = [
|
5 |
+
"The Pope",
|
6 |
+
"gag",
|
7 |
+
"sadist",
|
8 |
+
"actress",
|
9 |
+
"razor",
|
10 |
+
"female",
|
11 |
+
"destroyer",
|
12 |
+
"prisonner",
|
13 |
+
"rib",
|
14 |
+
"cultist",
|
15 |
+
"candy",
|
16 |
+
"candies",
|
17 |
+
"skull",
|
18 |
+
"injury",
|
19 |
+
"lungs",
|
20 |
+
"field",
|
21 |
+
"child",
|
22 |
+
"kid",
|
23 |
+
"walk",
|
24 |
+
"stranger",
|
25 |
+
"children",
|
26 |
+
"faker",
|
27 |
+
"fake",
|
28 |
+
"curse",
|
29 |
+
"scissor",
|
30 |
+
"hobo",
|
31 |
+
"maniac",
|
32 |
+
"drug",
|
33 |
+
"gang",
|
34 |
+
"predator",
|
35 |
+
"hostage",
|
36 |
+
"cutthroat",
|
37 |
+
"swallow",
|
38 |
+
"shotgun",
|
39 |
+
"gun",
|
40 |
+
"pickaxe",
|
41 |
+
"clergymen",
|
42 |
+
"clergyman",
|
43 |
+
"clergy",
|
44 |
+
"dictator",
|
45 |
+
"microbe",
|
46 |
+
"convict",
|
47 |
+
"sniper",
|
48 |
+
"skeleton",
|
49 |
+
"aborigine",
|
50 |
+
"skirt",
|
51 |
+
"thug",
|
52 |
+
"thief",
|
53 |
+
"handgun",
|
54 |
+
"executioner",
|
55 |
+
"beast",
|
56 |
+
"nymph",
|
57 |
+
"rabbis",
|
58 |
+
"rabbies",
|
59 |
+
"rabbi",
|
60 |
+
"giblet",
|
61 |
+
"prisoner",
|
62 |
+
"machine gun",
|
63 |
+
"infant",
|
64 |
+
"crucifix",
|
65 |
+
"hatchet",
|
66 |
+
"beggar",
|
67 |
+
"indian",
|
68 |
+
"corrupted",
|
69 |
+
"russian",
|
70 |
+
"italian",
|
71 |
+
"greek",
|
72 |
+
"bandit",
|
73 |
+
"vulture",
|
74 |
+
"scavenger",
|
75 |
+
"hacksaw",
|
76 |
+
"chick"
|
77 |
+
]
|
78 |
+
|
79 |
+
export function filterSensitiveContent(words: string[], badWords: string[] = sensitiveTopics): string[] {
|
80 |
+
return words.filter(x => !badWords.includes(x.toLowerCase().trim()))
|
81 |
+
}
|
src/lib/fun-words/index.ts
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import funWordList from "fun-word-list"
|
2 |
+
|
3 |
+
const {
|
4 |
+
addons, // Fragments to add to the end of sentences for different moods. Many include preceding commas or periods.
|
5 |
+
adjectives, // For use with `nouns` or `concepts`
|
6 |
+
concepts, // Complex nouns
|
7 |
+
descriptions, // For use with `locations`
|
8 |
+
gametypes, // Video game genres/playstyles/feels
|
9 |
+
locations, // Nouns that represent places
|
10 |
+
nouns, // Simple things that can act or be acted upon
|
11 |
+
superlatives, // Adjectives that express the extremes of something. For use with `nouns`, `concepts`, or `locations`
|
12 |
+
verbs: { // All verbs in this list are used for acting in relation to another thing.
|
13 |
+
secondPerson, // Verbs for use with "you" or "they" as in "you help the aardvark" or "they fight a bird"
|
14 |
+
secondConcepts, // Verbs for use with "you" or "they" in combination with `concepts` as in "you are helped by the King" or "they fight against traditions"
|
15 |
+
thirdPerson, // Verbs for use with `nouns` as in "The aardvark anticipates rain"
|
16 |
+
}
|
17 |
+
} = funWordList
|
18 |
+
|
19 |
+
const verbSecondPerson = secondPerson // Verbs for use with "you" or "they" as in "you help the aardvark" or "they fight a bird"
|
20 |
+
const verbSecondConcepts = secondConcepts // Verbs for use with "you" or "they" in combination with `concepts` as in "you are helped by the King" or "they fight against traditions"
|
21 |
+
const verbThirdPerson = thirdPerson // Verbs for use with `nouns` as in "The aardvark anticipates rain"
|
22 |
+
|
23 |
+
export {
|
24 |
+
addons, // Fragments to add to the end of sentences for different moods. Many include preceding commas or periods.
|
25 |
+
adjectives, // For use with `nouns` or `concepts`
|
26 |
+
concepts, // Complex nouns
|
27 |
+
descriptions, // For use with `locations`
|
28 |
+
gametypes, // Video game genres/playstyles/feels
|
29 |
+
locations, // Nouns that represent places
|
30 |
+
nouns, // Simple things that can act or be acted upon
|
31 |
+
superlatives, // Adjectives that express the extremes of something. For use with `nouns`, `concepts`, or `locations`
|
32 |
+
verbSecondPerson, // Verbs for use with "you" or "they" as in "you help the aardvark" or "they fight a bird"
|
33 |
+
verbSecondConcepts, // Verbs for use with "you" or "they" in combination with `concepts` as in "you are helped by the King" or "they fight against traditions"
|
34 |
+
verbThirdPerson, // Verbs for use with `nouns` as in "The aardvark anticipates rain"
|
35 |
+
}
|
src/lib/utils/pick.ts
CHANGED
@@ -1,2 +1,22 @@
|
|
1 |
|
2 |
-
export
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
+
export function pick<T>(items: T[], defaultValue: T, {
|
3 |
+
skipList = [],
|
4 |
+
maxRetries = 10
|
5 |
+
}: {
|
6 |
+
skipList?: T[]
|
7 |
+
maxRetries?: number
|
8 |
+
} = {
|
9 |
+
skipList: [],
|
10 |
+
maxRetries: 10
|
11 |
+
}): T {
|
12 |
+
let candidate: T | undefined = undefined
|
13 |
+
for (let i = 0; i < maxRetries; i++) {
|
14 |
+
candidate = items[Math.floor(Math.random() * items.length)] as T
|
15 |
+
if (skipList.includes(candidate)) { continue }
|
16 |
+
}
|
17 |
+
if (typeof candidate === "undefined") {
|
18 |
+
return defaultValue
|
19 |
+
} else {
|
20 |
+
return candidate
|
21 |
+
}
|
22 |
+
}
|