Websim
- nayutanadayo
- 4月4日
- 読了時間: 10分
更新日:5月20日
silly
Use a playful, joyful, exaggerated happy tone with silly jokes and wordplay.
// Generate AI chat reactions to voting
generatePollVoteMessage(activePoll.options[optionIndex].text);
}
function getRandomUsername() {
const usernames = [
'StreamFan', 'PixelGamer', 'TwitchViewer', 'ChatEnjoyer', 'StreamNinja',
'GamingWizard', 'ViewerX', 'StreamLover', 'PogChampion', 'ChatMaster',
'LurkerPro', 'StreamFollower', 'EmoteSpammer', 'SubScriber', 'TwitchPrime'
];
// Generate a random username and add random numbers
const baseUsername = usernames[Math.floor(Math.random() * usernames.length)];
return `${baseUsername}${Math.floor(Math.random() * 1000)}`;
}
async function generatePollVoteMessage(optionText) {
try {
const completion = await websim.chat.completions.create({
messages: [
{
role: "system",
content: `You're generating a single Twitch chat message reacting to someone voting in a poll.
The message should be brief (under 60 chars), conversational, and should reference the specific option.
Use casual chat expressions like "W", "L", "lmao", "lol", "pog", etc. where appropriate.
Generate both a username and message. Vary tone and style to create an authentic chat feel.
You can include Twitch emotes in your messages using the format :emoteName:. Available emotes are:
- :catJAM: - An animated cat bobbing its head (use for excitement, music, rhythm, vibing)
- :Kappa: - The classic sarcastic face (use for sarcasm, skepticism, jokes)
- :L: - Red L emote (use for failures, losses, disappointments)
- :OMEGALUL: - Exaggerated laughing emote (use for extreme humor, laughing hard)
- :poggers: - Surprised/excited frog face (use for amazement, excitement)
- :PogU: - Surprised face emote (use for shock, amazement, excitement)
- :W: - Green W emote (use for wins, successes, good plays)
- :PepeLaugh: - Pepe the Frog laughing with tears (use for schadenfreude, when something funny/embarrassing happens to others)
IMPORTANT: Don't mention the emote by name immediately after using it. Example: write ":W: let's go" NOT ":W: W let's go".
Respond directly with JSON, following this JSON schema, and no other text:
{
"username": "username1",
"message": "message1"
}`
},
{
role: "user",
content: `Generate a single chat message reacting to someone voting for the poll option: "${optionText}"`
}
],
json: true
});
// Parse the AI response
let result = JSON.parse(completion.content);
// Add the message to chat
const colorClass = `color-${Math.floor(Math.random() * 6) + 1}`;
addMessageToChat(result.username, result.message, colorClass);
} catch (error) {
console.error("Error generating poll reaction:", error);
}
}
function startPollTimer() {
// Clear any existing timer
if (pollTimer) {
clearInterval(pollTimer);
}
// Update the poll every second
pollTimer = setInterval(() => {
if (!activePoll) {
clearInterval(pollTimer);
return;
}
// Check if the poll has ended
if (activePoll.isActive && Date.now() >= activePoll.endTime) {
endPoll();
} else {
updateActivePoll();
// Add AI votes periodically during active polls
if (activePoll.isActive && Math.random() < 0.5) { // 50% chance each tick to add votes
// Generate 1-3 votes each time
const votesToAdd = Math.floor(Math.random() * 3) + 1;
for (let i = 0; i < votesToAdd; i++) {
simulateAIVote();
}
}
}
}, 1000);
}
function simulateAIVote() {
if (!activePoll || !activePoll.isActive) return;
// Randomly select an option to vote for
const optionIndex = Math.floor(Math.random() * activePoll.options.length);
// Increment votes for that option
activePoll.options[optionIndex].votes++;
totalVotes++;
// Update UI
updateActivePoll();
// Update popout window
if (chatPopupWindow && !chatPopupWindow.closed) {
chatPopupWindow.postMessage({
type: 'pollUpdate',
poll: JSON.parse(JSON.stringify(activePoll)),
totalVotes: totalVotes
}, '*');
}
// Occasionally have an AI chatter mention their vote
if (Math.random() < 0.2) { // 20% chance to announce the vote
generatePollVoteMessage(activePoll.options[optionIndex].text);
}
}
function endPoll() {
if (!activePoll) return;
activePoll.isActive = false;
activePoll.endTime = Date.now();
// Find winning option
let winningOption = activePoll.options[0];
let winningIndex = 0;
activePoll.options.forEach((option, index) => {
if (option.votes > winningOption.votes) {
winningOption = option;
winningIndex = index;
}
});
// Add winning option to poll data
activePoll.winningOption = winningOption;
activePoll.winningIndex = winningIndex;
updateActivePoll();
// Clear timer
clearInterval(pollTimer);
// Notify popup
if (chatPopupWindow && !chatPopupWindow.closed) {
chatPopupWindow.postMessage({
type: 'pollEnded',
poll: JSON.parse(JSON.stringify(activePoll)),
totalVotes: totalVotes
}, '*');
}
// Generate messages about poll results
generatePollResultMessages(winningOption, winningIndex);
// After 10 seconds, remove the poll
setTimeout(() => {
activePoll = null;
updateActivePoll();
// Notify popup
if (chatPopupWindow && !chatPopupWindow.closed) {
chatPopupWindow.postMessage({
type: 'pollRemoved'
}, '*');
}
}, 10000);
}
async function generatePollMessages(title, options) {
try {
// Streamer context
let streamerContext = streamerUsername ?
`The streamer's username is "${streamerUsername}". Some viewers might address them as "${streamerUsername}" or mention them in chat.` :
"The streamer's identity is unknown.";
const completion = await websim.chat.completions.create({
messages: [
{
role: "system",
content: `You're generating reactions to a new poll in a Twitch chat.
Generate 3 short chat messages from different users reacting to a new poll.
All messages should mention or reference the winning option.
Keep messages brief (under 60 chars), conversational, and varied in tone.
Use casual chat expressions like "W", "L", "lmao", "lol", or "pog".
Some should be excited, some should mention specific options.
Remember previous chat context: ${previousMessages.slice(-10).join(" | ")}
Some messages should reference previous conversations or what was happening before the poll.
Use previously established usernames when appropriate: ${previousUsernames.slice(-15).join(", ")}
If viewers previously showed preferences or opinions, have them be consistent with those in poll reactions.
${streamerContext}
You can include Twitch emotes in your messages using the format :emoteName:. Available emotes are:
- :catJAM: - An animated cat bobbing its head (use for excitement, music, rhythm, vibing)
- :Kappa: - The classic sarcastic face (use for sarcasm, skepticism, jokes)
- :L: - Red L emote (use for failures, losses, disappointments)
- :OMEGALUL: - Exaggerated laughing emote (use for extreme humor, laughing hard)
- :poggers: - Surprised/excited frog face (use for amazement, excitement)
- :PogU: - Surprised face emote (use for shock, amazement, excitement)
- :W: - Green W emote (use for wins, successes, good plays)
- :PepeLaugh: - Pepe the Frog laughing with tears (use for schadenfreude, when something funny/embarrassing happens to others)
IMPORTANT: Don't mention the emote by name immediately after using it. Example: write ":W: let's go" NOT ":W: W let's go".
Respond directly with JSON, following this JSON schema, and no other text:
{
"messages": [
{"username": "username1", "message": "message1"},
{"username": "username2", "message": "message2"},
{"username": "username3", "message": "message3"}
]
}`
},
{
role: "user",
content: `Generate chat reactions to this poll: "${title}" with options: ${options.map(o => `"${o.text}"`).join(', ')}`
}
],
json: true
});
// Parse the AI response
let result = JSON.parse(completion.content);
// Display messages with delays
result.messages.forEach((msgData, index) => {
setTimeout(() => {
const colorClass = `color-${Math.floor(Math.random() * 6) + 1}`;
addMessageToChat(msgData.username, msgData.message, colorClass);
}, 500 + index * 1500 + Math.random() * 1000);
});
} catch (error) {
console.error("Error generating poll reactions:", error);
}
}
async function generatePollResultMessages(winningOption, winningIndex) {
try {
const completion = await websim.chat.completions.create({
messages: [
{
role: "system",
content: `You're generating reactions to poll results in a Twitch chat.
Generate 3 short chat messages from different users reacting to the end of a poll.
All messages should mention or reference the winning option.
Keep messages brief (under 60 chars), conversational, and varied in tone.
Use casual chat expressions like "W", "L", "lmao", "lol", or "pog".
Some should be happy, some disappointed, some surprised.
Remember previous chat context: ${previousMessages.slice(-10).join(" | ")}
Reference previous opinions or predictions viewers had about the poll.
Have some viewers celebrate or complain based on whether their preferred option won.
Use previously established usernames when appropriate: ${previousUsernames.slice(-15).join(", ")}
Maintain continuity with how viewers were talking about the poll earlier.
You can include Twitch emotes in your messages using the format :emoteName:. Available emotes are:
- :catJAM: - An animated cat bobbing its head (use for excitement, music, rhythm, vibing)
- :Kappa: - The classic sarcastic face (use for sarcasm, skepticism, jokes)
- :L: - Red L emote (use for failures, losses, disappointments)
- :OMEGALUL: - Exaggerated laughing emote (use for extreme humor, laughing hard)
- :poggers: - Surprised/excited frog face (use for amazement, excitement)
- :PogU: - Surprised face emote (use for shock, amazement, excitement)
- :W: - Green W emote (use for wins, successes, good plays)
- :PepeLaugh: - Pepe the Frog laughing with tears (use for schadenfreude, when something funny/embarrassing happens to others)
IMPORTANT: Don't mention the emote by name immediately after using it. Example: write ":W: let's go" NOT ":W: W let's go".
Respond directly with JSON, following this JSON schema, and no other text:
{
"messages": [
{"username": "username1", "message": "message1"},
{"username": "username2", "message": "message2"},
{"username": "username3", "message": "message3"}
]
}`
},
{
role: "user",
content: `Generate chat reactions to this poll ending. The winning option was: "${winningOption.text}" with ${winningOption.votes} votes (${Math.round((winningOption.votes / totalVotes) * 100)}% of the total).`
}
],
json: true
});
// Parse the AI response
let result = JSON.parse(completion.content);
// Display messages with delays
result.messages.forEach((msgData, index) => {
setTimeout(() => {
const colorClass = `color-${Math.floor(Math.random() * 6) + 1}`;
addMessageToChat(msgData.username, msgData.message, colorClass);
}, 500 + index * 1500 + Math.random() * 1000);
});
} catch (error) {
console.error("Error generating poll result reactions:", error);
}
}
async function streamVideo() {
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'video/*';
fileInput.onchange = async (e) => {
const file = e.target.files[0];
if (file) {
try {
// Stop any ongoing screen recording if active
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
stopRecording();
}
// Reset state and UI for video file streaming
recordedChunks = [];
clearInterval(timerInterval);
startBtn.disabled = true;
stopBtn.disabled = false;
downloadBtn.disabled = true;
recordingStatus.textContent = "Streaming video...";
// Clear previous chat history when switching videos
previousMessages = [];
previousUsernames = [];
uniqueUsernames.clear(); // Reset unique usernames
updateViewerCount(); // Reset viewer count
// Create object URL for the selected video file
const videoURL = URL.createObjectURL(file);
// Use the preview element for video playback
preview.srcObject = null;
preview.src = videoURL;
preview.muted = false; // Enable sound for video files
preview.onloadedmetadata = () => {
startTime = Date.now();
startTimer();
preview.play();
startAIChatGeneration();
preview.onended = () => {
stopRecording();
recordingStatus.textContent = "Video streaming finished";
};
};
} catch (error) {
console.error("Error streaming video:", error);
recordingStatus.textContent = "Failed to stream video: " + error.message;
}
}
};
fileInput.click();
}
function startDonationGeneration() {
// Clear any existing interval
stopDonationGeneration();
// Don't start if donations are disabled
if (chatSettings.disableDonations) {
return;
}
donationTimer = setInterval(() => {
if (Math.random() < 0.08) {
generateDonation();
}
}, 2000);
}
function stopDonationGeneration() {
clearInterval(donationTimer);
}
async function generateDonation() {
try {
const completion = await websim.chat.completions.create({
messages: [
{
role: "system",
content: `Generate a simulated donation for a livestream. Include a username, donation amount (either $1-$100 or 100-10000 bits), and a short message.
For bits, use the format "X bits" and for dollars use the format "$X". Choose randomly between bits and dollars.
Keep the donation message brief and realistic. Users might express appreciation, ask a question, make a request, or just say something funny.
You can include Twitch emotes in your messages using the format :emoteName:. Available emotes are:
- :catJAM: - An animated cat bobbing its head (use for excitement, music, rhythm, vibing)
- :Kappa: - The classic sarcastic face (use for sarcasm, skepticism, jokes)
- :L: - Red L emote (use for failures, losses, disappointments)
- :OMEGALUL: - Exaggerated laughing emote (use for extreme humor, laughing hard)
- :poggers: - Surprised/excited frog face (use for amazement, excitement)
- :PogU: - Surprised face emote (use for shock, amazement, excitement)
- :W: - Green W emote (use for wins, successes, good plays)
- :PepeLaugh: - Pepe the Frog laughing with tears (use for schadenfreude, when something funny/embarrassing happens to others)
IMPORTANT: Don't mention the emote by name immediately after using it. Example: write ":W: let's go" NOT ":W: W let's go".
Respond directly with JSON, following this JSON schema, and no other text:
{
"username": "string",
"amount": "string",
"message": "string",
"type": "string" // either "bits" or "dollars"
}`
},
{
role: "user",
content: `Generate a realistic donation for a livestream. Previous messages in chat: ${previousMessages.slice(-10).join(" | ")}`
}
],
json: true
});
// Parse the AI response
let result = JSON.parse(completion.content);
// Add the donation to chat
addDonationToChat(result.username, result.amount, result.message, result.type);
// Generate chat reactions to the donation
generateDonationReactions(result.username, result.amount, result.type);
} catch (error) {
console.error("Error generating donation:", error);
}
}
async function generateDonationReactions(donorUsername, amount, donationType) {
try {
const completion = await websim.chat.completions.create({
messages: [
{
role: "system",
content: `You're generating 2-3 chat messages from different viewers reacting to a donation in a Twitch stream.
Messages should be brief (under 60 chars), varied in tone, and reference the donation or donor.
Use casual chat expressions like "W", "L", "lmao", "lol", "pog", etc.
Include short messages like "W ${donorUsername}" or "BIG W" for generous donations.
Be sure to include reactions like "lmao", "lol", "W", "Pog", or "L" in at least one message.
Include reactions like excitement, jokes about the amount, or emotes like "PogChamp" or "LUL".
IMPORTANT: These are messages from VIEWERS, not the streamer. They should NEVER say "thanks for the bits/donation" as if they're the streamer receiving it.
Generate unique usernames for each message.
Generate as unique usernames as possible – avoid common or overused examples.
Remember previous chat context: ${previousMessages.slice(-10).join(" | ")}
Use previously established usernames when appropriate: ${previousUsernames.slice(-15).join(", ")}
If certain viewers have shown consistent behavior or personalities, have them react consistently.
Reference any ongoing discussions or topics when reacting to the donation.
You can include Twitch emotes in your messages using the format :emoteName:. Available emotes are:
- :catJAM: - An animated cat bobbing its head (use for excitement, music, rhythm, vibing)
- :Kappa: - The classic sarcastic face (use for sarcasm, skepticism, jokes)
- :L: - Red L emote (use for failures, losses, disappointments)
- :OMEGALUL: - Exaggerated laughing emote (use for extreme humor, laughing hard)
- :poggers: - Surprised/excited frog face (use for amazement, excitement)
- :PogU: - Surprised face emote (use for shock, amazement, excitement)
- :W: - Green W emote (use for wins, successes, good plays)
- :PepeLaugh: - Pepe the Frog laughing with tears (use for schadenfreude, when something funny/embarrassing happens to others)
IMPORTANT: Don't mention the emote by name immediately after using it. Example: write ":W: let's go" NOT ":W: W let's go".
Respond directly with JSON, following this JSON schema, and no other text:
{
"messages": [
{"username": "username1", "message": "message1"},
{"username": "username2", "message": "message2"},
{"username": "username3", "message": "message3"}
]
}`
},
{
role: "user",
content: `Generate chat reactions to this donation: User "${donorUsername}" just donated ${amount} (${donationType})`
}
],
json: true
});
// Parse the AI response
let result = JSON.parse(completion.content);
// Add the messages to chat with slight delays
result.messages.forEach((msgData, index) => {
setTimeout(() => {
const colorClass = `color-${Math.floor(Math.random() * 6) + 1}`;
addMessageToChat(msgData.username, msgData.message, colorClass);
}, index * 1200 + 800);
});
} catch (error) {
console.error("Error generating donation reactions:", error);
}
}
function addDonationToChat(username, amount, message, type) {
const donationElement = document.createElement('div');
donationElement.className = 'donation-message';
// Set appropriate CSS class based on donation type
if (type === "bits") {
donationElement.classList.add('bits-donation');
} else {
donationElement.classList.add('dollars-donation');
}
donationElement.innerHTML = `
<div>
<span class="donation-amount">${amount}</span>
<span class="donation-username">${username}</span>
</div>
<div class="donation-text">${formatMessageWithEmotes(message)}</div>
`;
chatMessages.appendChild(donationElement);
chatMessages.scrollTop = chatMessages.scrollHeight;
// Add username to set for viewer count (excluding 'You')
if (username !== 'You') {
uniqueUsernames.add(username);
updateViewerCount();
}
// Also send to popup if it exists and is open
if (chatPopupWindow && !chatPopupWindow.closed) {
chatPopupWindow.postMessage({
type: 'newDonation',
donation: {
username: username,
amount: amount,
message: message,
type: type
}
}, '*');
}
}
コメント