Files
Copilot a93fc0443e Preserve image dimensions when generating swipe images (#5205)
* Initial plan

* feat: preserve image width/height when generating swipe images

Save width and height in ImageGenerationAttachmentProps when creating
MediaAttachment objects, and apply saved dimensions when generating
image swipes. Falls back to current extension settings if not specified.

Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>

* fix: validate dimension override with Number.isInteger and skip setTypeSpecificDimensions when override is present

Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>

* fix: call restoreOriginalDimensions when setTypeSpecificDimensions was used

Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>

* Contain the logic to setTypeSpecificDimensions

* Diff clean-up

* feat: enhance prompt refinement with negative input and saved resolution options

* fix: Only save image dimensions when running from command

* Fix wording in refine prompt dialog

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>
2026-02-23 20:51:25 +02:00

250 lines
7.7 KiB
TypeScript

import libs from './lib';
import getContext from './scripts/st-context';
import { power_user, getThemeObject } from './scripts/power-user';
import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi';
import { oai_settings } from './scripts/openai';
import { textgenerationwebui_settings } from './scripts/textgen-settings';
import { FileAttachment } from './scripts/chats';
import { ReasoningMessageExtra } from './scripts/reasoning';
import { IGNORE_SYMBOL, OVERSWIPE_BEHAVIOR } from './scripts/constants';
import { ToolInvocation } from './scripts/tool-calling';
import { getWorldInfoSettings } from './scripts/world-info';
declare global {
// Custom types
type InstructSettings = typeof power_user.instruct;
type ContextSettings = typeof power_user.context;
type ReasoningSettings = typeof power_user.reasoning;
type ChatCompletionSettings = typeof oai_settings;
type TextCompletionSettings = typeof textgenerationwebui_settings;
type WorldInfoSettings = ReturnType<typeof getWorldInfoSettings>;
type MessageTimestamp = string | number | Date;
type Character = import('./scripts/char-data').v1CharData;
type ChatMessageExtra = BaseMessageExtra & Partial<ReasoningMessageExtra> & Record<string, any>;
type Theme = ReturnType<typeof getThemeObject>;
interface Group {
id: string;
name: string;
members: string[];
disabled_members: string[];
chat_id: string;
chats: string[];
generation_mode?: number;
generation_mode_join_prefix?: string;
generation_mode_join_suffix?: string;
activation_strategy?: number;
auto_mode_delay?: number;
allow_self_responses?: boolean;
avatar_url?: string;
hideMutedSprites?: boolean;
fav?: boolean;
date_last_chat?: MessageTimestamp;
}
interface ChatFile extends Array<ChatMessage> {
[index: number]: ChatMessage;
0?: ChatHeader;
}
interface ChatHeader {
chat_metadata: ChatMetadata;
/** @deprecated For backward compatibility ONLY */
user_name: 'unused';
/** @deprecated For backward compatibility ONLY */
character_name: 'unused';
}
interface ChatMetadata {
tainted?: boolean;
integrity?: string;
scenario?: string;
persona?: string;
[key: string]: any;
}
interface ChatMessage {
name?: string;
mes?: string;
title?: string;
gen_started?: MessageTimestamp;
gen_finished?: MessageTimestamp;
send_date?: MessageTimestamp;
is_user?: boolean;
is_system?: boolean;
force_avatar?: string;
original_avatar?: string;
swipes?: string[];
swipe_info?: SwipeInfo[];
swipe_id?: number;
extra?: ChatMessageExtra;
};
interface SwipeInfo {
send_date?: MessageTimestamp;
gen_started?: MessageTimestamp;
gen_finished?: MessageTimestamp;
extra?: ChatMessageExtra;
}
interface BaseMessageExtra {
api?: string;
model?: string;
type?: string;
gen_id?: number;
bias?: string;
uses_system_ui?: boolean;
memory?: string;
display_text?: string;
reasoning_display_text?: string;
tool_invocations?: ToolInvocation[];
title?: string;
isSmallSys?: boolean;
token_count?: number;
/** When false, the message cannot be swiped. */
swipeable?: boolean;
overswipe_behavior?: OVERSWIPE_BEHAVIOR;
files?: FileAttachment[];
inline_image?: boolean;
media_display?: string;
media_index?: number;
media?: MediaAttachment[],
/** @deprecated Use `files` instead */
file?: FileAttachment;
/** @deprecated Use `media` instead */
image?: string;
/** @deprecated Use `media` instead */
video?: string;
/** @deprecated Use `media` with `media_display = 'gallery'` instead */
image_swipes?: string[];
/** @deprecated Use `MediaAttachment.append_title` instead */
append_title?: boolean;
/** @deprecated Use `MediaAttachment.generation_type` instead */
generationType?: number;
/** @deprecated Use `MediaAttachment.negative` instead */
negative?: string;
/** Will exclude this message from prompt processing */
[IGNORE_SYMBOL]?: boolean;
}
type MediaAttachment = MediaAttachmentProps & ImageGenerationAttachmentProps & ImageCaptionAttachmentProps;
interface MediaAttachmentProps {
url: string;
title?: string;
type: string;
source?: string;
}
interface ImageGenerationAttachmentProps {
generation_type?: number;
negative?: string;
width?: number;
height?: number;
}
interface ImageCaptionAttachmentProps {
/** Append title to the message text in case of non-inline captions. */
append_title?: boolean;
/** Marker for captioned images to prevent auto-caption from firing again. */
captioned?: boolean;
}
/** Media playback state */
interface MediaState {
/** Current playback time */
currentTime: number;
/** Whether the media is paused */
paused: boolean;
}
interface ChatCompletionMessage {
name?: string;
role: string;
content: string;
}
// Global namespace modules
interface Window {
ai: any;
}
var pdfjsLib;
var ePub;
var quickReplyApi: QuickReplyApi;
var SillyTavern: {
getContext(): typeof getContext;
llm: any;
libs: typeof libs;
};
// Jquery plugins
interface JQuery {
nanogallery2(options?: any): JQuery;
nanogallery2(method: string, options?: any): JQuery;
pagination(method: 'getCurrentPageNum'): number;
pagination(method: string, options?: any): JQuery;
pagination(options?: any): JQuery;
izoomify(options?: any): JQuery;
}
// NPM package doesn't have the 'queue' property in the type definition
interface JQueryTransitOptions {
queue?: boolean;
}
namespace Select2 {
interface Options<Result = DataFormat | GroupedDataFormat, RemoteResult = any> {
/**
* Extends Select2 v4 plugin by adding an option to set a placeholder for the 'search' input field
* [Custom Field]
* @default ''
*/
searchInputPlaceholder?: string;
/**
* Extends select2 plugin by adding a custom css class for the 'search' input field
* [Custom Field]
* @default ''
*/
searchInputCssClass?: string;
}
}
/**
* Translates a text to a target language using a translation provider.
* @param text Text to translate
* @param lang Target language
* @param provider Translation provider
*/
function translate(text: string, lang: string, provider?: string | null): Promise<string>;
interface ConvertVideoArgs {
buffer: Uint8Array;
name: string;
}
/**
* Converts a video file to an animated WebP format using FFmpeg.
* @param args - The arguments for the conversion function.
*/
function convertVideoToAnimatedWebp(args: ConvertVideoArgs): Promise<Uint8Array>;
type ColorPickerEvent = Omit<JQuery.ChangeEvent<HTMLElement>, "detail"> & {
detail: {
rgba: string;
}
};
type SwipeEvent = JQuery.TriggeredEvent<any, any, HTMLElement, HTMLElement>;
}
//Overrides for public/scripts/chats.js
declare module 'dompurify' {
interface Config {
MESSAGE_SANITIZE?: boolean;
MESSAGE_ALLOW_SYSTEM_UI?: boolean;
}
}