diff --git a/docs/sphinx_doc/en/source/tutorial/204-service.md b/docs/sphinx_doc/en/source/tutorial/204-service.md index 38b4047b0..71ecd902d 100644 --- a/docs/sphinx_doc/en/source/tutorial/204-service.md +++ b/docs/sphinx_doc/en/source/tutorial/204-service.md @@ -49,7 +49,10 @@ The following table outlines the various Service functions by type. These functi | | `openai_image_to_text` | Convert text to image using OpenAI API | | `openai_text_to_audio` | Convert text to audio using OpenAI API | | `openai_audio_to_text` | Convert audio to text using OpenAI API - +| Reasoning | `wolfram_alpha_short_answers_query` | Query the Wolfram Alpha Short Answers API and return a brief answer in text. | +| | `wolfram_alpha_simple_query` | Query the Wolfram Alpha Simple API and return the answer as a PNG image. | +| | `wolfram_alpha_show_steps_query` | Query the Wolfram Alpha Show Steps API and return the step-by-step solution in text. | +| | `wolfram_alpha_llm_query` | Query the Wolfram Alpha LLM API and return the answer from the LLM in text. | | *More services coming soon* | | More service functions are in development and will be added to AgentScope to further enhance its capabilities. | diff --git a/docs/sphinx_doc/zh_CN/source/tutorial/204-service.md b/docs/sphinx_doc/zh_CN/source/tutorial/204-service.md index 23c145a05..d270f3ec2 100644 --- a/docs/sphinx_doc/zh_CN/source/tutorial/204-service.md +++ b/docs/sphinx_doc/zh_CN/source/tutorial/204-service.md @@ -46,6 +46,10 @@ | | `openai_image_to_text` | 使用 OpenAI API 根据图片生成文字。 | | `openai_text_to_audio` | 使用 OpenAI API 根据文本生成音频。 | | `openai_audio_to_text` | 使用OpenAI API将音频转换为文本。 +| 推理 | wolfram_alpha_short_answers_query | 查询 Wolfram Alpha Short Answers API, 并以文本形式返回简短的答案。 | +| | wolfram_alpha_simple_query | 查询 Wolfram Alpha Simple API,并以PNG图片形式返回答案。。 | +| | wolfram_alpha_show_steps_query | 查询 Wolfram Alpha Show Steps API,并以文本形式返回返回逐步答案。 | +| | wolfram_alpha_llm_query | 查询 Wolfram Alpha LLM API,并将LLM返回的答案作为文本形式返回。 | | *更多服务即将推出* | | 正在开发更多服务功能,并将添加到 AgentScope 以进一步增强其能力。 | 关于详细的参数、预期输入格式、返回类型,请参阅[API文档](https://modelscope.github.io/agentscope/)。 diff --git a/src/agentscope/service/__init__.py b/src/agentscope/service/__init__.py index 2a0ba3e53..7d6cd02ea 100644 --- a/src/agentscope/service/__init__.py +++ b/src/agentscope/service/__init__.py @@ -26,6 +26,12 @@ dblp_search_authors, dblp_search_venues, ) +from .reasoning.wolfram_alpha import ( + wolfram_alpha_short_answers_query, + wolfram_alpha_simple_query, + wolfram_alpha_show_steps_query, + wolfram_alpha_llm_query, +) from .multi_modality.dashscope_services import ( dashscope_image_to_text, dashscope_text_to_image, @@ -101,6 +107,10 @@ def get_help() -> None: "openai_image_to_text", "openai_edit_image", "openai_create_image_variation", + "wolfram_alpha_short_answers_query", + "wolfram_alpha_simple_query", + "wolfram_alpha_show_steps_query", + "wolfram_alpha_llm_query", # to be deprecated "ServiceFactory", ] diff --git a/src/agentscope/service/reasoning/wolfram_alpha.py b/src/agentscope/service/reasoning/wolfram_alpha.py new file mode 100644 index 000000000..09bade7c6 --- /dev/null +++ b/src/agentscope/service/reasoning/wolfram_alpha.py @@ -0,0 +1,395 @@ +# -*- coding: utf-8 -*- +"""Query Wolfram Alpha API""" +import os +from typing import Any, Dict +import requests +from loguru import logger +from agentscope.service.service_response import ( + ServiceResponse, + ServiceExecStatus, +) + + +def wolfram_alpha_short_answers_query( + api_key: str, + query: str, +) -> ServiceResponse: + """ + Query the Wolfram Alpha Short Answers API. The Short Answers API returns + a single plain text result directly from Wolfram|Alpha. + + In general, this text is taken directly from the Result pod of + Wolfram|Alpha output. This API type is designed to deliver brief + answers in the most basic format possible. Suitable for queries + such as simple knowledge/facts retrieval. See + https://products.wolframalpha.com/short-answers-api/documentation + for more details. + + Args: + api_key (`str`): + Your Wolfram Alpha API key. + query (`str`): + The query string to search. + + Returns: + `ServiceResponse`: A dictionary with two variables: `status` and + `content`. The `status` variable is from the ServiceExecStatus enum, + and `content` is a dictionary containing + the result or error information, + which depends on the `status` variable. + + Example: + .. code-block:: python + + result = wolfram_alpha_short_answers_query( + "your_api_key", + "What is the capital of France?" + ) + if result.status == ServiceExecStatus.SUCCESS: + print(result.content['result']) + # Output: Paris, Île-de-France, France + """ + url = "http://api.wolframalpha.com/v1/result" + params = {"i": query, "appid": api_key} + + try: + response = requests.get(url, params=params) + if response.status_code == 200: + return ServiceResponse( + status=ServiceExecStatus.SUCCESS, + content={"result": response.text}, + ) + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={ + "error": f"HTTP Error: {response.status_code} {response.text}", + }, + ) + except Exception as e: + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={"error": str(e)}, + ) + + +def wolfram_alpha_simple_query( + api_key: str, + query: str, + save_path: str = "wolfram_alpha_result.png", +) -> ServiceResponse: + """ + Query the Wolfram Alpha Simple API. The Simple API generates full + Wolfram|Alpha output in a universally viewable image format. + + Suitable for queries such as knowledge/facts retrieval. See + https://products.wolframalpha.com/simple-api/documentation + for more details. + + Args: + api_key (`str`): + Your Wolfram Alpha API key. + query (`str`): + The query string to search. + save_path (`str`, optional): + The path where the result image will be saved. + Defaults to "wolfram_alpha_result.png" in the current directory. + + Returns: + `ServiceResponse`: A dictionary with two variables: `status` and + `content`. The `status` variable is from the ServiceExecStatus enum, + and `content` is a dictionary containing + the result or error information, + which depends on the `status` variable. + The returned image is saved in the specified save path. + + Example: + .. code-block:: python + + result = wolfram_alpha_simple_query( + "your_api_key", + "Plot sin(x)", + save_path="path/to/save/result.png" + ) + if result.status == ServiceExecStatus.SUCCESS: + logger.info(f"Result saved as '{result.content['result']}'") + """ + url = "http://api.wolframalpha.com/v1/simple" + params = {"i": query, "appid": api_key} + + try: + response = requests.get(url, params=params) + if response.status_code == 200: + # Get the directory path + dir_path = os.path.dirname(save_path) + + # If dir_path is not empty, create the directory + if dir_path: + os.makedirs(dir_path, exist_ok=True) + + with open(save_path, "wb") as file: + file.write(response.content) + logger.info(f"Result saved as '{save_path}'") + return ServiceResponse( + status=ServiceExecStatus.SUCCESS, + content={ + "result": save_path, + }, + ) + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={ + "error": f"HTTP Error: {response.status_code} {response.text}", + }, + ) + except Exception as e: + logger.error(f"Error in wolfram_alpha_simple_query: {str(e)}") + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={"error": str(e)}, + ) + + +def wolfram_alpha_show_steps_query( + api_key: str, + query: str, +) -> ServiceResponse: + """ + Query the Wolfram Alpha Show Steps API, gives step-by-step solution + in text. + + An extension of the Full Results API, the Show Steps API gives + direct access to Wolfram|Alpha's full for queries in a variety + of mathematical and scientific subjects. These explanations of + computed answers are designed to provide clarity and understanding + to the end user and are especially useful in educational and + training applications. see + https://products.wolframalpha.com/show-steps-api/documentation + for more details. + + Args: + api_key (`str`): + Your Wolfram Alpha API key. + query (`str`): + The query string to search. + + Returns: + `ServiceResponse`: A dictionary with two variables: `status` and + `content`. The `status` variable is from the ServiceExecStatus enum, + and `content` is a dictionary containing + the result or error information, + which depends on the `status` variable. + + Example: + .. code-block:: python + + result = wolfram_alpha_show_steps_query( + "your_api_key", + "Solve x^2 + 2x + 1 = 0" + ) + if result.status == ServiceExecStatus.SUCCESS: + print(result.content['result']) + + Output: + solve x^2 + 2 x + 1 = 0 + x = -1 + Solve for x: + x^2 + 2 x + 1 = 0 + Write the left hand side as a square: + (x + 1)^2 = 0 + Take the square root of both sides: + x + 1 = 0 + Subtract 1 from both sides: + Answer: | + | x = -1 + """ + url = "http://api.wolframalpha.com/v2/query" + params = { + "input": query, + "appid": api_key, + "output": "JSON", + "podstate": "Step-by-step solution", + } + + try: + response = requests.get(url, params=params) + if response.status_code == 200: + data: Dict[str, Any] = response.json() + steps = [] + logger.info(f"Show Steps API response: {data}") + for pod in data["queryresult"].get("pods", []): + logger.info(f"Processing pod: {pod.get('title')}") + for subpod in pod.get("subpods", []): + logger.info(f"Processing subpod: {subpod.get('title')}") + plaintext = subpod.get("plaintext", "").strip() + if plaintext: + steps.append(plaintext) + if not steps: + logger.warning( + "No step-by-step solution found in the response.", + ) + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={ + "error": ( + "No step-by-step solution found in the response." + ), + }, + ) + formatted_steps = "\n".join(steps) + print(formatted_steps) + return ServiceResponse( + status=ServiceExecStatus.SUCCESS, + content={"result": formatted_steps}, + ) + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={ + "error": f"HTTP Error: {response.status_code} {response.text}", + }, + ) + except Exception as e: + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={"error": str(e)}, + ) + + +def wolfram_alpha_llm_query( + api_key: str, + query: str, +) -> ServiceResponse: + """ + Query the Wolfram Alpha LLM API and return solution as text. + + The LLM API is built for use specifically with large language + models and chat products. Although the majority of data + available through the Wolfram|Alpha website is also available + through this API, certain subjects may be restricted by default. + see + https://products.wolframalpha.com/llm-api/documentation + for more details. + + Args: + api_key (`str`): + Your Wolfram Alpha API key. + query (`str`): + The query string to search. + + Returns: + `ServiceResponse`: A dictionary with two variables: `status` and + `content`. The `status` variable is from the ServiceExecStatus enum, + and `content` is a dictionary containing + the result or error information, + which depends on the `status` variable. + + Example: + .. code-block:: python + + result = wolfram_alpha_llm_query( + "your_api_key", + "3 densest elemental metals" + ) + if result.status == ServiceExecStatus.SUCCESS: + print(result.content['result']) + + Example output: + .. code-block:: text + + Query: + "3 densest elemental metals" + + Input interpretation: + 3 densest metallic elements | by mass density + + Result: + 1 | hassium | 41 g/cm^3 | + 2 | meitnerium | 37.4 g/cm^3 | + 3 | bohrium | 37.1 g/cm^3 | + + Periodic table location: + image: https://www6b3.wolframalpha.com/Calculate/... + + Images: + image: https://www6b3.wolframalpha.com/Calculate/... + Wolfram Language code: + Dataset[ + EntityValue[ + { + Entity["Element", "Hassium"], + Entity["Element", "Meitnerium"], + Entity["Element", "Bohrium"] + }, + EntityProperty["Element", "Image"], + "EntityAssociation" + ] + ] + + Basic elemental properties: + | hassium | meitnerium | bohrium + atomic symbol | Hs | Mt | Bh + atomic number | 108 | 109 | 107 + atomic mass | 269 u | 277 u | 270 u + half-life | 67 min | 30 min | 90 min + + Material properties: + | hassium | meitnerium | bohrium + mass density | 41 g/cm^3 | 37.4 g/cm^3 | 37.1 g/cm^3 + (properties at standard conditions) + + Reactivity: + | bohrium + valence | 7 + + Atomic properties: + | hassium | meitnerium | bohrium + term symbol | ^5D_4 | ^4F_(9/2) | ^6S_(5/2) + (electronic ground state properties) + + Abundances: + | (all cases) + crust abundance | 0 mass% + human abundance | 0 mass% + + Nuclear properties: + | hassium | meitnerium | bohrium + half-life | 67 min | 30 min | 90 min + specific radioactivity | 446085 TBq/g | 833168 TBq/g | 285952 TBq/g + unstable isotopes | hassium-276 (67 min) | ... + | meitnerium-278 (30 min) | ... + | bohrium-274 (90 min) | ... + + | (all cases) + decay mode | alpha emission + + Identifiers: + | hassium | meitnerium | bohrium + CAS number | 54037-57-9 | 54038-01-6 | 54037-14-8 + PubChem CID number | CID56951714 | CID56951716 | CID56951713 + + Wikipedia page hits history: + image: https://www6b3.wolframalpha.com/Calculate/... + + Wolfram|Alpha website result for "3 densest elemental metals": + https://www6b3.wolframalpha.com/input?i=3+densest+elemental+metals + """ + url = "https://www.wolframalpha.com/api/v1/llm-api" + params = {"input": query, "appid": api_key} + + try: + response = requests.get(url, params=params) + if response.status_code == 200: + return ServiceResponse( + status=ServiceExecStatus.SUCCESS, + content={"result": response.text}, + ) + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={ + "error": f"HTTP Error: {response.status_code} {response.text}", + }, + ) + except Exception as e: + return ServiceResponse( + status=ServiceExecStatus.ERROR, + content={"error": str(e)}, + )