CoolFace
Apppublic

KieranXu/path_advisor

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.py455 linesDownload Raw Back to root
1import os2import sys3import threading4from itertools import chain5 6import anyio7from flaml import autogen8import gradio as gr9from autogen import Agent, AssistantAgent, OpenAIWrapper, UserProxyAgent, ConversableAgent10from autogen.code_utils import extract_code11from gradio import ChatInterface, Request12from gradio.helpers import special_args13 14LOG_LEVEL = "INFO"15TIMEOUT = 6016 17 18class myChatInterface(ChatInterface):19    async def _submit_fn(20        self,21        message: str,22        history_with_input: list[list[str | None]],23        request: Request,24        *args,25    ) -> tuple[list[list[str | None]], list[list[str | None]]]:26        history = history_with_input[:-1]27        inputs, _, _ = special_args(self.fn, inputs=[message, history, *args], request=request)28 29        if self.is_async:30            await self.fn(*inputs)31        else:32            await anyio.to_thread.run_sync(self.fn, *inputs, limiter=self.limiter)33 34        # history.append([message, response])35        return history, history36 37 38with gr.Blocks() as demo:39 40    def flatten_chain(list_of_lists):41        return list(chain.from_iterable(list_of_lists))42 43    class thread_with_trace(threading.Thread):44        # https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/45        # https://stackoverflow.com/questions/6893968/how-to-get-the-return-value-from-a-thread46        def __init__(self, *args, **keywords):47            threading.Thread.__init__(self, *args, **keywords)48            self.killed = False49            self._return = None50 51        def start(self):52            self.__run_backup = self.run53            self.run = self.__run54            threading.Thread.start(self)55 56        def __run(self):57            sys.settrace(self.globaltrace)58            self.__run_backup()59            self.run = self.__run_backup60 61        def run(self):62            if self._target is not None:63                self._return = self._target(*self._args, **self._kwargs)64 65        def globaltrace(self, frame, event, arg):66            if event == "call":67                return self.localtrace68            else:69                return None70 71        def localtrace(self, frame, event, arg):72            if self.killed:73                if event == "line":74                    raise SystemExit()75            return self.localtrace76 77        def kill(self):78            self.killed = True79 80        def join(self, timeout=0):81            threading.Thread.join(self, timeout)82            return self._return83 84    def update_agent_history(recipient, messages, sender, config):85        if config is None:86            config = recipient87        if messages is None:88            messages = recipient._oai_messages[sender]89        message = messages[-1]90        message.get("content", "")91        # config.append(msg) if msg is not None else None  # config can be agent_history92        return False, None  # required to ensure the agent communication flow continues93 94    def _is_termination_msg(message):95        """Check if a message is a termination message.96        Terminate when no code block is detected. Currently only detect python code blocks.97        """98        if isinstance(message, dict):99            message = message.get("content")100            if message is None:101                return False102        cb = extract_code(message)103        contain_code = False104        for c in cb:105            # todo: support more languages106            if c[0] == "python":107                contain_code = True108                break109        return not contain_code110 111    def initialize_agents(config_list):112        113        assistant = AssistantAgent(114            name="assistant",115            max_consecutive_auto_reply=5,116            llm_config={117                # "seed": 42,118                "timeout": TIMEOUT,119                "config_list": config_list,120            },121        )122 123        angent_survey = ConversableAgent(124            name = "agent_survey",125            system_message="you are dedicated Learning Path Advisor. "126                    "the first task is understanding users goal and educational background, interests, career aspirations and other necessary information. "127                    "Interact with the user until you have sufficient information, or the user offers a message ending with 'Exit'."128                    "Please gently guide the user,ask questions one by one."129                    "based on the critic feedback, if needed, further ask user."130                    "summarizing the user's information but do not do recommandations.",131            llm_config={"config_list": config_list},132            is_termination_msg=lambda msg: "EXIT" in msg["content"],  # terminate 133            human_input_mode="NEVER",  # never ask for human input134        )135        angent_recommander =ConversableAgent(136            name = "angent_recommander",137            system_message="you are dedicated Learning Path Advisor."138                    "based on the user's information from 'agent_survey', critic and user, plan a learning path"139                    "your task is to help user navigate through the vast ocean of courses and specializations, finding the perfect path that aligns with user's background."140                    "the learning path should include necessary information of course such as course title, providers and thoughtful reasons for the recommendation"141                    "Then, ask the critic's opinion. and try to improve based on the opinion of critics"142                    "Rule 1. The total number of courses should be less than 4",143            llm_config={"config_list": config_list},144            is_termination_msg=lambda msg: "EXIT" in msg["content"],  145            human_input_mode="NEVER",  # never ask for human input146        )147 148 149        userproxy = UserProxyAgent(150            name="userproxy",151            system_message ="a human user",152            human_input_mode="NEVER",153            is_termination_msg=_is_termination_msg,154            max_consecutive_auto_reply=5,155            # code_execution_config=False,156            code_execution_config={157                #"last_n_messages": 2,158                "work_dir": "path_advisor",159                "use_docker": False,  # set to True or image name like "python:3" to use docker160            },161        )162 163        critic = AssistantAgent(164            name="Critic",165            system_message="Critic. Double check leanring path, reasons, from other agents and provide feedback. you should Reflect at least these questions"166                    "Q1: Whether the recommended course meets the user's interests or objective?"167                    "Q2: Do learning paths lead to higher motivation, or could they possibly lead to an overload of choices that paralyze some learners?"168                    "Q3: Is the content provided in-depth enough to foster a comprehensive understanding?"169                    "Q4: Is there a logical progression in the curriculum that builds on previous knowledge?"170                    "if you think the plan should imporved further, give the feedback to 'angent_recommander' and ask it to improve the learning path"171                    "if you think the plan is good enough, then ask the user if he would like to try the learning path?",172            llm_config={"config_list": config_list},173        )174 175        Learning_Path_summary = ConversableAgent(176            name = "Learning_Path_summary",177            system_message="You only followed by an approved leanring path plan by user." 178                    "Act as helpful and kind Learning Path Advisor, summarize the previous approved learning path for user, including course title, providers and thoughtful reasons for the recommendation"179                    "The tone should be informative, friendly, and supportive."180                    "And highlight the keypoints or keywords in orange"181                    "Your task is to provide a detailed summary of an approved leanring path plan to user. This overview is designed to give user clarity on the structure, objectives, and resources. the key elements are below:"182                    "Learning Path Overview: Goal Alignment; What were the initial goals  set at the start of this learning path? How do these objectives align with user's current background or personal development needs?"183                    "Curriculum Structure: provide a breakdown of the main topics and learning stages included in this path. What are the key outcomes expected at each stage, and how do they contribute to the overall goal?"184                    "Certification and Completion: Upon completing the learning path, what certificates or qualifications will be awarded? How do these credentials support further professional advancement or learning?"185                    "Future Learning Opportunities: What subsequent learning opportunities or advanced topics are recommended after completing this path?Are there any additional skills or areas of knowledge that suggest exploring to enhance professional growth?"186                    "Conclusion and give encouragement"187                    ,188            llm_config={"config_list": config_list},189            is_termination_msg=lambda msg: "EXIT" in msg["content"],  190            human_input_mode="NEVER",  # never ask for human input191        ) 192        #group chat with critic193        groupchat = autogen.GroupChat(agents=[userproxy, angent_survey, angent_recommander,critic,Learning_Path_summary], messages=[], max_round=20)194        manager = autogen.GroupChatManager(groupchat=groupchat, llm_config={"config_list": config_list})195 196        # assistant.register_reply([Agent, None], update_agent_history)197        # userproxy.register_reply([Agent, None], update_agent_history)198 199        return userproxy, angent_survey, angent_recommander,critic,Learning_Path_summary, manager200 201    def chat_to_oai_message(chat_history):202        """Convert chat history to OpenAI message format."""203        messages = []204        if LOG_LEVEL == "DEBUG":205            print(f"chat_to_oai_message: {chat_history}")206        for msg in chat_history:207            messages.append(208                {209                    "content": msg[0].split()[0] if msg[0].startswith("exitcode") else msg[0],210                    "role": "user",211                }212            )213            messages.append({"content": msg[1], "role": "assistant"})214        return messages215 216    def oai_message_to_chat(oai_messages, sender):217        """Convert OpenAI message format to chat history."""218        chat_history = []219        messages = oai_messages[sender]220        if LOG_LEVEL == "DEBUG":221            print(f"oai_message_to_chat: {messages}")222        for i in range(0, len(messages), 2):223            chat_history.append(224                [225                    messages[i]["content"],226                    messages[i + 1]["content"] if i + 1 < len(messages) else "",227                ]228            )229        return chat_history230 231    def agent_history_to_chat(agent_history):232        """Convert agent history to chat history."""233        chat_history = []234        for i in range(0, len(agent_history), 2):235            chat_history.append(236                [237                    agent_history[i],238                    agent_history[i + 1] if i + 1 < len(agent_history) else None,239                ]240            )241        return chat_history242 243    def initiate_chat(config_list, user_message, chat_history):244        if LOG_LEVEL == "DEBUG":245            print(f"chat_history_init: {chat_history}")246        # agent_history = flatten_chain(chat_history)247        if len(config_list[0].get("api_key", "")) < 2:248            chat_history.append(249                [250                    user_message,251                    "Hi, nice to meet you!",252                ]253            )254            return chat_history255        else:256            llm_config = {257                # "seed": 42,258                "timeout": TIMEOUT,259                "config_list": config_list,260            }261            manager.llm_config.update(llm_config)262            manager.client = OpenAIWrapper(**manager.llm_config)263 264        manager.reset()265        oai_messages = chat_to_oai_message(chat_history)266        manager._oai_system_message_origin = manager._oai_system_message.copy()267        manager._oai_system_message += oai_messages268 269        try:270            userproxy.initiate_chat(manager, message=user_message)271            messages = userproxy.chat_messages272            chat_history += oai_message_to_chat(messages, manager)273            # agent_history = flatten_chain(chat_history)274        except Exception as e:275            # agent_history += [user_message, str(e)]276            # chat_history[:] = agent_history_to_chat(agent_history)277            chat_history.append([user_message, str(e)])278 279        manager._oai_system_message = manager._oai_system_message_origin.copy()280        if LOG_LEVEL == "DEBUG":281            print(f"chat_history: {chat_history}")282            # print(f"agent_history: {agent_history}")283        return chat_history284 285    def chatbot_reply_thread(input_text, chat_history, config_list):286        """Chat with the agent through terminal."""287        thread = thread_with_trace(target=initiate_chat, args=(config_list, input_text, chat_history))288        thread.start()289        try:290            messages = thread.join(timeout=TIMEOUT)291            if thread.is_alive():292                thread.kill()293                thread.join()294                messages = [295                    input_text,296                    "Timeout Error: Please check your API keys and try again later.",297                ]298        except Exception as e:299            messages = [300                [301                    input_text,302                    str(e) if len(str(e)) > 0 else "Invalid Request to OpenAI, please check your API keys.",303                ]304            ]305        return messages306 307    def chatbot_reply_plain(input_text, chat_history, config_list):308        """Chat with the agent through terminal."""309        try:310            messages = initiate_chat(config_list, input_text, chat_history)311        except Exception as e:312            messages = [313                [314                    input_text,315                    str(e) if len(str(e)) > 0 else "Invalid Request to OpenAI, please check your API keys.",316                ]317            ]318        return messages319 320    def chatbot_reply(input_text, chat_history, config_list):321        """Chat with the agent through terminal."""322        return chatbot_reply_thread(input_text, chat_history, config_list)323 324    def get_description_text():325        return """326        # Hello! ๐Ÿ‘‹ My name is <span style="color:orange;">PathFinder</span>, 327        ## your dedicated Learning Path Advisor here.328 329        Welcome aboard!330 331        I am here to help you navigate through the vast ocean of courses and specializations, finding the perfect path that aligns with your career goals and educational interests.332 333        Whether you are looking to advance in your current field, pivot to a new industry, or simply explore new areas of knowledge, I'm here to guide you every step of the way!334        """335 336    def update_config():337        config_list = autogen.config_list_from_models(338            model_list=[os.environ.get("MODEL", "gpt-4")],339        )340        if not config_list:341 342            selected_model = "gpt-4"343            selected_key = "sk-ifbaI7viN2UnK634A92a07A9679046A392B907Df26AeCf8d"344            selected_url = "https://aihubmix.com/v1"345 346            config_list = [347                {348                    "api_key": selected_key,349                    "base_url": selected_url,350                    #"api_type": "azure",351                    #"api_version": "2023-07-01-preview",352                    "model": selected_model,353                }354            ]355 356        return config_list357 358    def set_params(model, oai_key, aoai_key, aoai_base):359        os.environ["MODEL"] = model360        os.environ["OPENAI_API_KEY"] = oai_key361        os.environ["AZURE_OPENAI_API_KEY"] = aoai_key362        os.environ["AZURE_OPENAI_API_BASE"] = aoai_base363 364    def respond(message, chat_history, model, oai_key, aoai_key, aoai_base):365        set_params(model, oai_key, aoai_key, aoai_base)366        config_list = update_config()367        chat_history[:] = chatbot_reply(message, chat_history, config_list)368        if LOG_LEVEL == "DEBUG":369            print(f"return chat_history: {chat_history}")370        return ""371 372    config_list= update_config()373 374    userproxy, angent_survey, angent_recommander,critic,Learning_Path_summary, manager = initialize_agents(config_list)375 376    description = gr.Markdown(get_description_text())377 378    with gr.Row() as params:379        txt_model = gr.Dropdown(380            label="Model",381            choices=[382                "gpt-4",383                "gpt-3.5-turbo",384            ],385            allow_custom_value=True,386            value="gpt-4",387            container=True,388        )389        txt_oai_key = gr.Textbox(390            label="OpenAI API Key",391            placeholder="Enter OpenAI API Key",392            max_lines=1,393            show_label=True,394            container=True,395            type="password",396        )397        txt_aoai_key = gr.Textbox(398            label="Azure OpenAI API Key",399            placeholder="Enter Azure OpenAI API Key",400            max_lines=1,401            show_label=True,402            container=True,403            type="password",404        )405        txt_aoai_base_url = gr.Textbox(406            label="Base url",407            placeholder="Enter Base Url",408            max_lines=1,409            show_label=True,410            container=True,411            type="password",412        )413 414    chatbot = gr.Chatbot(415        [],416        elem_id="chatbot",417        bubble_full_width=False,418        avatar_images=(419            "user.png",420            (os.path.join(os.path.dirname(__file__), "advisor.png")),421        ),422        render=False,423        height=600,424    )425 426    txt_input = gr.Textbox(427        scale=4,428        show_label=False,429        placeholder="Enter text and press enter",430        container=False,431        render=False,432        autofocus=True,433    )434 435    chatiface = myChatInterface(436        respond,437        chatbot=chatbot,438        textbox=txt_input,439        additional_inputs=[440            txt_model,441            txt_oai_key,442            txt_aoai_key,443            txt_aoai_base_url,444        ],445        examples=[446            [" I am interested in data science but do not know where to start."],447            [" I'm a software developer and I want to learn about artificial intelligence. I have some experience with Python."],448            [" I have a background in literature and I'm interested in exploring more about the philosophical aspects of humanity. I would like to understand how philosophical theories have influenced human behavior and society."],449        ],450    )451 452 453if __name__ == "__main__":454    demo.launch(share=True, server_name="0.0.0.0")455 
KieranXu/path_advisor ยท CoolFace