Spaces:
Running
Running
File size: 7,946 Bytes
f2df713 659018f 98df18e f2df713 81b2b4f f2df713 98df18e 63252d6 7131bb2 c946ef8 5e713b8 021c0a0 5e713b8 021c0a0 e2e6179 ad51fd9 df75fde f2df713 ad51fd9 24c0c07 ad51fd9 b327b50 f2df713 b327b50 ad51fd9 4d55477 0d640db 11a9c0a f2df713 021c0a0 5e713b8 fcf033f 47ef753 fcf033f 24c0c07 fcf033f f2df713 fcf033f 47ef753 155dba9 c475a85 76e1887 47ef753 c475a85 fcf033f c475a85 fcf033f 77ce9e1 8eeb045 4d845ff ad51fd9 55aa982 8eeb045 ad51fd9 021c0a0 ceaf106 021c0a0 8eeb045 4d845ff 021c0a0 55aa982 021c0a0 8eeb045 0d640db 021c0a0 155dba9 8eeb045 4d845ff 021c0a0 8eeb045 4d845ff fcf033f 8eeb045 021c0a0 ceaf106 11a9c0a 7711ff0 ad51fd9 7711ff0 021c0a0 8eeb045 4d845ff 021c0a0 ceaf106 ad51fd9 ceaf106 8eeb045 e2e6179 7711ff0 8eeb045 7711ff0 ceaf106 0d640db c475a85 f2df713 c475a85 33ae448 e2e6179 7711ff0 8eeb045 e2e6179 ad51fd9 57b0658 ad51fd9 c475a85 0d640db f2df713 c475a85 f2df713 ad51fd9 33e7105 0d640db 47ef753 155dba9 47ef753 155dba9 33e7105 c475a85 155dba9 8eeb045 e2e6179 021c0a0 ceaf106 8eeb045 e2e6179 ad51fd9 8eeb045 ad51fd9 fcf033f 8eeb045 ad51fd9 021c0a0 4d845ff 021c0a0 df75fde 021c0a0 f2df713 021c0a0 ad51fd9 021c0a0 8eeb045 f2df713 ad51fd9 7711ff0 ad51fd9 7711ff0 ad51fd9 b250f63 e4b6fd4 33ae448 b250f63 7711ff0 ad51fd9 021c0a0 4d845ff 021c0a0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | # ==============================================================================
# KU HMC Lab Chatbot
# Author: Kyle VanSaun, kavansaun@ku.edu
# Editors:
# Last Updated: April 2026
# Description: A ChatBot that can
# mimic human behavior
# and saves participant
# responses to Github.
# Uses: Hugging Face as the Web host
# Gradio for the User Interface
# Python for the code
# OpenAI for the ChatBot
# Github to save data
# ==============================================================================
# INSTRUCTIONS for Chat Bot on line 92, Insert Repository name on line 39, Model type on line 150
# Imports
import gradio as gr
from openai import OpenAI
import os
from github import Github
import uuid
import time
# Environment variables
openai_key = os.getenv("OPENAI_KEY")
github_key = os.getenv("GITHUB_KEY")
# Check if openai key was given
if not openai_key:
raise gr.Error("OPENAI_KEY not set")
client = OpenAI(api_key=openai_key)
# Check if Github key was given
g = Github(github_key) if github_key else None
# Repo name, if you want to save to a github repository change RepositoryName to your repo name, name must be under quotations
REPO_NAME = "RepositoryName"
# Session data dictionary for each user
user_dictionary = {}
# Function to create or update the GitHub chat log
def update_github_log(uid):
if g:
# Try to get repo
try:
repo = g.get_user().get_repo(REPO_NAME)
filename = f"{uid}.txt"
content = ""
for msg in user_dictionary[uid]:
role = msg["role"].capitalize()
content += f"{role}: {msg['content']}\n"
# Try to update the repo, otherwise create the repo
try:
file = repo.get_contents(filename)
repo.update_file(file.path, "Update chat log", content, file.sha)
except Exception:
repo.create_file(filename, "Create session log", content)
# If we didnt get the repo find and show the error
except Exception as e:
error_msg = str(e).lower()
if "bad_credentials" in error_msg or "bad credentials" in error_msg:
gr.Warning("The GitHub API Key provided is invalid.")
elif "repository" in error_msg or "404" in error_msg:
gr.Warning("Repo not found, Possible incorrect Repository name")
else:
gr.Warning(f"GitHub Error: {str(e)}")
else:
pass
# Gradio user interface, status and progress made invisible
with gr.Blocks(theme=gr.themes.Monochrome(), css="""footer {display:none !important;}[class*="status"] {display:none !important;}[class*="progress"] {display:none !important;}""") as chatblock:
# Hidden session variables
user_id = gr.Textbox(visible=False)
notifier = gr.HTML(visible=False) # If you embed this in html, this notifier is so you can catch and use the user_id in your script or url.
# Load user session
@chatblock.load(outputs=[user_id, notifier])
def load_user():
global user_dictionary
# Creating user ID
new_id = str(uuid.uuid4())
print(f"Session started. User ID: {new_id}") # Print User ID
user_dictionary[new_id] = []
# INSTRUCTIONS, instructions must be in quotations, \n means a new line to the AI (not needed).
instructions = (
"You are a Chat Bot for the KU HMC Lab\n"
"instruction...\n"
"instruction...\n"
)
# Add ID and instructions to users session data
user_dictionary[new_id].append({
"role": "system",
"content": instructions
})
# Create a GitHub repository file to store the Data
update_github_log(new_id)
return new_id, f"<script>window.parent.postMessage({{user_id:'{new_id}'}}, '*')</script>"
# User message function so we can show the messages separately
def add_user_message(user_input, user_id):
if not user_id:
return [], ""
if user_id not in user_dictionary:
user_dictionary[user_id] = []
# Add messages to users session data
user_dictionary[user_id].append({
"role": "user",
"content": user_input
})
# Format conversation
formatted_chat = [
msg for msg in user_dictionary[user_id]
if msg["role"] != "system"
]
return formatted_chat, ""
# Optional function to simulate the time it takes a "person" to read the users message, (amount of time reading, bubbles dont show up).
def pause_before_typing(user_id):
# Calculate reading time based on the length of the user's message
if user_id and user_id in user_dictionary and len(user_dictionary[user_id]) > 0:
user_msg = user_dictionary[user_id][-1]["content"]
# Fast reading speed, caps between 1.0 and 3.0 seconds
read_delay = max(1.0, min(len(user_msg) / 30, 3.0))
time.sleep(read_delay)
else:
time.sleep(1)
# Generate Chat Bot response
def predict_prompt(user_id):
if not user_id or user_id not in user_dictionary:
return []
# Try to get the response from OpenAI
try:
response = client.chat.completions.create(
model="gpt-4o", # Model Type, must be under quotations, for example model="gpt-4o-mini".
messages=user_dictionary[user_id]
)
reply = response.choices[0].message.content
# Optional delay for a "human" response time based on the length of the chatbot's reply (amount of time typing message, bubbles show up)
typing_delay = max(1.0, min(len(reply) / 40, 5.0)) # Caps typing delay between 1.0 and 5.0 seconds
time.sleep(typing_delay)
# If we didnt get the response find and show the Error
except Exception as e:
error_msg = str(e).lower()
# Catch invalid or expired API keys and show a error message
if "invalid_api_key" in error_msg or "incorrect api key" in error_msg:
gr.Warning("The OpenAI API Key provided is invalid or expired.")
reply = "System Error: The OpenAI API Key is invalid."
elif "ascii" in error_msg:
gr.Warning("OPENAI_KEY was set incorrectly.")
reply = "System Error: The OpenAI API Key is improperly formatted."
else:
gr.Warning(f"OpenAI Error: {str(e)}")
reply = f"System Error: {str(e)}"
# Add chatbot reply to session data
user_dictionary[user_id].append({
"role": "assistant",
"content": reply
})
# Format conversation
formatted_chat = [
msg for msg in user_dictionary[user_id]
if msg["role"] != "system"
]
# Save to GitHub
update_github_log(user_id)
return formatted_chat
# User Interface components
Chatbot = gr.Chatbot(
type="messages",
label="Anonymous User" # Participant User Name
)
# User textbox for them to type in
txt = gr.Textbox(
show_label=False,
placeholder="Please write your message and press Enter",
container=False
)
# Submits
txt.submit(
add_user_message,
inputs=[txt, user_id],
outputs=[Chatbot, txt],
queue=False
).then(
pause_before_typing,
inputs=[user_id],
outputs=None
).then(
predict_prompt,
inputs=[user_id],
outputs=Chatbot
)
# Lanch!
chatblock.launch() |