""" HuggingFace Spaces Entry Point This file is the entry point for HuggingFace Spaces deployment. It imports and launches the production-grade Writing Studio application. For local development or self-hosted deployment, you can also use: python -m writing_studio.main """ import os import sys # Add src to path for imports sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) # Set HuggingFace Spaces friendly defaults os.environ.setdefault("ENVIRONMENT", "production") os.environ.setdefault("DEBUG", "false") os.environ.setdefault("LOG_LEVEL", "INFO") os.environ.setdefault("ENABLE_METRICS", "false") # Disable metrics server on HF Spaces os.environ.setdefault("LOG_FORMAT", "text") # Text logs are easier to read on HF Spaces try: # Try to import the production application from writing_studio.core.analyzer import WritingAnalyzer from writing_studio.core.config import settings from writing_studio.core.exceptions import WritingStudioException from writing_studio.utils.logging import logger import gradio as gr logger.info(f"Starting {settings.app_name} v{settings.app_version}") logger.info(f"Environment: {settings.environment}") def create_interface() -> gr.Blocks: """Create production-grade Gradio interface for HuggingFace Spaces.""" analyzer = WritingAnalyzer() def analyze_wrapper(user_input: str, model_name: str, prompt_pack: str) -> tuple: """Wrapper for analysis with error handling.""" try: if not user_input or not user_input.strip(): return ( "", "", "āš ļø Please provide some text to analyze.", "", ) original, revision, feedback, diff_html, metadata = analyzer.analyze_and_compare( user_input, model_name, prompt_pack ) # Format feedback with metadata feedback_with_meta = f"{feedback}\n\n---\nā±ļø Processing time: {metadata['duration']:.2f}s\nšŸ¤– Model: {metadata['model']}" return original, revision, feedback_with_meta, diff_html except WritingStudioException as e: error_msg = f"āŒ Error: {e.message}" if e.details: error_msg += f"\n\nā„¹ļø Details: {e.details}" logger.error(f"Analysis failed: {error_msg}") return "", "", error_msg, "" except Exception as e: error_msg = f"āŒ Unexpected error: {str(e)}" logger.error(f"Unexpected error in analysis: {e}", exc_info=True) return "", "", error_msg, "" # Create Gradio interface with gr.Blocks( title=settings.app_name, theme=gr.themes.Soft(), ) as demo: gr.Markdown( f""" # āœļø {settings.app_name} **AI-Powered Writing Revision + Comprehensive Rubric Analysis** Get your text professionally revised by AI and receive detailed feedback across multiple criteria. **Features:** - šŸ¤– **AI-Powered Revision** using FLAN-T5 (instruction-tuned model) - šŸŽÆ **Real Rubric Scoring** (Clarity, Conciseness, Organization, Evidence, Grammar) - šŸ“Š **Visual Diff** highlighting all changes - šŸ“ **5 Specialized Modes** (General, Literature, Tech Comm, Academic, Creative) - šŸ’” **Actionable Feedback** to understand improvements **Version:** {settings.app_version} | **Model:** FLAN-T5 (instruction-following) """ ) with gr.Row(): with gr.Column(scale=2): user_input = gr.Textbox( lines=10, placeholder="Paste your draft here...", label="Your Draft", info=f"Maximum {settings.max_text_length:,} characters", ) with gr.Column(scale=1): model_name = gr.Textbox( value=settings.default_model, label="AI Model", info="FLAN-T5 (instruction-tuned for revision)", ) prompt_pack = gr.Dropdown( choices=analyzer.get_available_prompt_packs(), value="General", label="Revision Mode", info="Select writing context", ) run_btn = gr.Button("✨ Revise & Analyze", variant="primary", size="lg") gr.Markdown("## šŸ“Š Results") with gr.Row(): original = gr.Textbox( lines=12, label="šŸ“„ Original Text", interactive=False, ) revision = gr.Textbox( lines=12, label="šŸ¤– AI-Revised Text", interactive=False, ) feedback = gr.Textbox( lines=10, label="šŸ“Š Rubric Analysis", info="Detailed scoring across 5 writing criteria", interactive=False, ) diff_html = gr.HTML(label="šŸ” Changes Highlighted") # Wire up the button run_btn.click( fn=analyze_wrapper, inputs=[user_input, model_name, prompt_pack], outputs=[original, revision, feedback, diff_html], ) # Add footer gr.Markdown( """ --- ### šŸ’” How to Use 1. **Paste your text** in the input box 2. **Choose a revision mode** (General, Literature, Tech Comm, Academic, or Creative) 3. **Click "Revise & Analyze"** 4. **Review the AI revision** - see what improved 5. **Check the rubric scores** - understand the analysis 6. **View the diff** - see exactly what changed ### šŸ¤– About the AI Model **FLAN-T5** is an instruction-tuned model specifically trained to follow revision instructions. Unlike GPT-2 (text continuation), FLAN-T5 actually understands and executes revision tasks. **First analysis takes ~60s** (model loading), subsequent analyses are much faster! ### šŸ“Š Revision Modes - **General** - Improve clarity and readability - **Literature** - Strengthen literary analysis - **Tech Comm** - Enhance technical precision - **Academic** - Improve formal scholarly tone - **Creative** - Enhance imagery and engagement ### šŸ“š Documentation - [GitHub Repository](https://github.com/yourusername/writing-studio) - [User Guide](https://github.com/yourusername/writing-studio/blob/main/docs/USER_GUIDE.md) --- Built with [Gradio](https://gradio.app/) • Powered by FLAN-T5 + Custom Rubric Algorithms """ ) return demo # Create and launch the interface demo = create_interface() # Launch with HuggingFace Spaces friendly settings if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True, ) except ImportError as e: # Fallback to simple version if production code not available print(f"Warning: Could not import production code: {e}") print("Falling back to simple version...") import gradio as gr from transformers import pipeline import difflib # Simple version for emergency fallback generator = pipeline("text-generation", model="distilgpt2") def simple_analyze(user_text, model_name="distilgpt2"): """Simple analysis function.""" if not user_text: return "", "", "Please provide some text.", "" try: prompt = f"Revise this text for clarity:\n{user_text}" revision = generator(prompt, max_length=300, num_return_sequences=1, do_sample=True)[0]["generated_text"] feedback = "āš ļø Running in fallback mode. Install full version for rubric scoring." diff = difflib.HtmlDiff().make_table( user_text.splitlines(), revision.splitlines(), fromdesc="Original", todesc="AI Revision" ) return user_text, revision, feedback, diff except Exception as e: return "", "", f"Error: {str(e)}", "" with gr.Blocks(title="AI Writing Studio") as demo: gr.Markdown("# āœļø AI Writing Studio (Simplified)") gr.Markdown("āš ļø Running in fallback mode. Some features may be limited.") with gr.Row(): user_input = gr.Textbox(lines=10, placeholder="Paste your draft here...") model_name = gr.Textbox(value="distilgpt2", label="Model") with gr.Row(): original = gr.Textbox(lines=12, label="Original") revision = gr.Textbox(lines=12, label="Revision") feedback = gr.Textbox(lines=8, label="Feedback") diff_html = gr.HTML(label="Diff") run_btn = gr.Button("Analyze") run_btn.click( fn=simple_analyze, inputs=[user_input, model_name], outputs=[original, revision, feedback, diff_html] ) if __name__ == "__main__": demo.launch()