restoration of b-2-iv and fixes into c-1-i

This commit is contained in:
2026-06-14 12:24:56 -04:00
commit b1c2cc87ae
5 changed files with 1499 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
in-the-air/

450
chatchart-v-b-2-iv-final.py Normal file
View File

@@ -0,0 +1,450 @@
from rich import print as pr
from rich.layout import Layout
from rich.panel import Panel
import termcharts
import ollama
import tkinter as tk
from tkinter import filedialog
import re
import heapq
import time
import sys
cc_version = "ITA B-2-iv Final"
# P7MJ's ITA (In the Air) chat mood analyzer, as a YAY project between 3/2 and 3/3 and finished on 3/3 (A-2-i). No longer so yay...
# Version B-1-i Refining (aka B-2-i Testing) completed on 3/5
# Working on B-1-i 3/6 and 3/8. Procrastinating between. A-series, get ready to be lost in time, but i still have some copies
# B-2-i Testing testing on 3/8. Prelim testing completed.
# B-2-ii Final working on 3/8. Removing all TEST comments and running more test cases
# B-2-iii Final working on 3/9 Morning. Added a safeguard in case the LLM hallucinates giving the super_llm_rate.
# B-2-iv Final working on 3/9 Morning. Fixed and added static colors (then removed them)
# Presenting is 3/9
# TODO Add async I DONT KNOW WHEN DONT ASK ME BYE THE EnD
# TODO Add functions super_llm_rate for all-at-once YAY and batch_llm_rate for 5 at one time YAY
# TODO Integrate readable_format() YAY
# In competition with Sean. He's doing much better... NOOOO
# I HATE the "pg up" and "pg down" buttons above the left and right arrow keys! I always misclick them and my page jumps!
# WRITING LETTER TO H. COMBINED WITH THIS CODE MAKES MY BRAIN BURN
# Coding: ❌
# Breaking heart: ✔️
# Burning brain: ✔️
# Feeling like quitting: ✔️
# STATS VS OTHER VERSIONS: (ABORTED)
# Positive/Negative/Neutral Rating Time
# GOODLOG
# B-2-i/ii: 0/11/19 -0.307 89
# B-1-i:
rating_data = []
total_messages = 0
messages_rated = 0
posanslist = []
neganslist = []
chat_summary = ""
chat_message_list = ""
# Find indices of 5 ratings with largest value
def get_n_largest_indices(data, n):
largest_items = heapq.nlargest(n, enumerate(data), key=lambda x: x[1])
indices = [index for index, value in largest_items]
return indices
# Make single or more messages readable
def readable_format(inputs):
processed = "<log>\n"
for i in range(len(inputs)):
processed += f"{inputs[i][0]}: {inputs[i][1]}\n"
processed += "</log>"
return processed
# One readable message
def readable_one_message(single_input_list):
return f"{single_input_list[0]}: {single_input_list[1]}"
# Find indices of 5 ratings with smallest value
def get_n_smallest_indices(data, n):
smallest_items = heapq.nsmallest(n, enumerate(data), key=lambda x: x[1])
indices = [index for index, value in smallest_items]
return indices
# Processes the raw chat log into a readable list
def parse_chat_log(file_path):
# Regex to match the timestamp format: [03/02/2026 00:14]
pattern = re.compile(r"\[\d{2}/\d{2}/\d{4} \d{2}:\d{2}\]\s+(.*)")
chat_data = []
current_user = None
current_message = []
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line or line.startswith("===") or line.startswith("Exported"):
continue
match = pattern.match(line)
if match:
if current_user:
chat_data.append([current_user, "\n".join(current_message)])
current_user = match.group(1)
current_message = []
else:
current_message.append(line)
if current_user:
chat_data.append([current_user, "\n".join(current_message)])
return chat_data
def split_thy_list_for_thy_batch_function(inputses):
processing = inputses.copy()
batches = []
if len(inputses) > 5:
while True: # i actually mean while the numbers are larger than 5
if len(processing) > 5:
batches.append(processing[:5])
del processing[:5]
else:
batches.append(processing)
break
return batches
else:
batches.append(inputses)
return batches
# Filters and processes the values, replacing text answers (switches to -0.5 because usually in that case the topic is so bad that the LLM refuses to rate it, therefore an automatic rating of -0.5), and 0.00s since the LLM would rather classify bad chats as 0.00 rather than mark it negative
def float_filter(value):
try:
float(value)
if float(value) == 0.00:
return -0.10
else:
return float(value)
except ValueError:
return -0.5
def process_llm_list(input_string):
stripped = input_string.strip()
splitted = stripped.split(", ")
for i in range(len(splitted)):
try:
splitted[i] = float(splitted[i])
except:
print(f"E {splitted[i]} not_float")
splitted[i] = -2
return splitted
# Uses the LLM to rate messages
def llm_rate(user_input, length):
global messages_rated
response = ollama.chat(model='llama3.2', messages=[
# The system prompt DO NOT DELETE
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a float between -1.0 and 1.0."
"Chat message format is user: message. Analyze single message."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
"No prose."
)
},
# The user (DO NOT DELETE)
{'role': 'user', 'content': readable_one_message(user_input)}
])
messages_rated += 1 # PLUS ONE TO PROGRESS
print(f"\r{messages_rated}/{length} messages rated by LLM.", end = "")
# Add the rating data to rating data
rating_data.append(response['message']['content'])
# TODO make it rate all the messages at once
def super_llm_rate(inputs):
while True:
print("LLM All-at-once Rating Mode rating...", end = " ", flush=True)
global chatmessagelist
response = ollama.chat(model='llama3.2', messages=[
# The system prompt DO NOT DELETE
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a list of floats between -1.0 and 1.0, like '0.0, 0.5, -0.5'."
"Chat messages are between <log> and </log>. Analyze the chat records and give rating to each message in order."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
f"There are {len(chatmessagelist)} messages in total. Make sure you have the same amount of ratings."
"Exactly a comma followed by a space between ratings. No prose. Double check amount."
)
},
# The user (DO NOT DELETE)
{'role': 'user', 'content': readable_format(inputs)}
])
finished = process_llm_list(response['message']['content'])
# Add the rating data to rating data
if len(finished) == len(chatmessagelist):
for i in range(len(finished)):
rating_data.append(finished[i])
break
else:
print("LLM Hallucinated!")
# Accepts a list of junk! (unprocessed parsed list)
def batch_llm_rate(inputs):
global messages_rated, chatmessagelist
print("Creating batches...", end = " ", flush=True)
try:
batcheses = split_thy_list_for_thy_batch_function(inputs)
print("Success!")
except:
print("Fail!")
sys.exit(0)
print("Rating...", end = "", flush=True)
for i in range(len(batcheses)):
that_one_batch = batcheses[i]
response = ollama.chat(model='llama3.2', messages=[
# The system prompt DO NOT DELETE
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a list of floats between -1.0 and 1.0, like '0.0, 0.5, -0.5'."
"Chat messages are between <log> and </log>. Analyze the chat records and give rating to each message in order."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
f"There are {len(that_one_batch)} messages in total. Make sure you have {len(that_one_batch)} ratings."
"Exactly a comma followed by a space between ratings. No prose. Double check amount."
)
},
# The user (DO NOT DELETE)
{'role': 'user', 'content': readable_format(that_one_batch)}
])
finished_list = process_llm_list(response['message']['content'])
for i in range(len(finished_list)):
rating_data.append(finished_list[i])
print("\r" + f"{len(rating_data)}/{len(inputs)} messages rated", end = "")
# SUMMARIZE EVERYTHING YAYAYAYAAAYAYA
def chat_summarizer(lists):
global topicsummarizerlist
global chat_summary
print("Summarizing chat...", end = " ", flush=True)
response = ollama.chat(model='llama3.2', messages=[
# The system prompt DO NOT DELETE
{
'role': 'system',
'content': (
'Chat Summarizer Tool: Sumarize given chat between <log> and </log>. Return brief summary and lists of topics discussed in order. Explain chat flow. Hypothesize user personalities. Use as few lines as possible.'
)
},
# The user (DO NOT DELETE)
{'role': 'user', 'content': readable_format(lists)}
])
chat_summary = response['message']['content']
print("Success!")
# Start ITA Agent
def start_ita_agent(mood, summary):
messages = [
{
'role': 'system',
'content': (f"Sentiment Analysis Tool. Respond to the user's questions on analyzed chat."
f"Analyzed data was: mood = {mood} with 0 being average."
f"summary: {summary}. Respond in short and concise sentences."
)
}
]
print("Type 'exit' or 'quit' to end the session.\n")
# 2. Loop forever
while True:
user_input = input("You > ")
if user_input.lower() in ['exit', 'quit']:
break
# 3. Add user input to memory
messages.append({'role': 'user', 'content': user_input})
print("ITA Analysis Agent > ", end="", flush=True)
# 4. Stream the response
full_response = ""
stream = ollama.chat(model='llama3.2', messages=messages, stream=True)
for chunk in stream:
content = chunk['message']['content']
print(content, end="", flush=True)
full_response += content
# 5. Add assistant reply to memory so it stays in context
messages.append({'role': 'assistant', 'content': full_response})
print() # Add a final newline for formatting
# Counts answers for statistics chart
def countanswers(list):
goodanswers = 0
badanswers = 0
neutralanswers = 0
for z in range(len(list)):
if list[z] > -0.3 and list[z] < 0.3:
neutralanswers += 1
elif list[z] > 0.3:
goodanswers += 1
elif list[z] < -0.3:
badanswers += 1
return [goodanswers, badanswers, neutralanswers]
# MAIN
if __name__ == "__main__":
# Chat log choosing function
while True:
print(f"""
{"=" * 80}
ITA (In the Air) Mood Interpretor | Version: {cc_version} - P7MJ
{"=" * 80}
Choose a chat log to evaluate
[1] goodlog.txt
[2] badlog.txt
[3] testlog.txt
[4] specify""")
log_to_choose = input(" > ")
if log_to_choose == "1":
log_to_choose = "goodlog.txt"
break
if log_to_choose == "2":
log_to_choose = "badlog.txt"
break
if log_to_choose == "3":
log_to_choose = "testlog.txt"
break
if log_to_choose == "4":
log_to_choose = input("Text file name (w/extension) > ")
break
else:
print("Invalid Option!")
# Start the timer
start_time = time.perf_counter()
# Processes the chat log and stores in variable
print("Parsing chat message file...", end = " ")
try:
chatmessagelist = parse_chat_log(f"{log_to_choose}")
except:
input("File does not exist! Press enter to exit...")
sys.exit(0)
print("Complete.")
while True:
rating_mode = input("\nChoose rating mode:\n[1] Individual message rating\n[2] Batches of 5 rating\n[3] All-at-once rating\n > ")
try:
nonono = int(rating_mode)
if nonono <= 3:
break
else:
hi = 3/0
except:
print("Not an integer or within range!")
if rating_mode == "1":
# Gives the chatbot each message and has it rate it
for m in range(len(chatmessagelist)):
prompt = str(chatmessagelist[m][1])
llm_rate(prompt, len(chatmessagelist))
elif rating_mode == "2":
batch_llm_rate(chatmessagelist)
elif rating_mode == "3":
super_llm_rate(chatmessagelist)
# Filters and processes rating data
for i in range(len(rating_data)):
rating_data[i] = float_filter(rating_data[i])
# Calculates rating mean
sum_of_numbers = 0
for k in range(len(rating_data)):
sum_of_numbers += rating_data[k]
sum_of_numbers /= len(rating_data)
# Finding them
list_of_best_answers = get_n_largest_indices(rating_data, 5)
list_of_worst_answers = get_n_smallest_indices(rating_data, 5)
# Calculate best messages and appending to list
for j in range(len(list_of_best_answers)):
posanslist.append(f"[{j+1}] {chatmessagelist[list_of_best_answers[j]][0]}: {chatmessagelist[list_of_best_answers[j]][1]}")
# Calculate worst messages and appending to list
for k in range(len(list_of_worst_answers)):
neganslist.append(f"[{k+1}] {chatmessagelist[list_of_worst_answers[k]][0]}: {chatmessagelist[list_of_worst_answers[k]][1]}")
# Calculate number of results in each catagory
stastisticresults = countanswers(rating_data)
print() # Add a line after the ratings
# Summarizes everything
chat_summarizer((chatmessagelist))
# End the timer
end_time = time.perf_counter()
elapsed_time = end_time - start_time
# Sample data
data = {"Positive": stastisticresults[0], "Negative": stastisticresults[1], "Neutral": stastisticresults[2]}
chart1 = termcharts.bar(data, title="Chart of message emotions", rich=True)
# Define the layout
layout = Layout()
# 1. Split into Top and Bottom halves
layout.split_column(
Layout(name="upper", size=20), # Fixed height for top section
Layout(name="lower") # Bottom takes the remainder
)
# 2. Configure Top: 1/4 (25%) for chart, rest split 50/50
layout["upper"].split_row(
Layout(name="uleft", ratio=1), # 25% of total width (1 part)
Layout(name="uright", ratio=3), # 75% of total width (3 parts)
)
# Split the 75% right side into two text panels
layout["uright"].split_row(
Layout(Panel(f"STATISTICS\n\nRating Average: {round(sum_of_numbers, 3)}\nPositive Ratings: {stastisticresults[0]}\nNegative Ratings: {stastisticresults[1]}\nNeutral Ratings: {stastisticresults[2]}\nTotal messages analyzed: {len(rating_data)}\nTotal time elapsed: {elapsed_time:.4f} seconds")),
Layout(Panel(fr"""
___ _________ ________
|\ \|\___ ___\\ __ \
\ \ \|___ \ \_\ \ \|\ \
\ \ \ \ \ \ \ \ __ \
\ \ \ \ \ \ \ \ \ \ \
\ \__\ \ \__\ \ \__\ \__\
\|__| \|__| \|__|\|__|
©2026 P7MJ
All Rights Reserved
In the Air, {cc_version} by P7MJ
Know the mood - and what to say next.
"""))
)
# 3. Configure Bottom: 50/50 split
layout["lower"].split_row(
Layout(Panel(f"OUTSTANDING MESSAGES\n\nMOST POSITIVE ANSWERS\n{posanslist[0][:200]}\n{posanslist[1][:200]}\n{posanslist[2][:200]}\n{posanslist[3][:200]}\n{posanslist[4][:200]}\n\n\nMOST NEGATIVE ANSWERS\n{neganslist[0][:200]}\n{neganslist[1][:200]}\n{neganslist[2][:200]}\n{neganslist[3][:200]}\n{neganslist[4][:200]}")),
Layout(Panel(f"CHAT SUMMARY\n\n{chat_summary}")),
)
# 4. Fill the chart
layout["uleft"].update(Panel(chart1))
pr(layout)
input("PRESS ENTER TO LAUNCH ITA CHAT AGENT")
start_ita_agent(round(sum_of_numbers, 3), chat_summary)

406
chatchart-v-c-1-i.py Normal file
View File

@@ -0,0 +1,406 @@
from rich import print as pr
from rich.layout import Layout
from rich.panel import Panel
import termcharts
import ollama
import tkinter as tk
from tkinter import filedialog
import re
import heapq
import time
import sys
# Officially advanced to the C-series tier!
cc_version = "ITA C-1-i"
# P7MJ's ITA (In the Air) chat mood analyzer, as a YAY project between 3/2 and 3/3 and finished on 3/3 (A-2-i). No longer so yay...
# Version B-1-i Refining (aka B-2-i Testing) completed on 3/5
# Working on B-1-i 3/6 and 3/8. Procrastinating between. A-series, get ready to be lost in time, but i still have some copies
# B-2-i Testing testing on 3/8. Prelim testing completed.
# B-2-ii Final working on 3/8. Removing all TEST comments and running more test cases
# B-2-iii Final working on 3/9 Morning. Added a safeguard in case the LLM hallucinates giving the super_llm_rate.
# B-2-iv Final working on 3/9 Morning. Fixed and added static colors (then removed them)
# Presenting is 3/9
# C-1-i Patched 6/14/2026. Upgraded regex parser for flexible AM/PM 12-hour exporter logs & added crash safeguards.
rating_data = []
total_messages = 0
messages_rated = 0
posanslist = []
neganslist = []
chat_summary = ""
chat_message_list = ""
# Find indices of 5 ratings with largest value
def get_n_largest_indices(data, n):
largest_items = heapq.nlargest(n, enumerate(data), key=lambda x: x[1])
indices = [index for index, value in largest_items]
return indices
# Make single or more messages readable
def readable_format(inputs):
processed = "<log>\n"
for i in range(len(inputs)):
processed += f"{inputs[i][0]}: {inputs[i][1]}\n"
processed += "</log>"
return processed
# One readable message
def readable_one_message(single_input_list):
return f"{single_input_list[0]}: {single_input_list[1]}"
# Find indices of 5 ratings with smallest value
def get_n_smallest_indices(data, n):
smallest_items = heapq.nsmallest(n, enumerate(data), key=lambda x: x[1])
indices = [index for index, value in smallest_items]
return indices
# Processes the raw chat log into a readable list
def parse_chat_log(file_path):
# FIXED FOR C-1-i: Matches flexible [M/D/YYYY H:MM AM/PM] style formats seamlessly
pattern = re.compile(r"\[\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{2}\s*(?:AM|PM)?\]\s+(.*)")
chat_data = []
current_user = None
current_message = []
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line or line.startswith("===") or line.startswith("Exported"):
continue
match = pattern.match(line)
if match:
if current_user:
chat_data.append([current_user, "\n".join(current_message)])
current_user = match.group(1)
current_message = []
else:
current_message.append(line)
if current_user:
chat_data.append([current_user, "\n".join(current_message)])
return chat_data
def split_thy_list_for_thy_batch_function(inputses):
processing = inputses.copy()
batches = []
if len(inputses) > 5:
while True:
if len(processing) > 5:
batches.append(processing[:5])
del processing[:5]
else:
batches.append(processing)
break
return batches
else:
batches.append(inputses)
return batches
# Filters and processes the values, replacing text answers and 0.00s
def float_filter(value):
try:
float(value)
if float(value) == 0.00:
return -0.10
else:
return float(value)
except ValueError:
return -0.5
def process_llm_list(input_string):
stripped = input_string.strip()
splitted = stripped.split(", ")
for i in range(len(splitted)):
try:
splitted[i] = float(splitted[i])
except:
print(f"E {splitted[i]} not_float")
splitted[i] = -2
return splitted
# Uses the LLM to rate messages
def llm_rate(user_input, length):
global messages_rated
response = ollama.chat(model='llama3.2', messages=[
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a float between -1.0 and 1.0."
"Chat message format is user: message. Analyze single message."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
"No prose."
)
},
{'role': 'user', 'content': readable_one_message(user_input)}
])
messages_rated += 1
print(f"\r{messages_rated}/{length} messages rated by LLM.", end = "")
rating_data.append(response['message']['content'])
# Rate all the messages at once
def super_llm_rate(inputs):
global chat_message_list
while True:
print("LLM All-at-once Rating Mode rating...", end = " ", flush=True)
response = ollama.chat(model='llama3.2', messages=[
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a list of floats between -1.0 and 1.0, like '0.0, 0.5, -0.5'."
"Chat messages are between <log> and </log>. Analyze the chat records and give rating to each message in order."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
f"There are {len(chat_message_list)} messages in total. Make sure you have the same amount of ratings."
"Exactly a comma followed by a space between ratings. No prose. Double check amount."
)
},
{'role': 'user', 'content': readable_format(inputs)}
])
finished = process_llm_list(response['message']['content'])
# FIXED FOR C-1-i: Corrected global variable reference target
if len(finished) == len(chat_message_list):
for i in range(len(finished)):
rating_data.append(finished[i])
break
else:
print("LLM Hallucinated!")
# Accepts a list of unprocessed parsed entries
def batch_llm_rate(inputs):
global messages_rated
print("Creating batches...", end = " ", flush=True)
try:
batcheses = split_thy_list_for_thy_batch_function(inputs)
print("Success!")
except:
print("Fail!")
sys.exit(0)
print("Rating...", end = "", flush=True)
for i in range(len(batcheses)):
that_one_batch = batcheses[i]
response = ollama.chat(model='llama3.2', messages=[
{
'role': 'system',
'content': (
"Sentiment Analyzer: Output ONLY a list of floats between -1.0 and 1.0, like '0.0, 0.5, -0.5'."
"Chat messages are between <log> and </log>. Analyze the chat records and give rating to each message in order."
"Scoring: Hostile/Insulting (-0.8), Dismissive/Sarcastic (-0.5),"
"Apathetic/Short (-0.2), Neutral/Functional (0.0), Positive/Link (0.1-1.0)."
f"There are {len(that_one_batch)} messages in total. Make sure you have {len(that_one_batch)} ratings."
"Exactly a comma followed by a space between ratings. No prose. Double check amount."
)
},
{'role': 'user', 'content': readable_format(that_one_batch)}
])
finished_list = process_llm_list(response['message']['content'])
for k in range(len(finished_list)):
rating_data.append(finished_list[k])
print("\r" + f"{len(rating_data)}/{len(inputs)} messages rated", end = "")
# Summarizes logs
def chat_summarizer(lists):
global chat_summary
print("Summarizing chat...", end = " ", flush=True)
response = ollama.chat(model='llama3.2', messages=[
{
'role': 'system',
'content': (
'Chat Summarizer Tool: Sumarize given chat between <log> and </log>. Return brief summary and lists of topics discussed in order. Explain chat flow. Hypothesize user personalities. Use as few lines as possible.'
)
},
{'role': 'user', 'content': readable_format(lists)}
])
chat_summary = response['message']['content']
print("Success!")
# Start ITA Agent
def start_ita_agent(mood, summary):
messages = [
{
'role': 'system',
'content': (f"Sentiment Analysis Tool. Respond to the user's questions on analyzed chat."
f"Analyzed data was: mood = {mood} with 0 being average."
f"summary: {summary}. Respond in short and concise sentences."
)
}
]
print("Type 'exit' or 'quit' to end the session.\n")
while True:
user_input = input("You > ")
if user_input.lower() in ['exit', 'quit']:
break
messages.append({'role': 'user', 'content': user_input})
print("ITA Analysis Agent > ", end="", flush=True)
full_response = ""
stream = ollama.chat(model='llama3.2', messages=messages, stream=True)
for chunk in stream:
content = chunk['message']['content']
print(content, end="", flush=True)
full_response += content
messages.append({'role': 'assistant', 'content': full_response})
print()
# Counts answers for statistics chart
def countanswers(lst):
goodanswers = 0
badanswers = 0
neutralanswers = 0
for z in range(len(lst)):
if lst[z] > -0.3 and lst[z] < 0.3:
neutralanswers += 1
elif lst[z] > 0.3:
goodanswers += 1
elif lst[z] < -0.3:
badanswers += 1
return [goodanswers, badanswers, neutralanswers]
# MAIN
if __name__ == "__main__":
while True:
print(f"""
{"=" * 80}
ITA (In the Air) Mood Interpretor | Version: {cc_version} - P7MJ
{"=" * 80}
Choose a chat log to evaluate
[1] goodlog.txt
[2] badlog.txt
[3] testlog.txt
[4] specify""")
log_to_choose = input(" > ")
if log_to_choose == "1":
log_to_choose = "goodlog.txt"
break
elif log_to_choose == "2":
log_to_choose = "badlog.txt"
break
elif log_to_choose == "3":
log_to_choose = "testlog.txt"
break
elif log_to_choose == "4":
log_to_choose = input("Text file name (w/extension) > ")
break
else:
print("Invalid Option!")
start_time = time.perf_counter()
print("Parsing chat message file...", end = " ")
try:
chat_message_list = parse_chat_log(f"{log_to_choose}")
except Exception as e:
input(f"Error opening file! {e}. Press enter to exit...")
sys.exit(0)
# FIXED FOR C-1-i: Clean layout exit fallback if the file exists but has no matched lines
if len(chat_message_list) == 0:
input("\nError: No messages parsed! Check your timestamp formats. Press enter to exit...")
sys.exit(0)
print("Complete.")
while True:
rating_mode = input("\nChoose rating mode:\n[1] Individual message rating\n[2] Batches of 5 rating\n[3] All-at-once rating\n > ")
if rating_mode in ["1", "2", "3"]:
break
else:
print("Not an integer or within range!")
if rating_mode == "1":
for m in range(len(chat_message_list)):
prompt = str(chat_message_list[m][1])
llm_rate(chat_message_list[m], len(chat_message_list))
elif rating_mode == "2":
batch_llm_rate(chat_message_list)
elif rating_mode == "3":
super_llm_rate(chat_message_list)
# Filters and processes rating data
for i in range(len(rating_data)):
rating_data[i] = float_filter(rating_data[i])
# FIXED FOR C-1-i: Division-by-zero protection guard
if len(rating_data) > 0:
sum_of_numbers = 0
for k in range(len(rating_data)):
sum_of_numbers += rating_data[k]
sum_of_numbers /= len(rating_data)
else:
sum_of_numbers = 0.0
list_of_best_answers = get_n_largest_indices(rating_data, 5)
list_of_worst_answers = get_n_smallest_indices(rating_data, 5)
# FIXED FOR C-1-i: Added safe index length checks to cleanly populate panels if under 5 items exist
for j in range(5):
if j < len(list_of_best_answers) and list_of_best_answers[j] < len(chat_message_list):
posanslist.append(f"[{j+1}] {chat_message_list[list_of_best_answers[j]][0]}: {chat_message_list[list_of_best_answers[j]][1]}")
else:
posanslist.append(f"[{j+1}] N/A: No data available")
for k in range(5):
if k < len(list_of_worst_answers) and list_of_worst_answers[k] < len(chat_message_list):
neganslist.append(f"[{k+1}] {chat_message_list[list_of_worst_answers[k]][0]}: {chat_message_list[list_of_worst_answers[k]][1]}")
else:
neganslist.append(f"[{k+1}] N/A: No data available")
stastisticresults = countanswers(rating_data)
print()
chat_summarizer(chat_message_list)
end_time = time.perf_counter()
elapsed_time = end_time - start_time
data = {"Positive": stastisticresults[0], "Negative": stastisticresults[1], "Neutral": stastisticresults[2]}
chart1 = termcharts.bar(data, title="Chart of message emotions", rich=True)
layout = Layout()
layout.split_column(
Layout(name="upper", size=20),
Layout(name="lower")
)
layout["upper"].split_row(
Layout(name="uleft", ratio=1),
Layout(name="uright", ratio=3),
)
layout["uright"].split_row(
Layout(Panel(f"STATISTICS\n\nRating Average: {round(sum_of_numbers, 3)}\nPositive Ratings: {stastisticresults[0]}\nNegative Ratings: {stastisticresults[1]}\nNeutral Ratings: {stastisticresults[2]}\nTotal messages analyzed: {len(rating_data)}\nTotal time elapsed: {elapsed_time:.4f} seconds")),
Layout(Panel(fr"""
___ _________ ________
|\ \|\___ ___\\ __ \
\ \ \|___ \ \_\ \ \|\ \
\ \ \ \ \ \ \ \ __ \
\ \ \ \ \ \ \ \ \ \ \
\ \__\ \ \__\ \ \__\ \__\
\|__| \|__| \|__|\|__|
©2026 P7MJ
All Rights Reserved
In the Air, {cc_version} by P7MJ
Know the mood - and what to say next.
"""))
)
layout["lower"].split_row(
Layout(Panel(f"OUTSTANDING MESSAGES\n\nMOST POSITIVE ANSWERS\n{posanslist[0][:200]}\n{posanslist[1][:200]}\n{posanslist[2][:200]}\n{posanslist[3][:200]}\n{posanslist[4][:200]}\n\n\nMOST NEGATIVE ANSWERS\n{neganslist[0][:200]}\n{neganslist[1][:200]}\n{neganslist[2][:200]}\n{neganslist[3][:200]}\n{neganslist[4][:200]}")),
Layout(Panel(f"CHAT SUMMARY\n\n{chat_summary}")),
)
layout["uleft"].update(Panel(chart1))
pr(layout)
input("PRESS ENTER TO LAUNCH ITA CHAT AGENT")
start_ita_agent(round(sum_of_numbers, 3), chat_summary)

625
log-6-12to6-14.txt Normal file
View File

@@ -0,0 +1,625 @@
==============================================================
Guild: Direct Messages
Channel: wholeworldcoding
After: 6/12/2026 12:00AM
Before: 6/14/2026 12:00AM
==============================================================
[6/12/2026 1:26AM] p7mj_tehaiker814
idk seems quarter real quarter fake quarter advertisement quarter scam
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1514802968808001556/image.png?ex=6a2ffd73&is=6a2eabf3&hm=347ca44845f602386b71094df4128864e0b90e6e15d5493041c91c6a2c696a3e&
[6/12/2026 1:30AM] p7mj_tehaiker814
have officially began yt channel
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1514804150280523996/image.png?ex=6a2ffe8d&is=6a2ead0d&hm=14a48b825473facf437dc9499e275e160674def325d302387e98857971f47f2c&
{Reactions}
🔥
[6/12/2026 1:56AM] octolinkyt
Could be virus app?
[6/12/2026 1:57AM] octolinkyt
Or some1 trying to boost installs on their app?
[6/12/2026 2:00AM] p7mj_tehaiker814
Yes
[6/12/2026 2:00AM] p7mj_tehaiker814
I'm gonna make video abt it
[6/12/2026 3:45PM] spydrone2
Deep in the dense, uncharted rainforest of NHRHS, researchers astonished the scientific community by discovering an elusive new species which they call Jackson Sherry
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515019181085429790/20260612_113622.jpg?ex=6a2f7550&is=6a2e23d0&hm=4c4a01ecb81743805aa034ce78c3f2e46c390cba33a2475bb9b88a9354ac0241&
https://cdn.discordapp.com/attachments/1442619038587945100/1515019181534482512/20260612_113614.jpg?ex=6a2f7550&is=6a2e23d0&hm=b52b49de7b340759e5e6da091a6c6c0cc7f19656347f43e5fc23aa572ac0f141&
https://cdn.discordapp.com/attachments/1442619038587945100/1515019181953777735/20260612_113520.jpg?ex=6a2f7550&is=6a2e23d0&hm=589468d2af2591b3dd9ff34c5c0ef96437194af65d40e0850a5c21f5ff4b4335&
[6/12/2026 3:59PM] octolinkyt
Wha
[6/12/2026 3:59PM] octolinkyt
<@1126508920312168498> what when where why
[6/12/2026 4:00PM] octolinkyt
<@1126508920312168498>
[6/12/2026 4:00PM] octolinkyt
I wonder if <@1126508920312168498> knows that im pinging him
[6/12/2026 4:01PM] octolinkyt
Yk what, I feel bad for pinging <@1126508920312168498> so many times
[6/12/2026 4:01PM] octolinkyt
Im sorry <@1126508920312168498>, won't happen again
[6/12/2026 4:01PM] spydrone2
I just left
[6/12/2026 4:01PM] spydrone2
u didn't even notice
[6/12/2026 4:01PM] octolinkyt
Damn
[6/12/2026 6:41PM] spydrone2
<@967396075440853022> gimme a ride pls
[6/12/2026 6:41PM] spydrone2
pls
[6/12/2026 6:41PM] spydrone2
plez
[6/12/2026 6:41PM] spydrone2
please
[6/12/2026 6:41PM] spydrone2
plz
[6/12/2026 6:41PM] spydrone2
all forms of please
[6/12/2026 6:42PM] p7mj_tehaiker814
https://tenor.com/view/rejected-stamp-gif-12255531
[6/12/2026 8:34PM] octolinkyt
Nah I actually did give him a ride
[6/13/2026 12:38AM] spydrone2
npx sndcli
for jackson
[6/13/2026 12:57AM] spydrone2
https://github.com/SpaceCypher/doxa
{Embed}
https://github.com/SpaceCypher/doxa
GitHub - SpaceCypher/doxa
Contribute to SpaceCypher/doxa development by creating an account on GitHub.
https://images-ext-1.discordapp.net/external/Nh9ZlnnKfGIDyAtGvvRja0mnlFv9Cxh62L6aVN5Nx10/https/opengraph.githubassets.com/81e9a42167d25bda867ffa1418350bfa48fa6ee23bc6b944227b5e40940f48eb/SpaceCypher/doxa
[6/13/2026 1:22AM] p7mj_tehaiker814
Sean continues to search the web
[6/13/2026 1:22AM] p7mj_tehaiker814
https://tenor.com/view/boost-search-business-google-search-ranking-search-gif-7448249517589358712
{Embed}
https://tenor.com/view/boost-search-business-google-search-ranking-search-gif-7448249517589358712
https://images-ext-1.discordapp.net/external/Vb2xxsbbr4rtgTfL6gJXuSz0Evwtz3ikqY0fS79qwVI/https/media.tenor.com/Z11_eUZjaHgAAAAe/boost-search-business.png
[6/13/2026 1:26AM] spydrone2
Na
[6/13/2026 1:26AM] spydrone2
I have fallen so low because of boredom
[6/13/2026 1:26AM] spydrone2
I now search ....
[6/13/2026 1:27AM] spydrone2
https://giphy.com/gifs/reddit-snoo-rddt-reddit-logo-ZtDnSN82QjH0b4zIVQ
{Embed}
Reddit
https://giphy.com/gifs/reddit-snoo-rddt-reddit-logo-ZtDnSN82QjH0b4zIVQ
https://images-ext-1.discordapp.net/external/pKEmVwK83adTxFBPr3tjFHU5EejTL5rb4cdSg8e_8To/https/media1.giphy.com/media/v1.Y2lkPTczYjhmN2IxdnFxNGlqem80MWwzdno5d3N4aWd4MXhyeXZ5NGs3d2ZpMGs5YnFmZSZlcD12MV9naWZzX2dpZklkJmN0PWc/ZtDnSN82QjH0b4zIVQ/giphy_s.gif
[6/13/2026 1:27AM] spydrone2
https://giphy.com/gifs/pudgypenguins-work-computer-working-Qu9ZjFARNVBG1fYdc1
{Embed}
Pudgy Penguins
https://giphy.com/gifs/pudgypenguins-work-computer-working-Qu9ZjFARNVBG1fYdc1
https://images-ext-1.discordapp.net/external/v2__l1ZuIhtYGZcn7PfI-pudxUEZaBF_RM8OdhwlZDY/https/media4.giphy.com/media/v1.Y2lkPTczYjhmN2IxYzV1YTlmNm83emRhenk0YmM4YWN3NmRxMGJwbWp4b3lleTVwdWRwMSZlcD12MV9naWZzX2dpZklkJmN0PWc/Qu9ZjFARNVBG1fYdc1/giphy_s.gif
[6/13/2026 2:07AM] octolinkyt
This is another idea I had before someone did it
[6/13/2026 2:56AM] octolinkyt
I do wanna make my own
[6/13/2026 2:57AM] octolinkyt
Like almost an ant farm of llm models
[6/13/2026 2:57AM] octolinkyt
But give them the ability to create, give them a bunch of things they can build...
[6/13/2026 2:57AM] octolinkyt
Give the parents control over the children, give the children the opportunity to rebel (easier with age)
[6/13/2026 2:57AM] octolinkyt
Give different decisions one can make (like internet use)
[6/13/2026 2:58AM] octolinkyt
Give a whole plot of land like a mini earth and let them invent. But give them tools to Jumpstart it
[6/13/2026 12:37PM] p7mj_tehaiker814
Lol
[6/13/2026 12:37PM] p7mj_tehaiker814
We would need so much RAM
[6/13/2026 12:37PM] p7mj_tehaiker814
Also I installed so much shit on my TI Calc
[6/13/2026 12:39PM] octolinkyt
Cool!
[6/13/2026 12:42PM] p7mj_tehaiker814
I made: TI BASIC programs to solve Herons formula, solve for the three vars in electron charge and field equations
I downloaded:
TI-BASIC:
Distance formula solver
midpoint solver
Pythagorean utils
Right triangle solver
Radical simplification (although my other cheaper sci calc already does that)
ASM:
Adventur Text adventures
CMonster jailbreak game
2D Portal
Tetrica Tetris
TFiles text and note editor
C:
CE2048
Chess
Mines
Zombie Chase
[6/13/2026 12:43PM] p7mj_tehaiker814
The chess one actually has a chess bot that plays *very* decently
[6/13/2026 1:02PM] p7mj_tehaiker814
I love the text editor
[6/13/2026 1:09PM] octolinkyt
Cool
[6/13/2026 3:26PM] spydrone2
https://linkedout.app.space/home
[6/13/2026 3:28PM] spydrone2
https://github.com/deepdotspace/linkedout
{Embed}
https://github.com/deepdotspace/linkedout
GitHub - deepdotspace/linkedout: LinkedOut — a satirical LinkedIn...
LinkedOut — a satirical LinkedIn for the unemployed, built on DeepSpace. Live at linkedout.app.space - deepdotspace/linkedout
https://images-ext-1.discordapp.net/external/_qedNBemNl1x5hA8kCz0S9Aczg9NV6fqi8XTiZuat-c/https/opengraph.githubassets.com/16613c0ca54a48120abf34d984364cc4b9ad74d5021731a472f307d9b445e46c/deepdotspace/linkedout
[6/13/2026 3:53PM] octolinkyt
https://www.onworks.net/playonline/runonworks.php?os=linuxmint-19.1-cinnamon-32bit
{Embed}
https://www.onworks.net/playonline/runonworks.php?os=linuxmint-19.1-cinnamon-32bit
Run Online OS Linux free with OnWorks
Run Workstation online free start with OnWorks to run any Linux or Operative System free.
[6/13/2026 3:54PM] spydrone2
octo do u have debian installed somewhere
[6/13/2026 3:54PM] octolinkyt
no
[6/13/2026 3:54PM] p7mj_tehaiker814
I can
[6/13/2026 3:55PM] p7mj_tehaiker814
It better be fast
[6/13/2026 3:55PM] octolinkyt
i have arch ofc
[6/13/2026 3:55PM] p7mj_tehaiker814
And it better not beat the shit out of my daily driver
[6/13/2026 3:55PM] spydrone2
alex run this zip the folder and send to me
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515384084405158028/get_drivers.sh?ex=6a2f77a8&is=6a2e2628&hm=01c0ea367a8b7288186eace227e3635794ac4d07d8e2700d748d11d25f5d5f78&
[6/13/2026 3:55PM] p7mj_tehaiker814
I still have hw to do 🙁
[6/13/2026 3:55PM] p7mj_tehaiker814
Ok
[6/13/2026 3:55PM] spydrone2
i have a final project i didnt even start to do
[6/13/2026 3:57PM] p7mj_tehaiker814
i did 1 paragraph of i
[6/13/2026 3:57PM] spydrone2
its enjoyable playing tag with the mouse there
[6/13/2026 3:59PM] p7mj_tehaiker814
ok done
[6/13/2026 3:59PM] p7mj_tehaiker814
its so empty...
[6/13/2026 4:00PM] p7mj_tehaiker814
wait
[6/13/2026 4:00PM] p7mj_tehaiker814
me need sudo
[6/13/2026 4:00PM] p7mj_tehaiker814
Yeah
[6/13/2026 4:00PM] p7mj_tehaiker814
still empty
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515385398816280799/image.png?ex=6a2f78e1&is=6a2e2761&hm=5e7cb62ee638eddf31918193d08c0010b4a1d52459bc1aa64df139da15bba97b&
[6/13/2026 4:00PM] p7mj_tehaiker814
ok me need do math
[6/13/2026 4:01PM] p7mj_tehaiker814
```
if (me_no_do==1) {
return 1;
}
```
[6/13/2026 4:02PM] p7mj_tehaiker814
<@1126508920312168498>
[6/13/2026 4:02PM] p7mj_tehaiker814
oh idk if <@1126508920312168498> knows that he's being pinged
[6/13/2026 4:02PM] spydrone2
FAA
[6/13/2026 4:02PM] p7mj_tehaiker814
oh shit <@1126508920312168498> must be so angry that <@1126508920312168498> is being pinged so many times
[6/13/2026 4:02PM] p7mj_tehaiker814
<@1126508920312168498> can't return to sleep now
[6/13/2026 4:02PM] octolinkyt
poor <@1126508920312168498>
[6/13/2026 4:02PM] p7mj_tehaiker814
(are you <@1126508920312168498> sleeping now?)
[6/13/2026 4:02PM] octolinkyt
I'm so sorry that he's done this to you, <@1126508920312168498>
[6/13/2026 4:03PM] octolinkyt
i would never ping <@1126508920312168498> . That's just not something i would do to <@1126508920312168498>
[6/13/2026 4:03PM] p7mj_tehaiker814
```
while (1=1) {
printf("@SpyDrone");
}
```
[6/13/2026 4:03PM] p7mj_tehaiker814
lol
[6/13/2026 4:03PM] p7mj_tehaiker814
that has a pattern btw
[6/13/2026 4:03PM] octolinkyt
yes <@1126508920312168498> ?
[6/13/2026 4:04PM] spydrone2
<@1175028794176851982><@967396075440853022><@1175028794176851982><@967396075440853022><@1175028794176851982><@967396075440853022><@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022><@1175028794176851982><@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982> <@967396075440853022> <@1175028794176851982><@967396075440853022><@1175028794176851982><@967396075440853022><@1175028794176851982><@967396075440853022>
[6/13/2026 4:04PM] p7mj_tehaiker814
yes <@1126508920312168498> ? Why is <@1126508920312168498> spamming? Why is <@1126508920312168498> wasting my math hw time
[6/13/2026 4:04PM] octolinkyt
man, <@1126508920312168498> really needs to stop pinging me and <@1175028794176851982>
[6/13/2026 4:04PM] p7mj_tehaiker814
STOP <@1126508920312168498> you have to stop <@1126508920312168498> whoever owns this group delete <@1126508920312168498> 's messages now
[6/13/2026 4:05PM] octolinkyt
i think <@1126508920312168498> is done spamming
[6/13/2026 4:05PM] octolinkyt
whew
[6/13/2026 4:05PM] p7mj_tehaiker814
me comp open
me dnd up
me no get message
me in peace
[6/13/2026 4:05PM] p7mj_tehaiker814
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515386637008375978/image.png?ex=6a2f7a08&is=6a2e2888&hm=e42c14793d8aa61a3ba7705d7ec1d4a19f50c848c5eee5f67da025e374b80046&
[6/13/2026 4:05PM] octolinkyt
joke's on you, <@1126508920312168498>! my notifications are off!
[6/13/2026 4:05PM] p7mj_tehaiker814
yeah <@1126508920312168498> !
[6/13/2026 4:06PM] p7mj_tehaiker814
give me more functional `.sh` scripts next time, <@1126508920312168498> !
[6/13/2026 4:06PM] p7mj_tehaiker814
*creates new type of cyberbullying called ping bullying*
[6/13/2026 4:06PM] octolinkyt
lol
[6/13/2026 4:06PM] p7mj_tehaiker814
ok, this is P7MJ, gotta do math, out now
[6/13/2026 4:06PM] octolinkyt
but in all seriousness, we should stop pinging <@1126508920312168498>
[6/13/2026 4:06PM] octolinkyt
bye <@1126508920312168498>!
[6/13/2026 4:09PM] spydrone2
Well someone explain why 100% storage is used up on my server
[6/13/2026 4:09PM] p7mj_tehaiker814
Not it
[6/13/2026 4:10PM] p7mj_tehaiker814
(Didnt do it either)
[6/13/2026 4:11PM] spydrone2
jacksons server is only 51% used and we have same space
[6/13/2026 4:12PM] spydrone2
Kasm Swap File (4.1 GB)
[6/13/2026 4:22PM] spydrone2
i deleted a bunch of stuff now only 55% full
[6/13/2026 4:22PM] spydrone2
do we use kasm
[6/13/2026 4:22PM] spydrone2
if not lemme delete it
[6/13/2026 4:33PM] octolinkyt
Nah delete
[6/13/2026 4:33PM] octolinkyt
R u sure?
[6/13/2026 4:34PM] octolinkyt
I think mine has more
[6/13/2026 4:34PM] p7mj_tehaiker814
We should buy a physical server some day
[6/13/2026 4:35PM] p7mj_tehaiker814
Maybe a refurbished tower computer with rolling wheels and a bunch of old RAM and a decent CPU and GPU
[6/13/2026 4:35PM] octolinkyt
I have devices we could use but my parents dont like things running
[6/13/2026 4:36PM] spydrone2
Tep
[6/13/2026 4:36PM] octolinkyt
Like a 1tb drive in an atari that runs arch with like, low-level specs, but much more than the damn chromebook
[6/13/2026 4:37PM] octolinkyt
Alr
[6/13/2026 5:11PM] spydrone2
We can use this when we have smth good https://highpay-ads.com/
{Embed}
https://highpay-ads.com/
Highpay-ads
Maximize your earnings with Highpay Ads - Earn crypto advertising opportunities today!
[6/13/2026 6:40PM] p7mj_tehaiker814
Ive had enough of damned TAC
[6/13/2026 6:41PM] p7mj_tehaiker814
These days I cant even search up “Silicon Lottery” without someone trying to switch me to another tab
[6/13/2026 7:30PM] octolinkyt
Lol
[6/13/2026 7:30PM] octolinkyt
We got 3 more years man...
[6/13/2026 10:20PM] p7mj_tehaiker814
yeah...
[6/13/2026 10:21PM] p7mj_tehaiker814
the priority is figuring out the guest password, or sneaking a router into school so we can get some form of basic connection going
[6/13/2026 10:21PM] p7mj_tehaiker814
Another option is to make our own cheap wifi broadcasters using a sim card
[6/13/2026 10:22PM] p7mj_tehaiker814
but i honestly don't know how (it's possible, you just need the parts that broadcast celluar hotspots, a sim reader, and some code in between, but then I can't get another SIM card)
[6/13/2026 10:22PM] p7mj_tehaiker814
I do have a partially viable idea, which is to create a small thumb drive that has a mobile hotspot unit soldered to it
Since our computers' hotspot sharing functions are blocked, hopefully this will do it
[6/13/2026 10:26PM] p7mj_tehaiker814
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515482647244181504/image.png?ex=6a2fd373&is=6a2e81f3&hm=3d7d76127037d82b2807ff7128a04fd73bdbd638354f7ee3313afeb781e31303&
[6/13/2026 10:31PM] p7mj_tehaiker814
I shall do this👇
{Attachments}
https://cdn.discordapp.com/attachments/1442619038587945100/1515483724995629268/image.png?ex=6a2fd474&is=6a2e82f4&hm=4da99e8e576ade8e582cbd63103dabca50d132a9a2602e44f79ac5a4baa23b67&
[6/13/2026 10:31PM] p7mj_tehaiker814
Someone give me a broken laptop
==============================================================
Exported 130 message(s)
==============================================================

17
requirements.txt Normal file
View File

@@ -0,0 +1,17 @@
annotated-types==0.7.0
anyio==4.12.1
certifi==2026.2.25
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.11
markdown-it-py==4.0.0
mdurl==0.1.2
ollama==0.6.1
pydantic==2.12.5
pydantic_core==2.41.5
Pygments==2.19.2
rich==14.3.3
termcharts==1.1.2
typing-inspection==0.4.2
typing_extensions==4.15.0