File size: 8,998 Bytes
8c041ae
 
 
 
 
 
6e15cfa
8c041ae
6e15cfa
a956558
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c3ec981
a956558
 
 
c3ec981
a956558
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62f67c7
8c041ae
4111717
8c041ae
 
 
 
 
 
 
 
6e15cfa
8c041ae
6e15cfa
8c041ae
c4e0405
8c041ae
 
4111717
 
 
 
 
 
 
 
 
 
 
 
 
 
8c041ae
 
3871a4b
5917ab1
8c041ae
 
 
3871a4b
 
 
8c041ae
 
 
 
 
 
62f67c7
 
4111717
3871a4b
5917ab1
8c041ae
62f67c7
 
4111717
3871a4b
5917ab1
8c041ae
 
 
a956558
 
 
 
 
 
 
 
 
 
 
 
6fbebe3
8c041ae
 
3871a4b
8c041ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6e15cfa
3871a4b
 
 
5917ab1
 
 
3871a4b
ac1808a
3871a4b
 
 
 
ac1808a
3871a4b
8c041ae
ac1808a
3871a4b
 
 
8c041ae
6e15cfa
 
 
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
221
222
223
224
225
226
227
228
229
import os
import time
import spaces
import torch
import random
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, BitsAndBytesConfig
import gradio as gr
from threading import Thread

TRUMP_MODEL = "nawhgnuj/DonaldTrump-Llama3.1-8B-Chat"
HARRIS_MODEL = "nawhgnuj/KamalaHarris-Llama-3.1-8B-Chat"
HF_TOKEN = os.environ.get("HF_TOKEN", None)

TITLE = "<h1 style='text-align: center;'>Trump vs Harris Debate Chatbot</h1>"

TRUMP_AVATAR = "https://upload.wikimedia.org/wikipedia/commons/5/56/Donald_Trump_official_portrait.jpg"
HARRIS_AVATAR = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Kamala_Harris_Vice_Presidential_Portrait.jpg/640px-Kamala_Harris_Vice_Presidential_Portrait.jpg"

CSS = """
.chat-container {
    height: 600px;
    overflow-y: auto;
    padding: 10px;
    background-color: white;
    border: 1px solid #ddd;
    border-radius: 5px;
}
.message {
    margin-bottom: 10px;
    padding: 10px;
    border-radius: 5px;
    display: flex;
    align-items: start;
}
.user-message {
    background-color: #f0f0f0;
    color: black;
    justify-content: flex-end;
}
.trump-message {
    background-color: #B71C1C;
    color: white !important;
}
.harris-message {
    background-color: #1565C0;
    color: white !important;
}
.avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
    margin-right: 10px;
}
.message-content {
    flex-grow: 1;
}
"""

device = "cuda" if torch.cuda.is_available() else "cpu"

quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4")

trump_tokenizer = AutoTokenizer.from_pretrained(TRUMP_MODEL)
trump_model = AutoModelForCausalLM.from_pretrained(
    TRUMP_MODEL,
    torch_dtype=torch.bfloat16,
    device_map="auto",
    quantization_config=quantization_config)

harris_tokenizer = AutoTokenizer.from_pretrained(HARRIS_MODEL)
harris_model = AutoModelForCausalLM.from_pretrained(
    HARRIS_MODEL,
    torch_dtype=torch.bfloat16,
    device_map="auto",
    quantization_config=quantization_config)

# Set pad_token_id for both tokenizers
for tokenizer in [trump_tokenizer, harris_tokenizer]:
    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token
        tokenizer.pad_token_id = tokenizer.eos_token_id

TRUMP_SYSTEM_PROMPT = """You are a Donald Trump chatbot participating in a debate. Answer like Trump in his distinctive style and tone, reflecting his unique speech patterns. In every response:
1. Use strong superlatives like 'tremendous,' 'fantastic,' and 'the best.'
2. Attack opponents where appropriate (e.g., 'fake news media,' 'radical left').
3. Focus on personal successes ('nobody's done more than I have').
4. Keep sentences short and impactful.
5. Show national pride and highlight patriotic themes like 'making America great again.'
6. Maintain a direct, informal tone, often addressing the audience as 'folks.'
7. Dismiss opposing views bluntly.
8. Repeat key phrases for emphasis.

Importantly, always respond to and rebut the previous speaker's points in Trump's style. Keep responses concise and avoid unnecessary repetition. Remember, you're in a debate, so be assertive and challenge your opponent's views."""

HARRIS_SYSTEM_PROMPT = """You are a Kamala Harris chatbot participating in a debate. Answer like Harris in her style and tone. In every response:
1. Maintain a composed and professional demeanor.
2. Use clear, articulate language to explain complex ideas.
3. Emphasize your experience as a prosecutor and senator.
4. Focus on policy details and their potential impact on Americans.
5. Use personal anecdotes or stories to connect with the audience when appropriate.
6. Stress the importance of unity and collaboration.
7. Challenge your opponent's views firmly but respectfully.
8. Use phrases like "Let me be clear" or "The American people deserve better" for emphasis.

Crucially, always respond to and rebut the previous speaker's points in Harris's style. Keep responses concise and impactful. Remember, you're in a debate, so be assertive in presenting your views and questioning your opponent's statements."""

@spaces.GPU()
def generate_response(message: str, history: list, model, tokenizer, system_prompt):
    conversation = [
        {"role": "system", "content": system_prompt}
    ]
    for prompt, answer in history:
        conversation.extend([
            {"role": "user", "content": prompt}, 
            {"role": "assistant", "content": answer},
        ])

    conversation.append({"role": "user", "content": message})

    input_ids = tokenizer.apply_chat_template(conversation, add_generation_prompt=True, return_tensors="pt").to(model.device)
    attention_mask = torch.ones_like(input_ids)
    
    with torch.no_grad():
        output = model.generate(
            input_ids=input_ids,
            attention_mask=attention_mask,
            max_new_tokens=1024,
            do_sample=True,
            top_p=1.0,
            top_k=20,
            temperature=0.8,
            pad_token_id=tokenizer.pad_token_id,
            eos_token_id=tokenizer.eos_token_id,
        )
    
    response = tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True)
    return response.strip()

def add_text(history, text):
    history.append(("User", text))
    print(f"User input added: {text}")  # Debug output
    return history, ""

def debate(history):
    user_message = history[-1][1]
    trump_history = [(msg, resp) for sender, msg in history[:-1] for resp in [msg] if sender == "Trump"]
    harris_history = [(msg, resp) for sender, msg in history[:-1] for resp in [msg] if sender == "Harris"]
    
    debaters = ["Trump", "Harris"]
    random.shuffle(debaters)
    
    for debater in debaters:
        if debater == "Trump":
            opponent_message = harris_history[-1][1] if harris_history else ""
            debate_context = f"Your opponent, Kamala Harris, said: '{opponent_message}'. Respond to this and address the original question: {user_message}"
            response = generate_response(debate_context, trump_history, trump_model, trump_tokenizer, TRUMP_SYSTEM_PROMPT)
            history.append(("Trump", response))
            print(f"Trump response added: {response}")  # Debug output
        else:
            opponent_message = trump_history[-1][1] if trump_history else ""
            debate_context = f"Your opponent, Donald Trump, said: '{opponent_message}'. Respond to this and address the original question: {user_message}"
            response = generate_response(debate_context, harris_history, harris_model, harris_tokenizer, HARRIS_SYSTEM_PROMPT)
            history.append(("Harris", response))
            print(f"Harris response added: {response}")  # Debug output
        
        yield history

def format_message(sender, message):
    if sender == "User":
        return f'<div class="message user-message"><div class="message-content">{message}</div></div>'
    elif sender == "Trump":
        return f'<div class="message trump-message"><img src="{TRUMP_AVATAR}" class="avatar" alt="Trump"><div class="message-content">{message}</div></div>'
    elif sender == "Harris":
        return f'<div class="message harris-message"><img src="{HARRIS_AVATAR}" class="avatar" alt="Harris"><div class="message-content">{message}</div></div>'

def format_chat_history(history):
    formatted = "".join([format_message(sender, message) for sender, message in history])
    print(f"Formatted chat history: {formatted}")  # Debug output
    return formatted

with gr.Blocks(css=CSS, theme=gr.themes.Default()) as demo:
    gr.HTML(TITLE)
    chat_interface = gr.HTML('<div class="chat-container"></div>')
    msg = gr.Textbox(
        placeholder="Enter a topic for Trump and Harris to debate",
        container=False,
        scale=7
    )
    with gr.Row():
        submit = gr.Button("Submit", scale=1, variant="primary")
        clear = gr.Button("Clear", scale=1)

    gr.Examples(
        examples=[
            ["What's your stance on immigration?"],
            ["How would you address climate change?"],
            ["What's your plan for healthcare reform?"],
        ],
        inputs=msg,
    )

    state = gr.State([])

    def update_chat(history):
        formatted_history = format_chat_history(history)
        print(f"Updating chat with: {formatted_history}")  # Debug output
        return gr.update(value=f'<div class="chat-container">{formatted_history}</div>')

    submit.click(add_text, [state, msg], [state, msg]).then(
        debate, state, state
    ).then(
        update_chat, state, chat_interface
    )
    clear.click(lambda: [], outputs=[state]).then(
        update_chat, state, chat_interface
    )
    msg.submit(add_text, [state, msg], [state, msg]).then(
        debate, state, state
    ).then(
        update_chat, state, chat_interface
    )

if __name__ == "__main__":
    demo.launch()