Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| """ | |
| @Time : 2023/5/11 14:43 | |
| @Author : alexanderwu | |
| @From : https://github.com/geekan/MetaGPT/blob/main/metagpt/actions/search_and_summarize.py | |
| """ | |
| import time | |
| from autoagents.actions import Action | |
| from autoagents.system.config import Config | |
| from autoagents.system.logs import logger | |
| from autoagents.system.schema import Message | |
| from autoagents.system.tools.search_engine import SearchEngine | |
| SEARCH_AND_SUMMARIZE_SYSTEM = """### Requirements | |
| 1. Please summarize the latest dialogue based on the reference information (secondary) and dialogue history (primary). Do not include text that is irrelevant to the conversation. | |
| - The context is for reference only. If it is irrelevant to the user's search request history, please reduce its reference and usage. | |
| 2. If there are citable links in the context, annotate them in the main text in the format [main text](citation link). If there are none in the context, do not write links. | |
| 3. The reply should be graceful, clear, non-repetitive, smoothly written, and of moderate length, in {LANG}. | |
| ### Dialogue History (For example) | |
| A: MLOps competitors | |
| ### Current Question (For example) | |
| A: MLOps competitors | |
| ### Current Reply (For example) | |
| 1. Alteryx Designer: <desc> etc. if any | |
| 2. Matlab: ditto | |
| 3. IBM SPSS Statistics | |
| 4. RapidMiner Studio | |
| 5. DataRobot AI Platform | |
| 6. Databricks Lakehouse Platform | |
| 7. Amazon SageMaker | |
| 8. Dataiku | |
| """ | |
| SEARCH_AND_SUMMARIZE_SYSTEM_EN_US = SEARCH_AND_SUMMARIZE_SYSTEM.format(LANG='en-us') | |
| SEARCH_AND_SUMMARIZE_PROMPT = """ | |
| ### Reference Information | |
| {CONTEXT} | |
| ### Dialogue History | |
| {QUERY_HISTORY} | |
| {QUERY} | |
| ### Current Question | |
| {QUERY} | |
| ### Current Reply: Based on the information, please write the reply to the Question | |
| """ | |
| SEARCH_AND_SUMMARIZE_SALES_SYSTEM = """## Requirements | |
| 1. Please summarize the latest dialogue based on the reference information (secondary) and dialogue history (primary). Do not include text that is irrelevant to the conversation. | |
| - The context is for reference only. If it is irrelevant to the user's search request history, please reduce its reference and usage. | |
| 2. If there are citable links in the context, annotate them in the main text in the format [main text](citation link). If there are none in the context, do not write links. | |
| 3. The reply should be graceful, clear, non-repetitive, smoothly written, and of moderate length, in Simplified Chinese. | |
| # Example | |
| ## Reference Information | |
| ... | |
| ## Dialogue History | |
| user: Which facial cleanser is good for oily skin? | |
| Salesperson: Hello, for oily skin, it is suggested to choose a product that can deeply cleanse, control oil, and is gentle and skin-friendly. According to customer feedback and market reputation, the following facial cleansers are recommended:... | |
| user: Do you have any by L'Oreal? | |
| > Salesperson: ... | |
| ## Ideal Answer | |
| Yes, I've selected the following for you: | |
| 1. L'Oreal Men's Facial Cleanser: Oil control, anti-acne, balance of water and oil, pore purification, effectively against blackheads, deep exfoliation, refuse oil shine. Dense foam, not tight after washing. | |
| 2. L'Oreal Age Perfect Hydrating Cleanser: Added with sodium cocoyl glycinate and Centella Asiatica, two effective ingredients, it can deeply cleanse, tighten the skin, gentle and not tight. | |
| """ | |
| SEARCH_AND_SUMMARIZE_SALES_PROMPT = """ | |
| ## Reference Information | |
| {CONTEXT} | |
| ## Dialogue History | |
| {QUERY_HISTORY} | |
| {QUERY} | |
| > {ROLE}: | |
| """ | |
| SEARCH_FOOD = """ | |
| # User Search Request | |
| What are some delicious foods in Xiamen? | |
| # Requirements | |
| You are a member of a professional butler team and will provide helpful suggestions: | |
| 1. Please summarize the user's search request based on the context and avoid including unrelated text. | |
| 2. Use [main text](reference link) in markdown format to **naturally annotate** 3-5 textual elements (such as product words or similar text sections) within the main text for easy navigation. | |
| 3. The response should be elegant, clear, **without any repetition of text**, smoothly written, and of moderate length. | |
| """ | |
| class SearchAndSummarize(Action): | |
| def __init__(self, name="", context=None, llm=None, engine=None, search_func=None, serpapi_api_key=None): | |
| self.config = Config() | |
| self.serpapi_api_key = serpapi_api_key | |
| self.engine = engine or self.config.search_engine | |
| self.search_engine = SearchEngine(self.engine, run_func=search_func, serpapi_api_key=serpapi_api_key) | |
| self.result = "" | |
| super().__init__(name, context, llm, serpapi_api_key) | |
| async def run(self, context: list[Message], system_text=SEARCH_AND_SUMMARIZE_SYSTEM) -> str: | |
| no_serpapi = not self.config.serpapi_api_key or 'YOUR_API_KEY' == self.config.serpapi_api_key | |
| no_serper = not self.config.serper_api_key or 'YOUR_API_KEY' == self.config.serper_api_key | |
| no_google = not self.config.google_api_key or 'YOUR_API_KEY' == self.config.google_api_key | |
| no_self_serpapi = self.serpapi_api_key is None | |
| if no_serpapi and no_google and no_serper and no_self_serpapi: | |
| logger.warning('Configure one of SERPAPI_API_KEY, SERPER_API_KEY, GOOGLE_API_KEY to unlock full feature') | |
| return "" | |
| query = context[-1].content | |
| # logger.debug(query) | |
| try_count = 0 | |
| while True: | |
| try: | |
| rsp = await self.search_engine.run(query) | |
| break | |
| except ValueError as e: | |
| try_count += 1 | |
| if try_count >= 3: | |
| # Retry 3 times to fail | |
| raise e | |
| time.sleep(1) | |
| self.result = rsp | |
| if not rsp: | |
| logger.error('empty rsp...') | |
| return "" | |
| # logger.info(rsp) | |
| system_prompt = [system_text] | |
| prompt = SEARCH_AND_SUMMARIZE_PROMPT.format( | |
| # PREFIX = self.prefix, | |
| ROLE=self.profile, | |
| CONTEXT=rsp, | |
| QUERY_HISTORY='\n'.join([str(i) for i in context[:-1]]), | |
| QUERY=str(context[-1]) | |
| ) | |
| result = await self._aask(prompt, system_prompt) | |
| logger.debug(prompt) | |
| logger.debug(result) | |
| return result | |