File size: 6,656 Bytes
d06a4e9
87bf316
04efeb6
 
3535281
a4478f1
f0c2309
 
3535281
 
 
 
 
 
 
87bf316
d9af773
96f6d81
d9af773
 
256f1a5
87bf316
d9af773
04efeb6
87bf316
d9af773
5311e8c
d9af773
5311e8c
 
 
d9af773
5311e8c
 
a4478f1
 
 
 
 
d9af773
87bf316
 
d9af773
 
 
04efeb6
256f1a5
a91cd3d
87bf316
a4478f1
04efeb6
a4478f1
 
 
3535281
 
 
 
a4478f1
 
3535281
 
 
cfcf9ff
fd18cd5
3535281
fd18cd5
3535281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd18cd5
3535281
 
 
 
 
04efeb6
 
 
 
 
d9af773
04efeb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87bf316
 
d9af773
04efeb6
26f11b9
 
04efeb6
d9af773
5311e8c
 
d9af773
96f6d81
04efeb6
d9af773
04efeb6
d9af773
 
 
04efeb6
256f1a5
d9af773
a91cd3d
04efeb6
d9af773
04efeb6
87bf316
 
3b2bf39
d9af773
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
import gradio as gr
from huggingface_hub import InferenceClient
import torch
from transformers import pipeline
# from prometheus_client import start_http_server, Counter, Summary
import time

# Prometheus metrics
# REQUEST_COUNTER = Counter('app_requests_total', 'Total number of requests')
# SUCCESSFUL_REQUESTS = Counter('app_successful_requests_total', 'Total number of successful requests')
# FAILED_REQUESTS = Counter('app_failed_requests_total', 'Total number of failed requests')
# REQUEST_DURATION = Summary('app_request_duration_seconds', 'Time spent processing request')
# RESPONSE_LENGTH = Summary('app_response_length', 'Length of the chatbot response in characters')
# MODEL_ERRORS = Counter('app_model_errors_total', 'Total number of model errors', ['error_type'])
# MESSAGES_PER_SESSION = Summary('app_messages_per_session', 'Number of messages per user session')

# Set up the local model (Phi-3-mini-4k-instruct) for text generation
# local_pipe = pipeline("text-generation", model="microsoft/Phi-3-mini-4k-instruct", torch_dtype=torch.bfloat16, device_map="auto")

# Set up the Inference client for API-based inference (Zephyr 7B model)
client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")

# Global flag for stopping inference (if needed)
stop_inference = False

# Occam's Razor-themed system message
DEFAULT_SYSTEM_MESSAGE = (
    "You are a helpful chatbot who answers questions according to Occam's Razor, "
    "which suggests that the simplest explanation is usually the best one. Answer as concisely as possible. "
    "DO NOT explain everything in 3-5 paragraphs. Only provide the single simplest possible answer or solution. "
    "Ensure that the answer is still clearly explained to a user who does not understand, "
    "but avoid long and drawn-out answers to simple questions. Prioritize speed of answering."
)

SESSION_TIMEOUT = 300  # 5 minutes in seconds
last_activity_time = time.time()

message_count = 0

# Function to generate responses
def respond(
    message,
    history,
    system_message=DEFAULT_SYSTEM_MESSAGE,
    max_tokens=256,
    temperature=0.7,
    top_p=0.95,
    # use_local_model=False,
):
    global stop_inference, last_activity_time, message_count
    stop_inference = False  # Reset cancellation flag
    current_time = time.time()

    # Check if the session has timed out
    # if current_time - last_activity_time > SESSION_TIMEOUT:
    #     if message_count > 0:
    #         MESSAGES_PER_SESSION.observe(message_count)  # Log the message count for the session
    #     message_count = 0  # Reset message count for a new session

    # Update the last activity time and increment message count
    # last_activity_time = current_time
    # message_count += 1
    # REQUEST_COUNTER.inc()  # Increment request counter

    # Start timing the request
    # with REQUEST_DURATION.time():
        # Initialize history if it's None
    if history is None:
        history = []

    # Prepare the chat messages with the system message and conversation history
    messages = [{"role": "system", "content": system_message}]
    for user_input, bot_response in history:
        messages.append({"role": "user", "content": user_input})
        messages.append({"role": "assistant", "content": bot_response})
    messages.append({"role": "user", "content": message})

    # Generate response based on the model selected
    try:
        if False:
            pass
            # use_local_model:
                # # Use local model (Phi-3-mini-4k-instruct)
                # prompt = local_pipe.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
                # output = local_pipe(
                #     prompt,
                #     do_sample=True
                # )
                # response_text = output[0]["generated_text"].split("<|assistant|>")[-1].strip()
        else:
            # Use API-based model (Zephyr 7B)
            response = client.chat_completion(
                messages=messages,
                stream=False
            )
            response_text = response['choices'][0]['message']['content']
        # SUCCESSFUL_REQUESTS.inc()  # Increment successful request counter
        # RESPONSE_LENGTH.observe(len(response_text))

    except Exception as e:
        # FAILED_REQUESTS.inc()  # Increment failed request counter
        # MODEL_ERRORS.labels(error_type=str(type(e))).inc()
        print(f"Error in API response: {e}")
        response_text = "Error generating response"
        history.append((message, response_text))
        return history  # Return history with error message if an exception occurs

    # Append the user message and model response to history
    history.append((message, response_text))
    return history

def cancel_inference():
    global stop_inference
    stop_inference = True

# Custom CSS for Gradio interface styling
custom_css = """
#main-container {
    background-color: #f0f0f0;
    font-family: 'Arial', sans-serif;
}
.gradio-container {
    max-width: 700px;
    margin: 0 auto;
    padding: 20px;
    background: white;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border-radius: 10px;
}
.gr-button {
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 10px 20px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}
.gr-button:hover {
    background-color: #45a049;
}
.gr-slider input {
    color: #4CAF50;
}
.gr-chat {
    font-size: 16px;
}
#title {
    text-align: center;
    font-size: 2em;
    margin-bottom: 20px;
    color: #333;
}
"""

# Define the Gradio interface
with gr.Blocks(css=custom_css) as demo:
    gr.Markdown("<h1 style='text-align: center;'>🪒 Occam's Chatbot 🪒</h1>")
    gr.Markdown("Explanations, simplified")

    # System message state
    system_message_state = gr.State(value=DEFAULT_SYSTEM_MESSAGE)
    
    # Toggle to use the local model or API
    # use_local_model = gr.Checkbox(label="Use Local Model (Phi-3-mini-4k-instruct)", value=False)

    # Chat interface elements
    chat_history = gr.Chatbot(label="Chat")
    user_input = gr.Textbox(show_label=False, placeholder="The simplest solution is usually the best...")

    # Cancel button
    cancel_button = gr.Button("Cancel Inference", variant="danger")

    # Submit the input and generate response
    user_input.submit(respond, [user_input, chat_history, system_message_state], chat_history) #, use_local_model --removed

    # Cancel inference button
    cancel_button.click(cancel_inference)

if __name__ == "__main__":
    # start_http_server(8000)  # Expose metrics on port 8000
    demo.launch(share=False)