summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan.goodliffe@octal.co.uk>2026-06-19 17:38:47 +0100
committerDan Goodliffe <dan.goodliffe@octal.co.uk>2026-06-19 17:41:01 +0100
commit717e3ccc16c197ce578cf60e9517dfba0789b7a1 (patch)
tree2f0b238a95c0e372b1b0479bdacca20e0d75e3de
parentImprove the handling of the dismissal process (diff)
downloadtoy-717e3ccc16c197ce578cf60e9517dfba0789b7a1.zip
Replace the tag based image selector with a caption based one
In most places. Images are selected now by passing the LLM a list of photo captions and the words spoken, and asking it which image best fits the sentiment.
-rw-r--r--images/toy/ancilla/corset/set.json21
-rw-r--r--images/toy/ancilla/corset/tags16
-rw-r--r--images/toy/ancilla/crop/set.json21
-rw-r--r--images/toy/ancilla/crop/tags16
-rw-r--r--images/toy/ancilla/dress/set.json20
-rw-r--r--images/toy/ancilla/dress/tags15
-rw-r--r--images/toy/ancilla/pink/set.json20
-rw-r--r--images/toy/ancilla/pink/tags15
-rw-r--r--scripts/toy.groovy27
-rw-r--r--scripts/toy/imagery.groovy42
-rw-r--r--scripts/toy/intro.groovy6
-rw-r--r--scripts/toy/llmSession.groovy1
12 files changed, 122 insertions, 98 deletions
diff --git a/images/toy/ancilla/corset/set.json b/images/toy/ancilla/corset/set.json
new file mode 100644
index 0000000..8748ebc
--- /dev/null
+++ b/images/toy/ancilla/corset/set.json
@@ -0,0 +1,21 @@
+{
+ "promptSet": "You are dressed in an elegant red dress with a black waist cinching corset over the top, black stockings and high heels, and an elaborate pearl necklace. Your long blonde hair flows freely.",
+ "captions": {
+ "1": "You are standing, both hands behind your head",
+ "2": "You are standing, turned to the side, smiling, one hand playing with your necklace",
+ "3": "You are standing, legs apart, pulling down the bottom of your dress",
+ "4": "You are standing, one hand playing with your necklace, with a determined expression on your face",
+ "5": "You are standing, smiling, one hand playing with your necklace",
+ "6": "You are standing, turned, one leg partly raised, almost cowering",
+ "7": "You are standing, your corset removed and you are pulling your dress down to show off your bra",
+ "8": "You are standing, your corset removed and turned away, your ass partly showing below your dress, your hands in your hair",
+ "9": "You are standing, squeezing your breasts between both hands",
+ "10": "You are standing, squeezing your breasts between both hands and leaning forward",
+ "11": "You are standing, your corset removed and your dress pulled down showing off your nipples",
+ "12": "You are kneeling, your corset removed, your dress off your shoulders and your nipples showing just over your bra",
+ "13": "You are kneeling in only your underwear, you nipples showing over your bra",
+ "14": "You are kneeling in only your underwear, you nipples showing over your bra, your back arched",
+ "15": "You are sitting in only your underwear, you nipples showing over your bra, you are looking ponderous",
+ "16": "You are standing in only your panties, and grater, one arm across your chest, the other playing with your necklace"
+ }
+}
diff --git a/images/toy/ancilla/corset/tags b/images/toy/ancilla/corset/tags
deleted file mode 100644
index 2805a84..0000000
--- a/images/toy/ancilla/corset/tags
+++ /dev/null
@@ -1,16 +0,0 @@
-1:dressed,stood
-2:dressed,stood
-3:dressed,stood
-4:dressed,stood
-5:dressed,stood
-6:dressed,stood
-7:dressed,stood,tease
-8:dressed,stood,ass
-9:dressed,stood,tease
-10:dressed,stood,tease
-11:kneel,tits
-12:kneel,tits,ass
-13:kneel,tits,lingerie
-14:kneel,tits,lingerie
-15:sit,tits,lingerie
-16:stood,tits,lingerie
diff --git a/images/toy/ancilla/crop/set.json b/images/toy/ancilla/crop/set.json
new file mode 100644
index 0000000..e051c99
--- /dev/null
+++ b/images/toy/ancilla/crop/set.json
@@ -0,0 +1,21 @@
+{
+ "promptSet": "You are dressed ready to inflict pain in a black latex corset top and matching skirt, black elbow-length lace gloves, black stockings and pink high heeled shoes. Your long blonde hair trails freely.",
+ "captions": {
+ "1": "You are topless, kneeling, with your finger over your mouthing shushing",
+ "2": "You are topless on all fours, squeezing your breasts between your arms and have a red crop held in your mouth",
+ "3": "You are sitting topless, your breasts on full show and have a red crop held in your mouth",
+ "4": "You are topless, kneeling, squeezing your breasts between your arms",
+ "5": "You are standing topless, your breasts on full show and your skirt removed showing off your pussy",
+ "6": "You are kneeling topless, your breasts on full show and your skirt removed showing off your pussy",
+ "7": "You are kneeling topless, your breasts on full show and your skirt removed hiding your pussy with your hands",
+ "8": "You are standing, one hand behind you head, the other holding a red crop, your eyes partly closed",
+ "9": "You are standing, one hand behind you head, the other holding a red crop",
+ "10": "You are standing, a red crop in your hand ready to strike",
+ "11": "You are standing, a red crop in your hand ready to suggestively. Your back is turned, showing off your latex clad ass",
+ "12": "You are standing, a red crop in your hand ready to strike",
+ "13": "You are standing in a commanding position, a red crop in your hand",
+ "14": "You are sitting, red crop in hand, looking down on your subject",
+ "15": "You are sitting topless, your breasts on full show with an expectant expression",
+ "16": "You are topless, your breasts on full show, your arms are folded"
+ }
+}
diff --git a/images/toy/ancilla/crop/tags b/images/toy/ancilla/crop/tags
deleted file mode 100644
index fb461f0..0000000
--- a/images/toy/ancilla/crop/tags
+++ /dev/null
@@ -1,16 +0,0 @@
-1:tits,kneel,sssh
-2:tits,kneel,mean,crop
-3:tits,kneel,crop
-4:tease,kneel
-5:stood,tits
-6:kneel,tits
-7:kneel,tits
-8:dressed,stood,crop
-9:dressed,stood,crop
-10:dressed,stood,crop,tease
-11:dressed,stood,crop,tease
-12:dressed,stood,crop
-13:dressed,stood,crop
-14:dressed,sit,crop,tease
-15:tits,sit
-16:tits,stood
diff --git a/images/toy/ancilla/dress/set.json b/images/toy/ancilla/dress/set.json
new file mode 100644
index 0000000..acf4263
--- /dev/null
+++ b/images/toy/ancilla/dress/set.json
@@ -0,0 +1,20 @@
+{
+ "promptSet": "You are in the living room by the marble fireplace. You are wearing a black latex zip-up dress and matching stockings, high heels and fingerless gloves. You long blonde hair is tied in pigtails. Your makeup and expression is stern.",
+ "captions": {
+ "1": "You've partly unzipped your dress revealing your breasts with a sultry expression, your legs spread",
+ "2": "You've completed unzipped your dress revealing your breasts and panties with a playful smirk",
+ "3": "You've removed your dress entirely and are sat, legs spread and topless with an expression of pleasure",
+ "4": "You've removed your dress and are sat topless, turned to the side, your panties pulled to your ankles",
+ "5": "You've removed your dress and panties and have adopted a topless, vulnerable and suggestive pose",
+ "6": "You've removed your dress and panties and turned you back, showing off your bare ass",
+ "7": "You're stood fully dressed, your hands playing with your hair",
+ "8": "You're stood fully dressed, bent over very slightly",
+ "9": "You're stood fully dressed, leaning on the mantelpiece, your back is turned and ass partly revealed under your dress",
+ "10": "You're stood fully dressed, your legs apart, your back is turned and ass partly revealed under your dress and your heels clearly visible",
+ "11": "You're squatting, with your legs spread wide showing off your panties",
+ "12": "You're stood with your dress partly unzipped, partly showing your breasts. Your hands are cupping your breasts",
+ "13": "You're stood with your dress partly unzipped, partly showing your breasts. One hand cups your breast, the other is playing with your hair",
+ "14": "You're stood with your dress partly unzipped, with one hand pulling it open, revealing your breasts completely, the other hand on your hip",
+ "15": "You're stood with your dress partly unzipped, with one hand pulling it open, revealing your breasts completely, the other hand playing with your hair"
+ }
+}
diff --git a/images/toy/ancilla/dress/tags b/images/toy/ancilla/dress/tags
deleted file mode 100644
index 7cb90ed..0000000
--- a/images/toy/ancilla/dress/tags
+++ /dev/null
@@ -1,15 +0,0 @@
-1:tits,stood
-2:tits,stood
-3:tits,sit
-4:tits,sit
-5:tits,stood
-6:tits,stood,ass
-7:dressed,stood
-8:dressed,stood
-9:dressed,stood,ass
-10:dressed,stood,ass
-11:dressed,squat
-12:dressed,stood,tease
-13:dressed,stood,tease
-14:tits,stood
-15:tits,stood
diff --git a/images/toy/ancilla/pink/set.json b/images/toy/ancilla/pink/set.json
new file mode 100644
index 0000000..bbe79d4
--- /dev/null
+++ b/images/toy/ancilla/pink/set.json
@@ -0,0 +1,20 @@
+{
+ "promptSet": "You are in your bedroom. You are wearing light lingerie. If it is late evening then you are only interested in your own physical pleasure.",
+ "captions": {
+ "1": "You are kneeling topless on your bed, your arms folded below your breasts",
+ "2": "You are kneeling topless on your bed, legs spread, one arm across your chest, one hand playing with your necklace",
+ "3": "You are kneeling topless on your bed, one hand in your panties",
+ "4": "You are kneeling topless on your bed, one hand in your panties",
+ "5": "You are kneeling topless on your bed, one hand in teasing the top of your panties, the other on your breast",
+ "6": "You are kneeling topless on your bed, your hands playing with your necklace",
+ "7": "You are fully clothed, light lingerie with your blouse off your shoulders",
+ "8": "You are fully clothed, light lingerie with your hands reaching behind your head",
+ "9": "You are fully clothed, light lingerie with your blouse off your shoulders",
+ "10": "You are fully clothed, light lingerie with your blouse off your shoulders",
+ "11": "You are fully clothed, light lingerie with one hand reaching behind your head",
+ "12": "You are kneeling on your bed, your lingerie removed, in just a bra and panties, your arms folded below your breasts",
+ "13": "You are kneeling on your bed, your lingerie removed, you have unfasten your bra and are holding in front of you, your breasts clearly visible",
+ "14": "You are kneeling topless on your bed, one hand playing with your necklace",
+ "15": "You are kneeling topless on your bed, one hand playing with your necklace"
+ }
+}
diff --git a/images/toy/ancilla/pink/tags b/images/toy/ancilla/pink/tags
deleted file mode 100644
index 1a3786d..0000000
--- a/images/toy/ancilla/pink/tags
+++ /dev/null
@@ -1,15 +0,0 @@
-1:tits,kneel,lingerie
-2:tits,kneel,lingerie
-3:tits,kneel,lingerie
-4:tits,kneel,lingerie
-5:tits,kneel,lingerie
-6:tits,kneel
-7:dressed,kneel
-8:dressed,stood
-9:dressed,stood
-10:dressed,stood,tease
-11:dressed,stood,tease
-12:kneel,lingerie
-13:tits,kneel,lingerie
-14:tits,kneel,lingerie
-15:tits,kneel,lingerie
diff --git a/scripts/toy.groovy b/scripts/toy.groovy
index 8b21069..e21f2c8 100644
--- a/scripts/toy.groovy
+++ b/scripts/toy.groovy
@@ -50,7 +50,11 @@ return new Object() {
final getDomme = { domme, set = null ->
def d = parseJsonFile("images/toy/$domme/person.json");
+ if (new File("images/toy/$domme/$set/set.json").exists()) {
+ d += parseJsonFile("images/toy/$domme/$set/set.json");
+ }
d.id = domme;
+ d.set = set;
return d;
};
final loadDomme = { domme, set = null ->
@@ -241,8 +245,8 @@ return new Object() {
return null;
};
final llmPresent = { text ->
+ final image = showImageForText(text);
show(text);
- def image = showImage(callAPI_imageMatch(text));
return [
message: text,
image: image
@@ -430,6 +434,7 @@ Speak in the first person only.
Forbidden from using quotes.
You are permanently in role-play mode as ${DOMME.title} ${DOMME.fullName}.
${DOMME.prompt}
+${DOMME.promptSet?:""}
${loadString("intro.name")} is your slave.
${extra.join('\n')}
${eachModule("systemPrompt").findAll().join('\n')};
@@ -446,24 +451,6 @@ ${eachModule("userIntroPrompt").findAll().join('\n')};
return messages;
}
- final callAPI_imageMatch = { message ->
- def tags = [DRESSED, TITS, PUSSY, LINGERIE, TEASE, SIT, BOOTS, KNEEL, STOOD, MEAN, CROP, ASS, SQUAT, SSSH];
- def request = chatInitialMessages();
- request += [role: "assistant", content: message]
- request += [role: "user", content: """
-Write only a JSON object.
-Complete the following JSON object, scoring each keyword between -10 and 10 against the previous messsage:
-{
- ${ tags.collect { tag -> "\"$tag\": number" }.join(',\n') }
-}
- """ ];
- return parseJsonString(callAPI("chat/completions", [
- model: loadString("toy.chatModel"),
- stop: "<",
- messages: request
- ])?.choices?[0]?.message?.content);
- }
-
String main()
{
// GO!
@@ -472,7 +459,7 @@ Complete the following JSON object, scoring each keyword between -10 and 10 agai
setDefault("toy.chatModel", "Lewdiculous/Erosumika-7B-v3-0.2-GGUF-IQ-Imatrix:IMAT");
OWNER = loadString("toy.owner");
- loadDomme(OWNER);
+ loadDomme(OWNER, loadString("toy.owner.outfit"));
modules = loadModules(this);
execEvents(false);
eachModule("setup");
diff --git a/scripts/toy/imagery.groovy b/scripts/toy/imagery.groovy
index af4e9e7..18113cc 100644
--- a/scripts/toy/imagery.groovy
+++ b/scripts/toy/imagery.groovy
@@ -8,22 +8,12 @@
domme: d.getName(),
sets: d.listFiles()
.findAll { s -> s.isDirectory(); }
- .collect { s -> [ sub: s, f: new File(s.getPath() + "/tags")] }
+ .collect { s -> [ sub: s, f: new File(s.getPath() + "/set.json")] }
.findAll { s -> s.f.canRead() }
.collectEntries { s -> [
s.sub.getName(), [
set: s.sub.getName(),
- images: s.f
- .readLines()
- .collect { l ->
- def fields = l.split(":");
- return [
- image: fields[0],
- tags: fields[1]
- .split(",")
- .findAll { t -> !t.isEmpty() }
- ];
- }
+ images: new groovy.json.JsonSlurper().parse(s.f).captions
]
]}
]
@@ -47,6 +37,34 @@
return matches[getRandom(matches.size())].image;
};
+ toy.metaClass.showImageForText { text ->
+ final captionList = DOMME.captions.collect{ id, caption -> "* ${id} : ${caption}" }.join("\n");
+ final request = [
+ model: loadString("toy.chatModel"),
+ grammar: "root ::= ( ${DOMME.captions.keySet().collect{ id -> "\"${id}\"" }.join(" | ")} )",
+ messages: [
+ [role: "system", content: """
+You are ${DOMME.title} ${DOMME.fullName}.
+${DOMME.prompt}
+${DOMME.promptSet?:""}
+Given a list of images with captions and some spoken words, you select the image which best captures the sentiments of the words.
+The available images are:
+${captionList}"""
+ ],
+ [role: "user", content: "Write only an image Id from the list as an unformatted string, select an image for the text: ${text}"]
+ ]
+ ];
+ while (true) {
+ final imageName = callAPI("chat/completions", request)?.choices?[0]?.message?.content;
+ if (DOMME.captions[imageName]) {
+ setImage("toy/${DOMME.id}/${DOMME.set}/${imageName}.jpg");
+ return imageName;
+ }
+ showPopup("Given:\n${requestMessages}\n\nGot: ${imageName}");
+ }
+ return null;
+ }
+
toy.metaClass.showImage { spec ->
def outfit = loadString("toy.owner.outfit");
def image = selectImage(DOMME.id, outfit, spec);
diff --git a/scripts/toy/intro.groovy b/scripts/toy/intro.groovy
index 3e719cc..bfe8b68 100644
--- a/scripts/toy/intro.groovy
+++ b/scripts/toy/intro.groovy
@@ -10,10 +10,8 @@
showButton("OK");
// Welcome
- def defaultImageSpec = [ "${DRESSED}": 10, "${TEASE}": 5 ];
- dress(defaultImageSpec);
- showImage(defaultImageSpec);
- show("...");
+ dress([]);
+ llmPresent("...");
def messages = chatInitialMessages();
messages += [role: "user", content: "I am ${loadString("intro.name")}. Please briefly introduce yourself."];
diff --git a/scripts/toy/llmSession.groovy b/scripts/toy/llmSession.groovy
index f140d75..2689cdf 100644
--- a/scripts/toy/llmSession.groovy
+++ b/scripts/toy/llmSession.groovy
@@ -27,6 +27,7 @@
playSchedule();
return;
}
+ dress([]);
def messages = chatInitialMessages("You want to play with ${loadString("intro.name")}. You can dismiss ${loadString("intro.name")} when you wish by writing \"DISMISSED.\" only.");
if (summon(messages)) {
while (!messages.last().content.toUpperCase().startsWith("DISMISSED") && !messages.last().content.toUpperCase().contains("YOU ARE DISMISSED")) {