jest issue. about to try to fix https://github.com/nanostores/nanostores/issues/210
This commit is contained in:
106
src/lib/prompt.test.ts
Normal file
106
src/lib/prompt.test.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { randomUUID } from "crypto";
|
||||
import { Op } from "./operator";
|
||||
import {
|
||||
Library as LibraryType,
|
||||
Composition as CompositionType,
|
||||
$library,
|
||||
addItemToLibrary,
|
||||
removeItemFromLibrary,
|
||||
$composition,
|
||||
insertIntoComposition,
|
||||
Category,
|
||||
removeFromComposition,
|
||||
increaseNuggetScore,
|
||||
decreaseNuggetScore, changeOperationOp, nuggetToText, operationToText, textComposition,
|
||||
$slottedComposition,
|
||||
Operation,
|
||||
Nugget,
|
||||
} from "./prompt";
|
||||
|
||||
const mockLibrary: LibraryType = [
|
||||
{ id: randomUUID(), name: "Name1", prompt: "Prompt1", category: Category.subject },
|
||||
{ id: randomUUID(), name: "Name2", prompt: "Prompt2", category: Category.style },
|
||||
{ id: randomUUID(), name: "Name3", prompt: "Prompt3", category: Category.vibes },
|
||||
{ id: randomUUID(), name: "Name4", prompt: "Prompt4", category: Category.medium },
|
||||
];
|
||||
|
||||
const mockComposition: CompositionType = [
|
||||
{ id: randomUUID(), item: mockLibrary[0], score: 0 },
|
||||
{ id: randomUUID(), item: mockLibrary[1], score: 0 },
|
||||
{ id: randomUUID(), item: mockLibrary[2], score: 0 },
|
||||
{ id: randomUUID(), item: mockLibrary[3], score: 0 },
|
||||
{
|
||||
id: randomUUID(), op: Op.AND, items: [
|
||||
{ id: randomUUID(), item: mockLibrary[0], score: 0 },
|
||||
{ id: randomUUID(), item: mockLibrary[1], score: 0 },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
beforeAll(() => {
|
||||
mockLibrary.forEach(item => {
|
||||
addItemToLibrary(item);
|
||||
insertIntoComposition(item);
|
||||
});
|
||||
});
|
||||
|
||||
test("addItemToLibrary", () => {
|
||||
addItemToLibrary({ id: randomUUID(), name: "Name5", prompt: "Prompt5", category: Category.subject });
|
||||
expect($library.get().length).toBe(5);
|
||||
});
|
||||
|
||||
test("removeItemFromLibrary", () => {
|
||||
removeItemFromLibrary(mockLibrary[0]);
|
||||
expect($library.get().length).toBe(3);
|
||||
});
|
||||
|
||||
test("insertIntoComposition", () => {
|
||||
insertIntoComposition(mockLibrary[3]);
|
||||
expect($composition.get().length).toBe(5);
|
||||
});
|
||||
|
||||
test("removeFromComposition", () => {
|
||||
removeFromComposition(mockComposition[0]);
|
||||
expect($composition.get().length).toBe(4);
|
||||
});
|
||||
|
||||
test("increaseNuggetScore", () => {
|
||||
increaseNuggetScore(mockComposition[0].id, 2);
|
||||
expect((mockComposition[0] as Nugget).score).toBe(2);
|
||||
});
|
||||
|
||||
test("decreaseNuggetScore", () => {
|
||||
decreaseNuggetScore(mockComposition[0].id, 2);
|
||||
expect((mockComposition[0] as Nugget).score).toBe(-2);
|
||||
});
|
||||
|
||||
test("changeOperationOp", () => {
|
||||
changeOperationOp(mockComposition[4].id, Op.AND);
|
||||
expect((mockComposition[4] as Operation).op).toBe(Op.AND);
|
||||
});
|
||||
|
||||
test("nuggetToText", () => {
|
||||
expect(nuggetToText({ id: randomUUID(), item: mockLibrary[0], score: 0 })).toBe("(Prompt1)");
|
||||
});
|
||||
|
||||
test("operationToText", () => {
|
||||
expect(operationToText({
|
||||
id: randomUUID(), op: Op.AND, items: [
|
||||
{ id: randomUUID(), item: mockLibrary[0], score: 0 },
|
||||
{ id: randomUUID(), item: mockLibrary[1], score: 0 },
|
||||
]
|
||||
})).toBe("(Prompt1, Prompt2).concat()");
|
||||
});
|
||||
|
||||
test("textComposition", () => {
|
||||
expect(textComposition).toBe("(Prompt1)(Prompt2)(Prompt3)(Prompt4)(Prompt1, Prompt2).concat()");
|
||||
});
|
||||
|
||||
test("$slottedComposition", () => {
|
||||
expect($slottedComposition).toEqual([
|
||||
[mockComposition[0], mockComposition[1], mockComposition[2], mockComposition[3]],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
]);
|
||||
});
|
@ -1,113 +0,0 @@
|
||||
import { nSQL } from "@nano-sql/core";
|
||||
import { Op } from "./operator";
|
||||
import { RocksDB } from "@nano-sql/adapter-rocksdb";
|
||||
import tables from "./schema.json";
|
||||
import { uuid } from "@nano-sql/core/lib/utilities";
|
||||
|
||||
type Id = string;
|
||||
|
||||
type IdAble = {
|
||||
id: Id,
|
||||
}
|
||||
|
||||
export enum Category {
|
||||
subject = "subject",
|
||||
style = "style",
|
||||
vibes = "vibes",
|
||||
medium = "medium",
|
||||
}
|
||||
|
||||
export type LibraryItem = {
|
||||
id: Id,
|
||||
name?: string,
|
||||
prompt: string,
|
||||
category: Category,
|
||||
}
|
||||
|
||||
export type Library = Array<LibraryItem>;
|
||||
|
||||
export type Nugget = IdAble & {
|
||||
item: LibraryItem,
|
||||
score: number,
|
||||
}
|
||||
|
||||
export type Operation = IdAble & {
|
||||
op: Op,
|
||||
items: Array<Nugget>
|
||||
}
|
||||
|
||||
export type PromptItem = Operation | Nugget
|
||||
|
||||
export type PromptArea = Array<PromptItem>;
|
||||
|
||||
export async function getDb() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// typical setup
|
||||
nSQL().createDatabase({
|
||||
id: "my_db", // can be anything that's a string
|
||||
mode: new RocksDB(),
|
||||
tables: [
|
||||
{
|
||||
"name": "library_item",
|
||||
"model": {
|
||||
"id:uuid": { "pk": true },
|
||||
"name:string": {},
|
||||
"prompt:string": { notNull: true },
|
||||
"category:string": { notNull: true, }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nugget",
|
||||
"model": {
|
||||
"id:uuid": { "pk": true },
|
||||
"library_item:uuid": {},
|
||||
"score:number": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "operation",
|
||||
"model": {
|
||||
"id:uuid": { pk: true },
|
||||
"op:string": {},
|
||||
"items:array": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "library",
|
||||
"model": {
|
||||
"item:uuid": {},
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prompt_area",
|
||||
"model": {
|
||||
"type:string": {notNull: true},
|
||||
"item:obj": {notNull: true},
|
||||
}
|
||||
}
|
||||
],
|
||||
version: 1, // current schema/database version
|
||||
onVersionUpdate: (prevVersion) => { // migrate versions
|
||||
return new Promise((res, rej) => {
|
||||
switch (prevVersion) {
|
||||
case 1:
|
||||
// migrate v1 to v2
|
||||
res(2);
|
||||
break;
|
||||
case 2:
|
||||
// migrate v2 to v3
|
||||
res(3);
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}).then((db) => {
|
||||
resolve(db)
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
})
|
||||
});
|
||||
|
||||
}
|
138
src/lib/prompt.tsx
Normal file
138
src/lib/prompt.tsx
Normal file
@ -0,0 +1,138 @@
|
||||
import { randomUUID } from "crypto";
|
||||
import { Op } from "./operator";
|
||||
import { atom, computed } from "nanostores";
|
||||
|
||||
type Id = string;
|
||||
|
||||
type IdAble = {
|
||||
id: Id,
|
||||
}
|
||||
|
||||
export enum Category {
|
||||
subject = "subject",
|
||||
style = "style",
|
||||
vibes = "vibes",
|
||||
medium = "medium",
|
||||
}
|
||||
|
||||
const N_CATEGORIES = Object.keys(Category).length;
|
||||
|
||||
export function catI(c: Category | string): number {
|
||||
return Object.keys(Category).indexOf(c);
|
||||
}
|
||||
|
||||
export type LibraryItem = {
|
||||
id: Id,
|
||||
name?: string,
|
||||
prompt: string,
|
||||
category: Category,
|
||||
}
|
||||
|
||||
export type Library = Array<LibraryItem>;
|
||||
|
||||
export type Nugget = IdAble & {
|
||||
item: LibraryItem,
|
||||
score: number,
|
||||
}
|
||||
|
||||
export type Operation = IdAble & {
|
||||
op: Op,
|
||||
items: Array<Nugget>
|
||||
}
|
||||
|
||||
export type PromptItem = Operation | Nugget
|
||||
|
||||
export type Composition = Array<PromptItem>;
|
||||
|
||||
export const $library = atom<Library>([])
|
||||
|
||||
export function addItemToLibrary(item: LibraryItem) {
|
||||
$library.set([
|
||||
...$library.get(), item,
|
||||
]);
|
||||
}
|
||||
|
||||
export function removeItemFromLibrary(item: LibraryItem) {
|
||||
$library.set($library.get().filter(i => i.id != item.id));
|
||||
}
|
||||
|
||||
export const $composition = atom<Composition>([])
|
||||
|
||||
export function insertIntoComposition(item: LibraryItem) {
|
||||
$composition.set([
|
||||
...$composition.get(),
|
||||
{ id: randomUUID(), item, score: 0 } as Nugget,
|
||||
]);
|
||||
}
|
||||
|
||||
export function removeFromComposition(item: PromptItem) {
|
||||
$composition.set([
|
||||
...$composition.get().filter(i => i.id === item.id)
|
||||
]);
|
||||
}
|
||||
|
||||
export function increaseNuggetScore(nuggetId: Id, amount: number = 1) {
|
||||
$composition.set([
|
||||
...$composition.get().map(item => {
|
||||
return (item.id == nuggetId && "score" in item) ? { ...item, score: item.score + amount } : item;
|
||||
}
|
||||
),
|
||||
]);
|
||||
}
|
||||
export function decreaseNuggetScore(nuggetId: Id, amount: number = 1) {
|
||||
$composition.set([
|
||||
...$composition.get().map(item => {
|
||||
return (item.id == nuggetId && "score" in item) ? { ...item, score: item.score - amount } : item;
|
||||
}
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
export function changeOperationOp(operationId: Id, op: Op) {
|
||||
$composition.set([
|
||||
...$composition.get().map(item => {
|
||||
return (item.id == operationId) ? { ...item, op: op } : item;
|
||||
}
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
export function nuggetToText(nugget: Nugget) {
|
||||
const sign = (nugget.score > 0 ? '+' : (nugget.score < 0 ? '-' : ''))
|
||||
return "(" + nugget.item.prompt + ")" + (new Array(nugget.score)).map(i => sign).join("");
|
||||
}
|
||||
|
||||
export function operationToText(operation: Operation): string {
|
||||
return "(" + operation.items.map(nuggetToText).join(", ") + ")." + operation.op + "()";
|
||||
}
|
||||
|
||||
export const textComposition = computed($composition, (composition) => {
|
||||
const JOINER = ", ";
|
||||
composition.map(item => {
|
||||
return "op" in item ? operationToText(item) : nuggetToText(item);
|
||||
}).join(JOINER);
|
||||
});
|
||||
|
||||
export type SlottedComposition = PromptItem[][];
|
||||
|
||||
/**
|
||||
* This is necessary since a "composition" needs to have prompt items in
|
||||
* different columns.
|
||||
*
|
||||
* There are n columns (or slots) where n is the number of categories.
|
||||
*/
|
||||
export const $slottedComposition = computed($composition, (composition) => {
|
||||
const slotted = new Array(N_CATEGORIES) as SlottedComposition;
|
||||
composition.forEach(nugget => {
|
||||
if ("op" in nugget) {
|
||||
if (!nugget.items.length)
|
||||
return null;
|
||||
const cat = nugget.items[0].item.category;
|
||||
slotted[catI(cat)].push(nugget);
|
||||
} else {
|
||||
const cat = nugget.item.category;
|
||||
slotted[catI(cat)].push(nugget);
|
||||
}
|
||||
})
|
||||
return slotted;
|
||||
});
|
Reference in New Issue
Block a user