jbilcke-hf HF staff commited on
Commit
5566043
1 Parent(s): 8951ca1

working on the assistant

Browse files
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -12,13 +12,16 @@
12
  "dependencies": {
13
  "@aitube/clap": "0.0.26",
14
  "@aitube/engine": "0.0.19",
15
- "@aitube/timeline": "0.0.23",
16
  "@fal-ai/serverless-client": "^0.10.3",
17
  "@huggingface/hub": "^0.15.1",
18
  "@huggingface/inference": "^2.7.0",
19
  "@langchain/anthropic": "^0.2.0",
 
20
  "@langchain/core": "^0.2.6",
 
21
  "@langchain/groq": "^0.0.12",
 
22
  "@langchain/openai": "^0.1.1",
23
  "@monaco-editor/react": "^4.6.0",
24
  "@radix-ui/react-accordion": "^1.1.2",
 
12
  "dependencies": {
13
  "@aitube/clap": "0.0.26",
14
  "@aitube/engine": "0.0.19",
15
+ "@aitube/timeline": "file:/Users/jbilcke/Projects/Typescript_Libraries/aitube-timeline",
16
  "@fal-ai/serverless-client": "^0.10.3",
17
  "@huggingface/hub": "^0.15.1",
18
  "@huggingface/inference": "^2.7.0",
19
  "@langchain/anthropic": "^0.2.0",
20
+ "@langchain/cohere": "^0.0.11",
21
  "@langchain/core": "^0.2.6",
22
+ "@langchain/google-vertexai": "^0.0.18",
23
  "@langchain/groq": "^0.0.12",
24
+ "@langchain/mistralai": "^0.0.24",
25
  "@langchain/openai": "^0.1.1",
26
  "@monaco-editor/react": "^4.6.0",
27
  "@radix-ui/react-accordion": "^1.1.2",
src/app/api/assistant/askAnyAssistant.ts ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use server"
2
+
3
+ import { ClapSegmentCategory } from "@aitube/clap"
4
+ import { RunnableLike } from "@langchain/core/runnables"
5
+ import { ChatPromptValueInterface } from "@langchain/core/dist/prompt_values"
6
+ import { AIMessageChunk } from "@langchain/core/messages"
7
+ import { ChatPromptTemplate } from "@langchain/core/prompts"
8
+ import { StructuredOutputParser } from "@langchain/core/output_parsers"
9
+ import { ChatOpenAI } from "@langchain/openai"
10
+ import { ChatGroq } from "@langchain/groq"
11
+ import { ChatAnthropic } from "@langchain/anthropic"
12
+ import { ChatCohere } from "@langchain/cohere"
13
+ import { ChatMistralAI } from "@langchain/mistralai"
14
+ import { ChatVertexAI } from "@langchain/google-vertexai"
15
+ // Hugging Face will be supported once the following package becomes available
16
+ // import { ChatHuggingFace } from "@langchain/huggingface"
17
+
18
+ import { AssistantRequest, AssistantResponse, ComputeProvider } from "@/types"
19
+
20
+ import { SimplifiedSegmentData, simplifiedSegmentDataZ } from "./types"
21
+ import { examples, humanTemplate, systemTemplate } from "./templates"
22
+
23
+ const parser = StructuredOutputParser.fromZodSchema(simplifiedSegmentDataZ)
24
+
25
+ const formatInstructions = parser.getFormatInstructions()
26
+
27
+ /**
28
+ * Query the preferred language model on the user prompt + the segments of the current scene
29
+ *
30
+ * @param userPrompt
31
+ * @param segments
32
+ * @returns
33
+ */
34
+ export async function askAnyAssistant({
35
+ settings,
36
+
37
+ prompt,
38
+
39
+ // the slice to edit
40
+ segments = [],
41
+
42
+ fullScene = "",
43
+
44
+ actionLine = "",
45
+
46
+ // used to provide more context
47
+ entities = {},
48
+
49
+ // used to provide more context
50
+ projectInfo = ""
51
+ }: AssistantRequest): Promise<AssistantResponse> {
52
+
53
+ const provider = settings.assistantProvider
54
+
55
+ if (!provider) { throw new Error(`Missing assistant provider`)}
56
+
57
+ let coerceable: undefined | RunnableLike<ChatPromptValueInterface, AIMessageChunk> =
58
+ provider === ComputeProvider.GROQ
59
+ ? new ChatGroq({
60
+ apiKey: settings.groqApiKey,
61
+ modelName: settings.groqModelForAssistant,
62
+ // temperature: 0.7,
63
+ })
64
+ : provider === ComputeProvider.OPENAI
65
+ ? new ChatOpenAI({
66
+ openAIApiKey: settings.openaiApiKey,
67
+ modelName: settings.openaiModelForAssistant,
68
+ // temperature: 0.7,
69
+ })
70
+ : provider === ComputeProvider.ANTHROPIC
71
+ ? new ChatAnthropic({
72
+ anthropicApiKey: settings.anthropicApiKey,
73
+ modelName: settings.anthropicModelForAssistant,
74
+ // temperature: 0.7,
75
+ })
76
+ : provider === ComputeProvider.COHERE
77
+ ? new ChatCohere({
78
+ apiKey: settings.cohereApiKey,
79
+ model: settings.cohereModelForAssistant,
80
+ // temperature: 0.7,
81
+ })
82
+ : provider === ComputeProvider.MISTRALAI
83
+ ? new ChatMistralAI({
84
+ apiKey: settings.mistralAiApiKey,
85
+ modelName: settings.mistralAiModelForAssistant,
86
+ // temperature: 0.7,
87
+ })
88
+ : provider === ComputeProvider.GOOGLE
89
+ ? new ChatVertexAI({
90
+ apiKey: settings.googleApiKey,
91
+ modelName: settings.googleModelForAssistant,
92
+ // temperature: 0.7,
93
+ })
94
+ : undefined
95
+
96
+ if (!coerceable) { throw new Error(`Provider ${provider} is not supported yet. If a LangChain bridge exists for this provider, then you can add it to Clapper.`)}
97
+
98
+ const chatPrompt = ChatPromptTemplate.fromMessages(
99
+ [
100
+ ["system", systemTemplate],
101
+ ["human", humanTemplate],
102
+ ]
103
+ )
104
+
105
+ // we don't give the whole thing to the LLM as to not confuse it,
106
+ // and also to keep things tight and performant
107
+ const inputData: SimplifiedSegmentData[] = segments.map((segment) => ({
108
+ prompt: segment.prompt,
109
+ category: segment.category,
110
+ } as SimplifiedSegmentData))
111
+
112
+ // console.log("INPUT:", JSON.stringify(inputData, null, 2))
113
+
114
+ const chain = chatPrompt.pipe(coerceable).pipe(parser)
115
+
116
+ try {
117
+ const result = await chain.invoke({
118
+ formatInstructions,
119
+ examples,
120
+ projectInfo,
121
+ fullScene,
122
+ actionLine,
123
+ userPrompt: prompt,
124
+ inputData,
125
+ })
126
+
127
+ console.log("OUTPUT:", JSON.stringify(result, null, 2))
128
+
129
+ /*
130
+ this whole code doesn't work well actually..
131
+
132
+ let match: SegmentData | undefined = segments[result.index] || undefined
133
+
134
+ // LLM gave an object, but the index is wrong
135
+ if (!match) {
136
+ match = segments.find(s => s.category === result.category) || undefined
137
+ }
138
+ */
139
+
140
+ // let's create a new segment then!
141
+ const categoryName: ClapSegmentCategory =
142
+ result?.category && Object.keys(ClapSegmentCategory).includes(result.category.toUpperCase())
143
+ ? (result.category as ClapSegmentCategory)
144
+ : ClapSegmentCategory.GENERIC
145
+
146
+ return {
147
+ prompt: result?.prompt || "",
148
+ categoryName,
149
+ llmOutput: "",
150
+ }
151
+ } catch (err1) {
152
+
153
+ // a common scenario is when the output from the LLM is just not a JSON
154
+ // this can happen quite often, for instance if the user tried to bypass
155
+ // our prompt, or if they are just asking generic questions
156
+ const errObj = err1 as any
157
+ try {
158
+ const keys = Object.keys(errObj)
159
+ // console.log("keys:", keys)
160
+ if (errObj.llmOutput) {
161
+ return {
162
+ prompt: "",
163
+ categoryName: ClapSegmentCategory.GENERIC,
164
+ llmOutput: `${errObj.llmOutput || ""}`,
165
+ }
166
+ }
167
+ } catch (err2) {
168
+ // err2 is just the error for when the LLM failed to reply
169
+ console.error(`----<${err1}>----`)
170
+ }
171
+
172
+ return {
173
+ prompt: "",
174
+ categoryName: ClapSegmentCategory.GENERIC,
175
+ llmOutput: ""
176
+ }
177
+ }
178
+ }
src/app/api/assistant/providers/openai/askAssistant.ts CHANGED
@@ -9,19 +9,17 @@ import { AssistantRequest, AssistantResponse } from "@/types"
9
  import { SimplifiedSegmentData, simplifiedSegmentDataZ } from "../../types"
10
  import { examples, humanTemplate, systemTemplate } from "../../templates"
11
 
12
-
13
  const parser = StructuredOutputParser.fromZodSchema(simplifiedSegmentDataZ)
14
 
15
  const formatInstructions = parser.getFormatInstructions()
16
 
17
-
18
  /**
19
  * Query the preferred language model on the user prompt + the segments of the current scene
20
  * @param userPrompt
21
  * @param segments
22
  * @returns
23
  */
24
- export async function queryAssistant({
25
  settings,
26
 
27
  prompt,
@@ -54,9 +52,6 @@ export async function queryAssistant({
54
  ]
55
  )
56
 
57
-
58
-
59
-
60
  // we don't give the whole thing to the LLM as to not confuse it,
61
  // and also to keep things tight and performant
62
  const inputData: SimplifiedSegmentData[] = segments.map((segment) => ({
 
9
  import { SimplifiedSegmentData, simplifiedSegmentDataZ } from "../../types"
10
  import { examples, humanTemplate, systemTemplate } from "../../templates"
11
 
 
12
  const parser = StructuredOutputParser.fromZodSchema(simplifiedSegmentDataZ)
13
 
14
  const formatInstructions = parser.getFormatInstructions()
15
 
 
16
  /**
17
  * Query the preferred language model on the user prompt + the segments of the current scene
18
  * @param userPrompt
19
  * @param segments
20
  * @returns
21
  */
22
+ export async function askAssistant({
23
  settings,
24
 
25
  prompt,
 
52
  ]
53
  )
54
 
 
 
 
55
  // we don't give the whole thing to the LLM as to not confuse it,
56
  // and also to keep things tight and performant
57
  const inputData: SimplifiedSegmentData[] = segments.map((segment) => ({
src/app/api/assistant/route.TODO DELETED
File without changes
src/app/api/assistant/route.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { NextResponse, NextRequest } from "next/server"
2
+
3
+ import { AssistantRequest, AssistantResponse } from "@/types"
4
+ import { askAnyAssistant } from "./askAnyAssistant"
5
+
6
+ export async function POST(req: NextRequest) {
7
+ // do we really need to secure it?
8
+ // I mean.. in the end, the user is using their own credentials,
9
+ // so they cannot siphon free OpenAI, HF, Replicate tokens
10
+ // console.log(`TODO Julian: secure the endpoint`)
11
+ // await throwIfInvalidToken(req.headers.get("Authorization"))
12
+ const request = (await req.json()) as AssistantRequest
13
+
14
+ const response: AssistantResponse = await askAnyAssistant(request)
15
+
16
+ return NextResponse.json(response)
17
+ }
src/app/api/resolve/route.ts CHANGED
@@ -1,4 +1,5 @@
1
  import { NextResponse, NextRequest } from "next/server"
 
2
 
3
  import { resolveSegment as resolveSegmentUsingHuggingFace } from "./providers/huggingface"
4
  import { resolveSegment as resolveSegmentUsingComfyReplicate } from "./providers/comfy-replicate"
@@ -8,7 +9,6 @@ import { resolveSegment as resolveSegmentUsingFalAi } from "./providers/falai"
8
  import { resolveSegment as resolveSegmentUsingModelsLab } from "./providers/modelslab"
9
 
10
  import { ComputeProvider, ResolveRequest } from "@/types"
11
- import { ClapSegmentCategory } from "@aitube/clap"
12
 
13
  export async function POST(req: NextRequest) {
14
  // do we really need to secure it?
 
1
  import { NextResponse, NextRequest } from "next/server"
2
+ import { ClapSegmentCategory } from "@aitube/clap"
3
 
4
  import { resolveSegment as resolveSegmentUsingHuggingFace } from "./providers/huggingface"
5
  import { resolveSegment as resolveSegmentUsingComfyReplicate } from "./providers/comfy-replicate"
 
9
  import { resolveSegment as resolveSegmentUsingModelsLab } from "./providers/modelslab"
10
 
11
  import { ComputeProvider, ResolveRequest } from "@/types"
 
12
 
13
  export async function POST(req: NextRequest) {
14
  // do we really need to secure it?
src/app/main.tsx CHANGED
@@ -21,6 +21,7 @@ import { useUI } from "@/controllers/ui"
21
  import { TopBar } from "@/components/toolbars/top-bar"
22
  import { Timeline } from "@/components/core/timeline"
23
  import { useIO } from "@/controllers/io/useIO"
 
24
 
25
  type DroppableThing = { files: File[] }
26
 
@@ -71,23 +72,31 @@ function MainContent() {
71
  `flex flex-row flex-grow w-full overflow-hidden`,
72
  isEmpty ? "opacity-0" : "opacity-100"
73
  )}>
74
- <ReflexContainer orientation="horizontal">
75
- <ReflexElement
76
- minSize={showTimeline ? 100 : 1}
77
- >
78
- <Monitor />
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  </ReflexElement>
80
- <ReflexSplitter />
81
- <ReflexElement
82
- size={showTimeline ? 400 : 1}
83
- minSize={showTimeline ? 100 : 1}
84
- maxSize={showTimeline ? 1600 : 1}
85
- >
86
- <Timeline />
87
- </ReflexElement>
88
- {/* showChat && <ReflexSplitter /> */}
89
- {/* showChat && <ReflexElement size={300}><ChatView /></ReflexElement> */}
90
  </ReflexContainer>
 
91
  </div>
92
 
93
  <SettingsDialog />
 
21
  import { TopBar } from "@/components/toolbars/top-bar"
22
  import { Timeline } from "@/components/core/timeline"
23
  import { useIO } from "@/controllers/io/useIO"
24
+ import { ChatView } from "@/components/assistant/ChatView"
25
 
26
  type DroppableThing = { files: File[] }
27
 
 
72
  `flex flex-row flex-grow w-full overflow-hidden`,
73
  isEmpty ? "opacity-0" : "opacity-100"
74
  )}>
75
+ <ReflexContainer orientation="vertical">
76
+
77
+ <ReflexElement>
78
+ <ReflexContainer orientation="horizontal">
79
+ <ReflexElement
80
+ minSize={showTimeline ? 100 : 1}
81
+ >
82
+ <Monitor />
83
+ </ReflexElement>
84
+ <ReflexSplitter />
85
+ <ReflexElement
86
+ size={showTimeline ? 400 : 1}
87
+ minSize={showTimeline ? 100 : 1}
88
+ maxSize={showTimeline ? 1600 : 1}
89
+ >
90
+ <Timeline />
91
+ </ReflexElement>
92
+ </ReflexContainer>
93
  </ReflexElement>
94
+
95
+ {showChat && <ReflexSplitter />}
96
+ {showChat && <ReflexElement size={300}><ChatView /></ReflexElement>}
97
+
 
 
 
 
 
 
98
  </ReflexContainer>
99
+
100
  </div>
101
 
102
  <SettingsDialog />
src/components/assistant/ChatView.tsx CHANGED
@@ -1,12 +1,8 @@
1
  "use client"
2
 
3
  import { useState, useTransition } from "react"
4
- import { ClapOutputType, ClapProject, ClapSegment, ClapSegmentCategory, newSegment } from "@aitube/clap"
5
- import { DEFAULT_DURATION_IN_MS_PER_STEP, findFreeTrack, useTimeline } from "@aitube/timeline"
6
 
7
  import { useAssistant } from "@/controllers/assistant/useAssistant"
8
- import { queryAssistant } from "@/app/api/assistant/providers/openai/askAssistant"
9
- import { useSettings } from "@/controllers/settings"
10
 
11
  import { ChatBubble } from "./ChatBubble"
12
  import { Input } from "../ui/input"
@@ -14,22 +10,10 @@ import { Input } from "../ui/input"
14
  export function ChatView() {
15
  const [_isPending, startTransition] = useTransition()
16
 
17
- /*
18
- const others = useLiveProject((state) => state.liveblocks.others)
19
- const userCount = others.length
20
- console.log(`TODO: finish this There are ${userCount} other user(s) online`)
21
- */
22
 
23
  const [draft, setDraft] = useState("")
24
- const runCommand = useAssistant((s) => s.runCommand)
25
  const history = useAssistant((s) => s.history)
26
- const addEventToHistory = useAssistant((s) => s.addEventToHistory)
27
-
28
- /*
29
- const updateSegment = useApp((state) => state.updateSegment)
30
- const addSegment = useApp((state) => state.addSegment)
31
- const projectInfo = useApp((state) => state.projectInfo)
32
- */
33
 
34
  const handleSubmit = () => {
35
  const message = draft.trim()
@@ -39,146 +23,7 @@ export function ChatView() {
39
  }
40
 
41
  setDraft("")
42
-
43
- addEventToHistory({
44
- senderId: "director",
45
- senderName: "Director",
46
- message,
47
- })
48
-
49
- // the LLM is behind a server action
50
- startTransition(async () => {
51
-
52
-
53
- const basicCommand = await runCommand(message)
54
- // LLM analysis can be slow and expensive, so first we try to see if this was a trivial command
55
- // like "start", "pause", "stop" etc
56
- if (basicCommand) {
57
-
58
- addEventToHistory({
59
- senderId: "assistant",
60
- senderName: "Assistant",
61
- message: `${basicCommand}`,
62
- })
63
- return // no need to go further
64
- }
65
-
66
-
67
- const clap: ClapProject = useTimeline.getState().clap
68
-
69
- console.log(`TODO @julian: restore the concept of "addSegment()", "updateSegment()", "active segment" and "cursor position" inside @aitube-timeline`)
70
- // const { addSegment, activeSegments, cursorInSteps, } = useTimeline.getState()
71
-
72
- const activeSegments: ClapSegment[] = []
73
- const cursorInSteps = 0
74
-
75
- const referenceSegment: ClapSegment | undefined = activeSegments.at(0)
76
-
77
- if (!referenceSegment) {
78
- throw new Error(`No segment under the current cursor`)
79
- }
80
-
81
- console.log(`TODO @julian: filter entities to only keep the ones in the current active segment? (although.. maybe a bad idea since the LLM need as much context as possible to "fill in the gap" eg. repair/invent missing elements of the story)`)
82
-
83
- const entities = clap.entityIndex
84
-
85
- const projectInfo = clap.meta.description
86
-
87
- const sceneId = referenceSegment.sceneId
88
-
89
- const scene = clap.scenes.find(s => s.id === sceneId)
90
-
91
- const fullScene: string = scene?.sequenceFullText || ""
92
- const actionLine: string = scene?.line || ""
93
-
94
- const segments: ClapSegment[] = activeSegments
95
- .filter(s =>
96
- s.category === ClapSegmentCategory.LOCATION ||
97
- s.category === ClapSegmentCategory.TIME ||
98
- s.category === ClapSegmentCategory.LIGHTING ||
99
- s.category === ClapSegmentCategory.ACTION ||
100
- s.category === ClapSegmentCategory.DIALOGUE ||
101
- s.category === ClapSegmentCategory.WEATHER
102
- )
103
-
104
- console.log(`TODO @julian: provide both contextual segments and editable ones to the LLM?`)
105
-
106
- const { prompt, categoryName, llmOutput } = await queryAssistant({
107
- settings: useSettings.getState().getSettings(),
108
- prompt: message,
109
- segments,
110
- fullScene,
111
- actionLine,
112
- entities,
113
- projectInfo,
114
- })
115
- if (!prompt.length) {
116
- addEventToHistory({
117
- senderId: "assistant",
118
- senderName: "Assistant",
119
- message: llmOutput || "🤔" // or "???" for a "boomer" theme
120
- })
121
- return
122
- }
123
-
124
- let match = segments.find(s => s.category === categoryName) || undefined
125
- if (!match) {
126
-
127
- const startTimeInMs = cursorInSteps * DEFAULT_DURATION_IN_MS_PER_STEP
128
- const durationInSteps = 4
129
- const durationInMs = durationInSteps * DEFAULT_DURATION_IN_MS_PER_STEP
130
- const endTimeInMs = startTimeInMs + durationInMs
131
-
132
- const newSeg = newSegment({
133
- startTimeInSteps: cursorInSteps,
134
- prompt: [prompt],
135
- durationInSteps: 4,
136
- trackId: findFreeTrack({
137
- segments,
138
- startTimeInMs,
139
- endTimeInMs,
140
- }),
141
- outputType: ClapOutputType.TEXT,
142
- categoryName,
143
- })
144
- console.log("Creating new existing segment:", newSeg)
145
-
146
- console.log(`TODO Julian: add the segment!!`)
147
- // addSegment(newSeg)
148
-
149
- addEventToHistory({
150
- senderId: "assistant",
151
- senderName: "Assistant",
152
- message: `Segment added: ${newSeg.prompt}`,
153
- })
154
- } else {
155
-
156
- console.log("Updating an existing segment to:", {
157
- ...match,
158
- prompt,
159
- label: prompt,
160
- })
161
-
162
- console.log(`TODO Julian: update the segment!!`)
163
- // addSegment(newSeg)
164
-
165
- /*
166
- updateSegment({
167
- ...match,
168
- prompt,
169
- label: prompt,
170
- })
171
- */
172
-
173
- addEventToHistory({
174
- senderId: "assistant",
175
- senderName: "Assistant",
176
- message: `Segment updated: ${prompt}`,
177
- })
178
- }
179
-
180
- })
181
-
182
  }
183
 
184
  return (
 
1
  "use client"
2
 
3
  import { useState, useTransition } from "react"
 
 
4
 
5
  import { useAssistant } from "@/controllers/assistant/useAssistant"
 
 
6
 
7
  import { ChatBubble } from "./ChatBubble"
8
  import { Input } from "../ui/input"
 
10
  export function ChatView() {
11
  const [_isPending, startTransition] = useTransition()
12
 
 
 
 
 
 
13
 
14
  const [draft, setDraft] = useState("")
 
15
  const history = useAssistant((s) => s.history)
16
+ const processMessage = useAssistant((s) => s.processMessage)
 
 
 
 
 
 
17
 
18
  const handleSubmit = () => {
19
  const message = draft.trim()
 
23
  }
24
 
25
  setDraft("")
26
+ processMessage(draft.trim())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
  return (
src/components/settings/constants.ts CHANGED
@@ -1,25 +1,33 @@
1
  import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
2
 
3
  export const computeProviderShortNames = {
4
- [ComputeProvider.NONE]: "None",
5
- [ComputeProvider.CUSTOM]: "Custom API",
6
- [ComputeProvider.HUGGINGFACE]: "Hugging Face",
7
  [ComputeProvider.COMFY_HUGGINGFACE]: "Hugging Face Comfy",
8
- [ComputeProvider.REPLICATE]: "Replicate",
9
  [ComputeProvider.COMFY_REPLICATE]: "Replicate Comfy",
10
- [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu",
11
  [ComputeProvider.ELEVENLABS]: "ElevenLabs",
 
 
 
 
 
 
 
 
 
12
  [ComputeProvider.OPENAI]: "OpenAI",
 
13
  [ComputeProvider.STABILITYAI]: "StabilityAI",
14
- [ComputeProvider.GROQ]: "Groq",
15
- [ComputeProvider.FALAI]: "Fal.ai",
16
- [ComputeProvider.MODELSLAB]: "ModelsLab"
17
  }
18
 
19
  export const availableComputeProvidersForAssistant = [
20
  ComputeProvider.HUGGINGFACE,
21
  ComputeProvider.GROQ,
22
  ComputeProvider.OPENAI,
 
 
23
  ]
24
 
25
  export const availableComputeProvidersForImages = [
@@ -27,6 +35,8 @@ export const availableComputeProvidersForImages = [
27
  ComputeProvider.REPLICATE,
28
  ComputeProvider.COMFY_REPLICATE,
29
  ComputeProvider.COMFY_COMFYICU,
 
 
30
  ComputeProvider.FALAI,
31
  ComputeProvider.MODELSLAB,
32
  ]
@@ -36,6 +46,8 @@ export const availableComputeProvidersForVideos = [
36
  ComputeProvider.REPLICATE,
37
  ComputeProvider.COMFY_REPLICATE,
38
  ComputeProvider.COMFY_COMFYICU,
 
 
39
  ComputeProvider.FALAI,
40
  ComputeProvider.MODELSLAB,
41
  ]
@@ -45,6 +57,7 @@ export const availableComputeProvidersForMusic = [
45
  ComputeProvider.COMFY_REPLICATE,
46
  ComputeProvider.COMFY_COMFYICU,
47
  ComputeProvider.STABILITYAI,
 
48
  ComputeProvider.FALAI,
49
  ComputeProvider.MODELSLAB,
50
  ]
@@ -54,13 +67,16 @@ export const availableComputeProvidersForSound = [
54
  ComputeProvider.COMFY_REPLICATE,
55
  ComputeProvider.COMFY_COMFYICU,
56
  ComputeProvider.STABILITYAI,
 
57
  ComputeProvider.FALAI,
58
  ComputeProvider.ELEVENLABS,
59
  ]
60
 
61
  export const availableComputeProvidersForVoice = [
62
  ComputeProvider.ELEVENLABS,
 
63
  ComputeProvider.STABILITYAI,
 
64
  ComputeProvider.HUGGINGFACE,
65
  ComputeProvider.COMFY_REPLICATE,
66
  ComputeProvider.COMFY_COMFYICU,
@@ -79,7 +95,36 @@ export const availableComfyIcuAccelerators = {
79
 
80
  export const availableModelsForAssistant: Partial<Record<ComputeProvider, string[]>> = {
81
  [ComputeProvider.OPENAI]: [
 
 
82
  "gpt-4o",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  ]
84
  }
85
 
@@ -102,6 +147,17 @@ export const availableModelsForImageGeneration: Partial<Record<ComputeProvider,
102
  // "fal-ai/pulid",
103
  // "fal-ai/image-to-image",
104
  // "fal-ai/omni-zero",
 
 
 
 
 
 
 
 
 
 
 
105
  ]
106
  }
107
 
@@ -109,12 +165,19 @@ export const availableModelsForImageGeneration: Partial<Record<ComputeProvider,
109
  export const availableModelsForImageUpscaling: Partial<Record<ComputeProvider, string[]>> = {
110
  [ComputeProvider.FALAI]: [
111
  "fal-ai/ccsr",
112
- ]
 
 
 
 
113
  }
114
 
115
  export const availableModelsForVideoGeneration: Partial<Record<ComputeProvider, string[]>> = {
116
  [ComputeProvider.FALAI]: [
117
  "fal-ai/stable-video",
 
 
 
118
  ]
119
  }
120
 
 
1
  import { ComfyIcuAccelerator, ComputeProvider } from "@/types"
2
 
3
  export const computeProviderShortNames = {
4
+ [ComputeProvider.ANTHROPIC]: "Anthropic",
5
+ [ComputeProvider.COHERE]: "Cohere",
6
+ [ComputeProvider.COMFY_COMFYICU]: "Comfy.icu",
7
  [ComputeProvider.COMFY_HUGGINGFACE]: "Hugging Face Comfy",
 
8
  [ComputeProvider.COMFY_REPLICATE]: "Replicate Comfy",
9
+ [ComputeProvider.CUSTOM]: "Custom API",
10
  [ComputeProvider.ELEVENLABS]: "ElevenLabs",
11
+ [ComputeProvider.FALAI]: "Fal.ai",
12
+ [ComputeProvider.FIREWORKSAI]: "FireworksAI",
13
+ [ComputeProvider.GOOGLE]: "Google (VertexAI)",
14
+ [ComputeProvider.GROQ]: "Groq",
15
+ [ComputeProvider.HUGGINGFACE]: "Hugging Face",
16
+ [ComputeProvider.KITSAI]: "Kits.ai",
17
+ [ComputeProvider.MISTRALAI]: "MistralAI",
18
+ [ComputeProvider.MODELSLAB]: "ModelsLab",
19
+ [ComputeProvider.NONE]: "None", // <-- this is the default
20
  [ComputeProvider.OPENAI]: "OpenAI",
21
+ [ComputeProvider.REPLICATE]: "Replicate",
22
  [ComputeProvider.STABILITYAI]: "StabilityAI",
 
 
 
23
  }
24
 
25
  export const availableComputeProvidersForAssistant = [
26
  ComputeProvider.HUGGINGFACE,
27
  ComputeProvider.GROQ,
28
  ComputeProvider.OPENAI,
29
+ ComputeProvider.ANTHROPIC,
30
+ ComputeProvider.FIREWORKSAI,
31
  ]
32
 
33
  export const availableComputeProvidersForImages = [
 
35
  ComputeProvider.REPLICATE,
36
  ComputeProvider.COMFY_REPLICATE,
37
  ComputeProvider.COMFY_COMFYICU,
38
+ ComputeProvider.STABILITYAI,
39
+ ComputeProvider.FIREWORKSAI,
40
  ComputeProvider.FALAI,
41
  ComputeProvider.MODELSLAB,
42
  ]
 
46
  ComputeProvider.REPLICATE,
47
  ComputeProvider.COMFY_REPLICATE,
48
  ComputeProvider.COMFY_COMFYICU,
49
+ ComputeProvider.STABILITYAI,
50
+ // ComputeProvider.FIREWORKSAI,
51
  ComputeProvider.FALAI,
52
  ComputeProvider.MODELSLAB,
53
  ]
 
57
  ComputeProvider.COMFY_REPLICATE,
58
  ComputeProvider.COMFY_COMFYICU,
59
  ComputeProvider.STABILITYAI,
60
+ // ComputeProvider.FIREWORKSAI,
61
  ComputeProvider.FALAI,
62
  ComputeProvider.MODELSLAB,
63
  ]
 
67
  ComputeProvider.COMFY_REPLICATE,
68
  ComputeProvider.COMFY_COMFYICU,
69
  ComputeProvider.STABILITYAI,
70
+ // ComputeProvider.FIREWORKSAI,
71
  ComputeProvider.FALAI,
72
  ComputeProvider.ELEVENLABS,
73
  ]
74
 
75
  export const availableComputeProvidersForVoice = [
76
  ComputeProvider.ELEVENLABS,
77
+ ComputeProvider.KITSAI,
78
  ComputeProvider.STABILITYAI,
79
+ // ComputeProvider.FIREWORKSAI,
80
  ComputeProvider.HUGGINGFACE,
81
  ComputeProvider.COMFY_REPLICATE,
82
  ComputeProvider.COMFY_COMFYICU,
 
95
 
96
  export const availableModelsForAssistant: Partial<Record<ComputeProvider, string[]>> = {
97
  [ComputeProvider.OPENAI]: [
98
+ "gpt-4",
99
+ "gpt-4-turbo",
100
  "gpt-4o",
101
+ ],
102
+ [ComputeProvider.GROQ]: [
103
+ "Mixtral-8x7b-32768",
104
+ "Gemma-7b-lt",
105
+ "Llama3-70b-8192",
106
+ "Llama3-8b-8192",
107
+ ],
108
+ [ComputeProvider.ANTHROPIC]: [
109
+ "claude-3-opus-20240229",
110
+ "claude-3-sonnet-20240229",
111
+ "claude-3-haiku-20240307"
112
+ ],
113
+ [ComputeProvider.GOOGLE]: [
114
+ "claude-3-opus@20240229",
115
+ "claude-3-sonnet@20240229",
116
+ "claude-3-haiku@20240307"
117
+ ],
118
+ [ComputeProvider.MISTRALAI]: [
119
+ "mistral-small-latest",
120
+ "open-mistral-7b"
121
+ ],
122
+ [ComputeProvider.HUGGINGFACE]: [
123
+ "HuggingFaceH4/zephyr-7b-beta",
124
+ "mistralai/Mixtral-8x7B-Instruct-v0.1"
125
+ ],
126
+ [ComputeProvider.FIREWORKSAI]: [
127
+ "fireworks/llama-v3-70b-instruct",
128
  ]
129
  }
130
 
 
147
  // "fal-ai/pulid",
148
  // "fal-ai/image-to-image",
149
  // "fal-ai/omni-zero",
150
+ ],
151
+ [ComputeProvider.STABILITYAI]: [
152
+ "stable-image/generate/ultra",
153
+ "stable-image/generate/core",
154
+ "stable-image/generate/sd3"
155
+ ],
156
+ [ComputeProvider.FIREWORKSAI]: [
157
+ "stability/sd3",
158
+ "accounts/stability/models/sd3-turbo",
159
+ "fireworks/stable-diffusion-xl-1024-v1-0",
160
+ "accounts/fireworks/models/playground-v2-5-1024px-aesthetic",
161
  ]
162
  }
163
 
 
165
  export const availableModelsForImageUpscaling: Partial<Record<ComputeProvider, string[]>> = {
166
  [ComputeProvider.FALAI]: [
167
  "fal-ai/ccsr",
168
+ ],
169
+ [ComputeProvider.STABILITYAI]: [
170
+ "stable-image/upscale/conservative",
171
+ "stable-image/upscale/creative"
172
+ ],
173
  }
174
 
175
  export const availableModelsForVideoGeneration: Partial<Record<ComputeProvider, string[]>> = {
176
  [ComputeProvider.FALAI]: [
177
  "fal-ai/stable-video",
178
+ ],
179
+ [ComputeProvider.STABILITYAI]: [
180
+ "image-to-video",
181
  ]
182
  }
183
 
src/components/toolbars/top-menu/assistant/index.tsx ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import {
4
+ MenubarCheckboxItem,
5
+ MenubarContent,
6
+ MenubarItem,
7
+ MenubarMenu,
8
+ MenubarSeparator,
9
+ MenubarSub,
10
+ MenubarSubContent,
11
+ MenubarSubTrigger,
12
+ MenubarTrigger
13
+ } from "@/components/ui/menubar"
14
+ import { useSettings } from "@/controllers/settings"
15
+ import { useUI } from "@/controllers/ui"
16
+
17
+ import { ProviderList } from "../lists/ProviderList"
18
+ import { availableComputeProvidersForAssistant } from "@/components/settings/constants"
19
+ import { SettingsCategory } from "@/types"
20
+ import { AssistantModelList } from "../lists/AssistantModelList"
21
+
22
+ export function TopMenuAssistant() {
23
+ const setShowSettings = useUI(s => s.setShowSettings)
24
+ const assistantProvider = useSettings(s => s.assistantProvider)
25
+ const setAssistantProvider = useSettings(s => s.setAssistantProvider)
26
+ const assistantModel = useSettings(s => s.assistantModel)
27
+ const setAssistantModel = useSettings(s => s.setAssistantModel)
28
+ return (
29
+ <MenubarMenu>
30
+ <MenubarTrigger>Assistant</MenubarTrigger>
31
+ <MenubarContent>
32
+ <MenubarSub>
33
+ <MenubarItem onClick={() => { setShowSettings(SettingsCategory.ASSISTANT) }}>Show advanced settings</MenubarItem>
34
+ <MenubarSeparator />
35
+ <AssistantModelList provider={assistantProvider} current={assistantModel} setter={setAssistantModel} />
36
+ <ProviderList providers={availableComputeProvidersForAssistant} current={assistantProvider} setter={setAssistantProvider} />
37
+ <MenubarSeparator />
38
+ <MenubarItem
39
+ disabled
40
+ >Usage and costs: not implemented</MenubarItem>
41
+ </MenubarSub>
42
+ </MenubarContent>
43
+ </MenubarMenu>
44
+ )
45
+ }
src/components/toolbars/top-menu/index.tsx CHANGED
@@ -7,6 +7,7 @@ import { TopMenuVideo } from "./video"
7
  import { TopMenuVoice } from "./voice"
8
  import { TopMenuSound } from "./sound"
9
  import { TopMenuMusic } from "./music"
 
10
 
11
  import { TopMenuView } from "./view"
12
  import { cn } from "@aitube/timeline"
@@ -30,6 +31,7 @@ export function TopMenu() {
30
  <TopMenuVoice />
31
  <TopMenuSound />
32
  <TopMenuMusic />
 
33
  <TopMenuView />
34
  <div className={cn(`
35
  flex flex-row flex-grow
 
7
  import { TopMenuVoice } from "./voice"
8
  import { TopMenuSound } from "./sound"
9
  import { TopMenuMusic } from "./music"
10
+ import { TopMenuAssistant } from "./assistant"
11
 
12
  import { TopMenuView } from "./view"
13
  import { cn } from "@aitube/timeline"
 
31
  <TopMenuVoice />
32
  <TopMenuSound />
33
  <TopMenuMusic />
34
+ <TopMenuAssistant />
35
  <TopMenuView />
36
  <div className={cn(`
37
  flex flex-row flex-grow
src/components/toolbars/top-menu/lists/AssistantModelList.tsx ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import {
4
+ MenubarCheckboxItem,
5
+ MenubarContent,
6
+ MenubarItem,
7
+ MenubarMenu,
8
+ MenubarSeparator,
9
+ MenubarSub,
10
+ MenubarSubContent,
11
+ MenubarSubTrigger,
12
+ } from "@/components/ui/menubar"
13
+
14
+ import { TagColor } from "@/components/tags/types"
15
+ import { Tag } from "@/components/tags/Tag"
16
+ import { ComputeProvider } from "@/types"
17
+ import { availableModelsForAssistant } from "@/components/settings/constants"
18
+
19
+ export function AssistantModelList({
20
+ provider,
21
+ current,
22
+ setter,
23
+ }: {
24
+ provider?: ComputeProvider
25
+ current?: string
26
+ setter: (model: string) => void
27
+ }) {
28
+ const models: string[] = provider ? (availableModelsForAssistant[provider] || []) : []
29
+
30
+ if (models.length === 0) { return null }
31
+
32
+ return (
33
+ <MenubarSub>
34
+ <MenubarSubTrigger>
35
+ <Tag size="lg" color={TagColor.GREEN}>ai&nbsp;assistant</Tag>
36
+ {current || "None"}
37
+ </MenubarSubTrigger>
38
+ <MenubarSubContent>
39
+ {models.map(model => (
40
+ <MenubarCheckboxItem
41
+ key={model}
42
+ checked={current === model}
43
+ onClick={(e) => {
44
+ setter(model)
45
+ e.stopPropagation()
46
+ e.preventDefault()
47
+ return false
48
+ }}>
49
+ {model}
50
+ </MenubarCheckboxItem>
51
+ ))}
52
+ </MenubarSubContent>
53
+ </MenubarSub>
54
+ )
55
+ }
src/components/toolbars/top-menu/music/index.tsx CHANGED
@@ -18,13 +18,17 @@ import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForMusic } from "@/components/settings/constants"
20
  import { SettingsCategory } from "@/types"
 
21
 
22
  export function TopMenuMusic() {
23
  const setShowSettings = useUI(s => s.setShowSettings)
24
  const musicProvider = useSettings(s => s.musicProvider)
25
  const setMusicProvider = useSettings(s => s.setMusicProvider)
 
 
26
  const musicRenderingStrategy = useSettings((s) => s.musicRenderingStrategy)
27
  const setMusicRenderingStrategy = useSettings((s) => s.setMusicRenderingStrategy)
 
28
  return (
29
  <MenubarMenu>
30
  <MenubarTrigger>Music</MenubarTrigger>
@@ -32,6 +36,7 @@ export function TopMenuMusic() {
32
  <MenubarSub>
33
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.MUSIC) }}>Show advanced settings</MenubarItem>
34
  <MenubarSeparator />
 
35
  <ProviderList providers={availableComputeProvidersForMusic} current={musicProvider} setter={setMusicProvider} />
36
  <RenderingStrategyList current={musicRenderingStrategy} setter={setMusicRenderingStrategy} />
37
  <MenubarSeparator />
 
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForMusic } from "@/components/settings/constants"
20
  import { SettingsCategory } from "@/types"
21
+ import { MusicGenerationModelList } from "../lists/MusicGenerationModelList"
22
 
23
  export function TopMenuMusic() {
24
  const setShowSettings = useUI(s => s.setShowSettings)
25
  const musicProvider = useSettings(s => s.musicProvider)
26
  const setMusicProvider = useSettings(s => s.setMusicProvider)
27
+ const musicGenerationModel = useSettings(s => s.musicGenerationModel)
28
+ const setMusicGenerationModel = useSettings(s => s.setMusicGenerationModel)
29
  const musicRenderingStrategy = useSettings((s) => s.musicRenderingStrategy)
30
  const setMusicRenderingStrategy = useSettings((s) => s.setMusicRenderingStrategy)
31
+
32
  return (
33
  <MenubarMenu>
34
  <MenubarTrigger>Music</MenubarTrigger>
 
36
  <MenubarSub>
37
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.MUSIC) }}>Show advanced settings</MenubarItem>
38
  <MenubarSeparator />
39
+ <MusicGenerationModelList provider={musicProvider} current={musicGenerationModel} setter={setMusicGenerationModel} />
40
  <ProviderList providers={availableComputeProvidersForMusic} current={musicProvider} setter={setMusicProvider} />
41
  <RenderingStrategyList current={musicRenderingStrategy} setter={setMusicRenderingStrategy} />
42
  <MenubarSeparator />
src/components/toolbars/top-menu/sound/index.tsx CHANGED
@@ -18,11 +18,14 @@ import { ProviderList } from "../lists/ProviderList"
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForSound } from "@/components/settings/constants"
20
  import { SettingsCategory } from "@/types"
 
21
 
22
  export function TopMenuSound() {
23
  const setShowSettings = useUI(s => s.setShowSettings)
24
  const soundProvider = useSettings(s => s.soundProvider)
25
  const setSoundProvider = useSettings(s => s.setSoundProvider)
 
 
26
  const soundRenderingStrategy = useSettings((s) => s.soundRenderingStrategy)
27
  const setSoundRenderingStrategy = useSettings((s) => s.setSoundRenderingStrategy)
28
  return (
@@ -32,6 +35,7 @@ export function TopMenuSound() {
32
  <MenubarSub>
33
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.SOUND) }}>Show advanced settings</MenubarItem>
34
  <MenubarSeparator />
 
35
  <ProviderList providers={availableComputeProvidersForSound} current={soundProvider} setter={setSoundProvider} />
36
  <RenderingStrategyList current={soundRenderingStrategy} setter={setSoundRenderingStrategy} />
37
  <MenubarSeparator />
 
18
  import { RenderingStrategyList } from "../lists/RenderingStrategyList"
19
  import { availableComputeProvidersForSound } from "@/components/settings/constants"
20
  import { SettingsCategory } from "@/types"
21
+ import { SoundGenerationModelList } from "../lists/SoundGenerationModelList"
22
 
23
  export function TopMenuSound() {
24
  const setShowSettings = useUI(s => s.setShowSettings)
25
  const soundProvider = useSettings(s => s.soundProvider)
26
  const setSoundProvider = useSettings(s => s.setSoundProvider)
27
+ const soundGenerationModel = useSettings(s => s.soundGenerationModel)
28
+ const setSoundGenerationModel = useSettings(s => s.setSoundGenerationModel)
29
  const soundRenderingStrategy = useSettings((s) => s.soundRenderingStrategy)
30
  const setSoundRenderingStrategy = useSettings((s) => s.setSoundRenderingStrategy)
31
  return (
 
35
  <MenubarSub>
36
  <MenubarItem onClick={() => { setShowSettings(SettingsCategory.SOUND) }}>Show advanced settings</MenubarItem>
37
  <MenubarSeparator />
38
+ <SoundGenerationModelList provider={soundProvider} current={soundGenerationModel} setter={setSoundGenerationModel} />
39
  <ProviderList providers={availableComputeProvidersForSound} current={soundProvider} setter={setSoundProvider} />
40
  <RenderingStrategyList current={soundRenderingStrategy} setter={setSoundRenderingStrategy} />
41
  <MenubarSeparator />
src/components/toolbars/top-menu/view/index.tsx CHANGED
@@ -77,6 +77,7 @@ export function TopMenuView() {
77
  return false
78
  }}
79
  >Show asset explorer</MenubarCheckboxItem>
 
80
  <MenubarCheckboxItem
81
  checked={showChat}
82
  onClick={(e) => {
@@ -86,6 +87,7 @@ export function TopMenuView() {
86
  return false
87
  }}
88
  >Show chat assistant</MenubarCheckboxItem>
 
89
  <MenubarCheckboxItem
90
  checked={showVideoPlayer}
91
  onClick={(e) => {
 
77
  return false
78
  }}
79
  >Show asset explorer</MenubarCheckboxItem>
80
+ */}
81
  <MenubarCheckboxItem
82
  checked={showChat}
83
  onClick={(e) => {
 
87
  return false
88
  }}
89
  >Show chat assistant</MenubarCheckboxItem>
90
+ {/*
91
  <MenubarCheckboxItem
92
  checked={showVideoPlayer}
93
  onClick={(e) => {
src/controllers/assistant/askAssistant.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { AssistantRequest, AssistantResponse } from "@/types"
2
+
3
+ export async function askAssistant(request: AssistantRequest) {
4
+ const res = await fetch("/api/assistant", {
5
+ method: "POST",
6
+ headers: {
7
+ "Content-Type": "application/json",
8
+ },
9
+ body: JSON.stringify(request)
10
+ })
11
+
12
+ const response = (await res.json()) as AssistantResponse
13
+ return response
14
+ }
src/controllers/assistant/types.ts CHANGED
@@ -34,12 +34,13 @@ export type AssistantState = {
34
  socket?: WebSocket
35
  }
36
  export type AssistantControls = {
 
37
  /**
38
  * Toggle the speech to text on or off
39
  *
40
  * @returns true if operation succeeded, false otherwise
41
  */
42
- toggleVoice: () => Promise<boolean>
43
 
44
  /**
45
  * Run a prompt command (which can come from a transcript or somewhere else)
@@ -59,6 +60,8 @@ export type AssistantControls = {
59
  addEventToHistory: (event: Partial<ChatEvent>) => ChatEvent
60
 
61
  clearHistory: () => void
 
 
62
  }
63
 
64
  export type AssistantStore =
 
34
  socket?: WebSocket
35
  }
36
  export type AssistantControls = {
37
+
38
  /**
39
  * Toggle the speech to text on or off
40
  *
41
  * @returns true if operation succeeded, false otherwise
42
  */
43
+ // toggleVoice: () => Promise<boolean>
44
 
45
  /**
46
  * Run a prompt command (which can come from a transcript or somewhere else)
 
60
  addEventToHistory: (event: Partial<ChatEvent>) => ChatEvent
61
 
62
  clearHistory: () => void
63
+
64
+ processMessage: (input: string) => void
65
  }
66
 
67
  export type AssistantStore =
src/controllers/assistant/useAssistant.ts CHANGED
@@ -1,10 +1,14 @@
1
  "use client"
2
 
3
  import { create } from "zustand"
4
- import { UUID } from "@aitube/clap"
5
 
6
  import { AssistantStore, ChatEvent } from "./types"
7
  import { getDefaultAssistantState } from "./getDefaultAssistantState"
 
 
 
 
8
 
9
  // URL to the speech to text websocket server
10
  export const STT_API_URL = process.env.NEXT_PUBLIC_SPEECH_TO_TEXT_API_URL || ""
@@ -13,6 +17,7 @@ const enableTextToSpeech = false
13
 
14
  export const useAssistant = create<AssistantStore>((set, get) => ({
15
  ...getDefaultAssistantState(),
 
16
  toggleVoice: async (): Promise<boolean> => {
17
 
18
  if (!navigator?.mediaDevices?.getUserMedia || !MediaRecorder.isTypeSupported("audio/webm")) {
@@ -89,6 +94,7 @@ export const useAssistant = create<AssistantStore>((set, get) => ({
89
 
90
  return true
91
  },
 
92
 
93
  runCommand: (prompt: string) => {
94
 
@@ -135,6 +141,154 @@ export const useAssistant = create<AssistantStore>((set, get) => ({
135
 
136
  clearHistory: () => {
137
  set({ history: [] })
138
- }
139
- }))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  "use client"
2
 
3
  import { create } from "zustand"
4
+ import { ClapOutputType, ClapProject, ClapSegment, ClapSegmentCategory, newSegment, UUID } from "@aitube/clap"
5
 
6
  import { AssistantStore, ChatEvent } from "./types"
7
  import { getDefaultAssistantState } from "./getDefaultAssistantState"
8
+ import { DEFAULT_DURATION_IN_MS_PER_STEP, findFreeTrack, TimelineStore, useTimeline } from "@aitube/timeline"
9
+ import { useSettings } from "../settings"
10
+ import { AssistantRequest } from "@/types"
11
+ import { askAssistant } from "./askAssistant"
12
 
13
  // URL to the speech to text websocket server
14
  export const STT_API_URL = process.env.NEXT_PUBLIC_SPEECH_TO_TEXT_API_URL || ""
 
17
 
18
  export const useAssistant = create<AssistantStore>((set, get) => ({
19
  ...getDefaultAssistantState(),
20
+ /*
21
  toggleVoice: async (): Promise<boolean> => {
22
 
23
  if (!navigator?.mediaDevices?.getUserMedia || !MediaRecorder.isTypeSupported("audio/webm")) {
 
94
 
95
  return true
96
  },
97
+ */
98
 
99
  runCommand: (prompt: string) => {
100
 
 
141
 
142
  clearHistory: () => {
143
  set({ history: [] })
144
+ },
145
+
146
+ processMessage: async (input: string) => {
147
+ const message = input.trim()
148
+ if (!message) {
149
+ return
150
+ }
151
+ const { addEventToHistory, runCommand } = get()
152
+
153
+ const timelineState: TimelineStore = useTimeline.getState()
154
+ const { clap } = timelineState
155
+ if (!clap) { return }
156
+
157
+ // note: settings is not the store (with methods etc)
158
+ // but a serializable snapshot of the values only
159
+ const settings = useSettings.getState().getSettings()
160
+
161
+ addEventToHistory({
162
+ senderId: "director",
163
+ senderName: "Director",
164
+ message,
165
+ })
166
+
167
+
168
+ const basicCommand = await runCommand(message)
169
+ // LLM analysis can be slow and expensive, so first we try to see if this was a trivial command
170
+ // like "start", "pause", "stop" etc
171
+ if (basicCommand) {
172
+
173
+ addEventToHistory({
174
+ senderId: "assistant",
175
+ senderName: "Assistant",
176
+ message: `${basicCommand}`,
177
+ })
178
+ return // no need to go further
179
+ }
180
+
181
+ console.log(`TODO @julian: restore the concept of "addSegment()", "updateSegment()", "active segment" and "cursor position" inside @aitube-timeline`)
182
+ // const { addSegment, activeSegments, cursorInSteps, } = useTimeline.getState()
183
+
184
+ const activeSegments: ClapSegment[] = []
185
+ const cursorInSteps = 0
186
+
187
+ const referenceSegment: ClapSegment | undefined = activeSegments.at(0)
188
+
189
+ if (!referenceSegment) {
190
+ throw new Error(`No segment under the current cursor`)
191
+ }
192
+
193
+ console.log(`TODO @julian: filter entities to only keep the ones in the current active segment? (although.. maybe a bad idea since the LLM need as much context as possible to "fill in the gap" eg. repair/invent missing elements of the story)`)
194
+
195
+ const entities = clap.entityIndex
196
 
197
+ const projectInfo = clap.meta.description
198
+
199
+ const sceneId = referenceSegment.sceneId
200
+
201
+ const scene = clap.scenes.find(s => s.id === sceneId)
202
+
203
+ const fullScene: string = scene?.sequenceFullText || ""
204
+ const actionLine: string = scene?.line || ""
205
+
206
+ const segments: ClapSegment[] = activeSegments
207
+ .filter(s =>
208
+ s.category === ClapSegmentCategory.LOCATION ||
209
+ s.category === ClapSegmentCategory.TIME ||
210
+ s.category === ClapSegmentCategory.LIGHTING ||
211
+ s.category === ClapSegmentCategory.ACTION ||
212
+ s.category === ClapSegmentCategory.DIALOGUE ||
213
+ s.category === ClapSegmentCategory.WEATHER
214
+ )
215
+
216
+ console.log(`TODO @julian: provide both contextual segments and editable ones to the LLM?`)
217
+
218
+ const request: AssistantRequest = {
219
+ settings,
220
+ prompt: message,
221
+ segments,
222
+ fullScene,
223
+ actionLine,
224
+ entities,
225
+ projectInfo,
226
+ }
227
+
228
+ const { prompt, categoryName, llmOutput } = await askAssistant(request)
229
+ if (!prompt.length) {
230
+ addEventToHistory({
231
+ senderId: "assistant",
232
+ senderName: "Assistant",
233
+ message: llmOutput || "🤔" // or "???" for a "boomer" theme
234
+ })
235
+ return
236
+ }
237
+
238
+ let match = segments.find(s => s.category === categoryName) || undefined
239
+ if (!match) {
240
+
241
+ const startTimeInMs = cursorInSteps * DEFAULT_DURATION_IN_MS_PER_STEP
242
+ const durationInSteps = 4
243
+ const durationInMs = durationInSteps * DEFAULT_DURATION_IN_MS_PER_STEP
244
+ const endTimeInMs = startTimeInMs + durationInMs
245
+
246
+ const newSeg = newSegment({
247
+ startTimeInSteps: cursorInSteps,
248
+ prompt: [prompt],
249
+ durationInSteps: 4,
250
+ trackId: findFreeTrack({
251
+ segments,
252
+ startTimeInMs,
253
+ endTimeInMs,
254
+ }),
255
+ outputType: ClapOutputType.TEXT,
256
+ categoryName,
257
+ })
258
+ console.log("Creating new existing segment:", newSeg)
259
+
260
+ console.log(`TODO Julian: add the segment!!`)
261
+ // addSegment(newSeg)
262
+
263
+ addEventToHistory({
264
+ senderId: "assistant",
265
+ senderName: "Assistant",
266
+ message: `Segment added: ${newSeg.prompt}`,
267
+ })
268
+ } else {
269
+
270
+ console.log("Updating an existing segment to:", {
271
+ ...match,
272
+ prompt,
273
+ label: prompt,
274
+ })
275
+
276
+ console.log(`TODO Julian: update the segment!!`)
277
+ // addSegment(newSeg)
278
+
279
+ /*
280
+ updateSegment({
281
+ ...match,
282
+ prompt,
283
+ label: prompt,
284
+ })
285
+ */
286
+
287
+ addEventToHistory({
288
+ senderId: "assistant",
289
+ senderName: "Assistant",
290
+ message: `Segment updated: ${prompt}`,
291
+ })
292
+ }
293
+ }
294
+ }))
src/controllers/metrics/constants.ts CHANGED
@@ -43,10 +43,28 @@ export const estimatedMetrics: Record<ComputeProvider, Record<string, ProviderMe
43
  },
44
  [ComputeProvider.STABILITYAI]: {
45
  // TODO list the most popular models
 
 
 
46
  },
47
  [ComputeProvider.GROQ]: {
48
  // TODO list the most popular models
49
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  [ComputeProvider.FALAI]: {
51
  "fal-ai/fast-sdxl": {
52
  estimationType: ProviderMetricsEstimationType.MANUAL_MEASUREMENTS,
 
43
  },
44
  [ComputeProvider.STABILITYAI]: {
45
  // TODO list the most popular models
46
+ },
47
+ [ComputeProvider.FIREWORKSAI]: {
48
+
49
  },
50
  [ComputeProvider.GROQ]: {
51
  // TODO list the most popular models
52
  },
53
+ [ComputeProvider.KITSAI]: {
54
+ // TODO list the most popular models
55
+ },
56
+ [ComputeProvider.ANTHROPIC]: {
57
+ // TODO list the most popular models
58
+ },
59
+ [ComputeProvider.GOOGLE]: {
60
+ // TODO list the most popular models
61
+ },
62
+ [ComputeProvider.MISTRALAI]: {
63
+ // TODO list the most popular models
64
+ },
65
+ [ComputeProvider.COHERE]: {
66
+ // TODO list the most popular models
67
+ },
68
  [ComputeProvider.FALAI]: {
69
  "fal-ai/fast-sdxl": {
70
  estimationType: ProviderMetricsEstimationType.MANUAL_MEASUREMENTS,
src/controllers/metrics/getDefaultMetricsPerProvider.ts CHANGED
@@ -35,6 +35,9 @@ export function getDefaultMetricsPerProvider(): MetricsPerProvider {
35
  [ComputeProvider.STABILITYAI]: {
36
  ...getDefaultComputeProviderMetrics(),
37
  },
 
 
 
38
  [ComputeProvider.GROQ]: {
39
  ...getDefaultComputeProviderMetrics(),
40
  },
@@ -44,6 +47,21 @@ export function getDefaultMetricsPerProvider(): MetricsPerProvider {
44
  [ComputeProvider.MODELSLAB]: {
45
  ...getDefaultComputeProviderMetrics(),
46
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
  return metricsPerProvider
49
  }
 
35
  [ComputeProvider.STABILITYAI]: {
36
  ...getDefaultComputeProviderMetrics(),
37
  },
38
+ [ComputeProvider.FIREWORKSAI]: {
39
+ ...getDefaultComputeProviderMetrics(),
40
+ },
41
  [ComputeProvider.GROQ]: {
42
  ...getDefaultComputeProviderMetrics(),
43
  },
 
47
  [ComputeProvider.MODELSLAB]: {
48
  ...getDefaultComputeProviderMetrics(),
49
  },
50
+ [ComputeProvider.KITSAI]: {
51
+ ...getDefaultComputeProviderMetrics(),
52
+ },
53
+ [ComputeProvider.ANTHROPIC]: {
54
+ ...getDefaultComputeProviderMetrics(),
55
+ },
56
+ [ComputeProvider.GOOGLE]: {
57
+ ...getDefaultComputeProviderMetrics(),
58
+ },
59
+ [ComputeProvider.MISTRALAI]: {
60
+ ...getDefaultComputeProviderMetrics(),
61
+ },
62
+ [ComputeProvider.COHERE]: {
63
+ ...getDefaultComputeProviderMetrics(),
64
+ },
65
  }
66
  return metricsPerProvider
67
  }
src/controllers/metrics/useMetrics.ts CHANGED
@@ -8,5 +8,5 @@ import { getDefaultMetricsState } from "./getDefaultMetricsState"
8
  export const useMetrics = create<MetricsStore>((set, get) => ({
9
  ...getDefaultMetricsState(),
10
 
11
-
12
  }))
 
8
  export const useMetrics = create<MetricsStore>((set, get) => ({
9
  ...getDefaultMetricsState(),
10
 
11
+ // TODO: add a track metric callback
12
  }))
src/controllers/resolver/useResolver.ts CHANGED
@@ -91,8 +91,8 @@ export const useResolver = create<ResolverStore>((set, get) => ({
91
  // segments visible on screen are show first,
92
  // then those nearby, then the hidden ones
93
  const segments: RuntimeSegment[] = ([...allSegments] as RuntimeSegment[]).sort((segment1, segment2) => {
94
- const priority1 = SegmentVisibilityPriority[segment1.visibility || SegmentVisibility.HIDDEN] || 0
95
- const priority2 = SegmentVisibilityPriority[segment2.visibility || SegmentVisibility.HIDDEN] || 0
96
 
97
  return priority2 - priority1
98
  })
@@ -278,7 +278,7 @@ export const useResolver = create<ResolverStore>((set, get) => ({
278
  // throw new Error(`please call setSegmentRender(...) first`)
279
  }
280
 
281
- const shotSegments = filterSegments(
282
  ClapSegmentFilteringMode.ANY,
283
  segment,
284
  allSegments
 
91
  // segments visible on screen are show first,
92
  // then those nearby, then the hidden ones
93
  const segments: RuntimeSegment[] = ([...allSegments] as RuntimeSegment[]).sort((segment1, segment2) => {
94
+ const priority1 = (SegmentVisibilityPriority as any)[segment1.visibility || SegmentVisibility.HIDDEN] || 0
95
+ const priority2 = (SegmentVisibilityPriority as any)[segment2.visibility || SegmentVisibility.HIDDEN] || 0
96
 
97
  return priority2 - priority1
98
  })
 
278
  // throw new Error(`please call setSegmentRender(...) first`)
279
  }
280
 
281
+ const shotSegments: ClapSegment[] = filterSegments(
282
  ClapSegmentFilteringMode.ANY,
283
  segment,
284
  allSegments
src/controllers/settings/getDefaultSettingsState.ts CHANGED
@@ -20,6 +20,10 @@ export function getDefaultSettingsState(): SettingsState {
20
  groqApiKey: "",
21
  anthropicApiKey: "",
22
  elevenLabsApiKey: "",
 
 
 
 
23
 
24
  assistantProvider: ComputeProvider.NONE,
25
  imageProvider: ComputeProvider.NONE,
@@ -93,6 +97,13 @@ export function getDefaultSettingsState(): SettingsState {
93
  stabilityAiModelForSound: "",
94
  stabilityAiModelForMusic: "",
95
 
 
 
 
 
 
 
 
96
  falAiModelForImage: "fal-ai/fast-sdxl", // "fal-ai/fast-lightning-sdxl",
97
  falAiModelForVideo: "fal-ai/stable-video",
98
  falAiModelForVoice: "fal-ai/metavoice-v1",
@@ -122,6 +133,10 @@ export function getDefaultSettingsState(): SettingsState {
122
 
123
  elevenLabsModelForVoice: "v1",
124
  elevenLabsModelForSound: "v1",
 
 
 
 
125
  }
126
  return state
127
  }
 
20
  groqApiKey: "",
21
  anthropicApiKey: "",
22
  elevenLabsApiKey: "",
23
+ kitsAiApiKey: "",
24
+ cohereApiKey: "",
25
+ mistralAiApiKey: "",
26
+ fireworksAiApiKey: "",
27
 
28
  assistantProvider: ComputeProvider.NONE,
29
  imageProvider: ComputeProvider.NONE,
 
97
  stabilityAiModelForSound: "",
98
  stabilityAiModelForMusic: "",
99
 
100
+ fireworksAiModelForAssistant: "",
101
+ fireworksAiModelForImage: "",
102
+ fireworksAiModelForVideo: "",
103
+ fireworksAiModelForVoice: "",
104
+ fireworksAiModelForSound: "",
105
+ fireworksAiModelForMusic: "",
106
+
107
  falAiModelForImage: "fal-ai/fast-sdxl", // "fal-ai/fast-lightning-sdxl",
108
  falAiModelForVideo: "fal-ai/stable-video",
109
  falAiModelForVoice: "fal-ai/metavoice-v1",
 
133
 
134
  elevenLabsModelForVoice: "v1",
135
  elevenLabsModelForSound: "v1",
136
+
137
+ kitsAiModelForVoice: "",
138
+ cohereModelForAssistant: "",
139
+ mistralAiModelForAssistant: ""
140
  }
141
  return state
142
  }
src/controllers/settings/types.ts CHANGED
@@ -15,6 +15,10 @@ export type SettingsState = {
15
  groqApiKey: string
16
  anthropicApiKey: string
17
  elevenLabsApiKey: string
 
 
 
 
18
 
19
  // ------------- CATEGORY PROVIDERS ---------------
20
  assistantProvider: ComputeProvider
@@ -92,6 +96,13 @@ export type SettingsState = {
92
  stabilityAiModelForSound: string
93
  stabilityAiModelForMusic: string
94
 
 
 
 
 
 
 
 
95
  falAiModelForImage: string
96
  falAiModelForVideo: string
97
  falAiModelForVoice: string
@@ -121,6 +132,12 @@ export type SettingsState = {
121
 
122
  elevenLabsModelForVoice: string
123
  elevenLabsModelForSound: string
 
 
 
 
 
 
124
  }
125
 
126
  export type SettingsControls = {
@@ -131,12 +148,15 @@ export type SettingsControls = {
131
  setHuggingFaceApiKey: (huggingFaceApiKey?: string) => void
132
  setModelsLabApiKey: (modelsLabApiKey?: string) => void
133
  setFalAiApiKey: (falAiApiKey?: string) => void
134
-
135
  setOpenaiApiKey: (openaiApiKey?: string) => void
136
  setGoogleApiKey: (googleApiKey?: string) => void
137
  setGroqApiKey: (groqApiKey?: string) => void
 
138
  setAnthropicApiKey: (anthropicApiKey?: string) => void
139
  setElevenLabsApiKey: (elevenLabsApiKey?: string) => void
 
 
 
140
 
141
  setAssistantProvider: (assistantProvider?: ComputeProvider) => void
142
  setVideoProvider: (videoProvider?: ComputeProvider) => void
@@ -204,6 +224,13 @@ export type SettingsControls = {
204
  setStabilityAiModelForSound: (stabilityAiModelForSound?: string) => void
205
  setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => void
206
 
 
 
 
 
 
 
 
207
  setFalAiModelForImage: (falAiModelForImage?: string) => void
208
  setFalAiModelForVideo: (falAiModelForVideo?: string) => void
209
  setFalAiModelForVoice: (falAiModelForVoice?: string) => void
@@ -234,6 +261,11 @@ export type SettingsControls = {
234
  setElevenLabsModelForVoice: (elevenLabsModelForVoice?: string) => void
235
  setElevenLabsModelForSound: (elevenLabsModelForSound?: string) => void
236
 
 
 
 
 
 
237
  getSettings: () => SettingsState
238
  }
239
 
 
15
  groqApiKey: string
16
  anthropicApiKey: string
17
  elevenLabsApiKey: string
18
+ kitsAiApiKey: string
19
+ cohereApiKey: string
20
+ mistralAiApiKey: string
21
+ fireworksAiApiKey: string
22
 
23
  // ------------- CATEGORY PROVIDERS ---------------
24
  assistantProvider: ComputeProvider
 
96
  stabilityAiModelForSound: string
97
  stabilityAiModelForMusic: string
98
 
99
+ fireworksAiModelForAssistant: string
100
+ fireworksAiModelForImage: string
101
+ fireworksAiModelForVideo: string
102
+ fireworksAiModelForVoice: string
103
+ fireworksAiModelForSound: string
104
+ fireworksAiModelForMusic: string
105
+
106
  falAiModelForImage: string
107
  falAiModelForVideo: string
108
  falAiModelForVoice: string
 
132
 
133
  elevenLabsModelForVoice: string
134
  elevenLabsModelForSound: string
135
+
136
+ kitsAiModelForVoice: string
137
+
138
+ cohereModelForAssistant: string
139
+
140
+ mistralAiModelForAssistant: string
141
  }
142
 
143
  export type SettingsControls = {
 
148
  setHuggingFaceApiKey: (huggingFaceApiKey?: string) => void
149
  setModelsLabApiKey: (modelsLabApiKey?: string) => void
150
  setFalAiApiKey: (falAiApiKey?: string) => void
 
151
  setOpenaiApiKey: (openaiApiKey?: string) => void
152
  setGoogleApiKey: (googleApiKey?: string) => void
153
  setGroqApiKey: (groqApiKey?: string) => void
154
+ setFireworksAiApiKey: (fireworksAiApiKey?: string) => void
155
  setAnthropicApiKey: (anthropicApiKey?: string) => void
156
  setElevenLabsApiKey: (elevenLabsApiKey?: string) => void
157
+ setCohereApiKey: (cohereApiKey?: string) => void
158
+ setMistralAiApiKey: (mistralAiApiKey?: string) => void
159
+ setKitsAiApiKey: (kitsAiApiKey?: string) => void
160
 
161
  setAssistantProvider: (assistantProvider?: ComputeProvider) => void
162
  setVideoProvider: (videoProvider?: ComputeProvider) => void
 
224
  setStabilityAiModelForSound: (stabilityAiModelForSound?: string) => void
225
  setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => void
226
 
227
+ setFireworksAiModelForAssistant: (fireworksAiModelForAssistant?: string) => void
228
+ setFireworksAiModelForImage: (fireworksAiModelForImage?: string) => void
229
+ setFireworksAiModelForVideo: (fireworksAiModelForVideo?: string) => void
230
+ setFireworksAiModelForVoice: (fireworksAiModelForVoice?: string) => void
231
+ setFireworksAiModelForSound: (fireworksAiModelForSound?: string) => void
232
+ setFireworksAiModelForMusic: (fireworksAiModelForMusic?: string) => void
233
+
234
  setFalAiModelForImage: (falAiModelForImage?: string) => void
235
  setFalAiModelForVideo: (falAiModelForVideo?: string) => void
236
  setFalAiModelForVoice: (falAiModelForVoice?: string) => void
 
261
  setElevenLabsModelForVoice: (elevenLabsModelForVoice?: string) => void
262
  setElevenLabsModelForSound: (elevenLabsModelForSound?: string) => void
263
 
264
+ setCohereModelForAssistant: (cohereModelForAssistant?: string) => void
265
+ setMistralAiModelForAssistant: (mistralAiModelForAssistant?: string) => void
266
+
267
+ setKitsAiModelForVoice: (kitsAiModelForVoice?: string) => void
268
+
269
  getSettings: () => SettingsState
270
  }
271
 
src/controllers/settings/useSettings.ts CHANGED
@@ -84,6 +84,18 @@ export const useSettings = create<SettingsStore>()(
84
  setElevenLabsApiKey: (elevenLabsApiKey?: string) => {
85
  set({ elevenLabsApiKey: getValidString(elevenLabsApiKey, getDefaultSettingsState().elevenLabsApiKey) })
86
  },
 
 
 
 
 
 
 
 
 
 
 
 
87
  setCensorNotForAllAudiencesContent: (censorNotForAllAudiencesContent?: boolean) => {
88
  set({ censorNotForAllAudiencesContent: getValidBoolean(censorNotForAllAudiencesContent, getDefaultSettingsState().censorNotForAllAudiencesContent) })
89
  },
@@ -269,6 +281,24 @@ export const useSettings = create<SettingsStore>()(
269
  setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => {
270
  set({ stabilityAiModelForMusic: getValidString(stabilityAiModelForMusic, getDefaultSettingsState().stabilityAiModelForMusic) })
271
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  setFalAiModelForImage: (falAiModelForImage?: string) => {
273
  set({ falAiModelForImage: getValidString(falAiModelForImage, getDefaultSettingsState().falAiModelForImage) })
274
  },
@@ -338,6 +368,15 @@ export const useSettings = create<SettingsStore>()(
338
  setElevenLabsModelForSound: (elevenLabsModelForSound?: string) => {
339
  set({ elevenLabsModelForSound: getValidString(elevenLabsModelForSound, getDefaultSettingsState().elevenLabsModelForSound) })
340
  },
 
 
 
 
 
 
 
 
 
341
  getSettings: (): SettingsState => {
342
  const state = get()
343
  const defaultSettings = getDefaultSettingsState()
@@ -362,6 +401,10 @@ export const useSettings = create<SettingsStore>()(
362
  googleApiKey: state.googleApiKey || defaultSettings.googleApiKey,
363
  anthropicApiKey: state.anthropicApiKey || defaultSettings.anthropicApiKey,
364
  elevenLabsApiKey: state.elevenLabsApiKey || defaultSettings.elevenLabsApiKey,
 
 
 
 
365
  censorNotForAllAudiencesContent: state.censorNotForAllAudiencesContent || defaultSettings.censorNotForAllAudiencesContent,
366
  imagePromptPrefix: state.imagePromptPrefix || defaultSettings.imagePromptPrefix,
367
  imagePromptSuffix: state.imagePromptSuffix || defaultSettings.imagePromptSuffix,
@@ -415,6 +458,12 @@ export const useSettings = create<SettingsStore>()(
415
  stabilityAiModelForVoice: state.stabilityAiModelForVoice || defaultSettings.stabilityAiModelForVoice,
416
  stabilityAiModelForSound: state.stabilityAiModelForSound || defaultSettings.stabilityAiModelForSound,
417
  stabilityAiModelForMusic: state.stabilityAiModelForMusic || defaultSettings.stabilityAiModelForMusic,
 
 
 
 
 
 
418
  falAiModelForImage: state.falAiModelForImage || defaultSettings.falAiModelForImage,
419
  falAiModelForVideo: state.falAiModelForVideo || defaultSettings.falAiModelForVideo,
420
  falAiModelForVoice: state.falAiModelForVoice || defaultSettings.falAiModelForVoice,
@@ -438,6 +487,9 @@ export const useSettings = create<SettingsStore>()(
438
  anthropicModelForAssistant: state.anthropicModelForAssistant || defaultSettings.anthropicModelForAssistant,
439
  elevenLabsModelForVoice: state.elevenLabsModelForVoice || defaultSettings.elevenLabsModelForVoice,
440
  elevenLabsModelForSound: state.elevenLabsModelForSound || defaultSettings.elevenLabsModelForSound,
 
 
 
441
  }
442
  },
443
  }),
 
84
  setElevenLabsApiKey: (elevenLabsApiKey?: string) => {
85
  set({ elevenLabsApiKey: getValidString(elevenLabsApiKey, getDefaultSettingsState().elevenLabsApiKey) })
86
  },
87
+ setKitsAiApiKey: (kitsAiApiKey?: string) => {
88
+ set({ kitsAiApiKey: getValidString(kitsAiApiKey, getDefaultSettingsState().kitsAiApiKey) })
89
+ },
90
+ setCohereApiKey: (cohereApiKey?: string) => {
91
+ set({ cohereApiKey: getValidString(cohereApiKey, getDefaultSettingsState().cohereApiKey) })
92
+ },
93
+ setMistralAiApiKey: (mistralAiApiKey?: string) => {
94
+ set({ mistralAiApiKey: getValidString(mistralAiApiKey, getDefaultSettingsState().mistralAiApiKey) })
95
+ },
96
+ setFireworksAiApiKey: (fireworksAiApiKey?: string) => {
97
+ set({ fireworksAiApiKey: getValidString(fireworksAiApiKey, getDefaultSettingsState().fireworksAiApiKey) })
98
+ },
99
  setCensorNotForAllAudiencesContent: (censorNotForAllAudiencesContent?: boolean) => {
100
  set({ censorNotForAllAudiencesContent: getValidBoolean(censorNotForAllAudiencesContent, getDefaultSettingsState().censorNotForAllAudiencesContent) })
101
  },
 
281
  setStabilityAiModelForMusic: (stabilityAiModelForMusic?: string) => {
282
  set({ stabilityAiModelForMusic: getValidString(stabilityAiModelForMusic, getDefaultSettingsState().stabilityAiModelForMusic) })
283
  },
284
+ setFireworksAiModelForAssistant: (fireworksAiModelForAssistant?: string) => {
285
+ set({ fireworksAiModelForAssistant: getValidString(fireworksAiModelForAssistant, getDefaultSettingsState().fireworksAiModelForAssistant) })
286
+ },
287
+ setFireworksAiModelForImage: (fireworksAiModelForImage?: string) => {
288
+ set({ fireworksAiModelForImage: getValidString(fireworksAiModelForImage, getDefaultSettingsState().fireworksAiModelForImage) })
289
+ },
290
+ setFireworksAiModelForVideo: (fireworksAiModelForVideo?: string) => {
291
+ set({ fireworksAiModelForVideo: getValidString(fireworksAiModelForVideo, getDefaultSettingsState().fireworksAiModelForVideo) })
292
+ },
293
+ setFireworksAiModelForVoice: (fireworksAiModelForVoice?: string) => {
294
+ set({ fireworksAiModelForVoice: getValidString(fireworksAiModelForVoice, getDefaultSettingsState().fireworksAiModelForVoice) })
295
+ },
296
+ setFireworksAiModelForSound: (fireworksAiModelForSound?: string) => {
297
+ set({ fireworksAiModelForSound: getValidString(fireworksAiModelForSound, getDefaultSettingsState().fireworksAiModelForSound) })
298
+ },
299
+ setFireworksAiModelForMusic: (fireworksAiModelForMusic?: string) => {
300
+ set({ fireworksAiModelForMusic: getValidString(fireworksAiModelForMusic, getDefaultSettingsState().fireworksAiModelForMusic) })
301
+ },
302
  setFalAiModelForImage: (falAiModelForImage?: string) => {
303
  set({ falAiModelForImage: getValidString(falAiModelForImage, getDefaultSettingsState().falAiModelForImage) })
304
  },
 
368
  setElevenLabsModelForSound: (elevenLabsModelForSound?: string) => {
369
  set({ elevenLabsModelForSound: getValidString(elevenLabsModelForSound, getDefaultSettingsState().elevenLabsModelForSound) })
370
  },
371
+ setCohereModelForAssistant: (cohereModelForAssistant?: string) => {
372
+ set({ cohereModelForAssistant: getValidString(cohereModelForAssistant, getDefaultSettingsState().cohereModelForAssistant) })
373
+ },
374
+ setMistralAiModelForAssistant: (mistralAiModelForAssistant?: string) => {
375
+ set({ mistralAiModelForAssistant: getValidString(mistralAiModelForAssistant, getDefaultSettingsState().mistralAiModelForAssistant) })
376
+ },
377
+ setKitsAiModelForVoice: (kitsAiModelForVoice?: string) => {
378
+ set({ kitsAiModelForVoice: getValidString(kitsAiModelForVoice, getDefaultSettingsState().kitsAiModelForVoice) })
379
+ },
380
  getSettings: (): SettingsState => {
381
  const state = get()
382
  const defaultSettings = getDefaultSettingsState()
 
401
  googleApiKey: state.googleApiKey || defaultSettings.googleApiKey,
402
  anthropicApiKey: state.anthropicApiKey || defaultSettings.anthropicApiKey,
403
  elevenLabsApiKey: state.elevenLabsApiKey || defaultSettings.elevenLabsApiKey,
404
+ cohereApiKey: state.cohereApiKey || defaultSettings.cohereApiKey,
405
+ mistralAiApiKey: state.mistralAiApiKey || defaultSettings.mistralAiApiKey,
406
+ kitsAiApiKey: state.kitsAiApiKey || defaultSettings.kitsAiApiKey,
407
+ fireworksAiApiKey: state.fireworksAiApiKey || defaultSettings.fireworksAiApiKey,
408
  censorNotForAllAudiencesContent: state.censorNotForAllAudiencesContent || defaultSettings.censorNotForAllAudiencesContent,
409
  imagePromptPrefix: state.imagePromptPrefix || defaultSettings.imagePromptPrefix,
410
  imagePromptSuffix: state.imagePromptSuffix || defaultSettings.imagePromptSuffix,
 
458
  stabilityAiModelForVoice: state.stabilityAiModelForVoice || defaultSettings.stabilityAiModelForVoice,
459
  stabilityAiModelForSound: state.stabilityAiModelForSound || defaultSettings.stabilityAiModelForSound,
460
  stabilityAiModelForMusic: state.stabilityAiModelForMusic || defaultSettings.stabilityAiModelForMusic,
461
+ fireworksAiModelForAssistant: state.fireworksAiModelForAssistant || defaultSettings.fireworksAiModelForAssistant,
462
+ fireworksAiModelForImage: state.fireworksAiModelForImage || defaultSettings.fireworksAiModelForImage,
463
+ fireworksAiModelForVideo: state.fireworksAiModelForVideo || defaultSettings.fireworksAiModelForVideo,
464
+ fireworksAiModelForVoice: state.fireworksAiModelForVoice || defaultSettings.fireworksAiModelForVoice,
465
+ fireworksAiModelForSound: state.fireworksAiModelForSound || defaultSettings.fireworksAiModelForSound,
466
+ fireworksAiModelForMusic: state.fireworksAiModelForMusic || defaultSettings.fireworksAiModelForMusic,
467
  falAiModelForImage: state.falAiModelForImage || defaultSettings.falAiModelForImage,
468
  falAiModelForVideo: state.falAiModelForVideo || defaultSettings.falAiModelForVideo,
469
  falAiModelForVoice: state.falAiModelForVoice || defaultSettings.falAiModelForVoice,
 
487
  anthropicModelForAssistant: state.anthropicModelForAssistant || defaultSettings.anthropicModelForAssistant,
488
  elevenLabsModelForVoice: state.elevenLabsModelForVoice || defaultSettings.elevenLabsModelForVoice,
489
  elevenLabsModelForSound: state.elevenLabsModelForSound || defaultSettings.elevenLabsModelForSound,
490
+ cohereModelForAssistant: state.cohereModelForAssistant || defaultSettings.cohereModelForAssistant,
491
+ mistralAiModelForAssistant: state.mistralAiModelForAssistant || defaultSettings.mistralAiModelForAssistant,
492
+ kitsAiModelForVoice: state.kitsAiModelForVoice || defaultSettings.kitsAiModelForVoice,
493
  }
494
  },
495
  }),
src/lib/utils/parseComputeProvider.ts CHANGED
@@ -34,6 +34,9 @@ export function parseComputeProvider(input: any, defaultVendor?: ComputeProvider
34
  else if (unknownString === "stabilityai") {
35
  vendor = ComputeProvider.STABILITYAI
36
  }
 
 
 
37
  else if (unknownString === "groq") {
38
  vendor = ComputeProvider.GROQ
39
  }
 
34
  else if (unknownString === "stabilityai") {
35
  vendor = ComputeProvider.STABILITYAI
36
  }
37
+ else if (unknownString === "fireworksai") {
38
+ vendor = ComputeProvider.FIREWORKSAI
39
+ }
40
  else if (unknownString === "groq") {
41
  vendor = ComputeProvider.GROQ
42
  }
src/types.ts CHANGED
@@ -21,9 +21,15 @@ export enum ComputeProvider {
21
  COMFY_REPLICATE = "COMFY_REPLICATE", // https://replicate.com
22
  COMFY_COMFYICU = "COMFY_COMFYICU", // https://comfy.icu
23
  ELEVENLABS = "ELEVENLABS", // https://elevenlabs.io
 
24
  OPENAI = "OPENAI", // https://openai.com
25
  STABILITYAI = "STABILITYAI", // https://stability.ai
 
26
  GROQ = "GROQ", // https://groq.com
 
 
 
 
27
  FALAI = "FALAI", // https://fal.ai
28
  MODELSLAB = "MODELSLAB", // https://modelslab.com
29
  }
 
21
  COMFY_REPLICATE = "COMFY_REPLICATE", // https://replicate.com
22
  COMFY_COMFYICU = "COMFY_COMFYICU", // https://comfy.icu
23
  ELEVENLABS = "ELEVENLABS", // https://elevenlabs.io
24
+ KITSAI = "KITSAI", // https://kits.ai
25
  OPENAI = "OPENAI", // https://openai.com
26
  STABILITYAI = "STABILITYAI", // https://stability.ai
27
+ FIREWORKSAI = "FIREWORKSAI", // https://fireworks.ai
28
  GROQ = "GROQ", // https://groq.com
29
+ ANTHROPIC = "ANTHROPIC", // https://anthropic.com
30
+ GOOGLE = "GOOGLE", // https://google.com (in case you didn't know)
31
+ MISTRALAI = "MISTRALAI", // https://mistral.ai
32
+ COHERE = "COHERE", // https://cohere.com
33
  FALAI = "FALAI", // https://fal.ai
34
  MODELSLAB = "MODELSLAB", // https://modelslab.com
35
  }