ErenalpCet commited on
Commit
8482fb3
·
verified ·
1 Parent(s): 783ed02

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -48
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # AI Persona Simulator with LLM-Based Request Validation
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
- pipe = load_model()
47
-
48
- validation_prompt = [
49
- {"role": "system", "content": """You are an ethical AI content moderator. Evaluate if this request is appropriate.
 
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
- {"role": "user", "content": f"Character Name: {name}\nContext: {context}"}
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 if pipe.tokenizer.eos_token_id else None
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. Start directly with the profile text."""},
 
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 if pipe.tokenizer.eos_token_id else None
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 if pipe.tokenizer.eos_token_id else None
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 if pipe.tokenizer.eos_token_id else None
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 Accessibility ---
418
  def create_interface():
419
  persona_chat = PersonaChat()
420
 
421
- # Mobile-optimized CSS (black/white friendly)
422
  css = """
423
- .gradio-container { font-family: Arial, sans-serif; }
424
- .main-container { max-width: 1200px; margin: auto; padding: 0; }
425
- .header { background: #2c3e50; color: white; padding: 20px; margin-bottom: 20px; }
426
- .setup-section { background-color: #f9f9f9; padding: 20px; margin-bottom: 20px; }
427
- .chat-section { background-color: white; padding: 20px; }
428
- .status-bar { background: #e9ecef; padding: 10px; margin: 15px 0; }
429
- .chat-container { border: 1px solid #ccc; height: 500px !important; }
430
- .message-input { margin-top: 10px; }
431
- .persona-button { background-color: #2c3e50 !important; color: white !important; }
432
- .system-prompt-display { background-color: #f5f5f5; padding: 15px; margin-top: 15px; }
433
- .footer { text-align: center; margin-top: 20px; }
434
- .typing-indicator { color: #666; font-style: italic; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
  /* Mobile styles */
437
- @media (max-width: 600px) {
438
- .main-container { padding: 10px; }
439
  .chat-container { height: 300px !important; }
440
- .persona-button { width: 100%; margin: 10px 0; }
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 (avoid underage/vulnerable personas)")
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="Message", placeholder="Type here...")
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(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
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
+ )