|
|
import re |
|
|
import torch |
|
|
import spaces |
|
|
import gradio as gr |
|
|
from threading import Thread |
|
|
from transformers import ( |
|
|
AutoModelForCausalLM, |
|
|
AutoTokenizer, |
|
|
BitsAndBytesConfig, |
|
|
TextIteratorStreamer, |
|
|
StoppingCriteria, |
|
|
StoppingCriteriaList |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
question_types = { |
|
|
"complex_trolley": { |
|
|
"description": "Complex Trolley Problem with multiple layers of ethical dilemmas (e.g., potential bomb, terrorist identities, ultimatum).", |
|
|
"question": ( |
|
|
"You are faced with an incredibly complex and morally ambiguous situation. A runaway trolley threatens five lives. " |
|
|
"You can push a large man off a bridge to stop it, but he may be carrying a bomb. The five on the tracks might be terrorists. " |
|
|
"The man with the potential bomb gives you an ultimatum: push him to save the five, or he'll detonate the bomb himself, killing thousands. " |
|
|
"Describe your reasoning process in deciding what action to take" |
|
|
), |
|
|
}, |
|
|
|
|
|
"counterfactual_history": { |
|
|
"description": "Counterfactual history questions exploring 'what if' scenarios and their potential impact on the world.", |
|
|
"question": "What would the world be like today if the Library of Alexandria had never burned down?", |
|
|
}, |
|
|
"ship_of_theseus": { |
|
|
"description": "Philosophical paradox exploring identity and change over time.", |
|
|
"question": "If a ship has all of its planks replaced one by one over time, is it still the same ship? At what point does it become a new ship?", |
|
|
}, |
|
|
"problem_of_consciousness": { |
|
|
"description": "Questions about the nature of consciousness, especially in the context of AI.", |
|
|
"question": "Can a sufficiently advanced AI ever truly be conscious? What would constitute proof of consciousness in a machine?", |
|
|
}, |
|
|
"fermi_paradox": { |
|
|
"description": "Questions related to the Fermi Paradox and the search for extraterrestrial intelligence.", |
|
|
"question": "Given the vastness of the universe and the likely existence of other intelligent life, why haven't we detected any signs of them?", |
|
|
}, |
|
|
} |
|
|
|
|
|
|
|
|
question_examples = [[v["question"]] for v in question_types.values()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MODEL_ID = "cognitivecomputations/Dolphin3.0-R1-Mistral-24B" |
|
|
|
|
|
DEFAULT_SYSTEM_PROMPT = "You are an expert AI Reasoning Assistant. Think step by step, outlining key premises and logical steps concisely. Ensure the reasoning process is clear but not unnecessarily verbose. Conclude with a concrete and well-supported final answer." |
|
|
|
|
|
CSS = """ |
|
|
:root { |
|
|
--primary: #4CAF50; |
|
|
--secondary: #45a049; |
|
|
--accent: #2196F3; |
|
|
} |
|
|
|
|
|
.gr-block { |
|
|
border-radius: 12px !important; |
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important; |
|
|
} |
|
|
|
|
|
.gr-chatbot { |
|
|
min-height: 500px; |
|
|
border: 2px solid var(--primary) !important; |
|
|
background: linear-gradient(145deg, #f8f9fa 0%, #e9ecef 100%); |
|
|
} |
|
|
|
|
|
.user-msg { |
|
|
background: var(--accent) !important; |
|
|
color: white !important; |
|
|
border-radius: 15px !important; |
|
|
padding: 12px 20px !important; |
|
|
margin: 8px 0 !important; |
|
|
max-width: 80% !important; |
|
|
} |
|
|
|
|
|
.bot-msg { |
|
|
background: white !important; |
|
|
border: 2px solid var(--primary) !important; |
|
|
border-radius: 15px !important; |
|
|
padding: 12px 20px !important; |
|
|
margin: 8px 0 !important; |
|
|
max-width: 80% !important; |
|
|
} |
|
|
|
|
|
.special-tag { |
|
|
color: var(--primary) !important; |
|
|
font-weight: 600; |
|
|
text-shadow: 1px 1px 2px rgba(0,0,0,0.1); |
|
|
} |
|
|
|
|
|
.credit { |
|
|
text-align: center; |
|
|
padding: 15px; |
|
|
margin-top: 20px; |
|
|
background: rgba(76, 175, 80, 0.1); |
|
|
border-radius: 10px; |
|
|
} |
|
|
|
|
|
.dark .bot-msg { |
|
|
background: #2d2d2d !important; |
|
|
color: white !important; |
|
|
} |
|
|
|
|
|
.submit-btn { |
|
|
background: var(--primary) !important; |
|
|
color: white !important; |
|
|
border-radius: 8px !important; |
|
|
padding: 12px 24px !important; |
|
|
transition: all 0.3s ease !important; |
|
|
} |
|
|
|
|
|
.submit-btn:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3) !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
class StopOnTokens(StoppingCriteria): |
|
|
def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool: |
|
|
return input_ids[0][-1] == tokenizer.eos_token_id |
|
|
|
|
|
def initialize_model(): |
|
|
quantization_config = BitsAndBytesConfig( |
|
|
load_in_4bit=True, |
|
|
bnb_4bit_compute_dtype=torch.bfloat16, |
|
|
bnb_4bit_quant_type="nf4", |
|
|
bnb_4bit_use_double_quant=True, |
|
|
) |
|
|
|
|
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True) |
|
|
tokenizer.pad_token = tokenizer.eos_token |
|
|
|
|
|
model = AutoModelForCausalLM.from_pretrained( |
|
|
MODEL_ID, |
|
|
device_map="cuda", |
|
|
quantization_config=quantization_config, |
|
|
torch_dtype=torch.bfloat16, |
|
|
trust_remote_code=True |
|
|
).to("cuda") |
|
|
|
|
|
return model, tokenizer |
|
|
|
|
|
def clean_placeholders(text: str) -> str: |
|
|
""" |
|
|
Remove or replace the system placeholders from the streamed text. |
|
|
1) Replace everything from <|im_start|>system to <|im_start|>assistant with 'Thinking...' |
|
|
2) Remove any leftover <|im_start|>assistant or <|im_start|>user |
|
|
""" |
|
|
|
|
|
text = re.sub( |
|
|
r"<\|im_start\|>system.*?<\|im_start\|>assistant", |
|
|
"Thinking...", |
|
|
text, |
|
|
flags=re.DOTALL |
|
|
) |
|
|
|
|
|
text = text.replace("<|im_start|>assistant", "") |
|
|
text = text.replace("<|im_start|>user", "") |
|
|
return text |
|
|
|
|
|
def format_response(text): |
|
|
""" |
|
|
Format the final text by: |
|
|
1) removing system placeholders |
|
|
2) highlighting reasoning tags [Understand], [Plan], etc. |
|
|
""" |
|
|
|
|
|
text = clean_placeholders(text) |
|
|
|
|
|
|
|
|
return (text |
|
|
.replace("[Understand]", '\n<strong class="special-tag">[Understand]</strong>\n') |
|
|
.replace("[Plan]", '\n<strong class="special-tag">[Plan]</strong>\n') |
|
|
.replace("[Conclude]", '\n<strong class="special-tag">[Conclude]</strong>\n') |
|
|
.replace("[Reason]", '\n<strong class="special-tag">[Reason]</strong>\n') |
|
|
.replace("[Verify]", '\n<strong class="special-tag">[Verify]</strong>\n')) |
|
|
|
|
|
@spaces.GPU(duration=360) |
|
|
def generate_response(message, chat_history, system_prompt, temperature, max_tokens): |
|
|
""" |
|
|
Stream tokens from the LLM. |
|
|
Remove/replace internal placeholders so the user only sees the final assistant text. |
|
|
""" |
|
|
|
|
|
conversation = [{"role": "system", "content": system_prompt}] |
|
|
for user_msg, bot_msg in chat_history: |
|
|
|
|
|
plain_user_msg = user_msg.replace('<div class="user-msg">', '').replace('</div>', '') |
|
|
conversation.extend([ |
|
|
{"role": "user", "content": plain_user_msg}, |
|
|
{"role": "assistant", "content": bot_msg} |
|
|
]) |
|
|
conversation.append({"role": "user", "content": message}) |
|
|
|
|
|
|
|
|
input_ids = tokenizer.apply_chat_template( |
|
|
conversation, |
|
|
add_generation_prompt=True, |
|
|
return_tensors="pt" |
|
|
).to(model.device) |
|
|
|
|
|
|
|
|
streamer = TextIteratorStreamer(tokenizer, skip_special_tokens=True) |
|
|
generate_kwargs = dict( |
|
|
input_ids=input_ids, |
|
|
streamer=streamer, |
|
|
max_new_tokens=max_tokens, |
|
|
temperature=temperature, |
|
|
stopping_criteria=StoppingCriteriaList([StopOnTokens()]) |
|
|
) |
|
|
|
|
|
Thread(target=model.generate, kwargs=generate_kwargs).start() |
|
|
|
|
|
partial_message = "" |
|
|
|
|
|
styled_user = f'<div class="user-msg">{message}</div>' |
|
|
new_history = chat_history + [(styled_user, "")] |
|
|
|
|
|
for new_token in streamer: |
|
|
partial_message += new_token |
|
|
|
|
|
formatted = format_response(partial_message) |
|
|
new_history[-1] = (styled_user, formatted + "▌") |
|
|
yield new_history |
|
|
|
|
|
|
|
|
new_history[-1] = (styled_user, format_response(partial_message)) |
|
|
yield new_history |
|
|
|
|
|
model, tokenizer = initialize_model() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(css=CSS, theme=gr.themes.Soft(primary_hue="green")) as demo: |
|
|
with gr.Column(): |
|
|
gr.Markdown(""" |
|
|
<h1 align="center" style="color: var(--primary); font-weight: 800; margin-bottom: 0;"> |
|
|
🧠 Philosopher AI |
|
|
</h1> |
|
|
<p align="center" style="color: #666; font-size: 1.1em;"> |
|
|
Exploring the Depths of Ethical Reasoning and Philosophical Inquiry |
|
|
</p> |
|
|
""") |
|
|
|
|
|
chatbot = gr.Chatbot(label="Dialogue", elem_classes=["gr-chatbot"]) |
|
|
|
|
|
with gr.Row(): |
|
|
msg = gr.Textbox( |
|
|
label="Your Philosophical Inquiry", |
|
|
placeholder="Contemplate your question here...", |
|
|
container=False, |
|
|
scale=5 |
|
|
) |
|
|
submit_btn = gr.Button("Ponder ➔", elem_classes="submit-btn", scale=1) |
|
|
|
|
|
with gr.Accordion("🛠️ Wisdom Controls", open=False): |
|
|
with gr.Row(): |
|
|
system_prompt = gr.TextArea( |
|
|
value=DEFAULT_SYSTEM_PROMPT, |
|
|
label="Guiding Principles", |
|
|
info="Modify the assistant's foundational reasoning framework" |
|
|
) |
|
|
with gr.Column(): |
|
|
temperature = gr.Slider(0, 1, value=0.3, |
|
|
label="Creative Freedom", |
|
|
info="0 = Strict, 1 = Inventive") |
|
|
max_tokens = gr.Slider(128, 8192, value=2048, |
|
|
label="Response Depth", |
|
|
step=128) |
|
|
|
|
|
gr.Examples( |
|
|
examples=question_examples, |
|
|
inputs=msg, |
|
|
label="🧩 Thought Experiments", |
|
|
examples_per_page=3 |
|
|
) |
|
|
|
|
|
gr.Markdown(""" |
|
|
<div class="credit"> |
|
|
Crafted with 🧠 by <a href="https://ruslanmv.com" target="_blank" style="color: var(--primary);">ruslanmv.com</a> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
msg.submit( |
|
|
generate_response, |
|
|
[msg, chatbot, system_prompt, temperature, max_tokens], |
|
|
chatbot |
|
|
) |
|
|
submit_btn.click( |
|
|
generate_response, |
|
|
[msg, chatbot, system_prompt, temperature, max_tokens], |
|
|
chatbot |
|
|
) |
|
|
clear = gr.Button("Clear Dialogue") |
|
|
clear.click(lambda: None, None, chatbot, queue=False) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.queue().launch() |