├── README.md
└── Twitch.py
/README.md:
--------------------------------------------------------------------------------
1 | To get it running:
2 |
3 | 1. Python: Make sure you have Python installed (preferably Python 3.7+).
4 |
5 | 2. Required Python libraries:
6 | - openai
7 | - PyQt5
8 | - keyboard
9 |
10 | You can install these using pip:
11 | ```
12 | pip install openai PyQt5 keyboard
13 | ```
14 |
15 | 3. LM Studio: Download and install LM Studio from their official website.
16 |
17 | 4. Local LLM Server:
18 | - Use LM Studio to download the "bartowski/Llama-3.2-1B-Instruct-GGUF" model.
19 | - Start a local server in LM Studio using this model, ensuring it's running on http://localhost:1234.
20 |
21 | 5. Python Script:
22 | - Save the provided Python code in a .py file (e.g., twitch_simulator.py).
23 |
24 | 6. Running the Simulator:
25 | - Ensure the LM Studio server is running.
26 | - Run the Python script:
27 | ```
28 | python twitch_simulator.py
29 | ```
30 |
31 | 7. Usage:
32 | - The simulator will appear as a semi-transparent overlay on the right side of your screen.
33 | - It will generate random Twitch-like comments at intervals.
34 | - Press ESC to close the simulator.
35 |
--------------------------------------------------------------------------------
/Twitch.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import random
3 | import keyboard
4 | from openai import OpenAI
5 | from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QDesktopWidget
6 | from PyQt5.QtCore import Qt, QTimer, QPropertyAnimation, QEasingCurve
7 | from PyQt5.QtGui import QFont, QPainter, QColor, QLinearGradient
8 |
9 | # Point to the local server
10 | client = OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio")
11 |
12 | class ChatMessage(QLabel):
13 | def __init__(self, text, parent=None):
14 | super().__init__(text, parent)
15 | self.setStyleSheet("background-color: transparent; color: white;")
16 | self.setFont(QFont("Roboto", 14))
17 | self.setWordWrap(True)
18 |
19 | def colorize_username(self):
20 | text = self.text()
21 | username, message = text.split(':', 1)
22 | color = QColor(random.randint(100, 255), random.randint(100, 255), random.randint(100, 255))
23 | self.setText(f'{username}:{message}')
24 |
25 | class TransparentOverlay(QWidget):
26 | def __init__(self):
27 | super().__init__()
28 | self.initUI()
29 | self.messages = []
30 | self.timer = QTimer(self)
31 | self.timer.timeout.connect(self.add_new_comment)
32 | self.timer.start(random.randint(1000, 5000))
33 | keyboard.add_hotkey('esc', self.close)
34 |
35 | def initUI(self):
36 | self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
37 | self.setAttribute(Qt.WA_TranslucentBackground)
38 |
39 | self.layout = QVBoxLayout()
40 | self.layout.setAlignment(Qt.AlignBottom)
41 | self.setLayout(self.layout)
42 |
43 | # Get screen resolution
44 | screen = QDesktopWidget().screenNumber(QDesktopWidget().cursor().pos())
45 | screen_size = QDesktopWidget().screenGeometry(screen)
46 |
47 | # Set window size to 25% of screen width and 50% of screen height
48 | width = int(screen_size.width() * 0.25)
49 | height = int(screen_size.height() * 0.5)
50 |
51 | # Position the window on the right side of the screen
52 | x = screen_size.width() - width - 20 # 20px padding from the right edge
53 | y = (screen_size.height() - height) // 2 # Centered vertically
54 |
55 | self.setGeometry(x, y, width, height)
56 | self.show()
57 |
58 | def update_text(self, text):
59 | if len(self.messages) >= 15:
60 | self.layout.removeWidget(self.messages[0])
61 | self.messages[0].deleteLater()
62 | self.messages.pop(0)
63 |
64 | new_message = ChatMessage(text)
65 | new_message.colorize_username()
66 | self.messages.append(new_message)
67 | self.layout.addWidget(new_message)
68 |
69 | # Animate new message
70 | self.animate_new_message(new_message)
71 |
72 | def animate_new_message(self, message):
73 | animation = QPropertyAnimation(message, b"geometry")
74 | animation.setDuration(300)
75 | animation.setStartValue(message.geometry().adjusted(self.width(), 0, self.width(), 0))
76 | animation.setEndValue(message.geometry())
77 | animation.setEasingCurve(QEasingCurve.OutCubic)
78 | animation.start()
79 |
80 | def paintEvent(self, event):
81 | painter = QPainter(self)
82 | painter.setRenderHint(QPainter.Antialiasing)
83 |
84 | # Create a gradient background
85 | gradient = QLinearGradient(0, 0, 0, self.height())
86 | gradient.setColorAt(0, QColor(0, 0, 0, 180))
87 | gradient.setColorAt(1, QColor(0, 0, 0, 140))
88 |
89 | painter.setBrush(gradient)
90 | painter.setPen(Qt.NoPen)
91 | painter.drawRoundedRect(self.rect(), 10, 10)
92 |
93 | def add_new_comment(self):
94 | new_comment = generate_comment()
95 | self.update_text(new_comment)
96 | # Set a new random interval for the next comment
97 | self.timer.setInterval(random.randint(1000, 5000))
98 |
99 | def keyPressEvent(self, event):
100 | if event.key() == Qt.Key_Escape:
101 | self.close()
102 |
103 | def generate_comment():
104 | # Simulate special events
105 | if random.random() < 0.05: # 5% chance for a special event
106 | event_type = random.choice(['raid', 'donation', 'subscription'])
107 | if event_type == 'raid':
108 | return f"Streamlabs: {random.choice(['PogChamp', 'Kreygasm', 'Kappa'])} {random.choice(['Ninja', 'Pokimane', 'Shroud'])} is raiding with {random.randint(10, 1000)} viewers!"
109 | elif event_type == 'donation':
110 | return f"Streamlabs: {random.choice(['PogChamp', 'Kreygasm', 'Kappa'])} {random.choice(['John', 'Emma', 'Alex'])} donated ${random.randint(1, 100)}!"
111 | elif event_type == 'subscription':
112 | return f"Streamlabs: {random.choice(['PogChamp', 'Kreygasm', 'Kappa'])} {random.choice(['Sarah', 'Mike', 'Lisa'])} just subscribed for {random.randint(1, 12)} months!"
113 |
114 | completion = client.chat.completions.create(
115 | model="bartowski/Llama-3.2-1B-Instruct-GGUF",
116 | messages=[
117 | {"role": "system", "content": "This is a Twitch chat simulator! Your output will be used to generate a comment on Twitch! Respond like a Twitch gamer watching a stream. Respond in this format: : "},
118 | {"role": "user", "content": "Go ahead and generate exactly ONE username and comment for this Twitch stream! It doesn't have to make sense, it can even be just an emoji! Be sure to come up with a fun username, and respond only with : , but don't use quotation marks."}
119 | ],
120 | temperature=1.0,
121 | )
122 |
123 | # Get the raw content and clean it up
124 | raw_content = completion.choices[0].message.content
125 | cleaned_content = raw_content.strip('"').replace('\n', ' ').replace('\r', '')
126 | # Ensure the content is in the correct format
127 | if ':' not in cleaned_content:
128 | # If there's no colon, add a default username
129 | cleaned_content = f"Anonymous: {cleaned_content}"
130 |
131 | return cleaned_content
132 |
133 | if __name__ == "__main__":
134 | app = QApplication(sys.argv)
135 | overlay = TransparentOverlay()
136 |
137 | print("Simulating Twitch chat. Press ESC to stop...")
138 | sys.exit(app.exec_())
--------------------------------------------------------------------------------