diff --git a/src/lang/en.ts b/src/lang/en.ts
index ff575a56..62e17528 100644
--- a/src/lang/en.ts
+++ b/src/lang/en.ts
@@ -134,7 +134,7 @@ export const languageEnglish = {
legacyTranslation: "If enabled, it will use the old translation method, which preprocess markdown and quotes before translations instead of postprocessing after translations.",
luaHelp: "You can use Lua scripts as a trigger script. you can define onInput, onOutput, onStart functions. onInput is called when user sends a message, onOutput is called when character sends a message, onStart is called when the chat starts. for more information, see the documentation.",
claudeCachingExperimental: "Caching in Claude is experimental feature that can reduce the cost of the model, but it can also increase the cost if you use it without reroll. since this is a experimental feature, it can be unstable and behavior can be changed in the future.",
-
+ urllora: "You can use direct download link of the model file. you can make direct url from google drive like website like https://sites.google.com/site/gdocs2direct/ , or use civitai URL, copy the the AIR (looks like `urn:air:flux1:lora:civitai:180891@776656` or just `civitai:180891@776656`) and paste it.",
},
setup: {
chooseProvider: "Choose AI Provider",
@@ -688,4 +688,5 @@ export const languageEnglish = {
hideApiKeys: "Hide API Keys",
unformatQuotes: "Disable Quote Formatting",
enableDevTools: "Enable Dev Tools",
+ selectFile: "Select File"
}
\ No newline at end of file
diff --git a/src/lib/Setting/Pages/OtherBotSettings.svelte b/src/lib/Setting/Pages/OtherBotSettings.svelte
index 94b665e5..44a542ac 100644
--- a/src/lib/Setting/Pages/OtherBotSettings.svelte
+++ b/src/lib/Setting/Pages/OtherBotSettings.svelte
@@ -76,6 +76,7 @@
Dall-E
Stability API
ComfyUI
+ Fal.ai
{#if $DataBase.sdProvider === 'webui'}
@@ -295,6 +296,34 @@
Timeout (sec)
{/if}
+
+ {#if $DataBase.sdProvider === 'fal'}
+ Fal.ai API Key
+
+
+ Width
+
+ Height
+
+
+ Model
+
+ Flux[Dev]
+ Flux[Dev] with Lora
+ Flux[Pro]
+ Flux[Schnell]
+
+
+ {#if $DataBase.falModel === 'fal-ai/flux-lora'}
+ Lora Model URL
+
+
+ Lora Weight
+
+ {/if}
+
+
+ {/if}
{/if}
diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte
index a35b1b5f..162787cf 100644
--- a/src/lib/SideBars/CharConfig.svelte
+++ b/src/lib/SideBars/CharConfig.svelte
@@ -877,7 +877,7 @@
className="h-10">
{#if currentChar.data.gptSoVitsConfig.ref_audio_data.assetId === '' || currentChar.data.gptSoVitsConfig.ref_audio_data.assetId === undefined}
- Select File
+ {language.selectFile}
{:else}
{currentChar.data.gptSoVitsConfig.ref_audio_data.fileName}
{/if}
diff --git a/src/ts/process/stableDiff.ts b/src/ts/process/stableDiff.ts
index d95e9226..87e4120c 100644
--- a/src/ts/process/stableDiff.ts
+++ b/src/ts/process/stableDiff.ts
@@ -523,5 +523,68 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
return returnSdData
}
+ if(db.sdProvider === 'fal'){
+ const model = db.falModel
+ const token = db.falToken
+
+ let body:{[key:string]:any} = {
+ prompt: genPrompt,
+ enable_safety_checker: false,
+ sync_mode: true,
+ image_size: {
+ "width": db.sdConfig.width,
+ "height": db.sdConfig.height,
+ }
+ }
+
+ if(db.falModel === 'fal-ai/flux-lora'){
+ let loraPath = db.falLora
+ if(loraPath.startsWith('urn:') || loraPath.startsWith('civitai:')){
+ const id = loraPath.split('@').pop()
+ loraPath = `https://civitai.com/api/download/models/${id}?type=Model&format=SafeTensor`
+ }
+ body.loras = [{
+ "path": loraPath,
+ "scale": db.falLoraScale
+ }]
+ }
+
+ if(db.falModel === 'fal-ai/flux-pro'){
+ delete body.enable_safety_checker
+ }
+ console.log(body)
+
+ const res = await globalFetch('https://fal.run/' + model, {
+ headers: {
+ "Authorization": "Key " + token,
+ "Content-Type": "application/json"
+ },
+ method: 'POST',
+ body: body
+ })
+
+ console.log(res)
+
+ if(!res.ok){
+ alertError(JSON.stringify(res.data))
+ return false
+ }
+
+ let image = res.data?.images?.[0]?.url
+ if(!image){
+ alertError(JSON.stringify(res.data))
+ return false
+ }
+
+ if(returnSdData === 'inlay'){
+ return image
+ }
+ else{
+ let charemotions = get(CharEmotion)
+ const emos:[string, string,number][] = [[image, image, Date.now()]]
+ charemotions[currentChar.chaId] = emos
+ CharEmotion.set(charemotions)
+ }
+ }
return ''
}
diff --git a/src/ts/process/tts.ts b/src/ts/process/tts.ts
index 57a4dbfe..18b39caf 100644
--- a/src/ts/process/tts.ts
+++ b/src/ts/process/tts.ts
@@ -267,7 +267,7 @@ export async function sayTTS(character:character,text:string) {
'Content-Type': 'application/json'
},
rawResponse: false,
-
+ plainFetchDeforce: true,
})
console.log(path)
if(path.ok){
diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts
index aefc7686..b277f7bc 100644
--- a/src/ts/storage/database.ts
+++ b/src/ts/storage/database.ts
@@ -432,6 +432,8 @@ export function setDatabase(data:Database){
data.unformatQuotes ??= false
data.ttsAutoSpeech ??= false
data.translatorInputLanguage ??= 'auto'
+ data.falModel ??= 'fal-ai/flux/dev'
+ data.falLoraScale ??= 1
changeLanguage(data.language)
DataBase.set(data)
}
@@ -718,6 +720,11 @@ export interface Database{
hideApiKey: boolean
unformatQuotes: boolean
enableDevTools: boolean
+ falToken: string
+ falModel: string
+ falLora: string
+ falLoraName: string
+ falLoraScale: number
}
export interface customscript{
diff --git a/src/ts/storage/globalApi.ts b/src/ts/storage/globalApi.ts
index 20c37e1c..f06b96e2 100644
--- a/src/ts/storage/globalApi.ts
+++ b/src/ts/storage/globalApi.ts
@@ -577,6 +577,7 @@ const knownHostes = ["localhost","127.0.0.1","0.0.0.0"]
interface GlobalFetchArgs {
plainFetchForce?: boolean;
+ plainFetchDeforce?: boolean;
body?: any;
headers?: { [key: string]: string };
rawResponse?: boolean;
@@ -625,7 +626,7 @@ export async function globalFetch(url: string, arg: GlobalFetchArgs = {}): Promi
if (arg.abortSignal?.aborted) { return { ok: false, data: 'aborted', headers: {} }}
const urlHost = new URL(url).hostname
- const forcePlainFetch = (knownHostes.includes(urlHost) && !isTauri) || db.usePlainFetch || arg.plainFetchForce
+ const forcePlainFetch = ((knownHostes.includes(urlHost) && !isTauri) || db.usePlainFetch || arg.plainFetchForce) && !arg.plainFetchDeforce
if (knownHostes.includes(urlHost) && !isTauri && !isNodeServer){
return { ok: false, headers: {}, data: 'You are trying local request on web version. This is not allowed due to browser security policy. Use the desktop version instead, or use a tunneling service like ngrok and set the CORS to allow all.' }