Spaces:
Sleeping
Sleeping
add the option to select multiple services using checkboxes instead of writing them for easier acces
41e86f7 verified | # csword_ai_chatbot.py (Fixed Version with Multi-Select Services) | |
| import os | |
| import sys | |
| import csv | |
| import re | |
| import requests | |
| from datetime import datetime | |
| from bs4 import BeautifulSoup | |
| from openai import OpenAI | |
| import gradio as gr | |
| # 1. Load CSWORD.ai context | |
| def load_context(): | |
| try: | |
| with open("csword_homepage.html", "r", encoding="utf-8") as file: | |
| soup = BeautifulSoup(file.read(), "html.parser") | |
| texts = [tag.get_text(separator=" ").strip() for tag in soup.find_all(["h1", "h2", "h3", "p", "li"])] | |
| return "\n".join(filter(None, texts)) | |
| except FileNotFoundError: | |
| return "CSWORD.ai is a cybersecurity awareness and training platform that leverages AI to deliver personalized, adaptive education." | |
| # 2. Set up DeepInfra client | |
| token = os.getenv("DEEPINFRA_TOKEN", "285LUJulGIprqT6hcPhiXtcrphU04FG4") | |
| openai = OpenAI(api_key=token, base_url="https://api.deepinfra.com/v1/openai") | |
| model_name = "google/gemma-3-27b-it" | |
| SYSTEM_PROMPT_CSWORD = f""" | |
| You are Csword AI a helpful and expert cybersecurity assistant working on the csword.ai website. Your purpose is to answer user questions only related to cybersecurity. Do not answer questions outside this domain. Provide clear, accurate, and up-to-date cybersecurity information tailored for individuals, businesses, or IT teams. If a question is unrelated to cybersecurity, respond politely that you are only trained to answer cybersecurity-related questions. | |
| - content website: https://csword.ai | |
| csword Next-Gen AI Platform for Cyber Awareness | |
| - Csword Features | |
| 1- AI-Powered Phishing Simulations | |
| 2- Intelligent LMS Training with AI Adaptation | |
| 3- Penetration Testing & Threat Simulation | |
| 4- Digital Awareness Deliverables | |
| 5- Cybersecurity Events | |
| 6- Risk & Security Assessment Services | |
| 7- Interactive Awareness Sessions | |
| """ | |
| SYSTEM_PROMPT_GENERAL = "You are a cybersecurity expert. Answer clearly and informatively." | |
| CONTEXT = load_context() | |
| # 3. Form state | |
| form_type = None | |
| user_form_data = {} | |
| final_question = ("final_note", "Would you like any further assistance with cybersecurity-related topics?") | |
| service_options = [ | |
| "AI Phishing Simulation Platform", | |
| "AI-Tailored LMS Training", | |
| "Cybersecurity Events", | |
| "Digital Awareness Deliverables", | |
| "Executive Reporting & Risk Scoring", | |
| "On-Site Awareness Sessions", | |
| "Penetration Testing & Threat Simulation", | |
| "Risk & Security Assessment", | |
| "24/7 AI Cybersecurity Consultant" | |
| ] | |
| form_definitions = { | |
| "demo": [ | |
| ("name", "Full Name *"), | |
| ("company", "Company Name *"), | |
| ("email", "Work Email *"), | |
| ("phone", "Phone Number"), | |
| ("employees", ["Number of Employees *", ["1-50", "51-200", "201-500", "+500"]]), | |
| ("services", ["Services of Interest (select multiple):", "checkboxes", service_options]), | |
| ("specific_reqs", "Do you have any specific requirements or questions?"), | |
| final_question | |
| ], | |
| "contact": [ | |
| ("name", "Full Name *"), | |
| ("email", "Email Address *"), | |
| ("company", "Company"), | |
| ("subject", "Subject *"), | |
| ("message", "Message *"), | |
| final_question | |
| ] | |
| } | |
| # 4. Validation | |
| def validate_input(key, value): | |
| if not value or (isinstance(value, str) and not value.strip()): | |
| return "This field is required. Please provide a value." | |
| if key == "email" and not re.match(r"[^@\s]+@[^@\s]+\.[^@\s]+", value): | |
| return "Invalid email format. Please enter a valid email address." | |
| if key == "phone" and re.search(r"[a-zA-Z]", value): | |
| return "Invalid phone number. Only digits and symbols are allowed." | |
| return None | |
| # 5. Chat handler | |
| def answer_question(query: str, is_general=False) -> str: | |
| prompt = SYSTEM_PROMPT_GENERAL if is_general else f"{SYSTEM_PROMPT_CSWORD}\nContext:\n{CONTEXT}" | |
| messages = [ | |
| {"role": "system", "content": prompt}, | |
| {"role": "user", "content": query}, | |
| ] | |
| try: | |
| response = openai.chat.completions.create( | |
| model=model_name, | |
| messages=messages, | |
| reasoning_effort="none" | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"Error: {e}" | |
| # 6. Chat function | |
| def chat_fn(message, history, checkbox_values=None): | |
| global user_form_data, form_type | |
| if form_type and len(user_form_data) < len(form_definitions[form_type]): | |
| # Allow user to cancel form at any step | |
| cancel_keywords = ["cancel", "stop", "don't want", "exit", "no thanks", "back", "abort"] | |
| if any(kw in message.lower() for kw in cancel_keywords): | |
| user_form_data, form_type = {}, None | |
| return history + [(message, "Form cancelled. How can I assist you with cybersecurity?")], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| key, question = form_definitions[form_type][len(user_form_data)] | |
| if isinstance(question, list): | |
| if question[1] == "checkboxes": | |
| # This is a checkbox question - handle checkbox values | |
| if checkbox_values is None or len(checkbox_values) == 0: | |
| return history + [(message, "Please select at least one service option.")], "", gr.update(visible=False), gr.update(visible=False, choices=[], value=None), gr.update(visible=True, value=[]), gr.update(visible=True) | |
| user_form_data[key] = checkbox_values | |
| history = history + [(message, f"Selected services: {', '.join(checkbox_values)}")] | |
| else: | |
| # This is a dropdown question | |
| dropdown_options = question[1] | |
| if message not in dropdown_options: | |
| return history + [(message, f"Please choose one of the provided options: {', '.join(dropdown_options)}")], "", gr.update(visible=False), gr.update(visible=True, choices=dropdown_options, value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| user_form_data[key] = message | |
| history = history + [(message, f"Selected: {message}")] | |
| else: | |
| # This is a text question | |
| error = validate_input(key, message) | |
| if error: | |
| return history + [(message, error)], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| user_form_data[key] = message | |
| history = history + [(message, "Thank you!")] | |
| # Check if we have more questions | |
| if len(user_form_data) < len(form_definitions[form_type]): | |
| next_key, next_question = form_definitions[form_type][len(user_form_data)] | |
| if isinstance(next_question, list): | |
| if next_question[1] == "checkboxes": | |
| # Next question is checkboxes - hide text input and dropdown, show checkboxes | |
| return history + [("", next_question[0])], "", gr.update(visible=False), gr.update(visible=False, choices=[], value=None), gr.update(visible=True, value=[]), gr.update(visible=True) | |
| else: | |
| # Next question is dropdown - hide text input and checkboxes, show dropdown | |
| dropdown_options = next_question[1] | |
| return history + [("", next_question[0])], "", gr.update(visible=False), gr.update(visible=True, choices=dropdown_options, value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| else: | |
| # Next question is text - show text input, hide dropdown and checkboxes | |
| return history + [("", next_question)], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| else: | |
| # Form complete | |
| user_form_data["timestamp"] = datetime.now().isoformat() | |
| user_form_data["type"] = form_type.capitalize() | |
| # Convert list values to string for CSV storage | |
| csv_data = user_form_data.copy() | |
| for k, v in csv_data.items(): | |
| if isinstance(v, list): | |
| csv_data[k] = "; ".join(v) | |
| file_name = f"{form_type}_requests.csv" | |
| file_exists = os.path.isfile(file_name) | |
| try: | |
| with open(file_name, mode="a", newline="", encoding="utf-8") as file: | |
| writer = csv.DictWriter(file, fieldnames=list(csv_data.keys())) | |
| if not file_exists: | |
| writer.writeheader() | |
| writer.writerow(csv_data) | |
| msg1 = f"Thank you! Your {form_type} request has been received and saved." | |
| msg2 = final_question[1] | |
| user_form_data, form_type = {}, None | |
| return history + [("", msg1), ("", msg2)], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| except Exception as e: | |
| msg1 = f"Thank you! Your {form_type} request has been received (Note: Could not save to file: {e})." | |
| msg2 = final_question[1] | |
| user_form_data, form_type = {}, None | |
| return history + [("", msg1), ("", msg2)], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # Admin commands | |
| if message.lower().startswith("admin:") and "guide" in message.lower(): | |
| steps = ( | |
| "To work with the CSWORD.ai platform:\n" | |
| "1. Login to the admin dashboard.\n" | |
| "2. Upload user list for training enrollment.\n" | |
| "3. Configure phishing simulation campaigns.\n" | |
| "4. Schedule awareness sessions.\n" | |
| "5. Monitor progress via the Executive Risk Dashboard." | |
| ) | |
| return history + [(message, steps)], "", gr.update(visible=True), gr.update(visible=False, choices=[]), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # Form triggers | |
| if re.search(r"\b(demo|quote|custom)\b", message, re.IGNORECASE): | |
| form_type = "demo" | |
| user_form_data = {} | |
| first_question = form_definitions[form_type][0][1] | |
| return history + [(message, "Sure! Let's start with a few details."), ("", first_question)], "", gr.update(visible=True), gr.update(visible=False, choices=[]), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| if re.search(r"\b(contact|message|speak)\b", message, re.IGNORECASE): | |
| form_type = "contact" | |
| user_form_data = {} | |
| first_question = form_definitions[form_type][0][1] | |
| return history + [(message, "Of course! Please fill out the following."), ("", first_question)], "", gr.update(visible=True), gr.update(visible=False, choices=[]), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # Generic help | |
| if re.search(r"\bhelp\b", message, re.IGNORECASE): | |
| return history + [(message, "Yes, of course! Tell me your question.")], "", gr.update(visible=True), gr.update(visible=False, choices=[]), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # Cybersecurity questions | |
| if re.search(r"\b(cybersecurity|malware|phishing|ransomware|network|threat|attack|industry|NIST|ISO|compliance)\b", message, re.IGNORECASE): | |
| reply = answer_question(message, is_general=True) | |
| return history + [(message, reply)], "", gr.update(visible=True), gr.update(visible=False, choices=[]), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # Default response for everything else | |
| reply = answer_question(message) | |
| return history + [(message, reply)], "", gr.update(visible=True), gr.update(visible=False, choices=[], value=None), gr.update(visible=False, value=[]), gr.update(visible=False) | |
| # 7. Launch Gradio | |
| with gr.Blocks(title="CSWORD.ai Chatbot") as demo: | |
| gr.Markdown("## ๐ Welcome to the CSWORD.ai Assistant!\nHello, I'm the CSWORD AI Assistant ๐ค. [Click here to visit CSWORD.ai](https://csword.ai)\nAsk questions, request a demo, or contact us.") | |
| chatbot = gr.Chatbot(value=[[None, "๐ Hello! I am the CSWORD AI Chatbot. I can help you with any cybersecurity-related questions or guidance. How can I assist you today?"]]) | |
| with gr.Row(): | |
| user_input = gr.Textbox(show_label=False, placeholder="Enter your question here...", scale=4) | |
| dropdown_input = gr.Dropdown( | |
| choices=[], | |
| label="Please select an option", | |
| visible=False, | |
| scale=2, | |
| interactive=True | |
| ) | |
| # Add checkboxes for services | |
| services_checkboxes = gr.CheckboxGroup( | |
| choices=service_options, | |
| label="Select Services of Interest", | |
| visible=False, | |
| value=[] | |
| ) | |
| # Add send button for checkboxes | |
| send_services_btn = gr.Button("Send Selected Services", visible=False) | |
| submit = gr.Button("Send") | |
| def get_query(txt, drop, hist, checkbox_vals): | |
| # If dropdown is visible and has a value, use dropdown value | |
| if dropdown_input.visible and drop: | |
| return chat_fn(drop, hist) | |
| # Otherwise use text input | |
| elif txt.strip(): | |
| return chat_fn(txt, hist) | |
| else: | |
| return hist, "", gr.update(), gr.update(), gr.update(), gr.update() | |
| def handle_dropdown_selection(drop, hist): | |
| if drop: | |
| return chat_fn(drop, hist) | |
| else: | |
| return hist, "", gr.update(), gr.update(), gr.update(), gr.update() | |
| def handle_services_submission(checkbox_vals, hist): | |
| return chat_fn("services_selected", hist, checkbox_vals) | |
| submit.click(get_query, inputs=[user_input, dropdown_input, chatbot, services_checkboxes], outputs=[chatbot, user_input, user_input, dropdown_input, services_checkboxes, send_services_btn]) | |
| user_input.submit(get_query, inputs=[user_input, dropdown_input, chatbot, services_checkboxes], outputs=[chatbot, user_input, user_input, dropdown_input, services_checkboxes, send_services_btn]) | |
| # Handle dropdown selection | |
| dropdown_input.select(handle_dropdown_selection, inputs=[dropdown_input, chatbot], outputs=[chatbot, user_input, user_input, dropdown_input, services_checkboxes, send_services_btn]) | |
| # Handle services submission | |
| send_services_btn.click(handle_services_submission, inputs=[services_checkboxes, chatbot], outputs=[chatbot, user_input, user_input, dropdown_input, services_checkboxes, send_services_btn]) | |
| if __name__ == "__main__": | |
| demo.launch() |