refactor: 重构项目结构和代码组织
This commit is contained in:
@@ -1,299 +0,0 @@
|
||||
# 共享类型系统文档
|
||||
|
||||
## 概述
|
||||
|
||||
本目录包含项目的完整类型系统,采用**双格式兼容**设计:
|
||||
|
||||
1. **SillyTavern 原生格式** - 用于导入导出兼容
|
||||
2. **扩展内部格式** - 用于增强功能和自定义特性
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
shared/types/
|
||||
├── sillytavern/ # SillyTavern 原生格式(从官方文档读取)
|
||||
│ ├── character.types.ts # 角色卡 V2 规范
|
||||
│ ├── chat.types.ts # 聊天记录(JSONL)
|
||||
│ ├── world.types.ts # 世界书 / Lorebook
|
||||
│ └── preset.types.ts # 生成预设
|
||||
│
|
||||
├── extended/ # 您的自定义扩展
|
||||
│ ├── chat-ext.types.ts # 扩展聊天(动态表头)
|
||||
│ ├── preset-ext.types.ts # 扩展预设(位置锚点)
|
||||
│ └── world-ext.types.ts # 统一触发器系统
|
||||
│
|
||||
├── adapters/ # 导入导出适配器
|
||||
│ └── import-export.types.ts # 适配器接口
|
||||
│
|
||||
├── common.types.ts # 通用工具类型
|
||||
└── index.ts # 主导出文件
|
||||
```
|
||||
|
||||
## 核心设计原则
|
||||
|
||||
### 1. **双格式系统**
|
||||
|
||||
每个数据实体都有**两种表示形式**:
|
||||
|
||||
- **ST 格式**:精确的 SillyTavern 规范(用于兼容性)
|
||||
- **扩展格式**:增强了您的自定义功能
|
||||
|
||||
示例:
|
||||
```typescript
|
||||
// SillyTavern 格式(导入/导出)
|
||||
interface STChatMessage {
|
||||
name: string;
|
||||
is_user: boolean;
|
||||
mes: string;
|
||||
// ... ST 字段
|
||||
}
|
||||
|
||||
// 扩展格式(内部使用)
|
||||
interface ExtendedChatMessage {
|
||||
senderName: string;
|
||||
senderRole: 'user' | 'assistant';
|
||||
mes: string;
|
||||
reasoning?: string; // 您的自定义字段
|
||||
image?: string; // 您的自定义字段
|
||||
audio?: string; // 您的自定义字段
|
||||
dynamicData?: Record<string, any>; // 动态表头
|
||||
}
|
||||
```
|
||||
|
||||
### 2. **适配器模式**
|
||||
|
||||
适配器处理格式之间的转换:
|
||||
|
||||
```typescript
|
||||
interface ChatAdapter {
|
||||
importFromST(jsonlContent: string): InternalChatSession;
|
||||
exportToST(chat: InternalChatSession): string;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **保留原始数据**
|
||||
|
||||
内部模型保留原始 ST 数据:
|
||||
|
||||
```typescript
|
||||
interface InternalCharacter {
|
||||
// ... 您的字段
|
||||
stData?: STCharacterCardV2; // 保留原始数据
|
||||
}
|
||||
```
|
||||
|
||||
## Data Models
|
||||
|
||||
### Chat History (JSONL)
|
||||
|
||||
**Metadata (First line):**
|
||||
- `characterName`: Character name
|
||||
- `dynamicHeaders`: User-defined dynamic table headers
|
||||
- `characterDescription`: Character description
|
||||
- `systemPrompt`: System prompt
|
||||
- `firstMessages`: Alternate first messages
|
||||
|
||||
**Messages (Subsequent lines):**
|
||||
- `senderName`: Who sent the message
|
||||
- `senderRole`: user/assistant/system/narrator
|
||||
- `mes`: Message content
|
||||
- `swipes`: Alternative responses
|
||||
- `reasoning`: Chain of thought
|
||||
- `image/audio`: Media attachments
|
||||
- `dynamicData`: Custom dynamic header values
|
||||
|
||||
### 预设系统
|
||||
|
||||
**固定占位符位置(顺序必须保持):**
|
||||
1. `system` - 系统提示词(来自角色卡)
|
||||
2. `world_info_before` - 世界书(前置)
|
||||
3. `persona_description` - 角色设定描述
|
||||
4. `char_description` - 角色详细描述
|
||||
5. `world_info_after` - 世界书(后置)
|
||||
6. `history` - 聊天记录(对话历史)
|
||||
7. `user_input` - 用户当前输入
|
||||
|
||||
**核心参数:**
|
||||
- `temperature`: 温度(创造性)
|
||||
- `maxReplyLength`: 最大回复长度
|
||||
- `topP`, `topK`: 采样参数
|
||||
- `repetitionPenalty`: 重复惩罚系数
|
||||
- `entryOrder`: 预设条目名称的有序列表
|
||||
- `maxContextTokens`: 最大上下文 token 数
|
||||
- `streaming`: 是否流式传输
|
||||
|
||||
**API 配置:**
|
||||
```typescript
|
||||
interface ApiConfig {
|
||||
apiUrl: string; // API 地址
|
||||
apiKey: string; // API 密钥
|
||||
apiType: 'primary' | 'secondary' | 'image_gen' | 'rag'; // API 类型
|
||||
model: string; // 模型名称
|
||||
}
|
||||
```
|
||||
|
||||
### 世界书(统一触发器系统)
|
||||
|
||||
将原有的 `key` 和 `constant` 整合为统一的四元素字典:
|
||||
|
||||
```typescript
|
||||
interface TriggerConfig {
|
||||
permanent: PermanentTrigger; // 永久激活(无需触发器)
|
||||
keyword: KeywordTrigger; // 关键词触发
|
||||
rag: RagTrigger; // RAG/数据库触发
|
||||
variable: VariableTrigger; // 变量比较触发
|
||||
}
|
||||
```
|
||||
|
||||
**触发器类型详解:**
|
||||
|
||||
1. **永久触发器** (`permanent`)
|
||||
- `enabled`: 是否永久激活
|
||||
- 无其他条件,始终生效
|
||||
|
||||
2. **关键词触发器** (`keyword`)
|
||||
- `enabled`: 是否启用
|
||||
- `keywords`: 关键词数组
|
||||
- `useRegex`: 是否使用正则表达式
|
||||
- `matchWholeWords`: 是否匹配完整单词
|
||||
- `caseSensitive`: 是否区分大小写
|
||||
|
||||
3. **RAG 触发器** (`rag`)
|
||||
- `enabled`: 是否启用
|
||||
- `databaseName`: 关联的数据库/集合名称
|
||||
- `threshold`: 相似度阈值(0-1)
|
||||
- `topK`: 检索的相似条目数量
|
||||
|
||||
4. **变量触发器** (`variable`)
|
||||
- `enabled`: 是否启用
|
||||
- `variableA`: 变量 A
|
||||
- `operator`: 运算符(`>`, `<`, `=`, `contains`, `<=`, `>=`, `!=`)
|
||||
- `variableB`: 变量 B(可选)
|
||||
- `constantA`: 常量值(可选,替代 variableB)
|
||||
|
||||
**其他字段:**
|
||||
- `content`: 条目内容
|
||||
- `position`: 插入位置(`before_char` / `after_char`)
|
||||
- `scanDepth`: 扫描深度(扫描多少条消息)
|
||||
- `priority`: 优先级(同位置的先后顺序)
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 导入角色卡
|
||||
|
||||
```typescript
|
||||
import { CharacterAdapter, STCharacterCardV2 } from '@shared/types';
|
||||
|
||||
const adapter: CharacterAdapter = new CharacterAdapterImpl();
|
||||
|
||||
// 从 ST 格式导入
|
||||
const stCard: STCharacterCardV2 = parsePNG('character.png');
|
||||
const internalChar = adapter.importFromST(stCard);
|
||||
|
||||
// 导出为 ST 格式
|
||||
const stExport = adapter.exportToST(internalChar);
|
||||
```
|
||||
|
||||
### 聊天会话管理
|
||||
|
||||
```typescript
|
||||
import { ChatAdapter } from '@shared/types';
|
||||
|
||||
const adapter: ChatAdapter = new ChatAdapterImpl();
|
||||
|
||||
// 导入 JSONL
|
||||
const jsonlContent = await readFile('chat.jsonl');
|
||||
const chat = adapter.importFromST(jsonlContent);
|
||||
|
||||
// 添加带自定义字段的消息
|
||||
chat.messages.push({
|
||||
senderName: '用户',
|
||||
senderRole: 'user',
|
||||
mes: '你好!',
|
||||
reasoning: undefined,
|
||||
dynamicData: { mood: 'happy' }
|
||||
});
|
||||
|
||||
// 导出回 JSONL
|
||||
const exported = adapter.exportToST(chat);
|
||||
```
|
||||
|
||||
### 世界书统一触发器
|
||||
|
||||
```typescript
|
||||
import { ExtendedWorldInfoEntry, TriggerConfig } from '@shared/types';
|
||||
|
||||
const entry: ExtendedWorldInfoEntry = {
|
||||
id: '1',
|
||||
content: '魔法剑发出蓝色光芒。',
|
||||
position: 'after_char',
|
||||
scanDepth: 5,
|
||||
priority: 1,
|
||||
triggers: {
|
||||
permanent: { enabled: false },
|
||||
keyword: {
|
||||
enabled: true,
|
||||
keywords: ['剑', '武器'],
|
||||
useRegex: false,
|
||||
matchWholeWords: true,
|
||||
caseSensitive: false
|
||||
},
|
||||
rag: { enabled: false },
|
||||
variable: { enabled: false }
|
||||
},
|
||||
enabled: true
|
||||
};
|
||||
```
|
||||
|
||||
## 兼容性说明
|
||||
|
||||
### SillyTavern V2 规范
|
||||
- 完全兼容 [Character Card V2](https://github.com/malfoyslastname/character-card-spec-v2)
|
||||
- 支持 PNG 嵌入(tEXt 数据块)
|
||||
- 支持 JSON 格式
|
||||
|
||||
### 聊天记录
|
||||
- JSONL 格式(每行一个 JSON 对象)
|
||||
- 第一行:元数据
|
||||
- 后续行:消息
|
||||
- 支持完整性哈希校验
|
||||
|
||||
### 世界书
|
||||
- 兼容 ST Lorebook 格式
|
||||
- 扩展触发器系统可转换为 `keys` + `constant`
|
||||
|
||||
### 预设
|
||||
- 支持所有标准 ST 参数
|
||||
- 固定占位符位置用于提示词构建
|
||||
- 保留条目顺序
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从 SillyTavern 到内部格式
|
||||
|
||||
1. 解析 ST 格式(PNG/JSON/JSONL)
|
||||
2. 使用适配器转换为内部格式
|
||||
3. 原始 ST 数据保存在 `stData` 字段中
|
||||
4. 根据需要添加自定义字段
|
||||
|
||||
### 从内部格式到 SillyTavern 格式
|
||||
|
||||
1. 使用适配器将内部格式转换为 ST 格式
|
||||
2. 不在 ST 规范中的自定义字段会被排除
|
||||
3. 如果可用,使用原始 ST 数据
|
||||
4. 以所需格式导出(PNG/JSON/JSONL)
|
||||
|
||||
## 类型安全
|
||||
|
||||
所有类型都使用 TypeScript 完整定义:
|
||||
- 核心模型中不使用 `any` 类型
|
||||
- 严格的空值检查
|
||||
- 基于枚举的常量
|
||||
- 全面的接口定义
|
||||
|
||||
## 下一步计划
|
||||
|
||||
1. 实现适配器类
|
||||
2. 创建验证函数
|
||||
3. 为转换逻辑添加单元测试
|
||||
4. 构建导入导出 UI 组件
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
* Import/Export Adapter Interfaces
|
||||
* Ensures data compatibility between SillyTavern format and internal format
|
||||
*/
|
||||
|
||||
import type { STCharacterCardV2 } from '../sillytavern/character.types';
|
||||
import type { STChatSession } from '../sillytavern/chat.types';
|
||||
import type { STWorldInfo } from '../sillytavern/world.types';
|
||||
import type { STPreset } from '../sillytavern/preset.types';
|
||||
|
||||
import type { ExtendedChatMetadata, ExtendedChatMessage } from '../extended/chat-ext.types';
|
||||
import type { ExtendedPreset } from '../extended/preset-ext.types';
|
||||
import type { ExtendedWorldInfo } from '../extended/world-ext.types';
|
||||
|
||||
/**
|
||||
* Character Card Adapter
|
||||
*/
|
||||
export interface CharacterAdapter {
|
||||
/**
|
||||
* Import from SillyTavern format
|
||||
*/
|
||||
importFromST(stCard: STCharacterCardV2): InternalCharacter;
|
||||
|
||||
/**
|
||||
* Export to SillyTavern format
|
||||
*/
|
||||
exportToST(internalChar: InternalCharacter): STCharacterCardV2;
|
||||
|
||||
/**
|
||||
* Validate SillyTavern format
|
||||
*/
|
||||
validateSTFormat(data: any): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat Session Adapter
|
||||
*/
|
||||
export interface ChatAdapter {
|
||||
/**
|
||||
* Import from SillyTavern JSONL format
|
||||
*/
|
||||
importFromST(jsonlContent: string): InternalChatSession;
|
||||
|
||||
/**
|
||||
* Export to SillyTavern JSONL format
|
||||
*/
|
||||
exportToST(chat: InternalChatSession): string;
|
||||
|
||||
/**
|
||||
* Parse JSONL to structured data
|
||||
*/
|
||||
parseJSONL(jsonlContent: string): STChatSession;
|
||||
|
||||
/**
|
||||
* Convert structured data to JSONL
|
||||
*/
|
||||
toJSONL(session: STChatSession): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* World Info Adapter
|
||||
*/
|
||||
export interface WorldInfoAdapter {
|
||||
/**
|
||||
* Import from SillyTavern format
|
||||
*/
|
||||
importFromST(stWorldInfo: STWorldInfo): ExtendedWorldInfo;
|
||||
|
||||
/**
|
||||
* Export to SillyTavern format
|
||||
*/
|
||||
exportToST(extendedWorldInfo: ExtendedWorldInfo): STWorldInfo;
|
||||
|
||||
/**
|
||||
* Convert unified trigger config to ST format
|
||||
*/
|
||||
triggersToST(triggers: any): { keys: string[]; constant: boolean };
|
||||
|
||||
/**
|
||||
* Convert ST format to unified trigger config
|
||||
*/
|
||||
triggersFromST(keys: string[], constant: boolean): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset Adapter
|
||||
*/
|
||||
export interface PresetAdapter {
|
||||
/**
|
||||
* Import from SillyTavern format
|
||||
*/
|
||||
importFromST(stPreset: STPreset): ExtendedPreset;
|
||||
|
||||
/**
|
||||
* Export to SillyTavern format
|
||||
*/
|
||||
exportToST(extendedPreset: ExtendedPreset): STPreset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal unified data models
|
||||
*/
|
||||
export interface InternalCharacter {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
personality: string;
|
||||
scenario: string;
|
||||
firstMessage: string;
|
||||
exampleMessages: string;
|
||||
avatarUrl?: string;
|
||||
tags: string[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
// Original ST data preserved
|
||||
stData?: STCharacterCardV2;
|
||||
}
|
||||
|
||||
export interface InternalChatSession {
|
||||
id: string;
|
||||
characterId: string;
|
||||
metadata: ExtendedChatMetadata;
|
||||
messages: ExtendedChatMessage[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import result with validation
|
||||
*/
|
||||
export interface ImportResult<T = any> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
errors: ImportError[];
|
||||
warnings: ImportWarning[];
|
||||
sourceFormat: string;
|
||||
importedAt: Date;
|
||||
}
|
||||
|
||||
export interface ImportError {
|
||||
code: string;
|
||||
message: string;
|
||||
field?: string;
|
||||
severity: 'error' | 'critical';
|
||||
}
|
||||
|
||||
export interface ImportWarning {
|
||||
code: string;
|
||||
message: string;
|
||||
suggestion?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export options
|
||||
*/
|
||||
export interface ExportOptions {
|
||||
format: 'json' | 'png' | 'jsonl';
|
||||
includeMetadata: boolean;
|
||||
includeExtensions: boolean;
|
||||
compress: boolean;
|
||||
}
|
||||
|
||||
export interface ExportResult {
|
||||
success: boolean;
|
||||
content?: string | Blob;
|
||||
filename: string;
|
||||
mimeType: string;
|
||||
error?: string;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Common shared types
|
||||
*/
|
||||
|
||||
export interface BaseEntity {
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface SoftDeleteEntity {
|
||||
deletedAt?: Date;
|
||||
isDeleted: boolean;
|
||||
}
|
||||
|
||||
export type Entity<T = {}> = T & BaseEntity;
|
||||
|
||||
export interface PaginatedResponse<T> {
|
||||
items: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export interface SortOption {
|
||||
field: string;
|
||||
order: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
export interface FilterOption {
|
||||
field: string;
|
||||
operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains';
|
||||
value: any;
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Extended Chat Metadata (Your custom additions)
|
||||
* This is the "AI character card" part of chat JSONL
|
||||
*/
|
||||
|
||||
export interface ExtendedChatMetadata {
|
||||
// Core identity
|
||||
characterName: string;
|
||||
|
||||
// Dynamic table headers (user-defined, with defaults)
|
||||
dynamicHeaders: DynamicHeader[];
|
||||
|
||||
// Character info
|
||||
characterDescription: string;
|
||||
characterAvatar?: string; // URL or base64
|
||||
aiCharacterName: string;
|
||||
creatorNotes?: string;
|
||||
|
||||
// Messages
|
||||
firstMessages: string[]; // List of alternate first messages
|
||||
systemPrompt: string;
|
||||
|
||||
// Extensions (preserve original ST extensions)
|
||||
extensions?: Record<string, any>;
|
||||
|
||||
// Your custom fields
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
tags?: string[];
|
||||
category?: string;
|
||||
}
|
||||
|
||||
export interface DynamicHeader {
|
||||
id: string;
|
||||
name: string;
|
||||
type: 'text' | 'number' | 'boolean' | 'select' | 'multiselect';
|
||||
defaultValue?: any;
|
||||
options?: string[]; // For select/multiselect types
|
||||
required?: boolean;
|
||||
order: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended Chat Message (Your custom additions)
|
||||
*/
|
||||
export interface ExtendedChatMessage {
|
||||
// Core fields
|
||||
senderName: string;
|
||||
senderRole: 'user' | 'assistant' | 'system' | 'narrator';
|
||||
mes: string; // Message content
|
||||
|
||||
// Your custom fields
|
||||
swipes?: string[]; // Alternative responses
|
||||
reasoning?: string; // Chain of thought / reasoning process
|
||||
image?: string; // Base64 or URL
|
||||
audio?: string; // Base64 or URL
|
||||
|
||||
// Metadata
|
||||
timestamp: Date;
|
||||
tokens?: number;
|
||||
model?: string;
|
||||
|
||||
// Dynamic data (matches dynamicHeaders)
|
||||
dynamicData?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete Extended Chat Session
|
||||
*/
|
||||
export interface ExtendedChatSession {
|
||||
metadata: ExtendedChatMetadata;
|
||||
messages: ExtendedChatMessage[];
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Extended Preset Format (Your custom additions)
|
||||
*/
|
||||
|
||||
export interface ExtendedPreset {
|
||||
// Core sampling parameters
|
||||
temperature: number;
|
||||
maxReplyLength: number;
|
||||
topP: number;
|
||||
topK: number;
|
||||
repetitionPenalty: number;
|
||||
|
||||
// Ordered list of preset entry names
|
||||
entryOrder: string[];
|
||||
|
||||
// Context settings
|
||||
maxContextTokens: number;
|
||||
streaming: boolean;
|
||||
|
||||
// Your custom fields
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
// Preset entries with fixed placeholders
|
||||
entries: PresetEntry[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset Entry with position anchoring
|
||||
*/
|
||||
export interface PresetEntry {
|
||||
name: string;
|
||||
context: string; // Content/prompt
|
||||
position: PresetPosition;
|
||||
order: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed placeholder positions for preset entries
|
||||
* These anchor specific content types in the prompt
|
||||
*/
|
||||
export enum PresetPosition {
|
||||
SYSTEM = 'system', // System prompt (from character card)
|
||||
WORLD_INFO_BEFORE = 'world_info_before', // World Info (before character)
|
||||
PERSONA_DESCRIPTION = 'persona_description', // Character persona description
|
||||
CHAR_DESCRIPTION = 'char_description', // Character detailed description
|
||||
WORLD_INFO_AFTER = 'world_info_after', // World Info (after character)
|
||||
HISTORY = 'history', // Chat history
|
||||
USER_INPUT = 'user_input' // Current user input
|
||||
}
|
||||
|
||||
/**
|
||||
* API Configuration for LLM
|
||||
*/
|
||||
export interface ApiConfig {
|
||||
apiUrl: string;
|
||||
apiKey: string;
|
||||
apiType: ApiType;
|
||||
model: string;
|
||||
}
|
||||
|
||||
export enum ApiType {
|
||||
PRIMARY = 'primary', // Main chat/completion API
|
||||
SECONDARY = 'secondary', // Fallback API
|
||||
IMAGE_GEN = 'image_gen', // Image generation API
|
||||
RAG = 'rag' // RAG/Embedding API
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* Extended World Info Format (Your custom additions)
|
||||
* Integrates "key" and "constant" into a unified trigger system
|
||||
*/
|
||||
|
||||
export interface ExtendedWorldInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
|
||||
entries: ExtendedWorldInfoEntry[];
|
||||
|
||||
metadata: WorldInfoMetadata;
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface ExtendedWorldInfoEntry {
|
||||
id: string;
|
||||
content: string;
|
||||
position: 'before_char' | 'after_char';
|
||||
scanDepth: number; // How many messages to scan
|
||||
priority: number; // Order at same position
|
||||
|
||||
// Unified trigger system (replaces key + constant)
|
||||
triggers: TriggerConfig;
|
||||
|
||||
enabled: boolean;
|
||||
|
||||
// Your custom fields
|
||||
category?: string;
|
||||
tags?: string[];
|
||||
usageCount?: number;
|
||||
lastUsed?: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified Trigger Configuration
|
||||
* Replaces separate "key" and "constant" fields
|
||||
*/
|
||||
export interface TriggerConfig {
|
||||
permanent: PermanentTrigger; // Always active (no trigger needed)
|
||||
keyword: KeywordTrigger; // Keyword-based activation
|
||||
rag: RagTrigger; // RAG/database-based activation
|
||||
variable: VariableTrigger; // Variable/expression-based activation
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanent trigger - always active, no conditions
|
||||
*/
|
||||
export interface PermanentTrigger {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyword trigger - activates when keywords are found
|
||||
*/
|
||||
export interface KeywordTrigger {
|
||||
enabled: boolean;
|
||||
keywords: string[];
|
||||
useRegex: boolean;
|
||||
matchWholeWords: boolean;
|
||||
caseSensitive: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* RAG trigger - activates based on vector similarity
|
||||
*/
|
||||
export interface RagTrigger {
|
||||
enabled: boolean;
|
||||
databaseName: string; // Associated database/collection name
|
||||
threshold?: number; // Similarity threshold (0-1)
|
||||
topK?: number; // Number of similar entries to retrieve
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable trigger - activates based on variable comparison
|
||||
*/
|
||||
export interface VariableTrigger {
|
||||
enabled: boolean;
|
||||
variableA: string;
|
||||
operator: ComparisonOperator;
|
||||
variableB?: string; // Can be variable or constant
|
||||
constantA?: any; // Alternative to variableB
|
||||
}
|
||||
|
||||
export enum ComparisonOperator {
|
||||
GREATER_THAN = '>',
|
||||
LESS_THAN = '<',
|
||||
EQUALS = '=',
|
||||
CONTAINS = 'contains',
|
||||
NOT_GREATER_THAN = '<=',
|
||||
NOT_LESS_THAN = '>=',
|
||||
NOT_EQUALS = '!='
|
||||
}
|
||||
|
||||
export interface WorldInfoMetadata {
|
||||
entryCount: number;
|
||||
categories: string[];
|
||||
tags: string[];
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Shared Types - Main Export File
|
||||
* Import from this file in your application
|
||||
*/
|
||||
|
||||
// ============================================
|
||||
// SillyTavern Original Formats (Compatibility Layer)
|
||||
// ============================================
|
||||
export * from './sillytavern/character.types';
|
||||
export * from './sillytavern/chat.types';
|
||||
export * from './sillytavern/world.types';
|
||||
export * from './sillytavern/preset.types';
|
||||
|
||||
// ============================================
|
||||
// Extended Data (Your Custom Additions)
|
||||
// ============================================
|
||||
export * from './extended/chat-ext.types';
|
||||
export * from './extended/preset-ext.types';
|
||||
export * from './extended/world-ext.types';
|
||||
|
||||
// ============================================
|
||||
// Import/Export Adapters
|
||||
// ============================================
|
||||
export * from './adapters/import-export.types';
|
||||
|
||||
// ============================================
|
||||
// Common Types
|
||||
// ============================================
|
||||
export * from './common.types';
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* SillyTavern Character Card V2 Specification
|
||||
* Reference: https://github.com/malfoyslastname/character-card-spec-v2
|
||||
*/
|
||||
|
||||
export interface STCharacterCardV2 {
|
||||
spec: 'chara_card_v2';
|
||||
spec_version: '2.0';
|
||||
data: STCharacterData;
|
||||
}
|
||||
|
||||
export interface STCharacterData {
|
||||
// Core fields
|
||||
name: string;
|
||||
description: string;
|
||||
personality: string;
|
||||
scenario: string;
|
||||
first_mes: string;
|
||||
mes_example: string;
|
||||
|
||||
// Optional fields
|
||||
creator_notes?: string;
|
||||
system_prompt?: string;
|
||||
post_history_instructions?: string;
|
||||
alternate_greetings?: string[];
|
||||
tags?: string[];
|
||||
creator?: string;
|
||||
character_version?: string;
|
||||
|
||||
// Character Book (World Info)
|
||||
character_book?: STCharacterBook;
|
||||
|
||||
// Extensions
|
||||
extensions?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface STCharacterBook {
|
||||
entries: STWorldInfoEntry[];
|
||||
extensions?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface STWorldInfoEntry {
|
||||
id?: number;
|
||||
keys: string[];
|
||||
keysecondary?: string[];
|
||||
content: string;
|
||||
comment?: string;
|
||||
constant: boolean;
|
||||
constantRule?: 'none' | 'always' | 'position';
|
||||
selective: boolean;
|
||||
order: number;
|
||||
insertion_order?: number;
|
||||
position: 'before_char' | 'after_char';
|
||||
use_regex: boolean;
|
||||
match_whole_words?: boolean;
|
||||
case_sensitive?: boolean;
|
||||
useProbability?: boolean;
|
||||
probability?: number;
|
||||
depth?: number;
|
||||
scan_depth?: number;
|
||||
group?: string;
|
||||
group_override?: boolean;
|
||||
group_weight?: number;
|
||||
prevent_recursion?: boolean;
|
||||
delay_until_recursion?: boolean;
|
||||
display_index?: number;
|
||||
enabled: boolean;
|
||||
exclude_from_banbook?: boolean;
|
||||
linked_entries?: number[];
|
||||
search_range?: 'both' | 'user' | 'assistant';
|
||||
role?: number;
|
||||
vectorized?: boolean;
|
||||
sticky?: boolean;
|
||||
cooldown?: number;
|
||||
delay?: number;
|
||||
automation_id?: string;
|
||||
title?: string;
|
||||
display_title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* V1 Character Card (Legacy)
|
||||
*/
|
||||
export interface STCharacterCardV1 {
|
||||
name: string;
|
||||
context: string;
|
||||
greeting: string;
|
||||
examples: string;
|
||||
author: string;
|
||||
first_mes: string;
|
||||
avatar: string;
|
||||
chat: string;
|
||||
mes_example: string;
|
||||
description: string;
|
||||
personality: string;
|
||||
scenario: string;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* SillyTavern Chat History Format (JSONL)
|
||||
* Each line is a JSON object representing a message or metadata
|
||||
*/
|
||||
|
||||
/**
|
||||
* Chat Metadata (First line of JSONL file)
|
||||
*/
|
||||
export interface STChatMetadata {
|
||||
user_name: string;
|
||||
character_name: string;
|
||||
create_date: string; // ISO 8601 format
|
||||
chat_metadata?: {
|
||||
integrity?: string; // SHA256 hash for integrity check
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Chat Message (Subsequent lines in JSONL file)
|
||||
*/
|
||||
export interface STChatMessage {
|
||||
name: string;
|
||||
is_user: boolean;
|
||||
send_date: number; // Unix timestamp
|
||||
mes: string; // Message content
|
||||
|
||||
// Optional fields
|
||||
force_avatar?: string;
|
||||
extra?: STMessageExtra;
|
||||
is_system?: boolean;
|
||||
}
|
||||
|
||||
export interface STMessageExtra {
|
||||
gen_id?: number;
|
||||
send_date?: number;
|
||||
swipes?: string[]; // Alternative responses
|
||||
swipe_id?: number;
|
||||
continueHistory?: boolean;
|
||||
continueSwipeId?: number;
|
||||
dryReason?: string;
|
||||
abuse?: boolean;
|
||||
rollbackChecked?: boolean;
|
||||
prompt?: any;
|
||||
memory?: any;
|
||||
notes?: string;
|
||||
bias?: any[];
|
||||
display_text?: string;
|
||||
model?: string;
|
||||
model_params?: any;
|
||||
persona_description?: string;
|
||||
attachments?: STAttachment[];
|
||||
reasoning?: string; // Chain of thought / reasoning
|
||||
image?: string; // Base64 or path
|
||||
audio?: string; // Base64 or path
|
||||
}
|
||||
|
||||
export interface STAttachment {
|
||||
type: 'image' | 'file' | 'audio';
|
||||
path: string;
|
||||
preview?: string;
|
||||
name?: string;
|
||||
size?: number;
|
||||
mime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete Chat Session
|
||||
*/
|
||||
export interface STChatSession {
|
||||
metadata: STChatMetadata;
|
||||
messages: STChatMessage[];
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/**
|
||||
* SillyTavern Preset Format
|
||||
*/
|
||||
|
||||
export interface STPreset {
|
||||
name: string;
|
||||
|
||||
// Core sampling parameters
|
||||
temp?: number; // Temperature
|
||||
rep_pen?: number; // Repetition penalty
|
||||
rep_pen_range?: number;
|
||||
top_p?: number;
|
||||
top_k?: number;
|
||||
top_a?: number;
|
||||
min_p?: number;
|
||||
typical?: number;
|
||||
tfs?: number;
|
||||
epsilon_cutoff?: number;
|
||||
eta_cutoff?: number;
|
||||
|
||||
// Advanced parameters
|
||||
rep_pen_slope?: number;
|
||||
guidance_scale?: number;
|
||||
negative_prompt?: string;
|
||||
penalty_alpha?: number;
|
||||
num_beams?: number;
|
||||
length_penalty?: number;
|
||||
no_repeat_ngram_size?: number;
|
||||
encoder_rep_pen?: number;
|
||||
freq_pen?: number; // Frequency penalty
|
||||
presence_pen?: number; // Presence penalty
|
||||
|
||||
// Sampling options
|
||||
do_sample?: boolean;
|
||||
early_stopping?: boolean;
|
||||
|
||||
// Dynamic temperature
|
||||
dynatemp?: boolean;
|
||||
dynatemp_range?: number;
|
||||
dynatemp_exponent?: number;
|
||||
|
||||
// Smoothing
|
||||
smoothing_factor?: number;
|
||||
smoothing_curve?: number;
|
||||
|
||||
// DRY (Don't Repeat Yourself)
|
||||
dry_allowed_length?: number;
|
||||
dry_multiplier?: number;
|
||||
dry_base?: number;
|
||||
dry_sequence_breakers?: string[];
|
||||
dry_penalty_last_n?: number;
|
||||
|
||||
// Token settings
|
||||
add_bos_token?: boolean;
|
||||
ban_eos_token?: boolean;
|
||||
skip_special_tokens?: boolean;
|
||||
|
||||
// Mirostat
|
||||
mirostat_mode?: number;
|
||||
mirostat_tau?: number;
|
||||
mirostat_eta?: number;
|
||||
|
||||
// Grammar
|
||||
grammar_string?: string;
|
||||
json_schema?: any;
|
||||
|
||||
// Model specific
|
||||
model?: string;
|
||||
sampler_priority?: string[];
|
||||
sampler_order?: number[];
|
||||
use_default_badwordsids?: boolean;
|
||||
seed?: number;
|
||||
|
||||
// Context
|
||||
maxContextTokens?: number;
|
||||
streaming?: boolean;
|
||||
|
||||
// Metadata
|
||||
description?: string;
|
||||
created_at?: number;
|
||||
updated_at?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preset Entry (for ordered list in preset configuration)
|
||||
*/
|
||||
export interface STPresetEntry {
|
||||
name: string;
|
||||
context: string; // Content/prompt
|
||||
position: 'before_char' | 'after_char' | 'system' | 'history' | 'user_input';
|
||||
order: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick Preset (Simplified format)
|
||||
*/
|
||||
export interface STQuickPreset {
|
||||
name: string;
|
||||
settings: Partial<STPreset>;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* SillyTavern World Info (Lorebook) Format
|
||||
*/
|
||||
|
||||
export interface STWorldInfo {
|
||||
name: string;
|
||||
description?: string;
|
||||
entries: STWorldInfoEntry[];
|
||||
metadata?: STWorldInfoMetadata;
|
||||
}
|
||||
|
||||
export interface STWorldInfoEntry {
|
||||
uid?: number;
|
||||
key: string[]; // Trigger keywords
|
||||
keysecondary?: string[]; // Secondary triggers
|
||||
comment?: string;
|
||||
content: string; // Lore content
|
||||
constant: boolean; // Always active
|
||||
constantRule?: 'none' | 'always' | 'position';
|
||||
selective: boolean; // Use secondary keys
|
||||
order: number; // Insertion order
|
||||
position: 'before_char' | 'after_char'; // Insertion position
|
||||
use_regex: boolean;
|
||||
match_whole_words?: boolean;
|
||||
case_sensitive?: boolean;
|
||||
useProbability?: boolean;
|
||||
probability?: number;
|
||||
depth?: number; // Scan depth (how many messages to scan)
|
||||
scan_depth?: number;
|
||||
group?: string;
|
||||
group_override?: boolean;
|
||||
group_weight?: number;
|
||||
prevent_recursion?: boolean;
|
||||
delay_until_recursion?: boolean;
|
||||
display_index?: number;
|
||||
enabled: boolean;
|
||||
exclude_from_banbook?: boolean;
|
||||
linked_entries?: number[];
|
||||
search_range?: 'both' | 'user' | 'assistant';
|
||||
role?: number;
|
||||
vectorized?: boolean; // RAG support
|
||||
sticky?: boolean;
|
||||
cooldown?: number;
|
||||
delay?: number;
|
||||
automation_id?: string;
|
||||
title?: string;
|
||||
display_title?: string;
|
||||
}
|
||||
|
||||
export interface STWorldInfoMetadata {
|
||||
created_at?: number;
|
||||
updated_at?: number;
|
||||
version?: string;
|
||||
source?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user