Compare commits

...
Author SHA1 Message Date
Brandon Thomas 3c28f4073b get rid of instanceof checks 2025-09-23 10:50:35 -04:00
Brandon Thomas 232f40ebdb remove logging 2025-09-22 22:53:24 -04:00
Brandon Thomas 45c12ba512 patch model selector issues 2025-09-22 22:52:54 -04:00
Brandon Thomas b1ee3f513d log model selection 2025-09-22 21:56:57 -04:00
10 changed files with 63 additions and 21 deletions
@@ -21,17 +21,27 @@ export const useClassyModelSelectorStore = create<ClassyModelSelectorState>((set
export const getSelectedImageModel = (page: ModelPage) : ImageModel | undefined => {
const { selectedModels } = useClassyModelSelectorStore();
const maybeModel = selectedModels[page];
if (!maybeModel || !(maybeModel instanceof ImageModel)) {
if (!maybeModel) {
return undefined;
}
return maybeModel;
// NB: We can't use "instanceof" checks with Vite minification and class name mangling.
// We have to do type tagging a different way.
if (maybeModel.kind === "image_model") {
return maybeModel as ImageModel;
}
return undefined;
};
export const getSelectedVideoModel = (page: ModelPage) : VideoModel | undefined => {
const { selectedModels } = useClassyModelSelectorStore();
const maybeModel = selectedModels[page];
if (!maybeModel || !(maybeModel instanceof VideoModel)) {
if (!maybeModel) {
return undefined;
}
return maybeModel;
// NB: We can't use "instanceof" checks with Vite minification and class name mangling.
// We have to do type tagging a different way.
if (maybeModel.kind !== "video_model") {
return undefined;
}
return maybeModel as VideoModel;
};
@@ -31,6 +31,7 @@ export function ClassyModelSelector({
}, []);
const handleModelSelect = (item: PopoverItem) => {
console.log(`Model selector changed on page "${page}": `, item.model);
setSelectedModel(page, item.model!);
};
@@ -64,6 +64,8 @@ export const PromptBoxImage = ({
}: PromptBoxImageProps) => {
useSignals();
console.log("Selected model:", selectedModel);
useEffect(() => {
if (imageMediaId && url) {
const referenceImage: RefImage = {
@@ -233,6 +235,9 @@ export const PromptBoxImage = ({
return;
}
console.log("Selected model:", selectedModel)
console.log("Prompt:", prompt)
setIsEnqueueing(true);
gtagEvent("enqueue_image");
@@ -1,9 +1,14 @@
import { ModelCreator } from "src/index.js";
import { Model } from "./Model.js";
import { Model, ModelKind } from "./Model.js";
import { ModelCategory } from "../legacy/ModelConfig.js";
import { ModelTag } from "./metadata/ModelTag.js";
export class ImageModel extends Model {
// Typescript type discriminator property
// Since Vite minification and class name mangling can break instanceof checks,
// we have a type discriminator property to check against.
override readonly kind: ModelKind = "image_model";
// Maximum number of images that can be generated at once
readonly maxGenerationCount: number;
@@ -2,8 +2,15 @@ import { ModelCreator } from "./metadata/ModelCreator.js";
import { ModelCategory, ModelConfig } from "../legacy/ModelConfig.js";
import { ModelTag } from "./metadata/ModelTag.js";
export type ModelKind = "model" | "image_model" | "video_model";
// NB: Do not create instances of this class directly, use subclasses.
export class Model {
// Typescript type discriminator property
// Since Vite minification and class name mangling can break instanceof checks,
// we have a type discriminator property to check against.
readonly kind: ModelKind = "model";
// A unique frontend-only string for the model
readonly id: string;
@@ -1,9 +1,14 @@
import { ModelCreator } from "src/index.js";
import { Model } from "./Model.js";
import { Model, ModelKind } from "./Model.js";
import { ModelCategory } from "../legacy/ModelConfig.js";
import { ModelTag } from "./metadata/ModelTag.js";
export class VideoModel extends Model {
// Typescript type discriminator property
// Since Vite minification and class name mangling can break instanceof checks,
// we have a type discriminator property to check against.
override readonly kind: ModelKind = "video_model";
// Whether the model supports image starting frames
readonly startFrame: boolean;
@@ -240,10 +240,9 @@ export const lookupModelByTauriId = (
// Single exported capability resolver so callers never need to touch anything else
export const getCapabilitiesForModel = (
model?: Model | ModelInfo
model?: Model
): ModelCapabilities => {
if (!model) return DEFAULT_CAPABILITIES;
const tauriId = model instanceof Model ? model.tauriId : model.tauri_id;
const cfg = lookupModelByTauriId(tauriId);
const cfg = lookupModelByTauriId(model.tauriId);
return cfg?.capabilities ?? DEFAULT_CAPABILITIES;
};
@@ -1,11 +1,11 @@
import { invoke } from "@tauri-apps/api/core";
import { CommandResult } from "../common/CommandStatus";
import { ImageModel, ModelInfo } from "@storyteller/model-list";
import { ImageModel } from "@storyteller/model-list";
export interface EnqueueContextualEditImageRequest {
/// The model to use.
model?: ImageModel | ModelInfo | EnqueueContextualEditImageModel;
model?: ImageModel | EnqueueContextualEditImageModel;
/// If set, this is the first image in the contextual image set.
/// This gets submitted along with `image_media_tokens` and will
@@ -93,15 +93,18 @@ export const EnqueueContextualEditImage = async (request: EnqueueContextualEditI
let modelName = undefined;
if (!!request.model) {
// NB: We can't use "instanceof" checks with Vite minification and class name mangling.
if (typeof request.model === "string") {
modelName = request.model;
} else if (request.model instanceof ImageModel) {
} else if (typeof request.model.tauriId === "string") {
modelName = request.model.tauriId;
} else {
modelName = request.model.tauri_id;
}
}
if (!modelName) {
throw new Error("No model specified in request: " + JSON.stringify(request));
}
let mutableRequest : RawEnqueueContextualEditImageRequest = {
model: modelName,
prompt: request.prompt,
@@ -74,13 +74,17 @@ export const EnqueueImageInpaint = async (request: EnqueueImageInpaintRequest) :
if (!!request.model) {
if (typeof request.model === "string") {
modelName = request.model;
} else if (request.model instanceof ImageModel) {
} else if ("tauriId" in request.model && typeof request.model.tauriId === "string") {
modelName = request.model.tauriId;
} else {
} else if ("tauri_id" in request.model && typeof request.model.tauri_id === "string") {
modelName = request.model.tauri_id;
}
}
if (!modelName) {
throw new Error("No model specified in request: " + JSON.stringify(request));
}
let mutableRequest : RawEnqueueImageInpaintRequest = {
model: modelName,
prompt: request.prompt,
@@ -1,6 +1,6 @@
import { invoke } from "@tauri-apps/api/core";
import { CommandResult } from "../common/CommandStatus";
import { Model, ModelInfo } from "@storyteller/model-list";
import { Model } from "@storyteller/model-list";
export enum EnqueueTextToImageErrorType {
/// Caller didn't specify a model
@@ -15,7 +15,7 @@ export enum EnqueueTextToImageErrorType {
export interface EnqueueTextToImageRequest {
// The model to use.
model?: Model | ModelInfo | EnqueueTextToImageModel;
model?: Model | EnqueueTextToImageModel;
// The text prompt.
prompt?: string;
@@ -86,15 +86,18 @@ export const EnqueueTextToImage = async (request: EnqueueTextToImageRequest) : P
let modelName = undefined;
if (!!request.model) {
// NB: We can't use "instanceof" checks with Vite minification and class name mangling.
if (typeof request.model === "string") {
modelName = request.model;
} else if (request.model instanceof Model) {
} else if (typeof request.model.tauriId === "string") {
modelName = request.model.tauriId;
} else {
modelName = request.model.tauri_id;
}
}
if (!modelName) {
throw new Error("No model specified in request: " + JSON.stringify(request));
}
let mutableRequest : EnqueueTextToImageRawRequest = {
model: modelName,
prompt: request.prompt,