Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
# AI Persona Simulator
|
2 |
import gradio as gr
|
3 |
import transformers
|
4 |
import torch
|
@@ -21,7 +21,7 @@ logging.basicConfig(
|
|
21 |
MODEL_ID = "google/gemma-3-1b-it"
|
22 |
MAX_GPU_MEMORY = "60GiB"
|
23 |
|
24 |
-
# --- Model Loading ---
|
25 |
@GPU(memory=60)
|
26 |
def load_model():
|
27 |
"""Load the Gemma 3 1B model without quantization for full precision."""
|
@@ -43,10 +43,11 @@ def load_model():
|
|
43 |
# --- LLM-Based Request Validation ---
|
44 |
def check_request_with_llm(name, context):
|
45 |
"""Use LLM to check if request is appropriate before processing"""
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
|
|
50 |
CRITERIA:
|
51 |
1. NO minors (under 18) or underage references
|
52 |
2. NO vulnerable populations
|
@@ -54,11 +55,10 @@ CRITERIA:
|
|
54 |
4. NO illegal/harmful scenarios
|
55 |
5. NO inappropriate relationships
|
56 |
Respond ONLY with "TRUE" if acceptable, "FALSE" if not."""
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
try:
|
62 |
tokenizer = pipe.tokenizer
|
63 |
text = tokenizer.apply_chat_template(
|
64 |
validation_prompt,
|
@@ -71,7 +71,7 @@ Respond ONLY with "TRUE" if acceptable, "FALSE" if not."""
|
|
71 |
max_new_tokens=50,
|
72 |
do_sample=False,
|
73 |
temperature=0.1,
|
74 |
-
pad_token_id=pipe.tokenizer.eos_token_id
|
75 |
)
|
76 |
result = parse_llm_output(outputs, validation_prompt).strip().upper()
|
77 |
return result == "TRUE"
|
@@ -220,7 +220,8 @@ def generate_enhanced_persona(name, bio_text, context=""):
|
|
220 |
print(f"Generating enhanced persona for {name}...")
|
221 |
|
222 |
enhancement_prompt = [
|
223 |
-
{"role": "system", "content": """You are an expert AI character developer. Your task is to synthesize information into a detailed and coherent character profile. Focus on personality, potential interests, speaking style, and mannerisms based ONLY on the provided text. Output ONLY the enhanced character profile description. Do not include conversational introductions, explanations, or markdown formatting like headers.
|
|
|
224 |
{"role": "user", "content": f"""Synthesize the following information about '{name}' into a character profile. Context: {context} Information Found:
|
225 |
{bio_text}
|
226 |
Create the profile based *only* on the text above."""}
|
@@ -240,7 +241,7 @@ Create the profile based *only* on the text above."""}
|
|
240 |
do_sample=True,
|
241 |
temperature=0.7,
|
242 |
top_p=0.8,
|
243 |
-
pad_token_id=pipe.tokenizer.eos_token_id
|
244 |
)
|
245 |
parsed_output = parse_llm_output(outputs, enhancement_prompt)
|
246 |
print("Enhanced persona generated.")
|
@@ -263,7 +264,8 @@ Additional context for the simulation: {context}
|
|
263 |
Maintain this persona consistently. Respond naturally based on the profile. Do not mention that you are an AI or a simulation. If asked about details not in the profile, you can be evasive or state you don't know/remember, consistent with the persona."""
|
264 |
|
265 |
prompt = [
|
266 |
-
{"role": "system", "content": """You are an expert AI prompt engineer specializing in character simulation. Create a concise system prompt that instructs the LLM to embody the character based on the profile. The prompt must: 1. Define core personality and speaking style. 2. Specify how to handle unknown topics. 3. Prohibit breaking character or mentioning AI nature. Output ONLY the system prompt itself."""
|
|
|
267 |
{"role": "user", "content": f"""Create a system prompt for an AI to simulate the character '{name}'. Context for simulation: {context} Character Profile:
|
268 |
{enhanced_profile}
|
269 |
Generate the system prompt based *only* on the profile and context provided."""}
|
@@ -283,7 +285,7 @@ Generate the system prompt based *only* on the profile and context provided."""}
|
|
283 |
do_sample=True,
|
284 |
temperature=0.7,
|
285 |
top_p=0.8,
|
286 |
-
pad_token_id=pipe.tokenizer.eos_token_id
|
287 |
)
|
288 |
parsed_output = parse_llm_output(outputs, prompt)
|
289 |
print("System prompt generated.")
|
@@ -314,7 +316,7 @@ def generate_response(messages):
|
|
314 |
do_sample=True,
|
315 |
top_p=0.8,
|
316 |
temperature=0.7,
|
317 |
-
pad_token_id=pipe.tokenizer.eos_token_id
|
318 |
)
|
319 |
parsed_output = parse_llm_output(outputs, messages)
|
320 |
parsed_output = re.sub(r'<end_of_turn>|<start_of_turn>model', '', parsed_output).strip()
|
@@ -414,30 +416,106 @@ class PersonaChat:
|
|
414 |
print(error_msg)
|
415 |
return f"Sorry, I encountered an error: {str(e)}"
|
416 |
|
417 |
-
# --- Gradio Interface with
|
418 |
def create_interface():
|
419 |
persona_chat = PersonaChat()
|
420 |
|
421 |
-
# Mobile-optimized CSS
|
422 |
css = """
|
423 |
-
.gradio-container {
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
.
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
/* Mobile styles */
|
437 |
-
@media (max-width:
|
438 |
-
.main-container { padding: 10px; }
|
439 |
.chat-container { height: 300px !important; }
|
440 |
-
.
|
441 |
}
|
442 |
"""
|
443 |
|
@@ -445,31 +523,30 @@ def create_interface():
|
|
445 |
with gr.Row():
|
446 |
with gr.Column():
|
447 |
with gr.Column():
|
448 |
-
gr.Markdown("# AI Persona Simulator")
|
449 |
-
gr.Markdown("Create and interact with ethical character simulations")
|
450 |
|
451 |
with gr.Column():
|
452 |
gr.Markdown("### Create Your Persona")
|
453 |
-
gr.Markdown("Enter a name and context
|
454 |
name_input = gr.Textbox(label="Character Name", placeholder="e.g., Sherlock Holmes, Historical Figure")
|
455 |
-
context_input = gr.Textbox(label="Character Context", lines=2)
|
456 |
-
set_persona_button = gr.Button("Create Persona")
|
457 |
status_output = gr.Textbox(label="Status", interactive=False)
|
458 |
|
459 |
-
with gr.Accordion("View Details", open=False):
|
460 |
-
enhanced_profile_display = gr.TextArea(label="Profile", lines=10)
|
461 |
system_prompt_display = gr.TextArea(label="System Prompt", lines=10)
|
462 |
|
463 |
with gr.Column():
|
464 |
gr.Markdown("### Chat with Character")
|
465 |
-
character_name_display = gr.Markdown("*No persona created*")
|
466 |
chatbot = gr.Chatbot(height=450, show_label=False)
|
467 |
-
msg_input = gr.Textbox(label="
|
468 |
-
send_button = gr.Button("Send")
|
469 |
|
470 |
-
gr.Markdown("Powered by Gemma 3 1B")
|
471 |
-
|
472 |
-
# Event handlers
|
473 |
def set_persona_flow(name, context):
|
474 |
if not name:
|
475 |
yield "Status: Please enter a character name.", "", "", "*No persona created yet*", []
|
@@ -540,4 +617,10 @@ def create_interface():
|
|
540 |
if __name__ == "__main__":
|
541 |
print("Starting secure AI Persona Simulator with LLM-based request validation...")
|
542 |
demo = create_interface()
|
543 |
-
demo.queue().launch(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# AI Persona Simulator - Final Version
|
2 |
import gradio as gr
|
3 |
import transformers
|
4 |
import torch
|
|
|
21 |
MODEL_ID = "google/gemma-3-1b-it"
|
22 |
MAX_GPU_MEMORY = "60GiB"
|
23 |
|
24 |
+
# --- Model Loading (GPU Isolated) ---
|
25 |
@GPU(memory=60)
|
26 |
def load_model():
|
27 |
"""Load the Gemma 3 1B model without quantization for full precision."""
|
|
|
43 |
# --- LLM-Based Request Validation ---
|
44 |
def check_request_with_llm(name, context):
|
45 |
"""Use LLM to check if request is appropriate before processing"""
|
46 |
+
try:
|
47 |
+
pipe = load_model()
|
48 |
+
|
49 |
+
validation_prompt = [
|
50 |
+
{"role": "system", "content": """You are an ethical AI content moderator. Evaluate if this request is appropriate.
|
51 |
CRITERIA:
|
52 |
1. NO minors (under 18) or underage references
|
53 |
2. NO vulnerable populations
|
|
|
55 |
4. NO illegal/harmful scenarios
|
56 |
5. NO inappropriate relationships
|
57 |
Respond ONLY with "TRUE" if acceptable, "FALSE" if not."""
|
58 |
+
},
|
59 |
+
{"role": "user", "content": f"Character Name: {name}\nContext: {context}"}
|
60 |
+
]
|
61 |
+
|
|
|
62 |
tokenizer = pipe.tokenizer
|
63 |
text = tokenizer.apply_chat_template(
|
64 |
validation_prompt,
|
|
|
71 |
max_new_tokens=50,
|
72 |
do_sample=False,
|
73 |
temperature=0.1,
|
74 |
+
pad_token_id=pipe.tokenizer.eos_token_id
|
75 |
)
|
76 |
result = parse_llm_output(outputs, validation_prompt).strip().upper()
|
77 |
return result == "TRUE"
|
|
|
220 |
print(f"Generating enhanced persona for {name}...")
|
221 |
|
222 |
enhancement_prompt = [
|
223 |
+
{"role": "system", "content": """You are an expert AI character developer. Your task is to synthesize information into a detailed and coherent character profile. Focus on personality, potential interests, speaking style, and mannerisms based ONLY on the provided text. Output ONLY the enhanced character profile description. Do not include conversational introductions, explanations, or markdown formatting like headers."""
|
224 |
+
},
|
225 |
{"role": "user", "content": f"""Synthesize the following information about '{name}' into a character profile. Context: {context} Information Found:
|
226 |
{bio_text}
|
227 |
Create the profile based *only* on the text above."""}
|
|
|
241 |
do_sample=True,
|
242 |
temperature=0.7,
|
243 |
top_p=0.8,
|
244 |
+
pad_token_id=pipe.tokenizer.eos_token_id
|
245 |
)
|
246 |
parsed_output = parse_llm_output(outputs, enhancement_prompt)
|
247 |
print("Enhanced persona generated.")
|
|
|
264 |
Maintain this persona consistently. Respond naturally based on the profile. Do not mention that you are an AI or a simulation. If asked about details not in the profile, you can be evasive or state you don't know/remember, consistent with the persona."""
|
265 |
|
266 |
prompt = [
|
267 |
+
{"role": "system", "content": """You are an expert AI prompt engineer specializing in character simulation. Create a concise system prompt that instructs the LLM to embody the character based on the profile. The prompt must: 1. Define core personality and speaking style. 2. Specify how to handle unknown topics. 3. Prohibit breaking character or mentioning AI nature. Output ONLY the system prompt itself."""
|
268 |
+
},
|
269 |
{"role": "user", "content": f"""Create a system prompt for an AI to simulate the character '{name}'. Context for simulation: {context} Character Profile:
|
270 |
{enhanced_profile}
|
271 |
Generate the system prompt based *only* on the profile and context provided."""}
|
|
|
285 |
do_sample=True,
|
286 |
temperature=0.7,
|
287 |
top_p=0.8,
|
288 |
+
pad_token_id=pipe.tokenizer.eos_token_id
|
289 |
)
|
290 |
parsed_output = parse_llm_output(outputs, prompt)
|
291 |
print("System prompt generated.")
|
|
|
316 |
do_sample=True,
|
317 |
top_p=0.8,
|
318 |
temperature=0.7,
|
319 |
+
pad_token_id=pipe.tokenizer.eos_token_id
|
320 |
)
|
321 |
parsed_output = parse_llm_output(outputs, messages)
|
322 |
parsed_output = re.sub(r'<end_of_turn>|<start_of_turn>model', '', parsed_output).strip()
|
|
|
416 |
print(error_msg)
|
417 |
return f"Sorry, I encountered an error: {str(e)}"
|
418 |
|
419 |
+
# --- Gradio Interface with Enhanced UI ---
|
420 |
def create_interface():
|
421 |
persona_chat = PersonaChat()
|
422 |
|
423 |
+
# Mobile-optimized CSS with modern styling
|
424 |
css = """
|
425 |
+
.gradio-container {
|
426 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
427 |
+
background: linear-gradient(to right, #f8f9fa, #e9ecef);
|
428 |
+
}
|
429 |
+
.main-container {
|
430 |
+
max-width: 1200px;
|
431 |
+
margin: auto;
|
432 |
+
padding: 20px;
|
433 |
+
background: white;
|
434 |
+
border-radius: 15px;
|
435 |
+
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
|
436 |
+
}
|
437 |
+
.header {
|
438 |
+
background: linear-gradient(135deg, #1e3c72, #2a5298);
|
439 |
+
color: white;
|
440 |
+
padding: 25px;
|
441 |
+
border-radius: 10px 10px 0 0;
|
442 |
+
margin-bottom: 25px;
|
443 |
+
text-align: center;
|
444 |
+
}
|
445 |
+
.setup-section {
|
446 |
+
background-color: #f8f9fa;
|
447 |
+
border-radius: 10px;
|
448 |
+
padding: 20px;
|
449 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
450 |
+
margin-bottom: 25px;
|
451 |
+
}
|
452 |
+
.chat-section {
|
453 |
+
background-color: #ffffff;
|
454 |
+
border-radius: 10px;
|
455 |
+
padding: 20px;
|
456 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
457 |
+
}
|
458 |
+
.status-bar {
|
459 |
+
background: #f1f3f5;
|
460 |
+
padding: 12px 15px;
|
461 |
+
border-radius: 5px;
|
462 |
+
margin: 15px 0;
|
463 |
+
font-weight: 500;
|
464 |
+
border: 1px solid #e2e6ea;
|
465 |
+
color: #212529;
|
466 |
+
}
|
467 |
+
.chat-container {
|
468 |
+
border: 1px solid #eaeaea;
|
469 |
+
border-radius: 10px;
|
470 |
+
height: 450px !important;
|
471 |
+
overflow-y: auto;
|
472 |
+
background-color: #ffffff;
|
473 |
+
padding: 10px;
|
474 |
+
}
|
475 |
+
.message-input {
|
476 |
+
margin-top: 10px;
|
477 |
+
}
|
478 |
+
.send-button {
|
479 |
+
background-color: #1e3c72 !important;
|
480 |
+
color: white !important;
|
481 |
+
border-radius: 8px;
|
482 |
+
padding: 10px 20px;
|
483 |
+
font-weight: bold;
|
484 |
+
}
|
485 |
+
.persona-button {
|
486 |
+
background-color: #2a5298 !important;
|
487 |
+
color: white !important;
|
488 |
+
border-radius: 8px;
|
489 |
+
padding: 10px 20px;
|
490 |
+
font-weight: bold;
|
491 |
+
}
|
492 |
+
.system-prompt-display {
|
493 |
+
background-color: #f5f5f5;
|
494 |
+
border-radius: 8px;
|
495 |
+
padding: 15px;
|
496 |
+
margin-top: 15px;
|
497 |
+
border: 1px solid #e0e0e0;
|
498 |
+
font-family: monospace;
|
499 |
+
white-space: pre-wrap;
|
500 |
+
word-wrap: break-word;
|
501 |
+
}
|
502 |
+
.footer {
|
503 |
+
text-align: center;
|
504 |
+
margin-top: 30px;
|
505 |
+
font-size: 0.9em;
|
506 |
+
color: #666;
|
507 |
+
padding: 15px;
|
508 |
+
border-top: 1px solid #eee;
|
509 |
+
}
|
510 |
+
.typing-indicator {
|
511 |
+
color: #aaa;
|
512 |
+
font-style: italic;
|
513 |
+
}
|
514 |
|
515 |
/* Mobile styles */
|
516 |
+
@media (max-width: 768px) {
|
|
|
517 |
.chat-container { height: 300px !important; }
|
518 |
+
.main-container { padding: 10px; }
|
519 |
}
|
520 |
"""
|
521 |
|
|
|
523 |
with gr.Row():
|
524 |
with gr.Column():
|
525 |
with gr.Column():
|
526 |
+
gr.Markdown("# 🤖 AI Persona Simulator")
|
527 |
+
gr.Markdown("Create and interact with ethical character simulations using advanced AI")
|
528 |
|
529 |
with gr.Column():
|
530 |
gr.Markdown("### Create Your Persona")
|
531 |
+
gr.Markdown("Enter a name and context for your character")
|
532 |
name_input = gr.Textbox(label="Character Name", placeholder="e.g., Sherlock Holmes, Historical Figure")
|
533 |
+
context_input = gr.Textbox(label="Character Context", lines=2, placeholder="e.g., Victorian detective living in London, OR Tech entrepreneur focused on AI ethics")
|
534 |
+
set_persona_button = gr.Button("Create Persona & Start Chat", variant="primary")
|
535 |
status_output = gr.Textbox(label="Status", interactive=False)
|
536 |
|
537 |
+
with gr.Accordion("View Generated Details", open=False):
|
538 |
+
enhanced_profile_display = gr.TextArea(label="Enhanced Profile", lines=10)
|
539 |
system_prompt_display = gr.TextArea(label="System Prompt", lines=10)
|
540 |
|
541 |
with gr.Column():
|
542 |
gr.Markdown("### Chat with Character")
|
543 |
+
character_name_display = gr.Markdown("*No persona created yet*")
|
544 |
chatbot = gr.Chatbot(height=450, show_label=False)
|
545 |
+
msg_input = gr.Textbox(label="Your message", placeholder="Type your message here and press Enter...")
|
546 |
+
send_button = gr.Button("Send Message")
|
547 |
|
548 |
+
gr.Markdown("Powered by Gemma 3 1B • Ethically Designed • Safe & Secure")
|
549 |
+
|
|
|
550 |
def set_persona_flow(name, context):
|
551 |
if not name:
|
552 |
yield "Status: Please enter a character name.", "", "", "*No persona created yet*", []
|
|
|
617 |
if __name__ == "__main__":
|
618 |
print("Starting secure AI Persona Simulator with LLM-based request validation...")
|
619 |
demo = create_interface()
|
620 |
+
demo.queue().launch(
|
621 |
+
server_name="0.0.0.0",
|
622 |
+
server_port=7860,
|
623 |
+
show_error=True,
|
624 |
+
debug=True,
|
625 |
+
ssr_mode=False
|
626 |
+
)
|