jbilcke-hf HF staff commited on
Commit
d0c63f4
1 Parent(s): 013e696
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 { systemPrompt } from "./systemPrompt"
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
- const prompt = `${request?.prompt || ""}`.trim().slice(0, 512)
30
 
31
  console.log("api/v1/create(): request:", request)
32
 
33
- if (!prompt.length) { throw new Error(`please provide a prompt`) }
 
 
 
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 systemPrompt: 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).
 
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 const pick = (items: string[]) => items[Math.floor(Math.random()*items.length)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }