Emmanuel Frimpong Asante
		
	commited on
		
		
					Commit 
							
							·
						
						fb975db
	
1
								Parent(s):
							
							44a781d
								
update space
Browse files
    	
        app.py
    CHANGED
    
    | 
         @@ -6,8 +6,9 @@ import logging 
     | 
|
| 6 | 
         
             
            import dotenv
         
     | 
| 7 | 
         
             
            import gradio as gr
         
     | 
| 8 | 
         
             
            import numpy as np
         
     | 
| 9 | 
         
            -
            from pymongo import MongoClient
         
     | 
| 10 | 
         
             
            from datetime import datetime
         
     | 
| 
         | 
|
| 11 | 
         
             
            from utils import PoultryFarmBot, llama3_response
         
     | 
| 12 | 
         
             
            from transformers import AutoModelForCausalLM, AutoTokenizer
         
     | 
| 13 | 
         | 
| 
         @@ -20,26 +21,41 @@ logger = logging.getLogger(__name__) 
     | 
|
| 20 | 
         | 
| 21 | 
         
             
            # MongoDB Setup for logging and audit
         
     | 
| 22 | 
         
             
            MONGO_URI = os.getenv("MONGO_URI")
         
     | 
| 23 | 
         
            -
             
     | 
| 24 | 
         
            -
             
     | 
| 25 | 
         
            -
             
     | 
| 26 | 
         
            -
             
     | 
| 27 | 
         
            -
             
     | 
| 28 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 29 | 
         | 
| 30 | 
         
             
            def log_to_db(level, message):
         
     | 
| 31 | 
         
            -
                 
     | 
| 32 | 
         
            -
                     
     | 
| 33 | 
         
            -
             
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
             
     | 
| 36 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 37 | 
         | 
| 38 | 
         
             
            # Override logger methods to also log to MongoDB
         
     | 
| 39 | 
         
             
            class MongoHandler(logging.Handler):
         
     | 
| 40 | 
         
             
                def emit(self, record):
         
     | 
| 41 | 
         
             
                    log_entry = self.format(record)
         
     | 
| 42 | 
         
            -
                     
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 43 | 
         | 
| 44 | 
         
             
            mongo_handler = MongoHandler()
         
     | 
| 45 | 
         
             
            mongo_handler.setLevel(logging.INFO)
         
     | 
| 
         @@ -59,17 +75,21 @@ else: 
     | 
|
| 59 | 
         
             
            logger.info("Initializing PoultryFarmBot instance.")
         
     | 
| 60 | 
         
             
            bot = PoultryFarmBot(db)
         
     | 
| 61 | 
         | 
| 62 | 
         
            -
            # Load Llama 3. 
     | 
| 63 | 
         
            -
             
     | 
| 64 | 
         
            -
             
     | 
| 65 | 
         
            -
             
     | 
| 66 | 
         
            -
             
     | 
| 67 | 
         
            -
             
     | 
| 68 | 
         
            -
             
     | 
| 69 | 
         
            -
             
     | 
| 70 | 
         
            -
                 
     | 
| 71 | 
         
            -
             
     | 
| 72 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 73 | 
         | 
| 74 | 
         
             
            def chatbot_response(image, text, username, password):
         
     | 
| 75 | 
         
             
                """
         
     | 
| 
         @@ -84,30 +104,34 @@ def chatbot_response(image, text, username, password): 
     | 
|
| 84 | 
         
             
                Returns:
         
     | 
| 85 | 
         
             
                    str: Response generated by the chatbot.
         
     | 
| 86 | 
         
             
                """
         
     | 
| 87 | 
         
            -
                 
     | 
| 88 | 
         
            -
             
     | 
| 89 | 
         
            -
                     
     | 
| 90 | 
         
            -
             
     | 
| 91 | 
         
            -
             
     | 
| 92 | 
         
            -
             
     | 
| 93 | 
         
            -
             
     | 
| 94 | 
         
            -
             
     | 
| 95 | 
         
            -
                     
     | 
| 96 | 
         
            -
             
     | 
| 97 | 
         
            -
             
     | 
| 98 | 
         
            -
                         
     | 
| 99 | 
         
            -
             
     | 
| 100 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 101 | 
         
             
                    else:
         
     | 
| 102 | 
         
            -
                         
     | 
| 103 | 
         
            -
                         
     | 
| 104 | 
         
            -
                         
     | 
| 105 | 
         
            -
             
     | 
| 106 | 
         
            -
             
     | 
| 107 | 
         
            -
             
     | 
| 108 | 
         
            -
                     
     | 
| 109 | 
         
            -
                     
     | 
| 110 | 
         
            -
                    return response
         
     | 
| 111 | 
         | 
| 112 | 
         
             
            # Gradio interface
         
     | 
| 113 | 
         
             
            def build_gradio_interface():
         
     | 
| 
         @@ -117,66 +141,74 @@ def build_gradio_interface(): 
     | 
|
| 117 | 
         
             
                Returns:
         
     | 
| 118 | 
         
             
                    gr.Blocks: Gradio Blocks object representing the chatbot interface.
         
     | 
| 119 | 
         
             
                """
         
     | 
| 120 | 
         
            -
                 
     | 
| 121 | 
         
            -
             
     | 
| 122 | 
         
            -
                    gr. 
     | 
| 123 | 
         
            -
             
     | 
| 124 | 
         
            -
             
     | 
| 125 | 
         
            -
             
     | 
| 126 | 
         
            -
             
     | 
| 127 | 
         
            -
                        with gr. 
     | 
| 128 | 
         
            -
                             
     | 
| 129 | 
         
            -
                                 
     | 
| 130 | 
         
            -
             
     | 
| 131 | 
         
            -
             
     | 
| 132 | 
         
            -
             
     | 
| 133 | 
         
            -
             
     | 
| 134 | 
         
            -
             
     | 
| 135 | 
         
            -
                             
     | 
| 136 | 
         
            -
                                 
     | 
| 137 | 
         
            -
             
     | 
| 138 | 
         
            -
             
     | 
| 139 | 
         
            -
             
     | 
| 140 | 
         
            -
             
     | 
| 141 | 
         
            -
             
     | 
| 142 | 
         
            -
                                 
     | 
| 143 | 
         
            -
             
     | 
| 144 | 
         
            -
             
     | 
| 145 | 
         
            -
             
     | 
| 146 | 
         
            -
             
     | 
| 147 | 
         
            -
             
     | 
| 148 | 
         
            -
                                 
     | 
| 149 | 
         
            -
             
     | 
| 150 | 
         
            -
             
     | 
| 151 | 
         
            -
             
     | 
| 152 | 
         
            -
             
     | 
| 153 | 
         
            -
             
     | 
| 154 | 
         
            -
             
     | 
| 155 | 
         
            -
             
     | 
| 156 | 
         
            -
                         
     | 
| 157 | 
         
            -
             
     | 
| 158 | 
         
            -
             
     | 
| 159 | 
         
            -
             
     | 
| 160 | 
         
            -
             
     | 
| 161 | 
         
            -
             
     | 
| 162 | 
         
            -
             
     | 
| 163 | 
         
            -
             
     | 
| 164 | 
         
            -
                         
     | 
| 165 | 
         
            -
             
     | 
| 166 | 
         
            -
             
     | 
| 167 | 
         
            -
             
     | 
| 168 | 
         
            -
             
     | 
| 169 | 
         
            -
             
     | 
| 170 | 
         
            -
                         
     | 
| 171 | 
         
            -
             
     | 
| 172 | 
         
            -
             
     | 
| 173 | 
         
            -
             
     | 
| 174 | 
         
            -
             
     | 
| 175 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 176 | 
         | 
| 177 | 
         
             
            # Launch the Gradio interface
         
     | 
| 178 | 
         
             
            if __name__ == "__main__":
         
     | 
| 179 | 
         
            -
                 
     | 
| 180 | 
         
            -
             
     | 
| 181 | 
         
            -
             
     | 
| 182 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 6 | 
         
             
            import dotenv
         
     | 
| 7 | 
         
             
            import gradio as gr
         
     | 
| 8 | 
         
             
            import numpy as np
         
     | 
| 9 | 
         
            +
            from pymongo import MongoClient, errors
         
     | 
| 10 | 
         
             
            from datetime import datetime
         
     | 
| 11 | 
         
            +
            from werkzeug.security import generate_password_hash, check_password_hash
         
     | 
| 12 | 
         
             
            from utils import PoultryFarmBot, llama3_response
         
     | 
| 13 | 
         
             
            from transformers import AutoModelForCausalLM, AutoTokenizer
         
     | 
| 14 | 
         | 
| 
         | 
|
| 21 | 
         | 
| 22 | 
         
             
            # MongoDB Setup for logging and audit
         
     | 
| 23 | 
         
             
            MONGO_URI = os.getenv("MONGO_URI")
         
     | 
| 24 | 
         
            +
            if not MONGO_URI:
         
     | 
| 25 | 
         
            +
                logger.error("MONGO_URI is not set in the environment variables.")
         
     | 
| 26 | 
         
            +
                raise ValueError("MONGO_URI environment variable is required but not set.")
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
            try:
         
     | 
| 29 | 
         
            +
                logger.info("Connecting to MongoDB.")
         
     | 
| 30 | 
         
            +
                client = MongoClient(MONGO_URI, serverSelectionTimeoutMS=5000)  # Timeout after 5 seconds
         
     | 
| 31 | 
         
            +
                client.server_info()  # Trigger exception if cannot connect
         
     | 
| 32 | 
         
            +
                db = client.poultry_farm  # Connect to the 'poultry_farm' database
         
     | 
| 33 | 
         
            +
                enquiries_collection = db.enquiries  # Collection to store farmer enquiries
         
     | 
| 34 | 
         
            +
                users_collection = db.users  # Collection to store user credentials
         
     | 
| 35 | 
         
            +
                logs_collection = db.logs  # Collection to store application logs
         
     | 
| 36 | 
         
            +
            except errors.ServerSelectionTimeoutError as e:
         
     | 
| 37 | 
         
            +
                logger.error(f"Failed to connect to MongoDB: {e}")
         
     | 
| 38 | 
         
            +
                raise ConnectionError("Could not connect to MongoDB. Please check the MONGO_URI and ensure the database is running.")
         
     | 
| 39 | 
         | 
| 40 | 
         
             
            def log_to_db(level, message):
         
     | 
| 41 | 
         
            +
                try:
         
     | 
| 42 | 
         
            +
                    log_entry = {
         
     | 
| 43 | 
         
            +
                        "level": level,
         
     | 
| 44 | 
         
            +
                        "message": message,
         
     | 
| 45 | 
         
            +
                        "timestamp": datetime.utcnow()
         
     | 
| 46 | 
         
            +
                    }
         
     | 
| 47 | 
         
            +
                    logs_collection.insert_one(log_entry)
         
     | 
| 48 | 
         
            +
                except Exception as e:
         
     | 
| 49 | 
         
            +
                    logger.error(f"Failed to log to database: {e}")
         
     | 
| 50 | 
         | 
| 51 | 
         
             
            # Override logger methods to also log to MongoDB
         
     | 
| 52 | 
         
             
            class MongoHandler(logging.Handler):
         
     | 
| 53 | 
         
             
                def emit(self, record):
         
     | 
| 54 | 
         
             
                    log_entry = self.format(record)
         
     | 
| 55 | 
         
            +
                    try:
         
     | 
| 56 | 
         
            +
                        log_to_db(record.levelname, log_entry)
         
     | 
| 57 | 
         
            +
                    except Exception as e:
         
     | 
| 58 | 
         
            +
                        logger.error(f"Failed to emit log to MongoDB: {e}")
         
     | 
| 59 | 
         | 
| 60 | 
         
             
            mongo_handler = MongoHandler()
         
     | 
| 61 | 
         
             
            mongo_handler.setLevel(logging.INFO)
         
     | 
| 
         | 
|
| 75 | 
         
             
            logger.info("Initializing PoultryFarmBot instance.")
         
     | 
| 76 | 
         
             
            bot = PoultryFarmBot(db)
         
     | 
| 77 | 
         | 
| 78 | 
         
            +
            # Load Llama 3.2 model and tokenizer for text generation
         
     | 
| 79 | 
         
            +
            try:
         
     | 
| 80 | 
         
            +
                logger.info("Loading Llama 3.2 model and tokenizer.")
         
     | 
| 81 | 
         
            +
                model_name = "meta-llama/Llama-3.2-3B"
         
     | 
| 82 | 
         
            +
                tokenizer = AutoTokenizer.from_pretrained(model_name)
         
     | 
| 83 | 
         
            +
                model = AutoModelForCausalLM.from_pretrained(model_name)
         
     | 
| 84 | 
         
            +
             
     | 
| 85 | 
         
            +
                # Set the padding token to EOS token or add a new padding token
         
     | 
| 86 | 
         
            +
                if tokenizer.pad_token is None:
         
     | 
| 87 | 
         
            +
                    logger.info("Adding padding token to tokenizer.")
         
     | 
| 88 | 
         
            +
                    tokenizer.add_special_tokens({'pad_token': '[PAD]'})
         
     | 
| 89 | 
         
            +
                    model.resize_token_embeddings(len(tokenizer))
         
     | 
| 90 | 
         
            +
            except Exception as e:
         
     | 
| 91 | 
         
            +
                logger.error(f"Failed to load Llama 3.2 model or tokenizer: {e}")
         
     | 
| 92 | 
         
            +
                raise RuntimeError("Could not load the Llama 3.2 model or tokenizer. Please check the configuration.")
         
     | 
| 93 | 
         | 
| 94 | 
         
             
            def chatbot_response(image, text, username, password):
         
     | 
| 95 | 
         
             
                """
         
     | 
| 
         | 
|
| 104 | 
         
             
                Returns:
         
     | 
| 105 | 
         
             
                    str: Response generated by the chatbot.
         
     | 
| 106 | 
         
             
                """
         
     | 
| 107 | 
         
            +
                try:
         
     | 
| 108 | 
         
            +
                    user = bot.authenticate_user(username, password)
         
     | 
| 109 | 
         
            +
                    if not user:
         
     | 
| 110 | 
         
            +
                        return "Authentication failed. Please check your username and password."
         
     | 
| 111 | 
         
            +
             
     | 
| 112 | 
         
            +
                    user_id = user['_id']
         
     | 
| 113 | 
         
            +
             
     | 
| 114 | 
         
            +
                    # If an image is provided, diagnose the disease
         
     | 
| 115 | 
         
            +
                    if image is not None:
         
     | 
| 116 | 
         
            +
                        logger.info("Image input detected. Proceeding with disease diagnosis.")
         
     | 
| 117 | 
         
            +
                        diagnosis, name, status, recom = bot.diagnose_disease(image)
         
     | 
| 118 | 
         
            +
                        if name and status and recom:
         
     | 
| 119 | 
         
            +
                            logger.info("Diagnosis complete.")
         
     | 
| 120 | 
         
            +
                            bot.log_enquiry("image", "Image Enquiry", diagnosis, user_id)
         
     | 
| 121 | 
         
            +
                            return diagnosis
         
     | 
| 122 | 
         
            +
                        else:
         
     | 
| 123 | 
         
            +
                            logger.warning("Diagnosis incomplete.")
         
     | 
| 124 | 
         
            +
                            bot.log_enquiry("image", "Image Enquiry", diagnosis, user_id)
         
     | 
| 125 | 
         
            +
                            return diagnosis
         
     | 
| 126 | 
         
             
                    else:
         
     | 
| 127 | 
         
            +
                        # Generate a response using Llama 3.2 for general text input
         
     | 
| 128 | 
         
            +
                        logger.info("Text input detected. Generating response.")
         
     | 
| 129 | 
         
            +
                        response = llama3_response(text, tokenizer, model)
         
     | 
| 130 | 
         
            +
                        bot.log_enquiry("text", text, response, user_id)
         
     | 
| 131 | 
         
            +
                        return response
         
     | 
| 132 | 
         
            +
                except Exception as e:
         
     | 
| 133 | 
         
            +
                    logger.error(f"Error during chatbot response generation: {e}")
         
     | 
| 134 | 
         
            +
                    return "An error occurred while processing your request. Please try again later."
         
     | 
| 
         | 
|
| 135 | 
         | 
| 136 | 
         
             
            # Gradio interface
         
     | 
| 137 | 
         
             
            def build_gradio_interface():
         
     | 
| 
         | 
|
| 141 | 
         
             
                Returns:
         
     | 
| 142 | 
         
             
                    gr.Blocks: Gradio Blocks object representing the chatbot interface.
         
     | 
| 143 | 
         
             
                """
         
     | 
| 144 | 
         
            +
                try:
         
     | 
| 145 | 
         
            +
                    logger.info("Building Gradio interface.")
         
     | 
| 146 | 
         
            +
                    with gr.Blocks(theme=gr.themes.Base()):
         
     | 
| 147 | 
         
            +
                        gr.Markdown("# 🐔 Poultry Management Chatbot")
         
     | 
| 148 | 
         
            +
                        gr.Markdown("Welcome! This chatbot helps you manage your poultry with ease. You can upload an image for disease diagnosis or ask any questions about poultry management.")
         
     | 
| 149 | 
         
            +
             
     | 
| 150 | 
         
            +
                        chat_history = gr.Chatbot()
         
     | 
| 151 | 
         
            +
                        with gr.Row():
         
     | 
| 152 | 
         
            +
                            with gr.Column(scale=1):
         
     | 
| 153 | 
         
            +
                                fecal_image = gr.Image(
         
     | 
| 154 | 
         
            +
                                    label="Upload Image of Poultry Feces (Optional)",
         
     | 
| 155 | 
         
            +
                                    type="numpy",
         
     | 
| 156 | 
         
            +
                                    elem_id="image-upload",
         
     | 
| 157 | 
         
            +
                                    show_label=True,
         
     | 
| 158 | 
         
            +
                                )
         
     | 
| 159 | 
         
            +
                            with gr.Column(scale=2):
         
     | 
| 160 | 
         
            +
                                user_input = gr.Textbox(
         
     | 
| 161 | 
         
            +
                                    label="Ask a question",
         
     | 
| 162 | 
         
            +
                                    placeholder="Ask about poultry management...",
         
     | 
| 163 | 
         
            +
                                    lines=3,
         
     | 
| 164 | 
         
            +
                                    elem_id="user-input",
         
     | 
| 165 | 
         
            +
                                )
         
     | 
| 166 | 
         
            +
                                username = gr.Textbox(
         
     | 
| 167 | 
         
            +
                                    label="Username",
         
     | 
| 168 | 
         
            +
                                    placeholder="Enter your username",
         
     | 
| 169 | 
         
            +
                                    lines=1,
         
     | 
| 170 | 
         
            +
                                    elem_id="username-input",
         
     | 
| 171 | 
         
            +
                                )
         
     | 
| 172 | 
         
            +
                                password = gr.Textbox(
         
     | 
| 173 | 
         
            +
                                    label="Password",
         
     | 
| 174 | 
         
            +
                                    placeholder="Enter your password",
         
     | 
| 175 | 
         
            +
                                    type="password",
         
     | 
| 176 | 
         
            +
                                    lines=1,
         
     | 
| 177 | 
         
            +
                                    elem_id="password-input",
         
     | 
| 178 | 
         
            +
                                )
         
     | 
| 179 | 
         
            +
             
     | 
| 180 | 
         
            +
                        output_box = gr.Textbox(
         
     | 
| 181 | 
         
            +
                            label="Response",
         
     | 
| 182 | 
         
            +
                            placeholder="Response will appear here...",
         
     | 
| 183 | 
         
            +
                            interactive=False,
         
     | 
| 184 | 
         
            +
                            lines=10,
         
     | 
| 185 | 
         
            +
                            elem_id="output-box",
         
     | 
| 186 | 
         
            +
                        )
         
     | 
| 187 | 
         
            +
             
     | 
| 188 | 
         
            +
                        submit_button = gr.Button(
         
     | 
| 189 | 
         
            +
                            "Submit",
         
     | 
| 190 | 
         
            +
                            variant="primary",
         
     | 
| 191 | 
         
            +
                            elem_id="submit-button"
         
     | 
| 192 | 
         
            +
                        )
         
     | 
| 193 | 
         
            +
                        # Connect the submit button to the chatbot response function
         
     | 
| 194 | 
         
            +
                        submit_button.click(
         
     | 
| 195 | 
         
            +
                            fn=chatbot_response,
         
     | 
| 196 | 
         
            +
                            inputs=[fecal_image, user_input, username, password],
         
     | 
| 197 | 
         
            +
                            outputs=[output_box]
         
     | 
| 198 | 
         
            +
                        )
         
     | 
| 199 | 
         
            +
                    logger.info("Gradio interface built successfully.")
         
     | 
| 200 | 
         
            +
                    return chatbot_interface
         
     | 
| 201 | 
         
            +
                except Exception as e:
         
     | 
| 202 | 
         
            +
                    logger.error(f"Error building Gradio interface: {e}")
         
     | 
| 203 | 
         
            +
                    raise RuntimeError("Could not build the Gradio interface. Please check the configuration.")
         
     | 
| 204 | 
         | 
| 205 | 
         
             
            # Launch the Gradio interface
         
     | 
| 206 | 
         
             
            if __name__ == "__main__":
         
     | 
| 207 | 
         
            +
                try:
         
     | 
| 208 | 
         
            +
                    logger.info("Launching Gradio interface.")
         
     | 
| 209 | 
         
            +
                    interface = build_gradio_interface()
         
     | 
| 210 | 
         
            +
                    # Launch the interface with queuing enabled for concurrent requests
         
     | 
| 211 | 
         
            +
                    interface.queue().launch(debug=True, share=True)
         
     | 
| 212 | 
         
            +
                except Exception as e:
         
     | 
| 213 | 
         
            +
                    logger.error(f"Failed to launch Gradio interface: {e}")
         
     | 
| 214 | 
         
            +
                    raise RuntimeError("Could not launch the Gradio interface. Please check the application setup.")
         
     |