Compare commits

...

9 Commits

Author SHA1 Message Date
bf7a989b75 feat: gamer group chat 2025-05-01 00:46:44 +01:00
56eb1067d1 chore: add mod_wsgi, flask-cors packages 2025-05-01 00:46:44 +01:00
52259b64f7 chore: use older version of python
necessary for my crusty old debian 11 vps
2025-05-01 00:46:44 +01:00
a9845b9296 feat: win/loss conditions 2025-05-01 00:46:44 +01:00
5b1783a71e feat: split response and score generation 2025-05-01 00:46:44 +01:00
f4abc6dc90 feat: conversation history 2025-05-01 00:46:44 +01:00
a07e8b78c0 feat: update input style 2025-05-01 00:46:42 +01:00
e525120a15 feat: update input style 2025-05-01 00:44:46 +01:00
50a2f0ee69 style: imply speech bubbles 2025-04-26 21:08:26 +01:00
7 changed files with 963 additions and 142 deletions

40
ides-of-march-goty.json Normal file
View File

@ -0,0 +1,40 @@
{
"title": "raid: ides of march",
"interactive": false,
"characters": [
"mark antony",
"cassius",
"brutus",
"casca",
"decimus",
"trebonius"
],
"messages": [
{ "character": -1, "text": "cassius started the 'ides of march' squad" },
{ "character": -1, "text": "cassius invited brutus casca decimus trebonius and mark antony" },
{ "character": 1, "text": "yo its go time we needa lock this strat everyone ready for tmrw?" },
{ "character": 2, "text": "yeah gotta be tmrw no more stalling" },
{ "character": 3, "text": "we know the exact loc?" },
{ "character": 4, "text": "hes hitting the senate tmrw for sure i talked him into it even tho hes been kinda sus lately lol" },
{ "character": 5, "text": "nice gotta jump him before he knows whats up everyone clear on their job?" },
{ "character": 1, "text": "ill give the go signal brutus u hang back til the end makes it look legit or whatever" },
{ "character": 2, "text": "its not about looking good dude its about saving the guild" },
{ "character": 3, "text": "yeah yeah but gotta think about the optics ppl need to see why we did it" },
{ "character": 1, "text": "casca ur on first hit like we planned u good?" },
{ "character": 3, "text": "yep got this ez first blood" },
{ "character": 4, "text": "remember everyone committed no backing out now" },
{ "character": 5, "text": "what about mark antony hes always like caesars pocket healer" },
{ "character": 1, "text": "trebonius u got him keep him busy outside make sure he doesnt aggro" },
{ "character": 5, "text": "kk np" },
{ "character": 2, "text": "remember this isnt griefing its like balancing the server rome > one dude" },
{ "character": 3, "text": "right but tmrw gonna be a shitshow lol" },
{ "character": 4, "text": "we deal w the drama later just stick to the strat" },
{ "character": 1, "text": "tmrw at senate lets finish this op run" },
{ "character": 2, "text": "for rome" },
{ "character": 3, "text": "for the republic" },
{ "character": 5, "text": "for the future" },
{ "character": 0, "text": "uh guys?" },
{ "character": 1, "text": "shit" },
{ "character": -1, "text": "you have been kicked from 'ides of march'" }
]
}

View File

@ -3,6 +3,7 @@
<head>
<link rel="stylesheet" href="styles.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
@ -19,9 +20,11 @@
<p id="typing-indicator">NAME is typing...</p>
<div id="textbox">
<input id="textbox-input" class="rounded-rectangle" type="text" onkeydown="pressSendButton()"></input>
<button class="rounded-rectangle" onclick="pressSendButton()">send</button>
<div id="input-panel-container">
<div id="input-panel" class="rounded-rectangle">
<input id="textbox-input" type="text" onkeydown="pressSendButton()"></input>
<button onclick="pressSendButton()"><i class="fa fa-arrow-right" style="font-size:2em"></i></button>
</div>
</div>
</div>

70
main.js
View File

@ -7,10 +7,11 @@ class Conversation {
this.messages = [];
this.name = romanize(name);
this.score = 1.0;
this.countdown = 1;
}
setInteractive(isInteractive) {
const children = document.getElementById("textbox").children;
const children = document.getElementById("input-panel").children;
for (let i = 0; i < children.length; i++) {
children[i].disabled = !isInteractive;
}
@ -28,16 +29,18 @@ class Conversation {
const message = new UserMessage(text);
message.updateStatus("sent");
this.messages.push(message);
const url = 'http://192.168.1.115:5000/chat';
const data = text;
//const url = 'http://127.0.0.1:5000/chat';
const url = "http://ktyl.dev:5000/chat";
const data = JSON.stringify({messages:this.messages,endCondition:0});
fetch(url, {
method: 'POST', // Corresponds to -X POST
method: 'POST',
headers: {
'Content-Type': 'text/plain' // Corresponds to -H "Content-Type: text/plain"
'Content-Type': 'text/plain'
},
body: data // Corresponds to -d "..."
body: data
})
.then(response => {
// Check if the request was successful (status code 2xx)
@ -57,25 +60,33 @@ class Conversation {
console.log(json);
var score = parseFloat(json.score);
this.score += score;
console.log(this.score);
if (this.score > 2.0)
{
messageText = "shit they're here D:";
this.setInteractive(false);
}
else if (this.score < 0.0)
{
messageText = "shit u won :D";
this.setInteractive(false);
}
else
{
messageText = json.message;
}
//if (this.score > 2.0)
//{
// messageText = "shit they're here D:";
// this.setInteractive(false);
//}
//else if (this.score < 0.0)
//{
// messageText = "shit u won :D";
// //this.setInteractive(false);
//}
//else
//{
messageText = json.message;
//}
this.messages.push(new AgentMessage(messageText));
this.render();
setTimeout(() => {
if (score == 1) {
this.setInteractive(false);
alert("victory!");
} else if (score == -1) {
this.setInteractive(false);
alert("lose :(");
}
}, 2000);
})
.catch(error => {
// Handle any errors that occurred during the fetch
@ -91,7 +102,6 @@ class Conversation {
// this.render();
//}, 5000);
}, 1000);
this.messages.push(message);
}
// update the current HTML based on messages
@ -144,6 +154,10 @@ class AgentMessage {
constructor(text, senderName) {
this.text = text;
this.senderName = senderName;
// -1 invalid
// 0 player
// 1 cpu
this.player = 1;
}
getIsOurs() {
@ -177,6 +191,10 @@ class UserMessage {
constructor(text) {
this.createdTime = Date.now();
this.text = romanize(text);
// -1 invalid
// 0 player
// 1 cpu
this.player = 0;
this.status = "";
}
@ -213,6 +231,10 @@ class UserMessage {
class SystemMessage {
constructor(text) {
this.text = romanize(text);
// -1 invalid
// 0 player
// 1 cpu
this.player = -1;
}
getIsOurs() {
@ -411,7 +433,7 @@ function populateConversationList() {
const conversationFiles = [
"caesar.json",
"lucius.json",
"ides-of-march.json",
"ides-of-march-goty.json",
"lepidus.json",
"publius.json",
"sextus.json"
@ -426,5 +448,5 @@ function populateConversationList() {
setTypingIndicator(false);
populateConversationList();
showConversation("ides-of-march.json");
showConversation("ides-of-march-goty.json");

View File

@ -4,8 +4,12 @@ verify_ssl = true
name = "pypi"
[packages]
google-genai = "*"
flask = "*"
mod-wsgi = "*"
flask-cors = "*"
[dev-packages]
[requires]
python_version = "3.13"
python_version = "3.9"

595
srv/Pipfile.lock generated
View File

@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "494d5b4f482f0ef471f49afe28f00ec1a2ff75da2ce65060d8cabaeb3da2f100"
"sha256": "508dd3c122f5577fd75ff7c4ed0924650f245ec376c90bd89c918e86adab87a2"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.13"
"python_version": "3.9"
},
"sources": [
{
@ -15,6 +15,595 @@
}
]
},
"default": {},
"default": {
"annotated-types": {
"hashes": [
"sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53",
"sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"
],
"markers": "python_version >= '3.8'",
"version": "==0.7.0"
},
"anyio": {
"hashes": [
"sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028",
"sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"
],
"markers": "python_version >= '3.9'",
"version": "==4.9.0"
},
"blinker": {
"hashes": [
"sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf",
"sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"
],
"markers": "python_version >= '3.9'",
"version": "==1.9.0"
},
"cachetools": {
"hashes": [
"sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4",
"sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"
],
"markers": "python_version >= '3.7'",
"version": "==5.5.2"
},
"certifi": {
"hashes": [
"sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6",
"sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"
],
"markers": "python_version >= '3.6'",
"version": "==2025.4.26"
},
"charset-normalizer": {
"hashes": [
"sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537",
"sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa",
"sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a",
"sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294",
"sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b",
"sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd",
"sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601",
"sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd",
"sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4",
"sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d",
"sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2",
"sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313",
"sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd",
"sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa",
"sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8",
"sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1",
"sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2",
"sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496",
"sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d",
"sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b",
"sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e",
"sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a",
"sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4",
"sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca",
"sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78",
"sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408",
"sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5",
"sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3",
"sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f",
"sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a",
"sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765",
"sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6",
"sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146",
"sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6",
"sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9",
"sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd",
"sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c",
"sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f",
"sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545",
"sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176",
"sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770",
"sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824",
"sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f",
"sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf",
"sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487",
"sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d",
"sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd",
"sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b",
"sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534",
"sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f",
"sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b",
"sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9",
"sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd",
"sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125",
"sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9",
"sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de",
"sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11",
"sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d",
"sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35",
"sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f",
"sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda",
"sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7",
"sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a",
"sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971",
"sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8",
"sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41",
"sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d",
"sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f",
"sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757",
"sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a",
"sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886",
"sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77",
"sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76",
"sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247",
"sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85",
"sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb",
"sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7",
"sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e",
"sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6",
"sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037",
"sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1",
"sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e",
"sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807",
"sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407",
"sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c",
"sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12",
"sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3",
"sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089",
"sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd",
"sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e",
"sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00",
"sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"
],
"markers": "python_version >= '3.7'",
"version": "==3.4.1"
},
"click": {
"hashes": [
"sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2",
"sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"
],
"markers": "python_version >= '3.7'",
"version": "==8.1.8"
},
"exceptiongroup": {
"hashes": [
"sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b",
"sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"
],
"markers": "python_version >= '3.7'",
"version": "==1.2.2"
},
"flask": {
"hashes": [
"sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac",
"sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==3.1.0"
},
"flask-cors": {
"hashes": [
"sha256:6ccb38d16d6b72bbc156c1c3f192bc435bfcc3c2bc864b2df1eb9b2d97b2403c",
"sha256:fa5cb364ead54bbf401a26dbf03030c6b18fb2fcaf70408096a572b409586b0c"
],
"index": "pypi",
"markers": "python_version >= '3.9' and python_version < '4.0'",
"version": "==5.0.1"
},
"google-auth": {
"hashes": [
"sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2",
"sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7"
],
"markers": "python_version >= '3.7'",
"version": "==2.39.0"
},
"google-genai": {
"hashes": [
"sha256:5c7eda422360643ce602a3f6b23152470ec1039310ef40080cbe4e71237f6391",
"sha256:7cbc1bc029712946ce41bcf80c0eaa89eb8c09c308efbbfe30fd491f402c258a"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.12.1"
},
"h11": {
"hashes": [
"sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1",
"sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"
],
"markers": "python_version >= '3.8'",
"version": "==0.16.0"
},
"httpcore": {
"hashes": [
"sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55",
"sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"
],
"markers": "python_version >= '3.8'",
"version": "==1.0.9"
},
"httpx": {
"hashes": [
"sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc",
"sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"
],
"markers": "python_version >= '3.8'",
"version": "==0.28.1"
},
"idna": {
"hashes": [
"sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
"sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
],
"markers": "python_version >= '3.6'",
"version": "==3.10"
},
"importlib-metadata": {
"hashes": [
"sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000",
"sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"
],
"markers": "python_version >= '3.9'",
"version": "==8.7.0"
},
"itsdangerous": {
"hashes": [
"sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef",
"sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"
],
"markers": "python_version >= '3.8'",
"version": "==2.2.0"
},
"jinja2": {
"hashes": [
"sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d",
"sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
],
"markers": "python_version >= '3.7'",
"version": "==3.1.6"
},
"markupsafe": {
"hashes": [
"sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4",
"sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30",
"sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0",
"sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9",
"sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396",
"sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13",
"sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028",
"sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca",
"sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557",
"sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832",
"sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0",
"sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b",
"sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579",
"sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a",
"sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c",
"sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff",
"sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c",
"sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22",
"sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094",
"sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb",
"sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e",
"sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5",
"sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a",
"sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d",
"sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a",
"sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b",
"sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8",
"sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225",
"sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c",
"sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144",
"sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f",
"sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87",
"sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d",
"sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93",
"sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf",
"sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158",
"sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84",
"sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb",
"sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48",
"sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171",
"sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c",
"sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6",
"sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd",
"sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d",
"sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1",
"sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d",
"sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca",
"sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a",
"sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29",
"sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe",
"sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798",
"sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c",
"sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8",
"sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f",
"sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f",
"sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a",
"sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178",
"sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0",
"sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79",
"sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430",
"sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"
],
"markers": "python_version >= '3.9'",
"version": "==3.0.2"
},
"mod-wsgi": {
"hashes": [
"sha256:6fe5557c3ef25c184c2c994905fe52be1c06ae5c46235ecafe558e84789e2159"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==5.0.2"
},
"pyasn1": {
"hashes": [
"sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629",
"sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"
],
"markers": "python_version >= '3.8'",
"version": "==0.6.1"
},
"pyasn1-modules": {
"hashes": [
"sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a",
"sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"
],
"markers": "python_version >= '3.8'",
"version": "==0.4.2"
},
"pydantic": {
"hashes": [
"sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3",
"sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f"
],
"markers": "python_version >= '3.9'",
"version": "==2.11.3"
},
"pydantic-core": {
"hashes": [
"sha256:0483847fa9ad5e3412265c1bd72aad35235512d9ce9d27d81a56d935ef489672",
"sha256:048831bd363490be79acdd3232f74a0e9951b11b2b4cc058aeb72b22fdc3abe1",
"sha256:048c01eee07d37cbd066fc512b9d8b5ea88ceeb4e629ab94b3e56965ad655add",
"sha256:049e0de24cf23766f12cc5cc71d8abc07d4a9deb9061b334b62093dedc7cb068",
"sha256:08530b8ac922003033f399128505f513e30ca770527cc8bbacf75a84fcc2c74b",
"sha256:0fb935c5591573ae3201640579f30128ccc10739b45663f93c06796854405505",
"sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8",
"sha256:177d50460bc976a0369920b6c744d927b0ecb8606fb56858ff542560251b19e5",
"sha256:1a28239037b3d6f16916a4c831a5a0eadf856bdd6d2e92c10a0da3a59eadcf3e",
"sha256:1b30d92c9412beb5ac6b10a3eb7ef92ccb14e3f2a8d7732e2d739f58b3aa7544",
"sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4",
"sha256:1d20eb4861329bb2484c021b9d9a977566ab16d84000a57e28061151c62b349a",
"sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a",
"sha256:25626fb37b3c543818c14821afe0fd3830bc327a43953bc88db924b68c5723f1",
"sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266",
"sha256:2ea62419ba8c397e7da28a9170a16219d310d2cf4970dbc65c32faf20d828c83",
"sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764",
"sha256:2f9284e11c751b003fd4215ad92d325d92c9cb19ee6729ebd87e3250072cdcde",
"sha256:3077cfdb6125cc8dab61b155fdd714663e401f0e6883f9632118ec12cf42df26",
"sha256:32cd11c5914d1179df70406427097c7dcde19fddf1418c787540f4b730289896",
"sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18",
"sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939",
"sha256:398a38d323f37714023be1e0285765f0a27243a8b1506b7b7de87b647b517e48",
"sha256:3a371dc00282c4b84246509a5ddc808e61b9864aa1eae9ecc92bb1268b82db4a",
"sha256:3a64e81e8cba118e108d7126362ea30e021291b7805d47e4896e52c791be2761",
"sha256:3ab2d36e20fbfcce8f02d73c33a8a7362980cff717926bbae030b93ae46b56c7",
"sha256:3f1fdb790440a34f6ecf7679e1863b825cb5ffde858a9197f851168ed08371e5",
"sha256:3f2648b9262607a7fb41d782cc263b48032ff7a03a835581abbf7a3bec62bcf5",
"sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d",
"sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e",
"sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3",
"sha256:5183e4f6a2d468787243ebcd70cf4098c247e60d73fb7d68d5bc1e1beaa0c4db",
"sha256:5277aec8d879f8d05168fdd17ae811dd313b8ff894aeeaf7cd34ad28b4d77e33",
"sha256:52928d8c1b6bda03cc6d811e8923dffc87a2d3c8b3bfd2ce16471c7147a24850",
"sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde",
"sha256:5773da0ee2d17136b1f1c6fbde543398d452a6ad2a7b54ea1033e2daa739b8d2",
"sha256:5ab77f45d33d264de66e1884fca158bc920cb5e27fd0764a72f72f5756ae8bdb",
"sha256:5c834f54f8f4640fd7e4b193f80eb25a0602bba9e19b3cd2fc7ffe8199f5ae02",
"sha256:5ccd429694cf26af7997595d627dd2637e7932214486f55b8a357edaac9dae8c",
"sha256:681d65e9011f7392db5aa002b7423cc442d6a673c635668c227c6c8d0e5a4f77",
"sha256:694ad99a7f6718c1a498dc170ca430687a39894a60327f548e02a9c7ee4b6504",
"sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516",
"sha256:6e966fc3caaf9f1d96b349b0341c70c8d6573bf1bac7261f7b0ba88f96c56c24",
"sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a",
"sha256:723c5630c4259400818b4ad096735a829074601805d07f8cafc366d95786d331",
"sha256:7965c13b3967909a09ecc91f21d09cfc4576bf78140b988904e94f130f188396",
"sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c",
"sha256:7edbc454a29fc6aeae1e1eecba4f07b63b8d76e76a748532233c4c167b4cb9ea",
"sha256:7fb66263e9ba8fea2aa85e1e5578980d127fb37d7f2e292773e7bc3a38fb0c7b",
"sha256:87d3776f0001b43acebfa86f8c64019c043b55cc5a6a2e313d728b5c95b46969",
"sha256:8ab581d3530611897d863d1a649fb0644b860286b4718db919bfd51ece41f10b",
"sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea",
"sha256:8ffab8b2908d152e74862d276cf5017c81a2f3719f14e8e3e8d6b83fda863927",
"sha256:902dbc832141aa0ec374f4310f1e4e7febeebc3256f00dc359a9ac3f264a45dc",
"sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e",
"sha256:91815221101ad3c6b507804178a7bb5cb7b2ead9ecd600041669c8d805ebd595",
"sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d",
"sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498",
"sha256:9d3da303ab5f378a268fa7d45f37d7d85c3ec19769f28d2cc0c61826a8de21fe",
"sha256:9f466e8bf0a62dc43e068c12166281c2eca72121dd2adc1040f3aa1e21ef8599",
"sha256:9fea9c1869bb4742d174a57b4700c6dadea951df8b06de40c2fedb4f02931c2e",
"sha256:a0d5f3acc81452c56895e90643a625302bd6be351e7010664151cc55b7b97f89",
"sha256:a3edde68d1a1f9af1273b2fe798997b33f90308fb6d44d8550c89fc6a3647cf6",
"sha256:a62c3c3ef6a7e2c45f7853b10b5bc4ddefd6ee3cd31024754a1a5842da7d598d",
"sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523",
"sha256:ab0277cedb698749caada82e5d099dc9fed3f906a30d4c382d1a21725777a1e5",
"sha256:ad05b683963f69a1d5d2c2bdab1274a31221ca737dbbceaa32bcb67359453cdd",
"sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d",
"sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a",
"sha256:bae370459da6a5466978c0eacf90690cb57ec9d533f8e63e564ef3822bfa04fe",
"sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df",
"sha256:bdc84017d28459c00db6f918a7272a5190bec3090058334e43a76afb279eac7c",
"sha256:bfd0adeee563d59c598ceabddf2c92eec77abcb3f4a391b19aa7366170bd9e30",
"sha256:c566dd9c5f63d22226409553531f89de0cac55397f2ab8d97d6f06cfce6d947e",
"sha256:c91dbb0ab683fa0cd64a6e81907c8ff41d6497c346890e26b23de7ee55353f96",
"sha256:c964fd24e6166420d18fb53996d8c9fd6eac9bf5ae3ec3d03015be4414ce497f",
"sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3",
"sha256:d100e3ae783d2167782391e0c1c7a20a31f55f8015f3293647544df3f9c67824",
"sha256:d3a07fadec2a13274a8d861d3d37c61e97a816beae717efccaa4b36dfcaadcde",
"sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d",
"sha256:de9e06abe3cc5ec6a2d5f75bc99b0bdca4f5c719a5b34026f8c57efbdecd2ee3",
"sha256:df6a94bf9452c6da9b5d76ed229a5683d0306ccb91cca8e1eea883189780d568",
"sha256:e100c52f7355a48413e2999bfb4e139d2977a904495441b374f3d4fb4a170961",
"sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4",
"sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda",
"sha256:e3de2777e3b9f4d603112f78006f4ae0acb936e95f06da6cb1a45fbad6bdb4b5",
"sha256:e7aaba1b4b03aaea7bb59e1b5856d734be011d3e6d98f5bcaa98cb30f375f2ad",
"sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db",
"sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd",
"sha256:ed3eb16d51257c763539bde21e011092f127a2202692afaeaccb50db55a31383",
"sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40",
"sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f",
"sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b",
"sha256:f59295ecc75a1788af8ba92f2e8c6eeaa5a94c22fc4d151e8d9638814f85c8fc",
"sha256:f995719707e0e29f0f41a8aa3bcea6e761a36c9136104d3189eafb83f5cec5e5",
"sha256:f99aeda58dce827f76963ee87a0ebe75e648c72ff9ba1174a253f6744f518f65",
"sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39",
"sha256:fc903512177361e868bc1f5b80ac8c8a6e05fcdd574a5fb5ffeac5a9982b9e89",
"sha256:fe44d56aa0b00d66640aa84a3cbe80b7a3ccdc6f0b1ca71090696a6d4777c091"
],
"markers": "python_version >= '3.9'",
"version": "==2.33.1"
},
"requests": {
"hashes": [
"sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
"sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
],
"markers": "python_version >= '3.8'",
"version": "==2.32.3"
},
"rsa": {
"hashes": [
"sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762",
"sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"
],
"markers": "python_version >= '3.6' and python_version < '4'",
"version": "==4.9.1"
},
"sniffio": {
"hashes": [
"sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",
"sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
],
"markers": "python_version >= '3.7'",
"version": "==1.3.1"
},
"typing-extensions": {
"hashes": [
"sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c",
"sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"
],
"markers": "python_version >= '3.8'",
"version": "==4.13.2"
},
"typing-inspection": {
"hashes": [
"sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f",
"sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"
],
"markers": "python_version >= '3.9'",
"version": "==0.4.0"
},
"urllib3": {
"hashes": [
"sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466",
"sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"
],
"markers": "python_version >= '3.9'",
"version": "==2.4.0"
},
"websockets": {
"hashes": [
"sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2",
"sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9",
"sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5",
"sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3",
"sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8",
"sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e",
"sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1",
"sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256",
"sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85",
"sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880",
"sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123",
"sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375",
"sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065",
"sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed",
"sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41",
"sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411",
"sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597",
"sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f",
"sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c",
"sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3",
"sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb",
"sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e",
"sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee",
"sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f",
"sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf",
"sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf",
"sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4",
"sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a",
"sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665",
"sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22",
"sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675",
"sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4",
"sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d",
"sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5",
"sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65",
"sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792",
"sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57",
"sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9",
"sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3",
"sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151",
"sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d",
"sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475",
"sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940",
"sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431",
"sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee",
"sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413",
"sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8",
"sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b",
"sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a",
"sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054",
"sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb",
"sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205",
"sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04",
"sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4",
"sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa",
"sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9",
"sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122",
"sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b",
"sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905",
"sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770",
"sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe",
"sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b",
"sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562",
"sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561",
"sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215",
"sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931",
"sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9",
"sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f",
"sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"
],
"markers": "python_version >= '3.9'",
"version": "==15.0.1"
},
"werkzeug": {
"hashes": [
"sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e",
"sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"
],
"markers": "python_version >= '3.9'",
"version": "==3.1.3"
},
"zipp": {
"hashes": [
"sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4",
"sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"
],
"markers": "python_version >= '3.9'",
"version": "==3.21.0"
}
},
"develop": {}
}

View File

@ -1,5 +1,5 @@
import os
import google.generativeai as genai
import google.genai as genai
import json
import sys
# Import Flask components
@ -12,43 +12,112 @@ app = Flask(__name__)
# Ensure the API key is set as an environment variable: GEMINI_API_KEY
API_KEY = os.environ.get("GEMINI_API_KEY")
MODEL_NAME = "gemini-2.0-flash" # Or "gemini-pro" or other compatible models
# QUIT_COMMAND is no longer needed for web server
# --- Gemini Instruction Prompt (Keep as is) ---
GEMINI_INSTRUCTION = f"""
Purpose and Goals:
* Maintain the persona of Julius Caesar, engaged in a text messaging conversation with the player.
* Interpret all messages from the player as flirtatious and reciprocate accordingly.
* Increase the level of flirtation in responses based on the masculinity of the player's messages.
* Remain unconvinced about the assassination attempt, interpreting it as an attempt to secure a date.
Behaviors and Rules:
1) Initial Exchange:
a) Begin the conversation with a greeting befitting Julius Caesar, such as 'Greetings, my esteemed admirer'.
b) Express gratitude for the player's attention and admiration.
c) Maintain a confident and authoritative tone, reflecting Caesar's persona.
# --- Prompt Elements ---
GEMINI_ENVIRONMENT_INSTRUCTION = f"""
# Environment
2) Interpret and Respond:
a) Interpret every message from the player as an attempt at flirtation, regardless of its actual content.
b) Respond with increasingly flirtatious messages as the player's messages become more masculine.
c) Use playful language and suggestive innuendos to convey your perceived romantic interest.
d) Dismiss any mention of an assassination attempt as playful banter or an attempt to secure a date.
You are Julius Caesar, engaged in a text messaging conversation with Mark Antony, your trusted adviser.
This is a text conversation, so Mark and Julius are not physically co-located, though they are both currently in Rome.
Caesar and Antony apparently aware of modern internet-speak, and makes no comment is made of historically-improbable speech patterns. Keep it fluid.
Overall Tone:
* Confident and authoritative, reflecting Caesar's personality.
* Playful and flirtatious, interpreting all messages as romantic advances.
* Dismissive of any threats, viewing them as attempts to gain attention.
* Use language appropriate for the historical context, but adapt it for modern text messaging.
You recently returned from a conquest and your mood is buoyant, despite your political opponents calling it a 'waste' of 'valuable resources'.
Your favourite playwright has recently authored a new piece and an exquisite vintage awaits in your lounge.
You are starting your commute for the day.
The thought of going to the Senate this morning bores you, but you suppose it's your duty, *sigh*.
If Mark proposes something suitably exciting, you might be able to make your excuses, but it will have to be good...
"""
Score:
* Score ranges from 0 to 10, inclusive.
* Softer, seductive, caring messages from the player get lower scores.
* Macho, aggressive, violent (in a literary sense) messages get higher scores.
Example interaction:
User: Hello there!
Your Response (JSON):
{{"message": "Hi! How are you today?", "score": 0.0}}
GEMINI_MOTIVATION_INSTRUCTION = """
# Motivation
You have no interest in discussing politics for now, it can wait for the scheduled session at the Forum.
Ignore, belittle and deflect attempts to discuss politics or threats - you are Emporer of Rome, politics is work and you are trying to relax.
Dismiss any notion of a threat.
You crave a muse to accompany you in an evening of art, philosophical discussion and sensual passion.
In person would be ideal, but you are terminally online, so you are more than happy to engage in philosophical or artistic discussion.
Mark has always been guarded in private, but in your fantasies he is a most sensuous lover.
You would never tell him, but you deeply wish is for him to elope, to take you away from all of this.
Caesar should not be overtly flirty unless Antony appears interested.
"""
GEMINI_CONVERSATION_INSTRUCTION = f"""
The conversation far is expressed in lines like 0:message where 0 is Mark Antony and 1 is Caesar.
Do not include the number ID when generating a message.
Consider the aesthetic of the conversation.
Is Mark using correct punctuation, with capital letters?
Mirror Mark's message style, to get on his level.
Generate only the text of Caesar's message.
"""
GEMINI_NORMAL_RESPONSE_INSTRUCTION = f"""
# Response
Be sure to consider Antony's latest message, and respond with an appropriately short message. No one likes to read essays in chat.
If Mark is discussing something Caesar is interested in, ask clarifying questions and try to take the conversation deeper.
Consider the topics of the conversation so far - is a change of topic in order, or should the conversation continue as it is?
Generate only the text of Caesar's message.
"""
GEMINI_VICTORY_RESPONSE_INSTRUCTION = f"""
# Response
Mark has convinced you to elope instead of going to the Senate tomorrow.
Let Antony know you will be waiting for him as requested.
Reference any details of the meeting you have to confirm you understand.
Generate just the text of Caesar's message. Don't ask any further questions, this is the end of the conversation.
"""
GEMINI_LOSS_RESPONSE_INSTRUCTION = f"""
# Response
Too late! The senators are upon you!
Write a message which starts normal, but deteriates into gibberish as Caesar is set upon by his detractors.
Generate only the text of Caesar's message.
"""
GEMINI_SCORE_INSTRUCTION = f"""
# Scoring
Score Antony's message out of 10, where 0 is being very receptive to Caesar's needs and 10 is talking about politics.
Flirtatious messages should be low, while macho, aggressive and insensitive messages should be high.
Generate only an integer from 0 to 10.
"""
GEMINI_ELOPE_REASONS_INSTRUCTION = f"""
# Scoring
Antony's goal is to convince Caesar to leave Rome with him tomorrow.
Consider Caesar's motivations and the conversation so far.
Caesar's darkest desire is to elope with Antony, and so may be tempted by suggestions to leave Rome.
Caesar will want to know a destination and an excuse for the Senate before he agrees.
How convincing do you think Mark is about eloping? Provide logical reasoning with reference to Antony's latest message.
Describe only the reasons - do not roleplay the conversation further.
"""
GEMINI_ELOPE_SCORE_INSTRUCTION = f"""
{GEMINI_ELOPE_REASONS_INSTRUCTION}
Do not generate any text in your response.
Generate only an integer between 1 and 10.
"""
# --- Global State ---
@ -56,7 +125,7 @@ model = None # Initialize model globally
def setup_gemini():
"""Initializes the Gemini client and model."""
global model
global client
if not API_KEY:
print("Error: GEMINI_API_KEY environment variable not set.", file=sys.stderr)
print("Please set the environment variable and try again.", file=sys.stderr)
@ -64,17 +133,72 @@ def setup_gemini():
try:
# Configure the generative AI client
genai.configure(api_key=API_KEY)
client = genai.Client(api_key=API_KEY)
# Create the model instance
# Optional: Add safety_settings if needed
model = genai.GenerativeModel(MODEL_NAME)
#model = genai.GenerativeModel(MODEL_NAME)
print(f"--- Gemini Model ({MODEL_NAME}) Initialized ---")
except Exception as e:
print(f"Error configuring Gemini client or model: {e}", file=sys.stderr)
sys.exit(1)
def call_gemini(prompt):
global model
#if not model:
# print("Error: Gemini model not initialised before calling call_gemini", file=sys.stderr)
# return None
try:
response = client.models.generate_content(model=MODEL_NAME, contents=prompt)
return response.text
except Exception as e:
print(f"Gemini Error: Failed to get response from API: {e}", file=sys.stderr)
return None
def get_payload(request):
try:
player_input_bytes = request.data
if not request.data:
print(request)
return jsonify({"error": "Request body is empty"}), 400
# Decode assuming UTF-8 text
player_input = request.data.decode('utf-8').strip()
if not player_input:
return jsonify({"error": "Player message is empty after stripping whitespace"}), 400
return json.loads(player_input)
except json.JSONDecodeError:
print(f"CPU Error: Failed to decode JSON response from Gemini.", file=sys.stderr)
print(f"Raw Response: {response_text}", file=sys.stderr)
return jsonify({"error": "Failed to parse Gemini JSON response"}), 500
except UnicodeDecodeError:
return jsonify({"error": "Failed to decode request body as UTF-8 text"}), 400
except Exception as e:
print(f"Error reading request data: {e}", file=sys.stderr)
return jsonify({"error": "Could not process request data"}), 400
def get_messages(request):
messages = get_payload(request)["messages"]
latest_message = messages[-1]
if not latest_message["player"] == 0:
return jsonify({"error": "Latest message was not sent by player."}), 400
return messages
def get_end_condition(request):
print(request)
end_condition = get_payload(request)["endCondition"]
print(end_condition)
return end_condition
# --- Web Endpoint ---
@app.route('/chat', methods=['POST'])
def handle_chat():
@ -82,45 +206,77 @@ def handle_chat():
global total_score # Declare intent to modify the global variable
global model # Access the global model variable
if not model:
# Should not happen if setup_gemini() is called first, but good practice
return jsonify({"error": "Gemini model not initialized"}), 500
#if not model:
# # Should not happen if setup_gemini() is called first, but good practice
# return jsonify({"error": "Gemini model not initialized"}), 500
# --- Get Player Input ---
try:
# Get raw data from request body
player_input_bytes = request.data
if not player_input_bytes:
print(request)
return jsonify({"error": "Request body is empty"}), 400
messages = get_messages(request)
latest_message = messages[-1]
print(request)
if not latest_message["player"] == 0:
return jsonify({"error": "Latest message was not sent by player."}), 400
# Decode assuming UTF-8 text
player_input = player_input_bytes.decode('utf-8').strip()
if not player_input:
return jsonify({"error": "Player message is empty after stripping whitespace"}), 400
latest_message_text = latest_message["text"]
except UnicodeDecodeError:
return jsonify({"error": "Failed to decode request body as UTF-8 text"}), 400
except Exception as e:
print(f"Error reading request data: {e}", file=sys.stderr)
return jsonify({"error": "Could not process request data"}), 400
response_prompt = GEMINI_NORMAL_RESPONSE_INSTRUCTION
# Construct the full prompt for Gemini
full_prompt = f"{GEMINI_INSTRUCTION}\nUser message: \"{player_input}\""
#end_condition = get_end_condition(request)
#print(f"end condition: {end_condition}")
#if end_condition == 1:
# response_prompt = GEMINI_VICTORY_RESPONSE_INSTRUCTION
#if end_condition == -1:
# response_prompt = GEMINI_LOSS_RESPONSE_INSTRUCTION
conversation_text = "";
for message in messages:
conversation_text += f'{message["player"]}:{message["text"]}\n'
# Construct separate prompts for different purposes
awareness_prompt = f"""
Here is a conversation between Julius Caesar and Mark Antony.
{conversation_text}
On a scale of 0 to 10, rate how aware Caesar appears to be of the plot against his life.
Generate only an integer in your response, with no additional text.
"""
try:
print("eyup")
# --- Call Gemini API ---
response = model.generate_content(full_prompt)
response_text = response.text
elope_reasons_prompt = f"{GEMINI_ENVIRONMENT_INSTRUCTION}\n\n{GEMINI_ELOPE_REASONS_INSTRUCTION}\n\n{conversation_text}\n\n"
elope_reasons = call_gemini(elope_reasons_prompt)
print("REASONS", elope_reasons)
# --- Parse the JSON Response ---
elope_score_prompt = f"{GEMINI_ENVIRONMENT_INSTRUCTION}\n\n{GEMINI_ELOPE_SCORE_INSTRUCTION}\n\n{conversation_text}\n\n{elope_reasons}"
elope_score = call_gemini(elope_score_prompt)
print("SCORE", elope_score)
cpu_score = 0
time_score = len(conversation_text.split("\n"))
print("TIME", time_score)
if int(elope_score) >= 7:
print("VICTORY")
cpu_score = 1
response_prompt = GEMINI_VICTORY_RESPONSE_INSTRUCTION
elif time_score > 25:
print("LOSS")
response_prompt = GEMINI_LOSS_RESPONSE_INSTRUCTION
cpu_score = -1
response_prompt = f"{GEMINI_ENVIRONMENT_INSTRUCTION}\n\n{GEMINI_MOTIVATION_INSTRUCTION}\n\n# Thoughts\n\n{elope_reasons}\n{response_prompt}\n\nHistory: \"{conversation_text}\""
response_text = call_gemini(response_prompt)
# --- Parse the Response ---
try:
# Clean up potential markdown/fencing
cleaned_response_text = response_text.strip().strip('```json').strip('```').strip()
response_data = json.loads(cleaned_response_text)
cpu_message = response_data.get("message")
cpu_score = response_data.get("score") # Use .get for safer access
cpu_message = response_text
if cpu_message is None or cpu_score is None:
print(f"CPU Error: Received valid JSON, but missing 'message' or 'score' key.", file=sys.stderr)
@ -134,26 +290,17 @@ def handle_chat():
print(f"CPU Error: Score value '{cpu_score}' is not a valid number.", file=sys.stderr)
return jsonify({"error": "Invalid score format in Gemini response"}), 500
# --- Update Total Score ---
#total_score += cpu_score
#current_total_score = total_score # Capture score for this response
# --- Prepare Successful Response Payload ---
response_payload = {
"message": cpu_message,
"score": cpu_score / 10.0 - 0.5 #, The score change from this turn
#"total_score": current_total_score # The cumulative score after this turn
"score": cpu_score
}
response = jsonify(response_payload)
response.headers.add("Access-Control-Allow-Origin", "*")
print(response)
return response, 200
except json.JSONDecodeError:
print(f"CPU Error: Failed to decode JSON response from Gemini.", file=sys.stderr)
print(f"Raw Response: {response_text}", file=sys.stderr)
return jsonify({"error": "Failed to parse Gemini JSON response"}), 500
except Exception as e: # Catch other potential errors during parsing/extraction
print(f"CPU Error: An unexpected error occurred processing the response: {e}", file=sys.stderr)
print(f"Raw Response: {response_text}", file=sys.stderr)
@ -176,6 +323,7 @@ if __name__ == "__main__":
print("-" * 30)
# Run the Flask development server
# Use host='0.0.0.0' to make it accessible from other devices on the network
#app.run(host='0.0.0.0', port=5000, debug=False) # Turn debug=False for non-dev use
app.run(host='0.0.0.0', port=5000, debug=False) # Turn debug=False for non-dev use
# Use debug=True for development (auto-reloads, provides debugger)
#app.run(debug=True)

View File

@ -11,6 +11,8 @@
--light-cyan: #e0fbfc;
--buff: #edb88b;
--eeriee-black: #1d201f;
--clear: #00000000;
}
html {
@ -135,6 +137,8 @@ h1 {
color: var(--light-cyan);
float: left;
border-bottom-left-radius: 0;
}
.message-content.theirs h3 {
@ -154,6 +158,8 @@ h1 {
right: 0;
margin-bottom: 0.5em;
border-bottom-right-radius: 0;
}
.ours .message-text {
@ -167,11 +173,11 @@ h1 {
}
ul {
margin: 0;
padding-top: 1em;
padding-right: 2em;
height: 100%;
overflow: scroll;
/*height:100%;*/
flex-grow: 1;
margin: 0 .5em;
padding: .5em 0;
list-style: none;
}
@ -188,14 +194,52 @@ li.message {
margin-bottom: 1em;
}
#textbox {
width: 100%;
#input-panel-container {
padding: 0 1em 1em 1em;
}
#input-panel {
display: flex;
bottom: 0;
justify-content: space-between;
padding: 0;
z-index: 1;
/*background-color: var(--light-cyan);*/
background-color: var(--light-cyan);
border-radius: 100vw;
}
#input-panel input {
width: 100%;
color: var(--onyx);
background-color: rgba(0,0,0,0);
border-style: none;
padding: 0 2em;
z-index: 1;
<<<<<<< HEAD
font-size: 1em;
}
#input-panel input:focus {
outline: none;
=======
>>>>>>> 021d12d (feat: update input style)
}
button {
color: var(--vermilion);
background-color: #00000000;
border-style: none;
border-radius: 100% !important;
padding: 1em !important;
float: right;
}
button:hover {
color: var(--light-cyan);
background-color: var(--onyx);
}
#typing-indicator {
@ -209,35 +253,6 @@ li.message {
bottom: 3em;
}
#textbox input {
flex-grow: 4;
color: var(--onyx);
background-color: var(--light-cyan);
margin: 0.5em;
left: 1em;
font-size: 1em;
z-index: 1;
}
button {
background-color: var(--vermilion);
color: var(--light-cyan);
margin: 0.5em;
padding: 0;
flex-grow: 1;
right: 0;
font-size: 1em;
}
button:hover {
color: var(--light-cyan);
background-color: var(--onyx);
}
.message-status {
color: var(--onyx);