Skip to content

Commit 05226b5

Browse files
committed
draft
1 parent baf0075 commit 05226b5

17 files changed

+649
-2892
lines changed

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
・Sonnet Haikuをサブエージェントとすることは禁止、サブエージェントは基本的にOpusを使用する。
22
`file://` プロトコルで動作することが必須条件です。
33
・UIの変更は他の表示と調和させる。
4+
・fallbackは禁止。ユーザーを誤認させるので禁止。
45
・文言の追加は他の文言と合わせる。(Plannning、プランニング、企画中のように同じ意味で別々の表記にしない。)
56
・以下のフォルダは検索から除外し読み込まないこと:
67
- json_js

css/layout.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,10 @@ color:var(--text-color-C);
299299
width: var(--width-50);
300300
}
301301
.A1111_api_content,
302-
.Comfyui_api_content {
302+
.Comfyui_api_content,
303+
.RunPod_api_content,
304+
.RunPodEndpoint_api_content,
305+
.FalAI_api_content {
303306
padding: 6px 10px 6px 18px;
304307
}
305308
.es-section-title {
@@ -316,7 +319,8 @@ gap: 4px;
316319
list-style: none;
317320
padding: 2px 0;
318321
}
319-
.es-url-row input {
322+
.es-url-row input,
323+
.es-url-row select {
320324
flex: 1;
321325
font-size: 11px;
322326
padding: 3px 6px;
@@ -326,6 +330,10 @@ background: var(--background-color-B);
326330
color: var(--text-color-B);
327331
min-width: 180px;
328332
}
333+
.es-url-row select:disabled {
334+
opacity: 0.5;
335+
cursor: not-allowed;
336+
}
329337
.es-btn-small {
330338
font-size: 11px;
331339
padding: 2px 6px;

css/ui/object-menu.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ color: var(--fjm-button-hover-color);
5656
font-size: 15px;
5757
line-height: 1;
5858
flex-shrink: 0;
59+
width: 15px;
60+
overflow: hidden;
5961
}
6062

6163
.fabricjs-object-menu .menu-ai-action {

css/ui/role-assign-modal.css

Lines changed: 16 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -383,9 +383,7 @@
383383
<input type="password" id="runpodEndpointApiKey" value="" placeholder="API Key" autocomplete="off">
384384
<button id="runpodEndpointApiKeyToggle" class="es-btn-small" title="Show/Hide">👁</button>
385385
</li>
386-
<li class="es-url-row">
387-
<input type="number" id="runpodEndpointTimeout" value="120" min="10" max="600" placeholder="Timeout(s)">
388-
</li>
386+
<input type="hidden" id="runpodEndpointTimeout" value="120">
389387
</div>
390388
<div class="FalAI_api_content">
391389
<li class="es-section-title">Fal.ai</li>
@@ -394,22 +392,28 @@
394392
<button id="falaiApiKeyToggle" class="es-btn-small" title="Show/Hide">👁</button>
395393
</li>
396394
<li class="es-url-row">
397-
<input type="text" id="falaiModelT2I" value="" placeholder="T2I: fal-ai/flux/schnell">
395+
<select id="falaiModelT2I" disabled><option value="">T2I</option></select>
396+
<button id="falaiReloadT2I" class="es-btn-small" title="Reload"></button>
398397
</li>
399398
<li class="es-url-row">
400-
<input type="text" id="falaiModelI2I" value="" placeholder="I2I: fal-ai/image-to-image">
399+
<select id="falaiModelI2I" disabled><option value="">I2I</option></select>
400+
<button id="falaiReloadI2I" class="es-btn-small" title="Reload"></button>
401401
</li>
402402
<li class="es-url-row">
403-
<input type="text" id="falaiModelUpscale" value="" placeholder="Upscale: fal-ai/creative-upscaler">
403+
<select id="falaiModelUpscale" disabled><option value="">Upscale</option></select>
404+
<button id="falaiReloadUpscale" class="es-btn-small" title="Reload"></button>
404405
</li>
405406
<li class="es-url-row">
406-
<input type="text" id="falaiModelRembg" value="" placeholder="RemoveBG: fal-ai/birefnet">
407+
<select id="falaiModelRembg" disabled><option value="">RemoveBG</option></select>
408+
<button id="falaiReloadRembg" class="es-btn-small" title="Reload"></button>
407409
</li>
408410
</div>
409411
</ul>
410412
</li>
411413
</ul>
412414
<ul class="navbar-nav">
415+
<li class="nav-item dropdown">
416+
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownView" role="button"
413417
data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
414418
<span data-i18n="viewMenu">表示</span>
415419
</a>
@@ -1623,23 +1627,7 @@
16231627
</div>
16241628
<div id="esApi-controls-mini" class="controls-mini">
16251629
<div class="input-group" data-group="externalApiGroup">
1626-
<button id="comfyUIButton" data-value="comfyUIButton" onclick="changeExternalAPI(this,true)" class="selected">
1627-
ComfyUI
1628-
</button>
1629-
<button id="sdWebUIButton" data-value="sdWebUIButton" onclick='changeExternalAPI(this,true)'>
1630-
WebUI or Forge
1631-
</button>
1632-
<button id="runpodComfyUIButton" data-value="runpodComfyUIButton" onclick='changeExternalAPI(this,true)'>
1633-
RunPod
1634-
</button>
1635-
<button id="runpodEndpointButton" data-value="runpodEndpointButton" onclick='changeExternalAPI(this,true)'>
1636-
Serverless
1637-
</button>
1638-
<button id="falaiButton" data-value="falaiButton" onclick='changeExternalAPI(this,true)'>
1639-
Fal.ai
1640-
</button>
1641-
1642-
<button class="role-assign-trigger" onclick="roleAssignmentUI.open()" data-i18n="roleAssignButton">&#9881; Role</button>
1630+
<button class="role-assign-trigger" onclick="roleAssignmentUI.open()" data-i18n="roleAssignButton">&#9881; 使用APIサービス</button>
16431631
<div id="apiSettingsUrlHelpe">
16441632
</div>
16451633
</div>
@@ -1868,18 +1856,17 @@ <h2 data-i18n="roleAssignTitle">&#9881; Role Assignment</h2>
18681856
<table class="role-matrix">
18691857
<thead>
18701858
<tr>
1871-
<th data-i18n="roleAssignRole">Role</th>
1872-
<th data-i18n="roleDefault">Default</th>
1859+
<th></th>
18731860
<th>ComfyUI</th>
1874-
<th>WebUI</th>
1875-
<th>RunPod</th>
1876-
<th>Serverless</th>
1861+
<th>SD WebUI</th>
1862+
<th>RunPod<br>ComfyUI</th>
1863+
<th>RunPod<br>Serverless</th>
18771864
<th>Fal.ai</th>
18781865
</tr>
18791866
</thead>
18801867
<tbody id="roleMatrixBody"></tbody>
18811868
</table>
1882-
<div class="role-assign-note" data-i18n="roleAssignNote">&#8251; Greyed out = provider does not support this role. Default = follows the active provider.</div>
1869+
<div class="role-assign-note" data-i18n="roleAssignNote">「—」は非対応のプロバイダーです</div>
18831870
</div>
18841871
<div class="role-assign-modal-footer">
18851872
<button class="role-assign-btn-cancel" onclick="roleAssignmentUI.close()" data-i18n="roleAssignCancel">Cancel</button>

js/ai/ai-settings.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,25 @@ var input=$('falaiApiKey');
4949
input.type=input.type==='password'?'text':'password';
5050
});
5151

52+
var falaiProvider=providerRegistry.get('falai');
53+
$('falaiApiKey').addEventListener('change',function(){
54+
if(!falaiProvider)return;
55+
if(this.value.trim()){
56+
falaiProvider.fetchModels();
57+
}else{
58+
falaiProvider._enableSelects(false);
59+
}
60+
});
61+
['T2I','I2I','Upscale','Rembg'].forEach(function(role){
62+
$('falaiReload'+role).addEventListener('click',function(event){
63+
event.stopPropagation();
64+
if(!falaiProvider)return;
65+
if($('falaiApiKey').value.trim()){
66+
falaiProvider.fetchModels();
67+
}
68+
});
69+
});
70+
5271
setInterval(apiHeartbeat,1000*15);
5372
$('apiHeartbeatCheckbox').addEventListener('change',function () {
5473
apiHeartbeat();

js/ai/provider/falai-provider.js

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,76 @@ return'https://queue.fal.run';
2525
}
2626
_getModelId(role){
2727
var map={
28-
t2i:{id:'falaiModelT2I',fallback:'fal-ai/flux/schnell'},
29-
i2i:{id:'falaiModelI2I',fallback:'fal-ai/image-to-image'},
30-
upscale:{id:'falaiModelUpscale',fallback:'fal-ai/creative-upscaler'},
31-
rembg:{id:'falaiModelRembg',fallback:'fal-ai/birefnet'}
28+
t2i:'falaiModelT2I',
29+
i2i:'falaiModelI2I',
30+
upscale:'falaiModelUpscale',
31+
rembg:'falaiModelRembg'
3232
};
33-
var entry=map[role];
34-
if(!entry)return'';
35-
var el=$(entry.id);
36-
var val=el?el.value.trim():'';
37-
return val||entry.fallback;
33+
var id=map[role];
34+
if(!id)return'';
35+
var el=$(id);
36+
return el?el.value:'';
37+
}
38+
async fetchModels(){
39+
var apiKey=this.getApiKey();
40+
if(!apiKey){
41+
this._enableSelects(false);
42+
return;
43+
}
44+
var queries={
45+
falaiModelT2I:'category=text-to-image&status=active&limit=50',
46+
falaiModelI2I:'category=image-to-image&status=active&limit=50',
47+
falaiModelUpscale:'q=upscale&status=active&limit=50',
48+
falaiModelRembg:'q=background+removal&status=active&limit=50'
49+
};
50+
var headers={
51+
'Authorization':'Key '+apiKey
52+
};
53+
var entries=Object.entries(queries);
54+
var results=await Promise.allSettled(entries.map(function(entry){
55+
return fetch('https://api.fal.ai/v1/models?'+entry[1],{headers:headers}).then(function(r){
56+
if(!r.ok)throw new Error(r.status+'');
57+
return r.json();
58+
});
59+
}));
60+
for(var i=0;i<entries.length;i++){
61+
var selectId=entries[i][0];
62+
var result=results[i];
63+
if(result.status==='fulfilled'&&result.value&&result.value.models){
64+
this._populateSelect(selectId,result.value.models);
65+
}else{
66+
this._populateSelect(selectId,[]);
67+
}
68+
}
69+
}
70+
_enableSelects(enabled){
71+
var labels={falaiModelT2I:'T2I',falaiModelI2I:'I2I',falaiModelUpscale:'Upscale',falaiModelRembg:'RemoveBG'};
72+
var ids=Object.keys(labels);
73+
for(var i=0;i<ids.length;i++){
74+
var el=$(ids[i]);
75+
if(!el)continue;
76+
el.disabled=!enabled;
77+
if(!enabled){
78+
el.innerHTML='<option value="">'+labels[ids[i]]+'</option>';
79+
}
80+
}
81+
}
82+
_populateSelect(selectId,models){
83+
var el=$(selectId);
84+
if(!el)return;
85+
var prev=el.value;
86+
el.innerHTML='<option value="">-- select --</option>';
87+
for(var i=0;i<models.length;i++){
88+
var m=models[i];
89+
var opt=document.createElement('option');
90+
opt.value=m.endpoint_id||'';
91+
opt.textContent=m.metadata&&m.metadata.display_name?m.metadata.display_name:m.endpoint_id;
92+
el.appendChild(opt);
93+
}
94+
if(prev){
95+
el.value=prev;
96+
}
97+
el.disabled=false;
3898
}
3999
_authHeaders(){
40100
var apiKey=this.getApiKey();
@@ -238,7 +298,11 @@ removeSpinner(spinnerId);
238298
}
239299
async executeT2I(layer,spinnerId){
240300
var modelId=this._getModelId('t2i');
241-
var self=this;
301+
if(!modelId){
302+
removeSpinner(spinnerId);
303+
createToastError('Fal.ai','T2I model not selected',5000);
304+
return;
305+
}
242306
return this._execute(layer,spinnerId,'T2I',modelId,()=>{
243307
var rd=baseRequestData(layer);
244308
if(basePrompt.text2img_model!=''){
@@ -256,6 +320,11 @@ seed:rd.seed>0?rd.seed:undefined
256320
}
257321
async executeI2I(layer,spinnerId){
258322
var modelId=this._getModelId('i2i');
323+
if(!modelId){
324+
removeSpinner(spinnerId);
325+
createToastError('Fal.ai','I2I model not selected',5000);
326+
return;
327+
}
259328
return this._execute(layer,spinnerId,'I2I',modelId,()=>{
260329
var rd=baseRequestData(layer);
261330
var base64Image=imageObject2Base64ImageEffectKeep(layer);
@@ -273,6 +342,11 @@ seed:rd.seed>0?rd.seed:undefined
273342
}
274343
async executeUpscale(layer,spinnerId){
275344
var modelId=this._getModelId('upscale');
345+
if(!modelId){
346+
removeSpinner(spinnerId);
347+
createToastError('Fal.ai','Upscale model not selected',5000);
348+
return;
349+
}
276350
return this._execute(layer,spinnerId,'Upscaler',modelId,()=>{
277351
var base64Image=imageObject2Base64ImageEffectKeep(layer);
278352
return{
@@ -282,6 +356,11 @@ image_url:base64Image
282356
}
283357
async executeRembg(layer,spinnerId){
284358
var modelId=this._getModelId('rembg');
359+
if(!modelId){
360+
removeSpinner(spinnerId);
361+
createToastError('Fal.ai','RemoveBG model not selected',5000);
362+
return;
363+
}
285364
return this._execute(layer,spinnerId,'Rembg',modelId,()=>{
286365
var base64Image=imageObject2Base64ImageEffectKeep(layer);
287366
return{

0 commit comments

Comments
 (0)