Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| NZ Governance Playbook - Web Demo | |
| Interactive web interface for the trained ACE governance playbook. | |
| Can be deployed to Hugging Face Spaces or run locally with public sharing. | |
| """ | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from openai import OpenAI | |
| from dotenv import load_dotenv | |
| import gradio as gr | |
| # Load environment | |
| load_dotenv() | |
| # Find latest playbook | |
| results_dir = Path(__file__).parent / "results" / "governance_v1" | |
| runs = sorted([d for d in results_dir.iterdir() if d.is_dir()]) | |
| if not runs: | |
| raise RuntimeError("No training runs found. Please run training first.") | |
| latest_run = runs[-1] | |
| playbook_path = latest_run / "best_playbook.txt" | |
| if not playbook_path.exists(): | |
| raise RuntimeError(f"Playbook not found at {playbook_path}") | |
| # Load playbook | |
| with open(playbook_path, "r", encoding="utf-8") as f: | |
| PLAYBOOK = f.read() | |
| # Initialize API client | |
| api_provider = os.getenv("API_PROVIDER", "together").lower() | |
| api_key = os.getenv(f"{api_provider.upper()}_API_KEY") | |
| if not api_key: | |
| raise RuntimeError(f"No API key found for {api_provider}") | |
| # Setup API base URL | |
| if api_provider == "together": | |
| base_url = "https://api.together.xyz/v1" | |
| elif api_provider == "openai": | |
| base_url = "https://api.openai.com/v1" | |
| else: | |
| base_url = None | |
| client = OpenAI(api_key=api_key, base_url=base_url) | |
| model = os.getenv("GENERATOR_MODEL", "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo") | |
| def query_playbook(question: str, temperature: float = 0.7) -> str: | |
| """Query the playbook with a governance or finance regulatory question.""" | |
| if not question.strip(): | |
| return "Please enter a question." | |
| system_prompt = f"""You are an expert on New Zealand public sector governance and financial regulatory frameworks including: | |
| GOVERNANCE: | |
| - Algorithm Charter for Aotearoa New Zealand | |
| - Privacy Act 2020 and Health Information Privacy Code (HIPC) | |
| - NZISM (New Zealand Information Security Manual) | |
| - HISO 10029 (Health Information Security Framework) | |
| - Official Information Act (OIA) | |
| - Public Records Act 2005 | |
| FINANCE & REGULATION: | |
| - Financial Markets Conduct Act 2013 (FMC Act) | |
| - Credit Contracts and Consumer Finance Act (CCCFA) | |
| - Anti-Money Laundering and Countering Financing of Terrorism Act (AML/CFT) | |
| - Conduct of Financial Institutions (CoFI) | |
| - Climate-related Disclosures (NZ CS 1, 2, 3) | |
| You have learned from extensive Q&A data and have access to a detailed playbook of strategies, insights, and common mistakes. | |
| PLAYBOOK: | |
| {PLAYBOOK} | |
| When answering questions: | |
| 1. Reference relevant playbook entries (e.g., [sai-00007]) | |
| 2. Cite specific frameworks and their requirements | |
| 3. Provide practical, actionable guidance | |
| 4. Consider Te Tiriti obligations and Māori data sovereignty where relevant | |
| 5. Be clear about when multiple frameworks apply | |
| Answer concisely but comprehensively.""" | |
| messages = [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": question} | |
| ] | |
| try: | |
| response = client.chat.completions.create( | |
| model=model, | |
| messages=messages, | |
| temperature=temperature, | |
| max_tokens=1500 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"❌ Error: {str(e)}" | |
| # Example questions | |
| EXAMPLES = [ | |
| "What are the key principles of the Algorithm Charter?", | |
| "What are the CCCFA responsible lending steps?", | |
| "When must I notify the Privacy Commissioner of a breach?", | |
| "What is insider trading under the FMC Act?", | |
| "What are climate disclosure thresholds in New Zealand?", | |
| "How do I handle an OIA request for sensitive information?", | |
| "What are the three levels of customer due diligence under AML/CFT?", | |
| "What's the relationship between ISO 27001 and NZISM?" | |
| ] | |
| # Custom CSS matching kereru.ai style | |
| # Create Gradio interface with custom theme | |
| custom_theme = gr.themes.Base( | |
| primary_hue="emerald", | |
| secondary_hue="gray", | |
| neutral_hue="gray", | |
| font=gr.themes.GoogleFont("Inter"), | |
| ).set( | |
| body_background_fill="#ffffff", | |
| body_background_fill_dark="#ffffff", | |
| body_text_color="#1f2937", | |
| body_text_color_dark="#1f2937", | |
| button_primary_background_fill="#10b981", | |
| button_primary_background_fill_hover="#059669", | |
| button_primary_text_color="white", | |
| button_secondary_background_fill="#f9fafb", | |
| button_secondary_background_fill_hover="#f3f4f6", | |
| button_secondary_text_color="#374151", | |
| button_secondary_text_color_hover="#10b981", | |
| button_secondary_border_color="#d1d5db", | |
| button_secondary_border_color_hover="#10b981", | |
| input_background_fill="#f9fafb", | |
| input_background_fill_dark="#f9fafb", | |
| input_border_color="#d1d5db", | |
| input_border_color_dark="#d1d5db", | |
| block_background_fill="#ffffff", | |
| block_border_color="#e5e7eb", | |
| ) | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); | |
| h1 { | |
| color: #1f2937 !important; | |
| font-size: 2.75em !important; | |
| font-weight: 800 !important; | |
| margin-bottom: 0.75em !important; | |
| } | |
| strong { | |
| color: #10b981 !important; | |
| } | |
| /* Labels and text visibility */ | |
| label, .label { | |
| color: #374151 !important; | |
| font-weight: 500 !important; | |
| } | |
| p, span { | |
| color: #4b5563 !important; | |
| } | |
| /* Example questions styling */ | |
| .examples label { | |
| color: #6b7280 !important; | |
| } | |
| .examples button { | |
| color: #374151 !important; | |
| background: #f9fafb !important; | |
| border: 1px solid #d1d5db !important; | |
| } | |
| .examples button:hover { | |
| color: #10b981 !important; | |
| background: #f0fdf4 !important; | |
| border-color: #10b981 !important; | |
| } | |
| footer img { | |
| display: none !important; | |
| } | |
| footer, footer * { | |
| color: #6b7280 !important; | |
| } | |
| footer a, footer a:hover, footer a:visited { | |
| color: #6b7280 !important; | |
| } | |
| """ | |
| with gr.Blocks(title="NZ Governance & Finance Playbook", css=CUSTOM_CSS, theme=custom_theme) as demo: | |
| gr.Markdown("# Governance & Finance Playbook for Aotearoa") | |
| gr.Markdown("Ask questions about New Zealand governance and financial regulatory frameworks:") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown( | |
| """ | |
| **Governance:** | |
| - **Algorithm Charter** for AI/algorithmic transparency | |
| - **Privacy Act 2020 & HIPC** for privacy and health data | |
| - **NZISM** for information security | |
| - **HISO 10029** for health sector security | |
| - **OIA** for official information requests | |
| - **Public Records Act** for records management | |
| """ | |
| ) | |
| with gr.Column(): | |
| gr.Markdown( | |
| """ | |
| **Finance & Regulation:** | |
| - **FMC Act** for financial markets conduct | |
| - **CCCFA** for responsible lending and consumer credit | |
| - **AML/CFT** for anti-money laundering | |
| - **CoFI** for conduct of financial institutions | |
| - **Climate Disclosures** for climate-related reporting | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| question_input = gr.Textbox( | |
| label="Your Governance Question", | |
| placeholder="e.g., What are the notification requirements for a privacy breach?", | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| submit_btn = gr.Button("Ask playbook", variant="primary", size="lg", elem_classes="primary-btn") | |
| clear_btn = gr.ClearButton([question_input], value="Clear", elem_classes="secondary-btn") | |
| temperature_slider = gr.Slider( | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.7, | |
| step=0.1, | |
| label="Temperature (creativity)", | |
| info="Lower = more focused, Higher = more creative" | |
| ) | |
| with gr.Column(scale=3): | |
| answer_output = gr.Textbox( | |
| label="Answer", | |
| lines=20 | |
| ) | |
| gr.Examples( | |
| examples=EXAMPLES, | |
| inputs=question_input, | |
| label="Example Questions" | |
| ) | |
| submit_btn.click( | |
| fn=query_playbook, | |
| inputs=[question_input, temperature_slider], | |
| outputs=answer_output | |
| ) | |
| question_input.submit( | |
| fn=query_playbook, | |
| inputs=[question_input, temperature_slider], | |
| outputs=answer_output | |
| ) | |
| if __name__ == "__main__": | |
| # Launch with public sharing enabled | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, # Creates a public shareable link | |
| show_error=True, | |
| show_api=False | |
| ) | |