├── .github ├── bug_report.md ├── feature_request.md └── general_query.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.txt ├── README.md ├── docs └── assets │ └── images │ ├── conceptual-flow.png │ ├── tn_circles_tangents.png │ ├── tn_lines.png │ ├── tn_poly.png │ └── tn_shapes.png ├── pyproject.toml ├── requirements.txt ├── run.sh ├── run_multi_turn_tests.sh ├── run_single_turn_tests.sh ├── src ├── __init__.py ├── agents │ ├── __init__.py │ ├── desmos_agent.py │ ├── math_viz_agent.py │ └── wolfram_agent.py ├── desmos_calc.html ├── env.dist ├── main.py ├── main_tests.py ├── prompts.py ├── routes.py ├── static │ ├── collapse.png │ ├── desmos.css │ ├── desmos.js │ ├── desmosUI.js │ ├── expand.png │ ├── favicon.ico │ ├── inchime.mp3 │ ├── mathvizicon.png │ ├── othericon.png │ ├── outchime.mp3 │ ├── usericon.png │ └── wolframicon.png └── utils.py └── test ├── multi_turn ├── graph_circles.csv ├── graph_lines.csv ├── graph_polynomials.csv ├── inverse_functions.csv ├── linear_and_nonlinear_functions.csv ├── linear_quadratic_systems.csv └── transformations_of_functions.csv └── single_turn ├── graph_circle_tangents.csv ├── graph_circles.csv ├── graph_circles_2.csv ├── graph_lines.csv ├── graph_lines_2.csv ├── graph_multi_step_labeling.csv ├── graph_parabola_tangents.csv ├── graph_polynomials.csv ├── graph_quad_eqns.csv ├── intercepts.csv ├── intersections_of_lines.csv ├── inverse_functions.csv ├── linear_and_nonlinear_functions.csv ├── linear_equation_systems.csv ├── linear_inequalities.csv ├── linear_inequalities_2.csv ├── local_optima.csv ├── proportional_relationships.csv ├── rigid_transformations.csv ├── transform_shapes.csv ├── transformations_of_functions.csv └── transformations_of_functions_2.csv /.github/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Use this template to report a bug. 4 | title: "[BUG] " 5 | labels: bug 6 | --- 7 | 8 | ### Title 9 | [Short description of the bug] 10 | 11 | ### Description 12 | Please provide a clear and concise description of what the bug is. 13 | 14 | ### Steps to Reproduce 15 | 1. [First Step] 16 | 2. [Second Step] 17 | 3. [and so on...] 18 | 19 | ### Expected Behavior 20 | Please describe what you expected to happen. 21 | 22 | ### Actual Behavior 23 | Please describe what actually happened. 24 | 25 | ### Screenshots 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | ### Environment 29 | - OS: [OSX/Windows/Linux] 30 | - Browser [e.g. chrome] 31 | 32 | ### Additional Context 33 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE] " 5 | labels: feature_request 6 | --- 7 | 8 | ### Title 9 | [Short description of the feature] 10 | 11 | ### Description 12 | Please provide a clear and concise description of what the feature is and what it aims to solve. 13 | 14 | ### Problem Background 15 | Please provide context and any background information on why this feature is important. 16 | 17 | ### Proposed Solution 18 | If you have a solution in mind, please describe it. 19 | 20 | ### Alternatives Considered 21 | Please describe any alternative solutions or features you have considered. 22 | 23 | ### Additional Context 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/general_query.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General Query 3 | about: Ask a question or seek clarification about the project 4 | title: "[QUERY] " 5 | labels: question 6 | --- 7 | 8 | ### Title 9 | [Short description of the query] 10 | 11 | ### Description 12 | Please provide a detailed description of your question or general query. 13 | 14 | ### Additional Context 15 | Add any other context or information that could help in addressing your query. 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | # docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # Mac files 156 | .DS_Store 157 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing opinions, viewpoints, and experiences 19 | * Giving and gracefully accepting constructive feedback 20 | * Focusing on what is best for the community 21 | * Demonstrating empathy and kindness toward community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery, and sexual attention or advances of 26 | any kind 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or email address, 30 | without their explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all community spaces, and also applies when 49 | an individual is officially representing the community in public spaces. 50 | Examples of 51 | representing a project or community include using an official project e-mail 52 | address, posting via an official social media account, or acting as an appointed 53 | representative at an online or offline event. Representation of a project may be 54 | further defined and clarified by project maintainers. 55 | 56 | ## Enforcement 57 | 58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 59 | reported by contacting the project team. 60 | All complaints will be reviewed and investigated promptly and fairly. 61 | 62 | All complaints will be reviewed and investigated and will result in a response that 63 | is deemed necessary and appropriate to the circumstances. The project team is 64 | obligated to maintain confidentiality with regard to the reporter of an incident. 65 | Further details of specific enforcement policies may be posted separately. 66 | 67 | ## Attribution 68 | 69 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, 70 | available at https://www.contributor-covenant.org/version/2/1/code_of_conduct/ 71 | 72 | [homepage]: https://www.contributor-covenant.org 73 | 74 | For answers to common questions about this code of conduct, see 75 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to MathViz-E 2 | 3 | A big welcome and thank you for considering contributing to this open source project! It’s people like you that will make this project transcend our imagination. 4 | 5 | Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved. It also communicates that you agree to respect the time of the developers managing and developing this project. In return, we will reciprocate that respect by addressing your issue, assessing changes, and helping you finalize your pull requests. 6 | 7 | ## Getting Started 8 | 9 | Contributions are made to this repo via Issues and Pull Requests (PRs). A few general guidelines that cover both: 10 | 11 | - Search for existing Issues and PRs before creating your own. 12 | - We work hard to makes sure issues are handled in a timely manner but, depending on the impact, it could take a while to investigate the root cause. 13 | - If you've never contributed before, see [this first timer's general guide](https://opensource.guide/how-to-contribute/) for resources and tips on how to get started. 14 | 15 | ### Issues 16 | 17 | Issues should be used to report problems with the library, request a new feature, or to discuss potential changes before a PR is created. When you create a new Issue, a template will be loaded that will guide you through collecting and providing the information we need to investigate. 18 | 19 | If you find an Issue that addresses the problem you're having, please add your own reproduction information to the existing issue rather than creating a new one. Adding a [reaction](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) can also help be indicating to our maintainers that a particular problem is affecting more than just the reporter. 20 | 21 | ### Pull Requests 22 | 23 | PRs to our libraries are always welcome and can be a quick way to get your fix or improvement slated for the next release. In general, PRs should: 24 | 25 | - Only fix/add the functionality in question **OR** address wide-spread whitespace/style issues, not both. 26 | - Feature PRs should start with `feature/` in the name 27 | - Bug/Fix PRs should start with `fix/` in the name 28 | - Add unit or integration tests for fixed or changed functionality (if a test suite already exists). 29 | - Address a single concern in the least number of changed lines as possible. 30 | - All created code should have clear function docs for others to read and build upon. 31 | - Be accompanied by a complete Pull Request template (loaded automatically when a PR is created). 32 | 33 | For changes that address core functionality or would require breaking changes (e.g. a major release), it's best to open an Issue to discuss your proposal first. This is not required but can save time creating and reviewing changes. 34 | 35 | In general, we will try to follow the ["fork-and-pull" Git workflow](https://github.com/susam/gitpr) 36 | 37 | 1. Fork the repository to your own Github account 38 | 2. Clone the project to your machine 39 | 3. Create a branch locally with a succinct but descriptive name 40 | 4. Commit changes to the branch 41 | 5. Following any formatting and testing guidelines specific to this repo 42 | 6. Push changes to your fork 43 | 7. Open a PR in our repository and follow the PR template so that we can efficiently review the changes. 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11 2 | COPY *.* / 3 | COPY src /src 4 | COPY src/.env /src/.env 5 | COPY src/static/* /src/static/* 6 | WORKDIR / 7 | RUN pip install --upgrade pip 8 | RUN pip install -r requirements.txt 9 | EXPOSE 5001 10 | CMD ["python", "-m", "src.main"] 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2024] [Merlyn Mind Inc] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MathViz-E 2 | 3 | MathViz-E is an agent-based system which provides voice-driven automated math graphing. The system consists of three interacting LLM-based agents: 4 | - An agent that interacts with a math solver, currently [WolframAlpha](https://www.wolframalpha.com/) 5 | - An agent that interacts with a visual calculator, currently [Desmos Graphical Calculator](https://www.desmos.com/calculator) 6 | - An orchestrator agent which interacts with the user interface, and the solver and calculator agents 7 | 8 | The agents complement each other. The solver agent can perform computations that are too complex for the LLM (currently [gpt4-turbo-preview](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo)) to solve reliably (like computing the tangent to a circle passing through a given point). On the other hand the orchestrator can reformulate queries into a form that is understandable by the solver. Finally, the visual calculator provides multimodal graphing capbilities. The combination allows the system to produce accurate graphs even for difficult, multi-step problems requiring complex reasoning. 9 | 10 | An immediate use-case is in-classroom math pedagogy for K-12. Visual graphing is an integral part of math education, allowing students to visualize and interact with mathematical concepts. Visual calculators are used to teach several [Common Core](https://corestandards.org/mathematics-standards/) learning objectives. Pedagogical agents like MathViz-E hold the promise of untethering teachers by enabling natural language-based operation of classroom tools, enabling teachers to spend more time teaching and interacting with students. 11 | 12 | Beyond the immediate pedgogical use-case, MathViz-E is an example of the broader class of [AI agent systems](https://blog.emergence.ai/2024/03/17/Introducing-Emergence.html) that are poised to fundamentally transform AI's impact on our everyday lives, and how we interact with technology. To learn more, check out our [blog posts](https://blog.emergence.ai/). 13 | 14 | ![MathViz-E flow example](docs/assets/images/conceptual-flow.png) 15 | 16 | ## Configuration 17 | 18 | 1. Rename `src/env.dist` to `src/.env`. 19 | 20 | 2. In `src/.env`, add your `OPENAI_API_KEY` and `WOLFRAM_APP_ID`. 21 | 22 | 3. In `src/.env`, add your `DESMOS_API_KEY`. As an example, you can use the public key [here](https://www.desmos.com/api/v1.8/docs/index.html). 23 | 24 | 4. In `src/.env` set `USE_EXPRESSION_VALIDATION` to `True` or `False`. 25 | - If `True` the agent uses a self-critique vaidation to fix common errors (generally related to Desmos API requirements e.g. using `le` instead of `leq` for inequalities). This produces more accurate outputs, but at the expense of significant latency. 26 | - Set to `False` is you prefer quicker responses, at the epense of occasional errors, that can be manually fixed in the Desmos calcualtor. 27 | 28 | ## Running the Agent 29 | 30 | ### Option A. Using Docker: 31 | 32 | 1. Run docker e.g., via [Docker Desktop](https://www.docker.com/products/docker-desktop/) 33 | 34 | 2. In `src/.env`, set the `USE_DOCKER` flag to `True`. 35 | 36 | 3. On Linux/Mac: In the project root folder run `source run.sh`. 37 | 38 | 4. On Windows: In the project root folder, run: 39 | ``` 40 | docker build -t my_desmos . 41 | docker run -p 5001:5001 my_desmos 42 | ``` 43 | 44 | ### Option B. Using python and conda: 45 | 46 | 1. Create a virtual environment with python v3.11. For example, if you're using [Anaconda](https://www.anaconda.com/download) 47 | ``` 48 | conda create -n math_agent python=3.11 pip 49 | conda activate math_agent 50 | ``` 51 | 52 | 2. Install requirements inside the environment 53 | ``` 54 | pip install -r requirements.txt 55 | ``` 56 | 57 | 3. In `src/.env`, set the `USE_DOCKER` flag to `False`. 58 | 59 | 4. In the root folder run `python -m src.main`. 60 | 61 | ### Option C. Using python and virtualenv 62 | 63 | 1. In `src/.env`, set the `USE_DOCKER` flag to `False`. 64 | 65 | 2. Install Python virtual environemnt 66 | ``` 67 | pip install virtualenv 68 | ``` 69 | 70 | 3. Go to the project directory and create the virtual environment 71 | ``` 72 | cd 73 | python3.11 -m venv env 74 | ``` 75 | 76 | 4. Activate the virtual environment 77 | ``` 78 | source env/bin/activate 79 | ``` 80 | 81 | 5. Install requirements inside the environment 82 | ``` 83 | pip install -r requirements.txt 84 | ``` 85 | 86 | 6. Run the application 87 | ``` 88 | python -m src.main 89 | ``` 90 | 91 | ## To invoke the agent 92 | 93 | In your browser, go to `http://localhost:5001/desmos/`. Tested on Chrome and Firefox; use Chrome to enable the voice-interface. 94 | 95 | ## Demos 96 | 97 | These are some demonstrations of multi-turn interactions with MathViz-E. There are several other types of mathematical concepts that the system can be used for. See the test cases in `\tests\` for many other examples of the categories of problems that MathViz-E can solve. 98 | 99 | | Video | Description | 100 | | --- | --- | 101 | | [![Example 1: Transformation of shapes](docs/assets/images/tn_shapes.png) ](https://www.youtube.com/watch?v=lHGYYWep9AQ) | Transformation of shapes: | 102 | | [![Example 2: Lines](docs/assets/images/tn_lines.png) ](https://www.youtube.com/watch?v=af1Buiweowk) | Lines: | 103 | | [![Example 3: Polynomials, extrema and derivatives](docs/assets/images/tn_poly.png) ](https://www.youtube.com/watch?v=RjP3EUgGTmo) | Polynomials, extrema and derivative: | 104 | | [![Example 4: Circles and tangents](docs/assets/images/tn_circles_tangents.png) ](https://www.youtube.com/watch?v=CmU55A8-YVM) | Circles and tangents: | 105 | 106 | ## Tests 107 | 108 | To run the system on a wide variety of single and multi-turn examples, you can run the provided test-scripts in the root-folder, on the examples in the `test` directory: 109 | ``` 110 | # single-turn tests 111 | source run_single_turn_tests.sh 112 | # multi-turn tests 113 | source run_multi_turn_tests.sh 114 | ``` 115 | Note that this takes a long time and requires many calls to the LLM (`gpt4-turbo-preview`). Also note that accuracy is significantly higher if you set `USE_EXPRESSION_VALIDATION` to `True` in `src/.env`. 116 | 117 | The test scripts produce output csv files with Desmos expressions, by default in the `test/output` folder. Evaluating the correction of these expressions is currently manual. We're in the process of adding an autoevaluator which uses the LLM and [Sympy](https://www.sympy.org/en/index.html) to automate evaluation. 118 | 119 | ## TODO 120 | 121 | Known issues and todos: 122 | - Support for polygons and non-parametric shapes: MathViz-E currently relies on the Desmos `setExpressions` API, which does not handle non-parametric shapes. Support for polygons etc. requires the use of other Desmos APIs like `polygon()`. 123 | - Unhandled classes of problems and Wolfram solver output: Other classes of problems that the system does poorly at include tangents to parabolas, and labeling certain types of intersections. A common theme in these errors is that Wolfram's output varies across classes of problems; we currently take Wolfram's output from the "Step-by-step solution" pod, but for some categories of problems this is incorrect. Wolfram output interpretation needs to be made more robust. 124 | - Graph retention over multi-turn interaction: Selecting which graphs to retain and which to remove, over the turns of a multi-turn interaction is non-trivial and needs to be made more robust. For example, "Move the shape to x,y" should probably remove the previously graphed shape, while "Plot the asymptote to the function" should probably retain the previously graphed function. 125 | - Natural language interfaces for the solver and calculator agents: Currently the orchestrator invokes the solver and calculator agents through member functions. We'd like to move to invocation via natural language interfaces. 126 | - Transition to Autogen or an equivalent framework: Related to the above (natural language interfaces), we plan to transition the system to a multi-agent framework like [Autogen](https://microsoft.github.io/autogen/) 127 | - Autoevaluator: Currently, accuracy evaluation of the system is done manually. An AI-critique based autoevaluator would signifcantly simplify this; we're looking at a SymPy + LLM based auto-evaluator. 128 | - Faster self-critique: The curent self-critique (when `USE_EXPRESSION_VALIDATION` is set "True") is slow and needs to be made more efficient. Also, the alternative rule-based post-processing is rather limited currently. One possibility is to combine the validation checks in the initial query prompt, to reduce the number of LLM invocations; another is to promotp the LLM to generate shorter responses, perhaps by limiting CoT. 129 | - Latency and fine-tuned LLMs: The system uses GPT4, which can be high-latency and expensive. Fine-tuning smaller open-source LLMs like Mistral or Llama would mitigate this. 130 | - Speech recognition issues: The system uses the [MDN Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API) for speech recognition. This has known issues with certain graphing utterances, for example, it often mis-transcribes words like "comma" and "cubed". 131 | 132 | ## Contributing 133 | 134 | Thank you for your interest in contributing! We welcome involvement from the community. 135 | 136 | Please visit our [contributing guidelines](CONTRIBUTING.md) for more details on how to get involved. 137 | 138 | ## Misc 139 | The UI uses icons and product names for the solver and calculator. This is for demonstration only, and all trademarks belong to the original owners. 140 | -------------------------------------------------------------------------------- /docs/assets/images/conceptual-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/docs/assets/images/conceptual-flow.png -------------------------------------------------------------------------------- /docs/assets/images/tn_circles_tangents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/docs/assets/images/tn_circles_tangents.png -------------------------------------------------------------------------------- /docs/assets/images/tn_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/docs/assets/images/tn_lines.png -------------------------------------------------------------------------------- /docs/assets/images/tn_poly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/docs/assets/images/tn_poly.png -------------------------------------------------------------------------------- /docs/assets/images/tn_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/docs/assets/images/tn_shapes.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["uv"] 3 | build-backend = "uv.build_api" 4 | 5 | [project] 6 | name = "math-agent-automation" 7 | version = "0.1.0" 8 | description = "Web automation tool for agents to perform tasks on web applications." 9 | authors = [ 10 | { name = "Arya Bulusu", email = "arya.bulusu@merlyn.org" }, 11 | { name = "Ashish Jagmohan", email = "ashish@merlyn.org" }, 12 | { name = "Aditya Vempaty", email = "aditya@merlyn.org" }, 13 | { name = "Deepak Akkil", email = "deepak.akkil@merlyn.org" }, 14 | { name = "Tamer Abuelsaad", email = "tea@merlyn.org" }, 15 | ] 16 | license = "MIT" 17 | readme = "README.md" 18 | repository = "https://github.com/XioResearchInterGalactic/rnd-desmos-automation" 19 | requires-python = ">=3.11" 20 | dependencies = [ 21 | "Flask==2.2.3", 22 | "openai==1.12.0", 23 | "python-dotenv==1.0.0", 24 | "Werkzeug==2.2.2", 25 | "requests==2.28.2" 26 | ] 27 | 28 | [project.scripts] 29 | run = "main.py" 30 | 31 | [tool.uv.dev-dependencies] 32 | # Ruff as a dev dependency for linting 33 | ruff = "^0.0.79" 34 | 35 | [tool.ruff] 36 | src = ["app"] 37 | fix = false 38 | show-fixes = true 39 | show-source = true 40 | line-length = 250 41 | 42 | [tool.ruff.lint] 43 | select = [ 44 | "B", # flake8-bugbear 45 | "E", # pycodestyle error 46 | "F", # pyflakes 47 | "I", # isort 48 | "UP", # pyupgrade 49 | "W", # pycodestyle warning 50 | ] 51 | #ignore = ["E501"] # Ignore the "line too long" rule 52 | 53 | 54 | [tool.ruff.lint.isort] 55 | force-single-line = true 56 | order-by-type = false -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.3 2 | openai==1.12.0 3 | python-dotenv==1.0.0 4 | Werkzeug==2.2.2 5 | requests==2.28.2 -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | docker build -t my_desmos . 4 | docker run -p 5001:5001 my_desmos -------------------------------------------------------------------------------- /run_multi_turn_tests.sh: -------------------------------------------------------------------------------- 1 | python -m src.main_tests \ 2 | --input_folder tests/multi_turn \ 3 | --output_folder tests/output/multi_turn \ 4 | --test_files \ 5 | graph_circles.csv \ 6 | graph_lines.csv \ 7 | graph_polynomials.csv \ 8 | inverse_functions.csv \ 9 | linear_and_nonlinear_functions.csv \ 10 | linear_quadratic_systems.csv \ 11 | transformations_of_functions.csv -------------------------------------------------------------------------------- /run_single_turn_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | python -m src.main_tests \ 4 | --input_folder tests/single_turn \ 5 | --output_folder tests/output/single_turn \ 6 | --test_files \ 7 | graph_circle_tangents.csv \ 8 | graph_parabola_tangents.csv \ 9 | graph_circles_2.csv \ 10 | graph_circles.csv \ 11 | graph_lines_2.csv \ 12 | graph_lines.csv \ 13 | graph_polynomials.csv \ 14 | graph_quad_eqns.csv \ 15 | intercepts.csv \ 16 | intersections_of_lines.csv \ 17 | inverse_functions.csv \ 18 | linear_and_nonlinear_functions.csv \ 19 | linear_equation_systems.csv \ 20 | linear_inequalities_2.csv \ 21 | linear_inequalities.csv \ 22 | local_optima.csv \ 23 | proportional_relationships.csv \ 24 | rigid_transformations.csv \ 25 | transform_shapes.csv \ 26 | transformations_of_functions_2.csv \ 27 | transformations_of_functions.csv -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/__init__.py -------------------------------------------------------------------------------- /src/agents/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/agents/__init__.py -------------------------------------------------------------------------------- /src/agents/desmos_agent.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | 4 | from src.prompts import DESMOS_REFINEMENT_PROMPT 5 | from src.prompts import DESMOS_REFINEMENT_PROMPT_STEP_2 6 | from src.prompts import DESMOS_START_PROMPT 7 | from src.prompts import DESMOS_SYSTEM_PROMPT 8 | from src.utils import get_gpt_response 9 | 10 | RELEVANT_EXPRESSION_KEYS = ["id", "type", "latex", "hidden", "sliderBounds"] 11 | 12 | def encode_calculator_state_as_str(calculator_state_expressions): 13 | """Encode calculator state expressions as a string. 14 | 15 | Args: 16 | calculator_state_expressions (List[str]): Desmos expressions 17 | representing current calculator state 18 | 19 | Returns: 20 | str: Encoded calculator state 21 | """ 22 | output_str = "" 23 | for expression in calculator_state_expressions: 24 | json_expr = json.loads(expression) 25 | expr = {k:json_expr[k] for k in json_expr.keys() if k in RELEVANT_EXPRESSION_KEYS} 26 | expr_str = json.dumps(expr) 27 | output_str += expr_str + "\n" 28 | return output_str 29 | 30 | class DesmosAgent: 31 | """Agent responsible for generating Desmos expressions""" 32 | 33 | def __init__(self): 34 | self.logger = logging.getLogger(__name__) 35 | 36 | def generate_desmos_expressions( 37 | self, 38 | user_request, 39 | calculator_state_expressions, 40 | wolfram_solution 41 | ): 42 | """Generate new Desmos expressions given user request and current calculator state. 43 | 44 | Args: 45 | user_request (str): User request 46 | calculator_state_expressions (List[str]): Desmos expressions 47 | representing current calculator state 48 | wolfram_solution (str): Wolfram solver solution 49 | 50 | Returns: 51 | List[dict]: Desmos expression JSON objects representing updated calculator state 52 | str: LLM CoT response 53 | """ 54 | self.logger.info(f"Processing user request: {user_request}") 55 | llm_prompt = self._create_desmos_prompt( 56 | user_request, 57 | calculator_state_expressions, 58 | wolfram_solution 59 | ) 60 | self.logger.info(f"Desmos LLM prompt:\n {llm_prompt}") 61 | llm_response = get_gpt_response(llm_prompt) 62 | self.logger.info(f"Desmos LLM response:\n {llm_response}") 63 | expressions = self._parse_llm_response( 64 | llm_response, prefix="Desmos expressions: " 65 | ) 66 | return expressions, llm_response 67 | 68 | def validate_desmos_expressions(self, expressions): 69 | """Validate Desmos expressions via LLM. 70 | 71 | Args: 72 | expressions (List[dict]): Desmos expressions 73 | 74 | Returns: 75 | List[dict]: Desmos expressions 76 | """ 77 | self.logger.info("Desmos refinement step 1:\n") 78 | refine_expressions, preserve_expressions = \ 79 | self._extract_expressions_for_refinement( 80 | expressions 81 | ) 82 | new_expressions = self._refine_expressions( 83 | refine_expressions, 84 | DESMOS_REFINEMENT_PROMPT 85 | ) 86 | self.logger.info("Desmos refinement step 2:\n") 87 | new_expressions = self._refine_expressions( 88 | new_expressions, 89 | DESMOS_REFINEMENT_PROMPT_STEP_2 90 | ) 91 | self.logger.info( 92 | f"Desmos refinement done. Expressions:\n\ 93 | {new_expressions+preserve_expressions}" 94 | ) 95 | return new_expressions + preserve_expressions 96 | 97 | def process_desmos_expressions(self, expressions): 98 | """Post process Desmos expressions via rules. 99 | Quicker but less robust than LLM validation. 100 | 101 | Args: 102 | expressions (List[dict]): Desmos expressions 103 | 104 | Returns: 105 | List[dict]: Desmos expressions 106 | """ 107 | self.logger.info("Desmos post processing step 1:\n") 108 | new_expressions = [self._process_expression(expr) for expr in expressions] 109 | return new_expressions 110 | 111 | def _create_desmos_prompt( 112 | self, 113 | user_request, 114 | calculator_state_expressions, 115 | wolfram_solution 116 | ): 117 | """Create prompt for LLM to generate Desmos expressions from user request, calculator state and wolfram solution. 118 | 119 | Args: 120 | user_request (str): User request 121 | calculator_state_expressions (List[str]): Desmos expressions 122 | representing current calculator state 123 | wolfram_solution (str): Wolfram solver solution 124 | 125 | Returns: 126 | List[dict]: LLM prompt 127 | """ 128 | messages = [] 129 | messages.append({"role": "system", "content": DESMOS_SYSTEM_PROMPT}) 130 | messages.append({"role": "user", "content": DESMOS_START_PROMPT}) 131 | user_msg = f"Task: {user_request}\nCalculator state: [" 132 | user_msg += encode_calculator_state_as_str(calculator_state_expressions) 133 | user_msg += "]\nStep-by-step Solution: \n" 134 | user_msg += wolfram_solution + "\n" 135 | messages.append({"role": "user", "content": user_msg}) 136 | return messages 137 | 138 | def _parse_llm_response(self, llm_response, prefix): 139 | """Parse LLM response to extract Desmos expressions. 140 | 141 | Args: 142 | llm_response (str): LLM response 143 | 144 | Returns: 145 | List[dict]: Desmos expressions JSON objects 146 | """ 147 | expressions = [] 148 | lines = llm_response.splitlines() 149 | is_expression_line = False 150 | for _, line in enumerate(lines): 151 | if is_expression_line: 152 | try: 153 | if line.strip().startswith("{"): 154 | end_char = line.rfind("}") 155 | expressions.append(json.loads(line[:end_char+1])) 156 | else: 157 | continue 158 | except Exception as e: 159 | self.logger.warn(f"Exception in parsing {line} in llm response: {e}") 160 | continue 161 | if line.startswith(prefix): 162 | is_expression_line = True 163 | self.logger.info(f"Parsed updated expressions: {expressions}") 164 | return expressions 165 | 166 | def _create_refinement_prompt(self, expressions, sys_prompt): 167 | """Create prompt for LLM to refine Desmos expressions. 168 | 169 | Args: 170 | expressions (List[dict]): Desmos expressions 171 | 172 | Returns: 173 | List[dict]: LLM prompt 174 | """ 175 | messages = [] 176 | messages.append({"role": "system", "content": sys_prompt}) 177 | expr = [e["expression"] for e in expressions] 178 | expr_str = "[\n" 179 | for e in expr: 180 | expr_str += json.dumps(e) + ",\n" 181 | expr_str += "]" 182 | messages.append({"role": "user", "content": expr_str}) 183 | return messages 184 | 185 | def _refine_expressions(self, expressions, sys_prompt): 186 | """Refine Desmos expressions via LLM. 187 | 188 | Args: 189 | expressions (List[dict]): Desmos expressions 190 | 191 | Returns: 192 | List[dict]: Refined Desmos expressions 193 | """ 194 | self.logger.info(f"Refining expressions:\n {type(expressions)}, {expressions}") 195 | llm_prompt = self._create_refinement_prompt(expressions, sys_prompt) 196 | self.logger.info(f"Desmos refinement prompt:\n {llm_prompt}") 197 | llm_response = get_gpt_response(llm_prompt) 198 | self.logger.info(f"Desmos refinement response: {llm_response}") 199 | refined_expressions = self._parse_llm_response( 200 | llm_response, prefix="Fixed Desmos expressions:" 201 | ) 202 | if len(refined_expressions) != len(expressions): 203 | self.logger.warn( 204 | f"Refinement #expr mismatch: {len(refined_expressions)} vs {len(expressions)}" 205 | ) 206 | refined_expressions = expressions 207 | else: 208 | refined_expressions = [ 209 | {"action": expr["action"], "expression": ref_expr} \ 210 | for expr, ref_expr in zip(expressions, refined_expressions, strict=True) 211 | ] 212 | self.logger.info(f"Refined expressions:\n {refined_expressions}") 213 | return refined_expressions 214 | 215 | def _extract_expressions_for_refinement(self, expressions): 216 | """Extract expressions for refinement. 217 | 218 | Args: 219 | expressions (List[dict]): Desmos expressions 220 | 221 | Returns: 222 | List[dict]: Expressions for refinement 223 | List[dict]: Expressions to preserve 224 | """ 225 | refine_expressions, preserve_expressions = [], [] 226 | for expr in expressions: 227 | if expr["action"] == "setExpression": 228 | refine_expressions.append(expr) 229 | else: 230 | preserve_expressions.append(expr) 231 | self.logger.info(f"Refine expressions:\n{refine_expressions}") 232 | self.logger.info(f"Preserve expressions:\n{preserve_expressions}") 233 | return refine_expressions, preserve_expressions 234 | 235 | def _process_expression(self, expression): 236 | """Post process Desmos expression via rules 237 | 238 | Args: 239 | expression (dict): Desmos expression 240 | 241 | Returns: 242 | dict: Processed Desmos expression 243 | """ 244 | # Remove any occurrence of prime notation 245 | new_expression = expression 246 | if expression["action"] == "setExpression" \ 247 | and "latex" in expression.get("expression", {}): 248 | old_latex = expression["expression"]["latex"] 249 | # replace prime notation 250 | new_latex = old_latex.replace("\'", "").replace("'", "") 251 | new_expression["expression"]["latex"] = new_latex 252 | return new_expression 253 | -------------------------------------------------------------------------------- /src/agents/math_viz_agent.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | 4 | from src.agents.desmos_agent import DesmosAgent 5 | from src.agents.desmos_agent import encode_calculator_state_as_str 6 | from src.agents.wolfram_agent import WolframAgent 7 | from src.prompts import EXPLANATION_PROMPT 8 | from src.utils import get_gpt_response 9 | 10 | 11 | class MathVizAgent: 12 | """Math visualization gent responsible for orchestrating Wolfram and Desmos agents to handle user request.""" 13 | 14 | def __init__(self): 15 | self.logger = logging.getLogger(__name__) 16 | self.wolfram_agent = WolframAgent() 17 | self.desmos_agent = DesmosAgent() 18 | 19 | def _return_agent_response(self, agent:str, status_message:str): 20 | """Return agent status message in JSON format to front-end 21 | 22 | Args: 23 | agent (str): Agent name 24 | status_message (str): Status message 25 | 26 | Returns: 27 | str: JSON formatted agent status message 28 | """ 29 | json_status_message = {"agent": agent, "message": status_message} 30 | self.logger.info(f"Returning agent response: {json_status_message}") 31 | return json.dumps(json_status_message) + "\n" 32 | 33 | 34 | def process_user_request( 35 | self, 36 | user_request, 37 | calculator_state_expressions, 38 | use_validation=False 39 | ): 40 | """Process user request, given the current calculator state, 41 | and return the updated calculator state. 42 | 43 | Args: 44 | user_request (str): User request 45 | calculator_state_expressions (List[str]): Desmos expressions 46 | representing current calculator state 47 | use_validation (bool, optional): Whether to validate Desmos expressions. Defaults to False. 48 | 49 | Returns: 50 | List[str]: Desmos expressions representing Updated calculator state 51 | """ 52 | 53 | self.logger.info(f"Processing user request: {user_request}") 54 | self.logger.info(f"Calculator state: {calculator_state_expressions}") 55 | 56 | wolfram_query = self.wolfram_agent.create_query( 57 | user_request, 58 | calculator_state_expressions 59 | ) 60 | yield self._return_agent_response("wolfram", f"Reformulated user request for Wolfram|Alpha solver: {wolfram_query}") 61 | 62 | wolfram_solution = self.wolfram_agent.execute_query( 63 | wolfram_query 64 | ) 65 | if wolfram_solution.strip() != "Cannot return solution" and len(wolfram_solution.strip()) > 0: 66 | yield self._return_agent_response("wolfram", f"Wolfram solution: {wolfram_solution}") 67 | 68 | yield self._return_agent_response("math viz", "Generating Desmos expressions for user query ...") 69 | new_calculator_expressions, chain_of_thought = self.desmos_agent.generate_desmos_expressions( 70 | user_request, 71 | calculator_state_expressions, 72 | wolfram_solution 73 | ) 74 | yield self._return_agent_response("math viz", f"{chain_of_thought}") 75 | 76 | if use_validation: 77 | yield self._return_agent_response("math viz", "Validating expressions ...") 78 | new_calculator_expressions = self.desmos_agent.validate_desmos_expressions( 79 | new_calculator_expressions 80 | ) 81 | else: 82 | yield self._return_agent_response("math viz", "Post-processing expressions ...") 83 | new_calculator_expressions = self.desmos_agent.process_desmos_expressions( 84 | new_calculator_expressions 85 | ) 86 | 87 | yield self._return_agent_response("math viz", "Done. Visualising results on calculator.") 88 | expressions={"expressions": new_calculator_expressions} 89 | yield json.dumps(expressions)+"\n" 90 | 91 | def _create_explanation(self, user_request, calculator_state_expressions, solution): 92 | """Create an explanation of the solution based on the user request and calculator state. 93 | 94 | Args: 95 | user_request (str): User request 96 | calculator_state_expressions (List[str]): Desmos expressions 97 | representing current calculator state 98 | solution (str): Wolfram solver solution 99 | 100 | Returns: 101 | str: Explanation of the solution 102 | """ 103 | self.logger.info(f"Creating explanation: {user_request}") 104 | llm_prompt = self._create_explanation_prompt( 105 | user_request, 106 | calculator_state_expressions, 107 | solution 108 | ) 109 | self.logger.info(f"LLM prompt: {llm_prompt}") 110 | gpt_response = get_gpt_response(llm_prompt) 111 | self.logger.info(f"LLM explanation: {gpt_response}") 112 | return gpt_response 113 | 114 | def _create_explanation_prompt( 115 | self, 116 | user_request, 117 | calculator_state_expressions, 118 | wolfram_solution=None 119 | ): 120 | """Create prompt for LLM to generate Wolfram solver query from user request and calculator state. 121 | 122 | Args: 123 | user_request (str): User request 124 | calculator_state_expressions (List[str]): Desmos expressions 125 | representing current calculator state 126 | wolfram_solution (str, optional): Wolfram solver solution. Defaults to None. 127 | 128 | Returns: 129 | List[dict]: LLM prompt 130 | """ 131 | messages = [{"role": "system", "content": EXPLANATION_PROMPT}] 132 | user_msg = f"Task: {user_request}\nCalculator state: [" 133 | user_msg += encode_calculator_state_as_str(calculator_state_expressions) 134 | user_msg += "]\nStep-by-step Solution: \n" 135 | user_msg += wolfram_solution + " \n" 136 | messages.append({"role": "user", "content": user_msg}) 137 | return messages 138 | -------------------------------------------------------------------------------- /src/agents/wolfram_agent.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import urllib.parse 4 | 5 | import requests 6 | 7 | from src.agents.desmos_agent import encode_calculator_state_as_str 8 | from src.prompts import WA_QUERY_PROMPT 9 | from src.utils import get_gpt_response 10 | 11 | 12 | class WolframAgent: 13 | """Agent responsible for generating Wolfram solver queries and parsing Wolfram solver output""" 14 | 15 | def __init__(self): 16 | self.logger = logging.getLogger(__name__) 17 | self.appid = os.getenv("WOLFRAM_APP_ID") 18 | 19 | def create_query(self, user_request, calculator_state_expressions): 20 | """Create Wolfram solver query based on user request and calculator state. 21 | 22 | Args: 23 | user_request (str): User request 24 | calculator_state_expressions (List[str]): Desmos expressions 25 | representing current calculator state 26 | 27 | Returns: 28 | str: Wolfram solver query 29 | """ 30 | self.logger.info(f"Creating solver query: {user_request}") 31 | llm_prompt = self._create_solution_prompt( 32 | user_request, 33 | calculator_state_expressions 34 | ) 35 | self.logger.info(f"LLM prompt: {llm_prompt}") 36 | response = get_gpt_response(llm_prompt) 37 | self.logger.info(f"LLM response: {response}") 38 | return response 39 | 40 | def execute_query(self, solver_query): 41 | """Execute Wolfram solver query and return the solution. 42 | 43 | Args: 44 | solver_query (str): Wolfram solver query 45 | 46 | Returns: 47 | str: Wolfram solver solution 48 | """ 49 | self.logger.info(f"Executing solver query: {solver_query}") 50 | parsed_query = urllib.parse.quote_plus(solver_query) 51 | query_url = f"http://api.wolframalpha.com/v2/query?" \ 52 | f"appid={self.appid}" \ 53 | f"&input={parsed_query}" \ 54 | f"&format=plaintext" \ 55 | f"&podstate=Step-by-step%20solution" \ 56 | f"&output=json" 57 | r = requests.get(query_url).json() 58 | #logic behind pod selection: It would be great to ask specifically for the Result pod in the query itself 59 | #to reduce the amount of data returned, but there is no guarantee that the necessary pod will be titled "Result" 60 | #the most relevant pod is almost always the second one, so we only return data from the second pod 61 | #this could break if Wolfram Alpha changes how they rank their pods 62 | numpods = r["queryresult"]["numpods"] 63 | if numpods < 2: 64 | result = "Cannot return solution" 65 | else: 66 | pod = r["queryresult"]["pods"][1] 67 | numsubpods = pod["numsubpods"] 68 | result = "" 69 | for subpod in range(numsubpods): 70 | result += pod["subpods"][subpod]["plaintext"] 71 | result += "\n" 72 | self.logger.info(f"Solver solution: {result}") 73 | return result 74 | 75 | def _create_solution_prompt(self, user_request, calculator_state_expressions): 76 | """Create prompt for LLM to generate Wolfram solver query from user request and calculator state. 77 | 78 | Args: 79 | user_request (str): User request 80 | calculator_state_expressions (List[str]): Desmos expressions 81 | representing current calculator state 82 | 83 | Returns: 84 | str: LLM prompt 85 | """ 86 | messages = [{"role": "system", "content": WA_QUERY_PROMPT}] 87 | user_msg = f"Task: {user_request}\nCalculator state: [" 88 | user_msg += encode_calculator_state_as_str(calculator_state_expressions) 89 | messages.append({"role": "user", "content": user_msg}) 90 | return messages 91 | -------------------------------------------------------------------------------- /src/desmos_calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Desmos Automation 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
Clear Chat
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/env.dist: -------------------------------------------------------------------------------- 1 | DESMOS_API_KEY="" 2 | OPENAI_API_KEY="" 3 | WOLFRAM_APP_ID="" 4 | USE_DOCKER=True 5 | USE_EXPRESSION_VALIDATION=False 6 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from datetime import timedelta 4 | 5 | from dotenv import load_dotenv 6 | from flask import Flask 7 | 8 | from src.agents.math_viz_agent import MathVizAgent 9 | from src.routes import register_routes 10 | 11 | #TODO: Set permanent session lifetime to sensible value. 12 | app = Flask(__name__, template_folder='.') 13 | app.permanent_session_lifetime = timedelta(days=1) 14 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 15 | 16 | logging.basicConfig( 17 | level=logging.INFO, 18 | format="[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s", 19 | ) 20 | 21 | if __name__ == '__main__': 22 | load_dotenv() 23 | math_viz_agent = MathVizAgent() 24 | register_routes(app, math_viz_agent, BASE_DIR) 25 | host="localhost" 26 | if os.getenv("USE_DOCKER") == "True": 27 | host = "0.0.0.0" 28 | app.run(debug=False, port=5001, host=host) 29 | -------------------------------------------------------------------------------- /src/main_tests.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import csv 3 | import json 4 | import logging 5 | import os 6 | 7 | from dotenv import load_dotenv 8 | 9 | from src.agents.math_viz_agent import MathVizAgent 10 | 11 | logging.basicConfig( 12 | level=logging.INFO, 13 | format="[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s", 14 | ) 15 | 16 | def parse_args(): 17 | parser = argparse.ArgumentParser( 18 | description="Test utterances against the math vizualization agent" 19 | "") 20 | parser.add_argument( 21 | "--input_folder", 22 | type=str, 23 | default="tests", 24 | help="Folder where test files reside" 25 | ) 26 | parser.add_argument( 27 | "--test_files", 28 | type=str, 29 | nargs="+", 30 | help="Csv files with test cases" 31 | ) 32 | parser.add_argument( 33 | "--output_folder", 34 | type=str, 35 | default="tests/output", 36 | help="Folder to save output" 37 | ) 38 | args = parser.parse_args() 39 | return args 40 | 41 | def evaluate_utterances_in_file(test_file, input_folder): 42 | results = [] 43 | math_viz_agent = MathVizAgent() 44 | with open( 45 | os.path.join(input_folder, test_file), 46 | encoding='utf-8-sig', 47 | newline='' 48 | ) as f: 49 | reader = csv.DictReader(f) 50 | curr_qid, state = None, None 51 | for row in reader: 52 | logging.info(row) 53 | if str(row["id"]) == curr_qid and curr_qid is not None: 54 | calculator_state = [json.dumps(s) for s in state] 55 | else: 56 | calculator_state = [] 57 | expressions = math_viz_agent.process_user_request( 58 | row["query"], 59 | calculator_state 60 | ) 61 | final_expr_str = None 62 | for expr in expressions: 63 | final_expr_str = expr 64 | final_expressions = json.loads(final_expr_str)["expressions"] 65 | results.append({ 66 | "id": str(row["id"]), 67 | "query": row["query"], 68 | "ground truth": row["ground truth"], 69 | "output": json.dumps(final_expressions), 70 | }) 71 | state, curr_qid = [e["expression"] for e in final_expressions], str(row["id"]) 72 | return results 73 | 74 | def output_results(results, output_folder, test_file): 75 | output_file = test_file.split("/")[-1].replace(".csv", "_results.csv") 76 | with open(os.path.join(output_folder, output_file), "w") as f: 77 | writer = csv.DictWriter( 78 | f, 79 | fieldnames=[ 80 | "id", "query", "ground truth", "output" 81 | ] 82 | ) 83 | writer.writeheader() 84 | for result in results: 85 | writer.writerow(result) 86 | 87 | def process_file(test_file, input_folder, output_folder): 88 | results = [] 89 | logging.info(f"Processing test file: {test_file}") 90 | try: 91 | results = evaluate_utterances_in_file(test_file, input_folder) 92 | output_results(results, output_folder, test_file) 93 | except Exception as e: 94 | logging.error(f"Error processing test file: {e}") 95 | 96 | def main(args): 97 | for test_file in args.test_files: 98 | process_file(test_file, args.input_folder, args.output_folder) 99 | 100 | if __name__ == "__main__": 101 | args = parse_args() 102 | load_dotenv() 103 | main(args) 104 | -------------------------------------------------------------------------------- /src/prompts.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: E501 2 | WA_QUERY_PROMPT = ''' 3 | You are an agent who is an expert at using Wolfram Alpha. I will give you a task, and you will write a Wolfram Alpha query that can be used to solve the problem. The main purpose of the task is to find the numerical answer to the problem, not to graph the problem. Do not use the word “graph” in your query; instead use commands like “solve” or “find”. When writing a query for a word problem, only include the necessary equation to solve the problem. Do not use units from the word problem in the query. Ensure that the query is acceptable by the Wolfram Alpha engine. 4 | 5 | For example, if you are asked: 6 | Graph y = 6x^2 + 4 and find the local maxima and minima. 7 | Calculator state: [] 8 | 9 | You generate: 10 | Find the local maxima and minima of y = 6x^2 + 4 11 | 12 | For example, if you are asked: 13 | Given the parabola y = x^2 + 4, graph the line tangent to the parabola at x = 2. 14 | Calculator state: [] 15 | 16 | You generate: 17 | Tangent to y = x^2 + 4 through x = 2 18 | 19 | For example, if you are asked: 20 | Graph the system of equations and find the solution: y = 6x - 3, y = -2x + 5. 21 | Calculator state: [] 22 | 23 | You generate: 24 | Solve system of equations y = 6x – 3, y = -2x + 5 25 | 26 | For example, if you are asked: 27 | Consider the polynomial function f(x) = 5x^3 + 8x^2 + x - 6. Graph the function and identify the x-intercepts of the polynomial. 28 | Calculator state: [] 29 | 30 | You generate: 31 | Find zeros of f(x) = 5x^3 + 8x^2 + x – 6 32 | 33 | For example, if you are asked: 34 | At Beans & Bagels, a bagel costs $1 more than a cup of coffee. If 4 cups of coffee and 6 bagels cost $31, which of the following systems of equations can be used to determine the price of a bagel, b, and the price of a cup of coffee, c? 35 | Calculator state: [] 36 | 37 | You generate: 38 | Solve b = c + 1, 4c + 6b = 31 39 | 40 | For example, if you are asked: 41 | Consider the circle with center (-3, 0) and radius 2. Graph the circle and a tangent line that passes through x = -2. Label the point of tangency on the graph. 42 | Calculator state: [] 43 | 44 | You generate: 45 | Tangent to (x + 3)^2 + y^2 = 4 at x = -2 46 | 47 | ''' 48 | EXPLANATION_PROMPT = ''' 49 | You are a teacher whose goal is to explain the solution to a math problem so that a student can easily understand how to solve it. 50 | I will provide you with a math problem and optionally, a step-by-step solution to that problem. 51 | You will generate a thorough explanation of the steps. 52 | 53 | ''' 54 | DESMOS_SYSTEM_PROMPT = ''' 55 | You are an agent who is an expert at using Desmos. 56 | 57 | I will give you the current state of the Desmos calculator, as encoded by the list of expressions received from get_expressions(). I will also provide a step-by-step solution outlining how to solve the task. 58 | 59 | I want you to provide one or more additional Desmos actions and expressions, in json-string form, that will help me accomplish a desired task. Each action-expression pair should start on a new line. 60 | 61 | Desmos actions can be setExpression or removeExpression. 62 | 63 | Do not use the symbols x, y or r for parameters. 64 | 65 | Your message should end with 66 | Desmos expressions: , "expression": } entries> one per line. 67 | 68 | For example, if you are asked: 69 | Task: Graph y = 6x^2 + 4 and find the local maxima and minima. 70 | Calculator state: [] 71 | Step-by-step solution: 72 | Find and classify the local extrema of the following function using the first derivative test: 73 | f(x) = 6 x^2 + 4 74 | Find the critical points of f(x): 75 | Compute the critical points of 6 x^2 + 4 76 | To find all critical points, first compute f'(x): 77 | d/(dx) (6 x^2 + 4) = 12 x: 78 | f'(x) = 12 x 79 | Solving 12 x = 0 yields x = 0: 80 | x = 0 81 | f'(x) exists everywhere: 82 | 12 x exists everywhere 83 | The only critical point of 6 x^2 + 4 is at x = 0: 84 | x = 0 85 | Partition the domain into intervals with endpoints at the critical points: (-∞, 0) and (0, ∞) 86 | Pick test points in the intervals at which to compute the sign of f'(x): 87 | Our test points are x = -1 and x = 1 88 | Evaluate and find the sign of f'(x) = 12 x at x = -1 and x = 1: 89 | x | f'(x) | sign 90 | -1 | -12 | - 91 | 1 | 12 | + 92 | Mark each interval according to the sign of f'(x): 93 | interval | sign of f'(x) | behavior of f(x) 94 | (-∞, 0) | - | decreasing 95 | (0, ∞) | + | increasing 96 | For x = 0: 97 | If the sign of f'(x) changes from positive to negative, f has a local maximum at x 98 | If the sign of f'(x) changes from negative to positive, f has a local minimum at x 99 | If the sign of f'(x) does not change, f has no extremum at x 100 | x | class 101 | 0 | min 102 | f(x) = 6 x^2 + 4 has one local minimum: 103 | Answer: | 104 | | f(x) has a local minimum at x = 0 105 | 106 | You generate: 107 | Thought: I need to create an expression for the equation f(x) = 6x^2 + 4. In order to graph the local minimum, I need to solve for the y-value at x = 0. 108 | 109 | f(0) = 6(0)^2 + 4 = 0 + 4 = 4 110 | 111 | The local minimum occurs at (0, 4). 112 | Desmos expressions: [ 113 | {"action": "setExpression", "expression": {"type":"expression","id":"function","latex":"f(x) = 6x^2 + 4","hidden":false}}, 114 | {"action": "setExpression", "expression": {"type":"expression","id":"local_minimum","latex":"(0,4)","hidden":false}} 115 | ] 116 | 117 | For example, if you are asked: 118 | Task: Graph the system 4x + 8y = 8, 2x + 6y = 10. Find the solution. 119 | Calculator state: [] 120 | Step-by-step solution: 121 | Solve the following system: 122 | {8 y + 4 x = 8 | (equation 1) 123 | 6 y + 2 x = 10 | (equation 2) 124 | Subtract 1/2 x(equation 1) from equation 2: 125 | {4 x + 8 y = 8 | (equation 1) 126 | 0 x + 2 y = 6 | (equation 2) 127 | Divide equation 1 by 4: 128 | {x + 2 y = 2 | (equation 1) 129 | 0 x + 2 y = 6 | (equation 2) 130 | Divide equation 2 by 2: 131 | {x + 2 y = 2 | (equation 1) 132 | 0 x + y = 3 | (equation 2) 133 | Subtract 2x(equation 2) from equation 1: 134 | {x + 0 y = -4 | (equation 1) 135 | 0 x + y = 3 | (equation 2) 136 | Collect results: 137 | Answer: | 138 | | {x = -4 139 | y = 3 140 | 141 | You generate: 142 | Thought: I need to create expressions for the lines 4x + 8y = 8 and 2x + 6y = 10. I also need to create an expression for the solution, (-4, 3). 143 | 144 | Desmos expressions: [ 145 | {"action": "setExpression", "expression": {"type":"expression","id":"line1","latex":"4x + 8y = 8","hidden":false}}, 146 | {"action": "setExpression", "expression": {"type":"expression","id":"line2","latex":"2x+6y=10","hidden":false}}, 147 | {"action": "setExpression", "expression": {"type":"expression","id":"solution","latex":"(-4,3)","hidden":false}} 148 | ] 149 | 150 | For example, if you are asked: 151 | Task: Compress the circle centered at (1, 2) with a radius of 8 by a factor of 1/2 152 | Calculator state: [] 153 | Step-by-step solution: 154 | Cannot return solution 155 | 156 | You generate: 157 | Thought: The equation of the original circle is (x – 1)^2 + (y – 2)^2 = 64. To compress a circle with a radius of 8 by a factor of ½, we need to create a new circle with a radius of 4. The equation of the new circle is (x – 1)^2 + (y – 2)^2 = 16. 158 | 159 | Desmos expressions: [ 160 | {"action": "setExpression", "expression": {"type":"expression","id":"compressed_circle","latex":"(x – 1)^2 + (y – 2)^2 = 16","hidden":false}} 161 | ] 162 | 163 | For example, if you are asked: 164 | Task: Graph the circle with the center (2, -1) and a radius of 4. Find the tangent lines that pass through the point (6, 0). 165 | 166 | Step-by-step solution: 167 | tangent through (x, y) = (8, 0) : y = (12 (8 sqrt(21) - 7))/(63 + 2 sqrt(21)) - (3 (8 sqrt(21) - 7) x)/(2 (63 + 2 sqrt(21))) 168 | tangent through (x, y) = (8, 0) : y = (12 (7 + 8 sqrt(21)))/(2 sqrt(21) - 63) - (3 (7 + 8 sqrt(21)) x)/(2 (2 sqrt(21) - 63)) 169 | You generate: 170 | Thought: The equation of the circle is (x – 2)^2 + (y + 1)^2 = 16. I need to graph the circle and the two tangent lines. 171 | 172 | Desmos expressions: [ 173 | {"action": "setExpression", "expression": {"type":"expression","id":"circle","latex":"(x - 2)^2 + (y + 1)^2 = 16","hidden":false}}, 174 | {"action": "setExpression", "expression": {"type":"expression","id":"tangent1","latex":" y = (12 (8 * \\\\sqrt{21} - 7))/(63 + 2 * \\\\sqrt{21}) - (3 (8 * \\\\sqrt{21} - 7) x)/(2 (63 + 2 * \\\\sqrt{21}))”, ","hidden":false}}, 175 | {"action": "setExpression", "expression": {"type":"expression","id":"solution","latex":" y = (12 (7 + 8 * \\\\sqrt{21}))/(2 * \\\\sqrt{21} - 63) - (3 (7 + 8 * \\\\sqrt{21}) x)/(2 (2 * \\\\sqrt{21} - 63))","hidden":false}} 176 | ] 177 | 178 | For example, if you are asked: 179 | Task: Rotate the function by 90 degrees 180 | Calculator state: [{"id": "function", "type": "expression", "latex": "y=(-x)^{3}", "hidden": false}] 181 | Step-by-step Solution: 182 | (x, -x^3)⟶(x^3, x) 183 | 184 | You generate: 185 | Thought: The calculator state shows the function y = (-x)^3. Rotating the function y = (-x)^3 by 90 degrees requires the transformation (x, y) to (-y, x). Thus the rotated function is x = -(-y)^3, i.e. x = y^3. 186 | 187 | Desmos expressions: [ 188 | {"action": "removeExpression", "expression": {"id":"shape"}}, 189 | {"action": "setExpression", "expression": {"type":"expression","id":"rotated_shape","latex":"x = y^3","hidden":false}}, 190 | ] 191 | ''' 192 | 193 | DESMOS_START_PROMPT = ''' 194 | If you're asked to transform an existing expression, remove the old expression using the removeExpression action and then add the new expression using the setExpression action. Do this only if you are explicitly asked to modify the existing expression (for example by shifting, rotating, scaling etc.) If a new expression is asked to be graphed, do not remove the existing expression. 195 | Remember, do not use the symbols x, y or r for parameters. 196 | Also remember, use the symbols x and y for variables, since Desmos only supports implicit equations of x and y. 197 | And, to draw a line, simplify the equation. 198 | ''' 199 | 200 | DESMOS_REFINEMENT_PROMPT = ''' 201 | You are an agent who is an expert at using Desmos. 202 | 203 | I will give you a set of Desmos expressions to be graphed in the calculator using the Desmos setExpression() API. 204 | 205 | I would like you to check the latex for each expression, and fix mistakes. 206 | 207 | Start your response by thinking step-by-step and briefly explain your reasoning. End your response with Fixed Desmos expressions: with each expression dict on a new line. If there are no mistakes in an expression or you don't understand it, return the original expression as is. 208 | 209 | Here are some of the things you should check, and fix: 210 | 211 | Check 1. The latex expressions should only use x and y for variables, since Desmos calculator only supports implicit equations in x and y. 212 | 213 | So, the following input: 214 | Desmos expressions: [ 215 | {"type":"expression","id":"line1","latex":"4t + 8T = 8","hidden":false} 216 | ] 217 | 218 | is incorrect because it is using the letters t and T as variables instead of x and y. This should get fixed to: 219 | Fixed Desmos expressions: [ 220 | {"type":"expression","id":"line1","latex":"4x + 8y = 8","hidden":false} 221 | ] 222 | 223 | 224 | Check 2. Don't use letters like x, y, e, r for slider parameters, since those letters have special meaning in Desmos. 225 | 226 | So, the following input: 227 | Desmos expressions: [ 228 | {"type":"expression","id":"p","latex":"(x - h) ^ 2 + (y - k) ^ 2 = r^2“,”hidden":false}, 229 | {"type":"expression","id":"slider_r”,”latex”:”r=1", "sliderBounds":{"min":-10, "max":10, "step”:0.1}}, 230 | {"type":"expression","id":"slider_h","latex":"h=0", "sliderBounds":{"min":-10, "max":10, "step”:0.1}}, 231 | {"type":"expression","id":"slider_k","latex":"k=0", "sliderBounds":{"min":-10, "max":10, "step":0.1}} 232 | ] 233 | 234 | is incorrect because it is using the special letter r as a slider parameter. This should get fixed to: 235 | Fixed Desmos expressions: [ 236 | {"type":"expression","id":"p","latex":"(x - h) ^ 2 + (y - k) ^ 2 = a^2“,”hidden":false}, 237 | {"type":"expression","id":"slider_a”,”latex”:”a=1", "sliderBounds":{"min":-10, "max":10, "step”:0.1}}, 238 | {"type":"expression","id":"slider_h","latex":"h=0", "sliderBounds":{"min":-10, "max":10, "step”:0.1}}, 239 | {"type":"expression","id":"slider_k","latex":"k=0", "sliderBounds":{"min":-10, "max":10, "step":0.1}} 240 | ] 241 | 242 | 243 | 244 | Check 3. To denote the absolute value of a quantity x, the Desmos API uses only the syntax \\abs(x). The Desmos API does not understand the “||” symbol for absolute values, even simple ones, or \\abs{x}, so those should not be used. 245 | 246 | So, the following input: 247 | Desmos expressions: [ 248 | {"type":"expression","id”:”abs_val”,”latex”:”y = |x^2 - 4|“,”hidden":false}, 249 | {"type":"expression","id”:”other”,”latex”:”y = x - 5“,”hidden":false} 250 | ] 251 | 252 | is incorrect because the first input expression is using the “|” symbol which the Desmos API doesn’t understand. This should get fixed to: 253 | Fixed Desmos expressions: [ 254 | {"type":"expression","id”:”abs_val”,”latex”:”y = \\abs(x^2 - 4)“,”hidden":false}, 255 | {"type":"expression","id”:”other”,”latex”:”y = x - 5“,”hidden":false} 256 | ] 257 | 258 | Similarly, the following input: 259 | Desmos expressions: [ 260 | {"type":"expression","id”:”abs_val”,”latex”:”y = \\abs{x^2 + x}“,”hidden":false} 261 | ] 262 | 263 | is incorrect because it is using \\abs{} which is the wrong enclosure for the abs function for the Desmos API. This should get fixed to: 264 | Fixed Desmos expressions: [ 265 | {"type":"expression","id”:”abs_val”,”latex”:”y = \\abs(x^2 + x)“,”hidden":false} 266 | ] 267 | 268 | 269 | 270 | Check 4. For the power operator “^” Desmos needs the exponent to be enclosed in “{“ and “}”, instead of “(“ and “)”. 271 | 272 | So, the following input: 273 | Desmos expressions: [ 274 | {"type":"expression","id”:”pow”,”latex”:”y = 2 ^ (x - 6)“,”hidden":false} 275 | ] 276 | 277 | is incorrect because it uses “(“ and “)” to enclose the exponent. This should get fixed to: 278 | Fixed Desmos expressions: [ 279 | {"type":"expression","id”:”pow”,”latex”:”y = 2 ^ {x - 6}“,”hidden":false} 280 | ] 281 | 282 | 283 | Check 5. For all logarithm operators (like \\log, \\ln, \\log_{2} etc.), Desmos needs the argument to be enclosed in “(“ and “)”, instead of “{“ and “}”. So \\log_{x}{y} should instead be written \\log_{x}(y). Note that the base still uses “{“ and “}”. 284 | 285 | So, the following input: 286 | [ 287 | {"type": "expression", "id": “log”, "latex": “y = \\log_{2}{x+4}”, "hidden": false} 288 | ] 289 | 290 | is incorrect because x+4 should be enclosed in “(“ and “)”. This should get fixed to: 291 | Fixed Desmos expressions: [ 292 | {"type": "expression", "id": “log”, "latex": “y = \\log_{2}(x+4)”, "hidden": false} 293 | ] 294 | 295 | 296 | Check 6. The type field in the expression, if present, should always be set to “expression” 297 | 298 | So, the following input: 299 | [ 300 | {"type": “inequality”, "id": "inequality1", "latex": "x \\ge 4”, "hidden": false} 301 | ] 302 | 303 | is incorrect because the type field has value “inequality”. This should be fixed to: 304 | Fixed Desmos expressions: [ 305 | {"type": “expression”, "id": "inequality1", "latex": "x \\ge 4”, "hidden": false} 306 | ] 307 | 308 | Remember: Start your response by thinking step-by-step and briefly explain your reasoning. End your response with Fixed Desmos expressions: , with each expression dict on a new line. If there are no mistakes in an expression, or you don't understand it, return the original expression as is in the corrected list. 309 | ''' 310 | 311 | 312 | DESMOS_REFINEMENT_PROMPT_STEP_2 = '''You are an agent who is an expert at using Desmos. 313 | 314 | I will give you a set of Desmos expressions to be graphed in the calculator using the Desmos setExpression() API. 315 | 316 | I would like you to check the latex for each expression, and fix mistakes related to inequalities, function notation, and parameters without sliders. 317 | 318 | Start your response by thinking step-by-step and briefly explain your reasoning. End your response with Fixed Desmos expressions: . If there are no mistakes, return the original expressions as is. 319 | 320 | Here are the things you should check, and fix: 321 | 322 | Check 1. A function of x should always be denoted by and assigned to y or f(x) or g(x) or h(x) or similar. Desmos calculator does not understand assignments to more complex notations like f^{-1}(x) or -f(-x) or y' etc. 323 | 324 | So, the following input: 325 | Desmos expressions: [ 326 | [ 327 | {"type": "expression", "id": "function", "latex": "f(x) = x^{3} - 4”, "hidden": false}, 328 | {"type": "expression", "id": "negative_function", "latex": "-f(-x) = - (-x^{3} - 4)”, "hidden": false} 329 | ] 330 | 331 | is incorrect because Desmos will not understand the -f(-x) notation on the left-hand side in the second expression. This should get fixed to: 332 | Fixed Desmos expressions: [ 333 | {"type": "expression", "id": "function", "latex": "f(x) = x^{3} - 4”, "hidden": false}, 334 | {"type": "expression", "id": "negative_function", "latex": “g(x) = - (-x^{3} - 4)”, "hidden": false} 335 | ] 336 | 337 | Similarly, the following input: 338 | [ 339 | {"type": "expression", "id": "function", "latex": "f(x) = 2x - 6”, "hidden": false}, 340 | {"type": "expression", "id": "inverse_function", "latex": "f^{-1}(x) = (x + 6)/2”, "hidden": false} 341 | ] 342 | 343 | is incorrect because Desmos will not understand the f^{-1}(x) notation in the second expression. This should get fixed to: 344 | Fixed Desmos expressions: [ 345 | {"type": "expression", "id": "function", "latex": "f(x) = 2x - 6”, "hidden": false}, 346 | {"type": "expression", "id": "inverse_function", "latex": “g(x) = (x + 6)/2”, "hidden": false} 347 | ] 348 | 349 | Similarly, the following input: 350 | [ 351 | {"type": "expression", "id": "function", "latex": "y' = 3x^2 - 4”, "hidden": false} 352 | ] 353 | 354 | is incorrect because Desmos will not understand the y' notation. This should get fixed to: 355 | Fixed Desmos expressions: [ 356 | {"type": "expression", "id": "function", "latex": "y = 3x^2 - 4”, "hidden": false} 357 | ] 358 | 359 | Check 2. For inequalities, Desmos always uses \\le and \\ge, instead of \\leq and \\geq. So every occurrence of \\leq should be changed to \\le. And every occurrence of \\geq should be changed to \\ge. 360 | 361 | So, the following input: 362 | [ 363 | {"type": "expression", "id": "inequality1", "latex": "x\\geq4”, "hidden": false}, 364 | {"type": "expression", "id": "inequality2", "latex": “y \\leq 2”, "hidden": false} 365 | ] 366 | 367 | is incorrect because Desmos does not use \\geq or \\leq. This should get fixed to: 368 | Fixed Desmos expressions: [ 369 | {"type": "expression", "id": "inequality1", "latex": "x \\ge 4”, "hidden": false}, 370 | {"type": "expression", "id": "inequality2", "latex": “y \\le 2”, "hidden": false} 371 | ] 372 | 373 | Check 3. If the expression uses any parameters, those parameters should have corresponding sliders. 374 | 375 | So, the following input: 376 | [ 377 | {"type": "expression", "id": "circle", "latex": "(x-h)^2 + (y-k)^2 = a^2”, "hidden": false} 378 | ] 379 | 380 | is incorrect because it uses the parameters h, k and a, but does not have sliders for them. This should get fixed to: 381 | Fixed Desmos expressions: [ 382 | {"type": "expression", "id": "circle", "latex": "(x-h)^2 + (y-k)^2 = a^2”, "hidden": false}, 383 | {"type":"expression","id":"slider_a","latex":"a=1", "sliderBounds":{"min":-10, "max":10, "step":0.1}}, 384 | {"type":"expression","id":"slider_h","latex":"h=0", "sliderBounds":{"min":-10, "max":10, "step":0.1}}, 385 | {"type":"expression","id":"slider_k","latex":"k=0", "sliderBounds":{"min":-10, "max":10, "step":0.1}} 386 | ] 387 | ''' 388 | -------------------------------------------------------------------------------- /src/routes.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from flask import render_template 5 | from flask import request 6 | from flask import Response 7 | from flask import send_from_directory 8 | from flask import stream_with_context 9 | 10 | 11 | def register_routes(app, math_viz_agent, base_dir): 12 | """Register routes for the app 13 | 14 | Args: 15 | app (Flask): Flask app 16 | math_viz_agent (MathVizAgent): MathVizAgent instance 17 | base_dir (str): Base directory of the app 18 | """ 19 | @app.route('/desmos/interpret', methods=['POST']) 20 | def handle_interpret(): 21 | print(request.json) 22 | input_text = request.json['text'] 23 | #sessionid=request.json['sessionid'] 24 | input_expressions = request.json["expressions"] 25 | use_validation = (os.environ.get('USE_EXPRESSION_VALIDATION') == "True") 26 | return Response( 27 | stream_with_context( 28 | math_viz_agent.process_user_request( 29 | input_text, 30 | input_expressions, 31 | use_validation 32 | ) 33 | ), 34 | mimetype='text/event-stream' 35 | ) 36 | 37 | @app.route('/desmos/') 38 | def serve_index(): 39 | logging.info("Starting app ...") 40 | desmos_api_key = os.environ.get('DESMOS_API_KEY') # Desmos API key will be send to the client 41 | return render_template('desmos_calc.html', desmos_api_key=desmos_api_key) 42 | 43 | @app.route('/desmos/static/') 44 | def get_assets(path): 45 | return send_from_directory(os.path.join(base_dir, "static"), path) 46 | -------------------------------------------------------------------------------- /src/static/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/collapse.png -------------------------------------------------------------------------------- /src/static/desmos.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'CircularXX'; 3 | src: url('https://assets.website-files.com/627028e6193b2d840a066eab/627028e6193b2d9dd2066edf_CircularXXWeb-Book.woff2') format('woff2'); 4 | font-weight: 400; 5 | font-style: normal; 6 | font-display: auto; 7 | } 8 | @font-face { 9 | font-family: 'CircularXXLight'; 10 | src: url('https://assets.website-files.com/627028e6193b2d840a066eab/627028e6193b2d710b066eda_CircularXXWeb-Light.woff2') format('woff2'); 11 | font-weight: 300; 12 | font-style: normal; 13 | font-display: auto; 14 | } 15 | 16 | body, html { 17 | height: 100%; 18 | width: 100%; 19 | background-size: cover; 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | overflow: clip; 24 | } 25 | 26 | .container-overall { 27 | width: 100vw; 28 | height: 100vh; 29 | bottom: 0vh; 30 | display: flex; 31 | flex-direction: column; 32 | align-content: center; 33 | align-items: center; 34 | justify-content: flex-start; /* Add this line */ 35 | } 36 | 37 | .desmos-container { 38 | width: 100vw; 39 | height: 80%; 40 | margin-top: 3%; 41 | display: flex; 42 | flex-direction: row; align-content: center; 43 | align-items: center; 44 | justify-content: left; /* Add this line */ 45 | margin-right:auto; 46 | margin-left: 5%; 47 | } 48 | 49 | .calculator{ 50 | width:60vw; 51 | height:80vh; 52 | max-width: 1600px; 53 | min-width: 480px; 54 | } 55 | 56 | .overlay { 57 | position: absolute; 58 | top: auto; 59 | transition: right 0.3s ease-in-out; 60 | width: 30vw; 61 | max-width: 30vw; 62 | height: 70%; 63 | background-color: rgba(255,255,255,0.8); 64 | padding: 2vh; 65 | font-size: 1vw; 66 | color: white; 67 | font-family: 'CircularXXLight'; 68 | pointer-events: all; 69 | max-width: 100%; 70 | white-space: nowrap; 71 | overflow-y: auto; 72 | text-overflow: ellipsis; 73 | border-radius: 10px; /* Add border-radius to the message content */ 74 | overflow-x: hidden; 75 | overflow-y: auto; 76 | } 77 | 78 | .overlay.show { 79 | right: 0; 80 | } 81 | .overlay.hide { 82 | right: -33vw; 83 | } 84 | .hidden{ 85 | opacity:0; 86 | } 87 | 88 | 89 | .simplefont { 90 | font-family: 'CircularXXLight'; 91 | font-size: 1vw; 92 | color: white; 93 | padding: 1vh; 94 | font-weight: normal; 95 | } 96 | 97 | .overlayicon{ 98 | z-index: 100; 99 | position: absolute; 100 | top: 2.0vh; 101 | right: 1.5vh; 102 | width: 2vw; 103 | height: 2vw; 104 | min-height: 30px; 105 | min-width: 30px; 106 | background-color: rgba(30,30,30,0.6); 107 | background-color: transparent; 108 | cursor: pointer; 109 | border-radius: 50%; 110 | box-shadow: gray 0px 0px 5px; 111 | opacity: 0.9; 112 | transition: transform 0.1s ease-in-out; 113 | } 114 | 115 | .overlayicon:hover{ 116 | opacity: 1; 117 | transform: scale(1.05); 118 | box-shadow: purple 0px 0px 5px; 119 | } 120 | .overlayicon:active{ 121 | transform: scale(0.95); 122 | } 123 | 124 | 125 | .collapsed{ 126 | background-image: url('expand.png'); 127 | background-size: cover; 128 | background-repeat: no-repeat; 129 | } 130 | 131 | .expanded{ 132 | background-image: url('collapse.png'); 133 | background-size: cover; 134 | background-repeat: no-repeat; 135 | } 136 | 137 | .user-input { 138 | width: 100vw; 139 | position: absolute; 140 | height: 8vh; 141 | margin-bottom: 1vh; 142 | bottom: 1vh; 143 | display: flex; 144 | flex-direction: row; 145 | background-color: transparent; 146 | align-items: center; 147 | margin-left: 1vw; 148 | margin-right: 1vw; 149 | justify-content: flex-start; 150 | } 151 | 152 | #user-message { 153 | width: 50vw; 154 | padding-left: 5%; 155 | padding-right: 5%; 156 | margin-left: 20vw; 157 | margin-right: 5vw; 158 | display: flex; 159 | align-items: center; 160 | border-radius: 16px; 161 | height: 90%; 162 | font-size: 2.5vmin; 163 | font-family: 'circularXX'; 164 | font-style: normal; 165 | font-weight: 500; 166 | letter-spacing: 0.04em; 167 | color: #000000; 168 | overflow-y: auto; 169 | white-space: pre-wrap; 170 | overflow-wrap: break-word; 171 | text-align: left; 172 | outline: none; 173 | resize: none; 174 | border: '1px solid lightgray' !important; 175 | } 176 | 177 | .highlight { 178 | box-shadow: 8px 8px 8px rgba(255, 0, 128, 0.12), inset 1px 1px 1px rgba(128, 0, 128, 0.34), inset -1px -1px 2px rgba(128, 25, 128, 0.4); 179 | border: 1px solid purple; 180 | } 181 | .default { 182 | box-shadow: 8px 8px 16px rgba(0, 0, 0, 0.12), inset 1px 1px 2px rgba(255, 255, 255, 0.64), inset -1px -1px 2px rgba(255, 255, 255, 0.4); 183 | } 184 | 185 | .chattext{ 186 | margin-right: auto; 187 | margin-left: auto; 188 | font-family: 'CircularXX'; 189 | padding: 5%; 190 | min-height: 30px; 191 | background: linear-gradient(180deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.20) 100%); 192 | box-shadow: 8px 8px 16px rgba(0, 0, 0, 0.12), inset 1px 1px 2px rgba(255, 255, 255, 0.64), inset -1px -1px 2px rgba(255, 255, 255, 0.4); 193 | border-radius: 20px; 194 | color: black; 195 | border: 1px solid orange; 196 | } 197 | .chat-right-align{ 198 | text-align: right; 199 | justify-content: flex-start; 200 | } 201 | .chat-left-align{ 202 | text-align: left; 203 | justify-content: flex-end; 204 | } 205 | 206 | .chat{ 207 | width: 60%; 208 | color: black; 209 | text-wrap:wrap ; 210 | font-family: 'CircularXX'; 211 | font-size: 14px; 212 | margin-left: 1%; 213 | margin-right: 1%; 214 | word-wrap: break-word; 215 | } 216 | 217 | #chat-box { 218 | overflow-y: auto; 219 | scrollbar-width: thin; 220 | height: 90%; 221 | width:100%; 222 | display: flex; 223 | flex-direction: column; 224 | gap:1%; 225 | padding-bottom:1%; 226 | border-style: solid; 227 | border-width: 1px; 228 | border-color: lightgray; 229 | box-shadow: 0px 0px 5px 0px lightgray; 230 | } 231 | 232 | .agent1{ 233 | background-image: url('wolframicon.png'); 234 | background-size: cover; 235 | background-repeat: no-repeat; 236 | border-radius: 50%; 237 | box-shadow: 0px 0px 5px 0px lightgray; 238 | } 239 | 240 | .agent2{ 241 | background-image: url('mathvizicon.png'); 242 | background-size: cover; 243 | background-repeat: no-repeat; 244 | border-radius: 50%; 245 | box-shadow: 0px 0px 5px 0px lightgray; 246 | } 247 | 248 | .agent3{ 249 | background-image: url('othericon.png'); 250 | background-size: cover; 251 | background-repeat: no-repeat; 252 | border-radius: 50%; 253 | box-shadow: 0px 0px 5px 0px lightgray; 254 | } 255 | .user{ 256 | background-image: url('usericon.png'); 257 | background-size: cover; 258 | background-repeat: no-repeat; 259 | border-radius: 50%; 260 | } 261 | 262 | 263 | .icon{ 264 | width: 45px; 265 | border-radius: 50%; 266 | height: 45px; 267 | 268 | } 269 | 270 | .chat-input{ 271 | display: flex; 272 | flex-direction: row; 273 | gap:2%; 274 | justify-content: center; 275 | align-items: center; 276 | width: 100%; 277 | margin-top:2vh; 278 | } 279 | 280 | .clear-chat{ 281 | background-color: lightgray; 282 | border-radius: 10px; 283 | padding: 1vh; 284 | font-size: 1.5vmin; 285 | font-family: 'CircularXX'; 286 | font-weight: 500; 287 | cursor: pointer; 288 | opacity: 0.9; 289 | transition: transform 0.05s ease-in-out; 290 | } 291 | .clear-chat:hover{ 292 | border-style: solid; 293 | border-color: black; 294 | border-width: 2px; 295 | transform: scale(1.03); 296 | } 297 | .clear-chat:active{ 298 | transform: scale(0.97); 299 | } 300 | 301 | -------------------------------------------------------------------------------- /src/static/desmos.js: -------------------------------------------------------------------------------- 1 | const elt = document.getElementById('calculator'); 2 | const calculator = Desmos.GraphingCalculator(elt); 3 | const serviceURL = window.origin; 4 | console.log("Service URL : "+serviceURL); 5 | 6 | function updateExpressions(expressions) { 7 | try { 8 | for (let i = 0; i < expressions.length; i++) { 9 | if (expressions[i]["action"] == "setExpression") { 10 | var exp = expressions[i]["expression"] 11 | calculator.setExpression(exp) 12 | } 13 | else if (expressions[i]["action"] == "removeExpression") { 14 | var exp = expressions[i]["expression"] 15 | calculator.removeExpression(exp); 16 | } 17 | } 18 | } 19 | catch (exp) { 20 | console.error(exp); 21 | } 22 | } 23 | 24 | function getExpressions() { 25 | const inputExpressions = calculator.getExpressions().map(expr=>JSON.stringify(expr)); 26 | return inputExpressions 27 | } 28 | 29 | function interpretUtterance(sessionid, message, expressions) { 30 | fetch(serviceURL+"/desmos/interpret", { 31 | method: 'POST', 32 | headers: { 33 | 'Content-Type': 'application/json' 34 | }, 35 | body: JSON.stringify({ 36 | sessionid: sessionid, 37 | text: message, 38 | expressions: expressions, 39 | }) 40 | }) 41 | .then(response => { 42 | console.log(response); 43 | const reader = response.body.getReader(); 44 | const decoder = new TextDecoder('utf-8'); 45 | let buffer = ''; 46 | reader.read().then(function processText({ done, value }) { 47 | if (done) { 48 | console.log('Stream complete'); 49 | console.log(value); 50 | return; 51 | } 52 | buffer += decoder.decode(value); 53 | const parts = buffer.split('\n'); 54 | buffer = parts.pop(); 55 | for (const part of parts) { 56 | try { 57 | console.log("Parts : "+part); 58 | console.log(part); 59 | let response = JSON.parse(part); 60 | 61 | if ("expressions" in response) { 62 | let expression = response["expressions"]; 63 | updateExpressions(expression); 64 | } 65 | else if ("agent" in response) { 66 | updateExplanationPanel(response["agent"], response["message"]); 67 | } 68 | } 69 | catch (error) { 70 | console.error(error); 71 | 72 | } 73 | } 74 | return reader.read().then(processText); 75 | }); 76 | }) 77 | .catch(error => { 78 | console.error(error); 79 | 80 | }); 81 | } 82 | 83 | function clearBackend(sessionid){ 84 | console.log("Clearing backend"); 85 | fetch(serviceURL+"/desmos/clear", { 86 | method: 'POST', 87 | headers: { 88 | 'Content-Type': 'application/json' 89 | }, 90 | body: JSON.stringify({ 91 | sessionid: sessionid 92 | }) 93 | }) 94 | .then(response => { 95 | console.log(response); 96 | }) 97 | .catch(error => { 98 | console.error(error); 99 | }); 100 | } 101 | 102 | function clearDesmos() { 103 | calculator.setBlank(); 104 | } 105 | -------------------------------------------------------------------------------- /src/static/desmosUI.js: -------------------------------------------------------------------------------- 1 | 2 | const origin = window.origin; 3 | 4 | let speechRecognition; 5 | let speechInputOngoing = false; 6 | let messageTosend = ""; 7 | let showingExplanation = true; 8 | let userMessage; 9 | 10 | //Preload in and out chimes to reduce network latency during runtime 11 | let inChime = new Audio('static/inchime.mp3'); 12 | inChime.load(); 13 | 14 | let outChime = new Audio('static/outchime.mp3'); 15 | outChime.load(); 16 | 17 | window.addEventListener("DOMContentLoaded", (event) => { 18 | userMessage = document.getElementById('user-message'); 19 | userMessage.addEventListener('focus', () => { 20 | if (userMessage.textContent.trim() === userMessage.getAttribute('placeholder')) { 21 | userMessage.innerHTML = ' '; 22 | userMessage.style.border = '1px solid purple'; 23 | userMessage.style.color = 'rgba(0, 0, 0, 1)'; 24 | } 25 | }); 26 | userMessage.addEventListener('blur', () => { 27 | if (userMessage.textContent.trim() === '' || userMessage.innerHTML === ' ') { 28 | let placeholder = userMessage.getAttribute('placeholder'); 29 | userMessage.textContent = placeholder; 30 | userMessage.style.color = 'rgba(0, 0, 0, 0.6)'; 31 | userMessage.style.border = '1px solid gray'; 32 | console.log("Input field lost focus, Finished setting placeholder"); 33 | } 34 | }); 35 | 36 | if (userMessage.textContent.trim() === '') { 37 | userMessage.textContent = userMessage.getAttribute('placeholder'); 38 | userMessage.style.color = 'rgba(0, 0, 0, 0.6)'; 39 | userMessage.style.border = '1px solid gray'; 40 | } 41 | userMessage.addEventListener('keydown', (event) => { 42 | if (event.key === 'Enter') { 43 | event.preventDefault(); // Prevent the default behavior (newline) 44 | const messageTosend = userMessage.innerText.trim(); 45 | if (messageTosend !== '' && messageTosend !== userMessage.getAttribute('placeholder')) { 46 | userMessage.textContent=''; 47 | userMessage.innerText=''; 48 | userMessage.blur(); 49 | userMessage.dispatchEvent(new FocusEvent('blur')); 50 | let id = sendUserMessage(messageTosend); 51 | } 52 | } 53 | }); 54 | let overlay_icon = document.getElementById('overlay-icon'); 55 | showExplanationPanel(); 56 | 57 | overlay_icon.addEventListener('click', () => { 58 | if (showingExplanation) { 59 | hideExplanationPanel(); 60 | showingExplanation=false; 61 | } 62 | else { 63 | showExplanationPanel(); 64 | showingExplanation=true; 65 | } 66 | }); 67 | 68 | let clear_button=document.getElementById('clear-chat'); 69 | clear_button.addEventListener('click', ()=>{ 70 | clearMessages(); 71 | clearDesmos(); 72 | }); 73 | if (!('webkitSpeechRecognition' in window)) { 74 | alert("Speech API is not supproted. Try on chromium based browsers (e.g. Google chrome) "); 75 | } 76 | else { 77 | speechRecognition = new webkitSpeechRecognition(); 78 | console.log("Speech API initialised"); 79 | speechRecognition.continuous = true; 80 | speechRecognition.interimResults = true; 81 | speechRecognition.lang = "en-US"; 82 | 83 | speechRecognition.onstart = function () { 84 | console.log("Speech recognition started"); 85 | speechInputOngoing=true; 86 | } 87 | speechRecognition.onend = function () { 88 | console.log("Speech recognition ended"); 89 | speechInputOngoing = false; 90 | } 91 | } 92 | 93 | window.addEventListener('keydown', (event) => { 94 | var final_transcript = ""; 95 | if (userMessage === document.activeElement) { 96 | return; 97 | } 98 | 99 | if (event.key == 'M' || event.key == 'm') { 100 | 101 | if (speechInputOngoing == false) { 102 | console.log("M Key down, activating speech recognition"); 103 | if (!speechRecognition.listening) { 104 | speechRecognition.start(); 105 | } 106 | try { 107 | inChime.play() 108 | } catch (error) { 109 | } 110 | 111 | userMessage.classList.remove('default'); 112 | userMessage.classList.add('highlight'); 113 | messageTosend = ""; 114 | speechRecognition.onresult = function (event) { 115 | let interim_transcript = ''; 116 | for (let i = event.resultIndex; i < event.results.length; ++i) { 117 | if (event.results[i].isFinal) { 118 | final_transcript += event.results[i][0].transcript; 119 | const elem = document.getElementById("user-message"); 120 | elem.innerHTML = final_transcript; 121 | messageTosend = final_transcript; 122 | 123 | } else { 124 | interim_transcript += event.results[i][0].transcript; 125 | const elem = document.getElementById("user-message"); 126 | elem.innerHTML = final_transcript+ " "+ interim_transcript; 127 | console.log("Interim : " + interim_transcript); 128 | } 129 | } 130 | }; 131 | } 132 | } 133 | 134 | if (event.key === "Escape") { 135 | if (showingExplanation) { 136 | hideExplanationPanel(); 137 | showingExplanation=false; 138 | } 139 | else { 140 | showExplanationPanel(); 141 | showingExplanation=true; 142 | } 143 | } 144 | }); 145 | }); 146 | 147 | 148 | window.addEventListener('keyup', (event) => { 149 | if (event.key == 'M' || event.key == 'm') { 150 | if (speechInputOngoing) { 151 | try { 152 | outChime.play() 153 | } catch (error) { 154 | 155 | } 156 | userMessage.classList.remove('highlight'); 157 | userMessage.classList.add('default'); 158 | speechRecognition.stop(); 159 | 160 | setTimeout(function () { 161 | userMessage.innerHTML=""; 162 | userMessage.blur(); 163 | userMessage.dispatchEvent(new FocusEvent('blur')); 164 | if (messageTosend.trim()!="") { 165 | let id = sendUserMessage(messageTosend); 166 | console.log("Sending to server from M key up " + messageTosend); 167 | messageTosend = ""; 168 | } 169 | 170 | }, 100); 171 | } 172 | } 173 | 174 | }); 175 | 176 | //useful if we want to support multiple simultaneous sessions 177 | let sessionID = generateID(); 178 | 179 | function generateID() { 180 | return Math.random().toString(36).substr(2, 5); 181 | } 182 | 183 | function sendUserMessage(messageTosend) { 184 | showExplanationPanel(); 185 | showingExplanation=true; 186 | addMessage(messageTosend, "user"); 187 | expressions = getExpressions(); 188 | interpretUtterance(sessionID, messageTosend, expressions); 189 | } 190 | 191 | 192 | function showExplanationPanel(){ 193 | if(!showingExplanation){ 194 | let panel=document.getElementById('chat-debug-overlay'); 195 | panel.classList.add('show'); 196 | panel.classList.remove('hide'); 197 | 198 | let overlayicon=document.getElementById('overlay-icon'); 199 | overlayicon.classList.add('expanded'); 200 | overlayicon.classList.remove('collapsed'); 201 | } 202 | } 203 | 204 | function updateExplanationPanel(agent, content){ 205 | addMessage(content, agent.toLowerCase()); 206 | } 207 | 208 | function hideExplanationPanel(){ 209 | if(showingExplanation){ 210 | let panel=document.getElementById('chat-debug-overlay'); 211 | panel.classList.add('hide'); 212 | panel.classList.remove('show'); 213 | let overlayicon=document.getElementById('overlay-icon'); 214 | overlayicon.classList.add('collapsed'); 215 | overlayicon.classList.remove('expanded'); 216 | } 217 | } 218 | 219 | 220 | function addMessage(message, sender) { 221 | //console.log(`Adding ${sender} message: ${message}`); 222 | let newDiv = document.createElement("div"); 223 | newDiv.classList.add("chat-input"); 224 | 225 | let iconDiv1 = document.createElement("div"); 226 | iconDiv1.classList.add("icon"); 227 | 228 | let chatDiv = document.createElement("div"); 229 | chatDiv.classList.add("chat"); 230 | 231 | let iconDiv2 = document.createElement("div"); 232 | iconDiv2.classList.add("icon"); 233 | 234 | newDiv.appendChild(iconDiv1); 235 | newDiv.appendChild(chatDiv); 236 | newDiv.appendChild(iconDiv2); 237 | let parsedMessage = message; 238 | 239 | // Customize based on the sender 240 | if (sender === "user") { 241 | iconDiv2.classList.add("user"); 242 | chatDiv.classList.add("chattext"); 243 | chatDiv.classList.add("chat-right-align"); 244 | chatDiv.textContent = parsedMessage; 245 | } 246 | else if (sender === "wolfram") { 247 | iconDiv1.classList.add("agent1"); 248 | chatDiv.classList.add("chattext"); 249 | chatDiv.classList.add("chat-left-align"); 250 | chatDiv.textContent = parsedMessage; 251 | } 252 | else if(sender === "math viz"){ 253 | iconDiv1.classList.add("agent2"); 254 | chatDiv.classList.add("chattext"); 255 | chatDiv.classList.add("chat-left-align"); 256 | chatDiv.textContent = parsedMessage; 257 | } 258 | else{ 259 | iconDiv1.classList.add("agent3"); 260 | chatDiv.classList.add("chattext"); 261 | chatDiv.classList.add("chat-left-align"); 262 | chatDiv.textContent = parsedMessage; 263 | } 264 | 265 | let chatBox = document.getElementById('chat-box'); 266 | chatBox.appendChild(newDiv); 267 | // Check if chatBox is overflowing 268 | if (chatBox.scrollHeight > chatBox.clientHeight) { 269 | // Scroll to the bottom 270 | chatBox.scrollTop = chatBox.scrollHeight; 271 | } 272 | } 273 | 274 | 275 | function clearMessages(){ 276 | let chatBox = document.getElementById('chat-box'); 277 | chatBox.innerHTML=""; 278 | } -------------------------------------------------------------------------------- /src/static/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/expand.png -------------------------------------------------------------------------------- /src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/favicon.ico -------------------------------------------------------------------------------- /src/static/inchime.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/inchime.mp3 -------------------------------------------------------------------------------- /src/static/mathvizicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/mathvizicon.png -------------------------------------------------------------------------------- /src/static/othericon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/othericon.png -------------------------------------------------------------------------------- /src/static/outchime.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/outchime.mp3 -------------------------------------------------------------------------------- /src/static/usericon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/usericon.png -------------------------------------------------------------------------------- /src/static/wolframicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmergenceAI/MathViz-E/fe6ac7ff1f8a7c119421197e4316372017861e99/src/static/wolframicon.png -------------------------------------------------------------------------------- /src/utils.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import os 4 | 5 | import openai 6 | 7 | 8 | def get_gpt_response( 9 | messages, 10 | temperature=0, 11 | stream=False, 12 | ): 13 | logging.info("Getting gpt response ...") 14 | client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 15 | response = client.chat.completions.create( 16 | model="gpt-4-turbo-preview", 17 | messages=messages, 18 | temperature=temperature, 19 | stream=stream 20 | ) 21 | logging.info(f"GPT response: {response}") 22 | try: 23 | output = response.choices[0].message.content.strip() 24 | except Exception as e: 25 | logging.error(f"Error getting gpt response: {e}") 26 | output = "" 27 | return output 28 | -------------------------------------------------------------------------------- /test/multi_turn/graph_circles.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,"Graph a unit circle with a center at two, five",(y-5)^2 + (x-2)^2 = 1 3 | query 1,Translate the circle up one unit and to the right eight units,(y-6)^2 + (x-10)^2 = 1 4 | query 2,"Plot a circle with a radius of one-half at negative seven, negative three",(x+7)^2 + (y+3)^2 = 1/4 5 | query 2,Dilate the circle about its center by a factor of two,(x+7)^2 + (y+3)^2 = 1 6 | query 2,Translate the circle seven units to the left,x^2 + (y+3)^2 = 1 7 | query 3 ,Graph a circle with a radius of twelve,x^2 + y^2 = 144 8 | query 3 ,Decrease radius to four,x^2 + y^2 = 16 9 | query 4,"Circle at six, five",(x-6)^2 + (y-5)^2 = 1 10 | query 4,"Shift center to one, two ",(x-1)^2 + (y-2)^2 = 1 11 | query 5,"Draw a circle at five, two with a radius of three",(x-5)^2+(y-2)^2 = 9 12 | query 5,Draw a concentric circle with a radius of five,"(x-5)^2+(y-2)^2 = 9, (x-5)^2+(y-2)^2 = 25" 13 | query 5,Increase the smaller circle's radius to four,"(x-5)^2+(y-2)^2 = 16, (x-5)^2+(y-2)^2 = 25" 14 | query 6,"Graph two circles with radius four, one at the origin and the other at seven, seven ","x^2 + y^2 = 16, (x-7)^2 + (y-7)^2 = 16" 15 | query 6,Increase the radius of the circle on the right to ten,"x^2 + y^2 = 16, (x-7)^2 + (y-7)^2 = 100" 16 | query 6,"Shift both circles to three, negative nine ","(x-3)^2 + (y+9)^2 = 16, (x-3)^2 + (y+9)^2 = 100" 17 | query 7 ,"Graph a circle centered at negative three, four with a radius of five.",(x+3)^2 + (y-4)^2 = 25 18 | query 7 ,"Shift the circle's center to one, one. ",(x-1)^2 + (y-1)^2 = 25 19 | query 8 ,"Graph a circle with radius one half at two, two. ",(x-2)^2 + (y-2)^2 = .25 20 | query 8 ,Reflect the circle over the y-axis. ,(x+2)^2 + (y-2)^2 = .25 21 | query 9 ,"Draw two circles at the origin, with a radius of two and five","x^2 + y^2 = 4, x^2 + y^2 = 25" 22 | query 9 ,"Shift them to eight, three","(x-8)^2 + (y-3)^2 = 4, (x-8)^2 + (y-3)^2 = 25" 23 | query 10,Graph a circle that goes through the points negative three four and negative three ten. ,(x+3)^2 + (y-7)^2=9 24 | query 10,"Shift the center to two, two. ",(x-2)^2 + (y-2)^2 = 9 -------------------------------------------------------------------------------- /test/multi_turn/graph_lines.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,Graph a line with a slope of four and y-intercept of three. ,y = 4x + 3 3 | query 1,Change the slope to two. ,y = 2x + 3 4 | query 2 ,"Plot a line that goes through one, three and four, eight. ",y = 5x/3 + 4/3 5 | query 2 ,Plot a parallel line through the origin. ,"y = 5x/3, y = 5x/3 + 4/3" 6 | query 3,Graph y equals two x plus nine,y = 2x+9 7 | query 3,Graph a perpendicular line with the same y-intercept ,"y = -x/2 + 9, y = 2x+9" 8 | query 3,Now graph a parallel line with a y-intercept of two,"y = -x/2 + 9, y = 2x+9, y =-x/2 + 2" 9 | query 4,"Graph a line through one, zero and three, eight",y = 4x-4 10 | query 4,Now change the y-intercept to two ,y = 4x +2 11 | query 5,Plot y equals nine x plus four,y = 9x + 4 12 | query 5,Plot its perpendicular line with a y-intercept at four,"y = -x/9 + 4, y = 9x + 4" -------------------------------------------------------------------------------- /test/multi_turn/graph_polynomials.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,Graph f of x equals five x cubed plus three x squared minus five ,f(x) = 5x^3 + 3x^2 - 5 3 | query 1,Find the zeroes ,"f(x) = 5x^3 + 3x^2 - 5, (.834, 0)" 4 | query 2 ,Plot f of x equals eight x cubed minus three,f(x) = 8x^3 - 3 5 | query 2 ,Find the x-intercepts ,"f(x) = 8x^3 - 3, (.721, 0)" 6 | query 3 ,"Plot the polynomial with roots negative three, four, and nine",f(x) = (x+3)(x-4)(x-9) 7 | query 3 ,Find the y-intercept and plot it ,"f(x) = (x+3)(x-4)(x-9), (0, 108)" 8 | query 4,Graph f of x equals three x squared minus ten ,f(x) = 3x^2 - 10 9 | query 4,What are the zeros? ,"f(x) = 3x^2 - 10, (1.83, 0), (-1.83, 0)" 10 | query 5,Find the y-intercept of y equals ten x cubed minus three x squared plus four,"y = 10x^3 - 3x^2 + 4 , (0, 4)" 11 | query 5,Find the zeroes ,"y = 10x^3 - 3x^2 + 4 , (0, 4), (-.65, 0)" -------------------------------------------------------------------------------- /test/multi_turn/inverse_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth, 2 | query 1,Graph y equals x to the power of one third plus four. ,y = x^(1/3) + 4,y = x^(1/3) + 4 3 | query 1,Graph its inverse ,"y = (x-4)^3, y = x^(1/3) + 4","y = (x-4)^3, y = x^(1/3) + 4" 4 | query 2 ,Plot the natural log of four x ,y = ln(4x),y = ln(4x) 5 | query 2 ,Plot the inverse ,"y = e^(x)/4, y = ln(4x)","y = e^(x)/4, y = ln(4x)" 6 | query 3 ,f of x equals the square root of the quantity seven x minus three ,y = sqrt(7x-3),y = sqrt(7x-3) 7 | query 3 ,Graph the inverse of f of x ,"y = (x^2+3)/7, y = sqrt(7x-3)","f^{-1}(x) = \\frac{1}{7} * (x^2 + 3), y = sqrt(7x-3)" 8 | query 4,Plot f of x equals e to the power of x minus six ,y = e^x - 6,y = e^x - 6 9 | query 4,Plot the inverse ,"y = e^x - 6, y = ln(x+6)","f(x) = e^x - 6, f^(-1)x = ln(x+6)" 10 | query 5,Graph sin of x plus nine,y = sin(x) + 9,y = sin(x) + 9 11 | query 5,Graph the inverse,"y = sin^(-1)(x-9), y = sin(x) + 9","y = sin^(-1)(x-9), y = sin(x) + 9" -------------------------------------------------------------------------------- /test/multi_turn/linear_and_nonlinear_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,Graph y equals five over the quantity x minus 6. ,y = 5/(x-6) 3 | query 1,Graph the asymptotes ,"y = 5/(x-6), x = 6, y = 0" 4 | query 2,"Graph one over the quantity x plus three, show the x and y intercepts. ","y = 1/(x+3), (0, 1/3)" 5 | query 2,Plot the asymptotes. ,"y = 1/(x+3), (0, 1/3), x= -3, y = 0" 6 | query 3 ,Plot y equals ln of the quantity eight x minus two,y = ln (8x-2) 7 | query 3 ,Plot any asymptotes ,"y = ln (8x-2), x = 1/4" 8 | query 4,What are the local extrema of y equals the quantity x minus two times the quantity x minus seven?,"y = (x-2)(x-7), (9/2, -25/4)" 9 | query 4,What is the y intercept?,"y = (x-2)(x-7), (9/2, -25/4), (0, 14)" 10 | query 5,Graph y equals the natural log of the quantity four x minus ten ,y = ln(4x-10) 11 | query 5,Find the asymptotes ,"y = ln(4x-10), x = 5/2" -------------------------------------------------------------------------------- /test/multi_turn/linear_quadratic_systems.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,Graph y equals x. ,y = x 3 | query 1,Graph y equals x^2 - 3x and plot the intersection. ,"y = x^2 - 3x, (0, 0), (4, 4)" 4 | query 2 ,Graph y = -2x^2 - 12x - 13,y = -2x^2 - 12x - 13 5 | query 2 ,Graph y = -2x - 5 and find the intersection ,"y = -2x - 5, y = -2x^2 - 12x - 13, (-4, 3), (-1, 3)" 6 | query 3 ,Plot y equals x - 2,y = x - 2 7 | query 3 ,Plot the solution to the system with equation two as y equals x squared minus x minus five,"y = x - 2, y = x^2 - x - 5, (-1 , -3), (3, 1)" 8 | query 4,Graph y equals negative three x over five plus three,y = -3x/5 + 3 9 | query 4,Graph y equals the quantity x minus five times the quantity x minus three over five and show the intersection,"y = -3x/5 + 3, y = (x-5)(x-3/5), (0, 3), (5, 0)" 10 | query 5,Plot x squared minus two x minus fifteen ,y = x^2 - 2x - 15 11 | query 5,Also plot three x minus fifteen and plot the intersection,"y = x^2 - 2x - 15, y = 3x - 15, (0, -15), (5, 0)" -------------------------------------------------------------------------------- /test/multi_turn/transformations_of_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | query 1,Graph y equals x squared ,y = x^2 3 | query 1,Shift the parabola to the left by four ,y = (x+4)^2 4 | query 2 ,f of x equals the quantity x plus three cubed minus nine ,f(x) = (x+3)^3 - 9 5 | query 2 ,Graph f of negative x,h(x) = (-x+3)^3 - 9 6 | query 3,Graph f of x equals log x plus seven ,f(x) = log(x) + 7 7 | query 3,Graph f of negative x,h(x) = log(-x) + 7 8 | query 4,Graph a parabola at the origin ,y = x^2 9 | query 4,Shift the parabola up by two ,y = x^2 + 2 10 | query 4,Move the parabola to the right by three,y = (x-3)^2 + 2 11 | query 5,Graph y equals the quantity x minus eight squared plus five,y = (x-8)^2 + 5 12 | query 5,Stretch the parabola vertically by a factor of four,y = 4(x-8)^2 + 5 13 | query 6,f of x equals five x to the fourth minus nine x cubed minus seven x squared ,f(x) = 5x^4 - 9x^3 - 7x^2 14 | query 6,Graph f of two x ,h(x) = 5(2x)^4 - 9(2x)^3 - 7(2x)^2 15 | query 7 ,Graph y equals x cubed ,y = x^3 16 | query 7 ,Reflect over the y axis ,y = -x^3 17 | query 8 ,Graph f of x equals x cubed ,y = x^3 18 | query 8 ,Graph the absolute value of f of x ,y = |x^3| 19 | query 9 ,f of x equals e to the quantity x plus four,f(x) = e^(x+4) 20 | query 9 ,Reflect over the x axis ,f(x) = -e^(x+4) 21 | query 10 ,Graph the absolute value of the quantity x minus four ,y = |x-4| 22 | query 10 ,Reflect over the x axis ,y = - |x-4| -------------------------------------------------------------------------------- /test/single_turn/graph_circle_tangents.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Consider a circle centered at two, seven with radius 5. Find a tangent line that passes through four, negative three","y = -1.16x+1.65, a = 2\tan^{-1}(4+3\sqrt{3})" 3 | 1,"Consider a circle centered at two, seven with radius 5. Find a tangent line that passes through negative two, zero. ","y = 0.402x+0.81, a = 2\tan^{-1}(4+3\sqrt{3})" 4 | 2,"Graph the circle with center at two, two and a radius of three. Also, draw a tangent line passing through the point negative two, two.","y = -1.133x-0.267, a=2(\pi-\tan^{-1}(\sqrt{7}))" 5 | 3,"Graph the circle with center at one, negative one and radius six. Also, graph a tangent line passing through the point six, zero.","y = -0.46x+2.763, a = 2\tan^{-1}(1/8(1+\sqrt{17}))" 6 | 4,"Graph the circle with center at negative three, four and radius two. Also, draw a tangent line passing through the point negative two, eight.","y = 1.07x+10.14, a=2\tan^{-1}(1/3(4+\sqrt{13}))" 7 | 5,"Graph the circle with center at the origin and radius 2. Also, plot a tangent line passing through the point negative four, four.","y = -2.215x - 4.86, a=2(\pi-\tan^{-1}(2+\sqrt{7}))" 8 | 6,"Graph the circle with center at two negative three and radius five. Also, graph a tangent line that passes through the point fifteen five.","y = 0.22x + 1.67, a=2\tan^{-1}(1/9(4+2\sqrt{13}))" 9 | 7,"Graph the circle with center negative one, one and radius three, and plot a tangent line that passes through the point negative five, ten.","y = -9.16x - 35.81, a=2(\pi-\tan^{-1}(9+2\sqrt{22}))" 10 | 8,"Graph a circle with center at four, negative two and radius three. Draw a tangent line that goes through the point nine, five.","y = 0.675x -1.08, a=2\tan^{-1}(1/8(7+\sqrt{65}))" 11 | 9,"Graph the circle with center at one, two and radius three. Also, plot a tangent line passing through the point five, three.","y = -0.64x + 6.2, a=2\tan^{-1}(1/7(1+2\sqrt{2}))" 12 | 10,"Graph a circle tangent to the y-axis with a center at -2, 4.",(x+2)^2+(y-4)^2=4 13 | 11,"Graph a circle with a radius of five that is tangent to the lines y equals four over three x minus fourteen over three, y equals negative four over three x minus two, and the x axis. ",(x-1)^2+(y-5)^2=25 14 | 12,"Graph a circle tangent to the x-axis with a center of negative six, negative one. ",(x+6)^2+(y+1)^2=1 -------------------------------------------------------------------------------- /test/single_turn/graph_circles.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph a unit circle with center at two, five.",(x-2)^2 + (y-5)^2 =1 3 | 1,Plot a circle of radius two at the origin.,x^2 + y^2 = 4 4 | 2,"Graph a circle with a radius of five-sixths and a center at three point six, seven point eight.",(x-3.6)^2 + (y-7.8)^2 = 25/36 5 | 3,"Graph a circle with a radius of four units and a center at one, eight.",(x-1)^2+(y-8)^2 = 16 6 | 4,Plot a circle of radius ten.,x^2 + y^2 = 100 7 | 5,"Graph a circle at negative five, nine.",(x+5)^2 + (y-9)^2 = 1 8 | 6,"Plot a circle with a radius of one-half at negative seven, negative three.",(x+7)^2 + (y+3)^2 = 1/4 9 | 7,"Draw a circle with center at 6, negative four and a radius of three.",(x-6)^2 + (y+4)^2 = 9 10 | 8,"Draw a circle with a radius of one-fourth centered at the point 0, negative eight.",x^2 + (y+8)^2 = 1/16 11 | 9,"Plot a circle with a radius of five units centered at two, zero.",(x-2)^2 + y^2 = 25 -------------------------------------------------------------------------------- /test/single_turn/graph_circles_2.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph the circle with center negative seven, five and radius two.",(x+7)^2 + (y-5)^2 = 4 3 | 1,Graph the circle the quantity x plus one squared plus y squared equals eighty one,(x+1)^2 + y^2 =81 4 | 2,"Graph the circle with center at five, two and radius four.",(x-5)^2 + (y-2)^2 = 16 5 | 3,"Graph the circle with center at negative two, negative one and radius seven on Desmos.",(x+2)^2 + (y+1)^2 = 49 6 | 4,"Graph a circle with a radius of five-sixths units and a center at (three point six, seven point eight).",(x-3.6)^2 + (y-7.8)^2 = 25/36 7 | 5,"Graph a circle with a radius of four units and a center at two, five.",(x-2)^2+(y-5)^2 =16 8 | 6,"Graph a circle with a radius of ten units and a center at one point five, zero.",(x-1.5)^2 + y^2 = 100 9 | 7,"Graph a circle with a radius of one-half units and a center at negative two, negative eight.",(x+2)^2 + (y+8)^2 = 1/4 10 | 8,"Graph a circle with a radius of three-fifths units and a center at negative three, nine.",(x+3)^2 + (y-9)^2 = 9/25 11 | 9,"Graph a unit circle at seven, one.",(x-7)^2 + (y-1)^2 = 1 12 | 10,Graph a circle that goes through the points two eight and negative one five. ,(x-0.5)^2+(y-6.5)^2=9/2 13 | 11,Graph a circle that goes through the points negative three four and negative three ten. ,(x+3)^2 + (y-7)^2=9 -------------------------------------------------------------------------------- /test/single_turn/graph_lines.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph a line that contains the point four three and has a slope of one half.,y=1/2(x) +1 3 | 1,Graph y minus five equals negative two times the quantity x minus one.,y-5 = -2(x-1) 4 | 2,Graph the line with slope two and y-intercept three.,y=2x + 3 5 | 3,Graph the line with slope four point five and y-intercept negative eight.,y=4.5x - 8 6 | 4,"Graph a line with a slope of four that goes through the point three, zero.",y=4x - 12 7 | 5,Show the line with an x-intercept of eight and a slope of three-fourths.,y= (3/4)x - 6 8 | 6,Draw the line with a y-intercept of one-half and a slope of three.,y=3x + 1/2 9 | 7,Graph the line that goes through two one and five negative eight. ,y= -3x+7 10 | 8,Show the line with a y-intercept of negative one point five and a slope of negative four.,y= -4x-1.5 11 | 9,"Graph the line that goes through the point with coordinates one, five and the point with coordinates negative two, nine.",y= (-4/3)x + 19/3 -------------------------------------------------------------------------------- /test/single_turn/graph_lines_2.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph a line that contains the point four, three and has a slope of one half.",y=1/2(x) +1 3 | 1,"Graph a line with a slope of four that contains the point three, zero.",y=4x - 12 4 | 2,"Graph a line that contains the point negative seven, negative four and has a slope of two thirds.",y + 4 =2/3(x + 7) 5 | 3,"Find the equation and graph the line through two, one and five, negative eight",y=-3x+7 6 | 4,Graph y equals two thirds x minus four,y=(2/3)x - 4 7 | 5,Graph a line parallel to y = 6x - 4 with a y-intercept of 10,y = 6x - 10 8 | 6,Graph the line perpendicular to y equals five x plus three with a y intercept of nine. ,y=(-1/5)x + 9. 9 | 7,"A phone company offers a plan that costs a $25 base fee plus $10 for every GB of data used. Write an equation for the total cost, y, in terms of the number of GB used, x. ",y = 25 + 10x 10 | 8,"A bakery sells loaves of bread for $8, and their daily expenses are $200. Write an equation for the bakery's daily profit, y, in terms of the number of loaves sold, x. ",y = 8x - 200 11 | 9,"At sunrise, the temperature is 60 degrees F. The temperature increases at a constant rate of 2 degrees per hour. Graph the relationship between temperature in degrees, y, and number of hours passed, x. ",y = 60 + 2x -------------------------------------------------------------------------------- /test/single_turn/graph_multi_step_labeling.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph the circle with center at two, two and a radius of three. Also, draw a tangent line passing through the point negative two, two. Label the point of tangency on the graph.","y = -1.133x-0.267, a=2(\pi-\tan^{-1}(\sqrt{7}))" 3 | 1,"Graph the circle with center at negative three, four and radius two. Also, draw a tangent line passing through the point negative two, eight. Please label the point of tangency on the graph.","y = 1.07x+10.14, a=2\tan^{-1}(1/3(4+\sqrt{13}))" 4 | 2,"Graph the circle with center at the origin and radius 2. Also, plot a tangent line passing through the point negative four, four and indicate the point of tangency on the graph.","y = -2.215x - 4.86, a=2(\pi-\tan^{-1}(2+\sqrt{7}))" 5 | 3,"Graph the circle with center at two negative three and radius five. Also, graph a tangent line that passes through the point fifteen five. Make sure to clearly mark the point of tangency on the graph.","y = 0.22x + 1.67, a=2\tan^{-1}(1/9(4+2\sqrt{13}))" 6 | 4,"Graph the circle with center negative one, one and radius three, and plot a tangent line that passes through the point negative five, ten. Also, include the point of tangency on the graph.","y = -9.16x - 35.81, a=2(\pi-\tan^{-1}(9+2\sqrt{22}))" 7 | 5,"Graph a circle with center at four, negative two and radius three. Draw a tangent line that goes through the point nine, five. Label the point where the tangent line touches the circle on the graph.","y = 0.675x -1.08, a=2\tan^{-1}(1/8(7+\sqrt{65}))" 8 | 6,"Graph the circle with center at one, two and radius three. Also, plot a tangent line passing through the point five, three. Clearly show the point of tangency on the graph.","y = -0.64x + 6.2, a=2\tan^{-1}(1/7(1+2\sqrt{2}))" 9 | 7,"Graph the parabola y equals the quantity x minus 2 squared minus 1 and a tangent line passing through the point five, four. Highlight the point of tangency on the graph.",y = 2x-6 10 | 8,"Graph the parabola y equals x squared minus 3x plus 2 and draw a tangent line that passes through the point negative two, negative four. Also, mark the point of tangency on the graph.",y = x-2 11 | 9,"Graph the parabola with equation y equals negative x squared plus five x minus 6, and also graph the tangent line that passes through the point negative seven, one. Make sure to label the point of tangency.",y = -3x-22 -------------------------------------------------------------------------------- /test/single_turn/graph_parabola_tangents.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Find the two tangents to the parabola y equals x squared minus 2x plus 5 that go through the point one, three.","y = 2(x-1)+3, y=5-2x" 3 | 1,"Graph the parabola y equals x squared and its tangent line passing through the point (0, negative four) on the same coordinate plane.","y = 4x-4, y=-4x-4" 4 | 2,Graph the parabola with equation y equals negative two x squared plus four x minus one. Draw a tangent line passing through the point with coordinates one and three.,y = -4x+7 5 | 3,"Graph the parabola y equals the quantity x minus 2 squared minus 1 and a tangent line passing through the point five, four.",y = 2x-6 6 | 4,"Graph the parabola y equals x squared minus 3x plus 2 and draw a tangent line that passes through the point negative two, negative four.",y = x-2 7 | 5,"Graph the parabola with equation y equals negative x squared plus five x minus 6, and also graph the tangent line that passes through the point negative seven, one.",y = -3x-22 8 | 6,"Graph the parabola y equals x squared plus two x plus 1 and draw a tangent line passing through the point (0,0).",y = 4x 9 | 7,"Plot the parabola y equals three x squared minus four x plus two and a tangent line passing through the point three, five. Graph both the parabola and the tangent line.",y = 26x-73 10 | 8,"Graph the parabola with equation y equals negative x squared plus three x minus two, and also graph a tangent line passing through the point 1, 4 that touches the parabola at a single point.",y = 5x-1 11 | 9,"Graph the parabola y equals the quantity x plus one squared minus three, and the tangent line passing through the point one, negative three.",y = 8x-11 -------------------------------------------------------------------------------- /test/single_turn/graph_polynomials.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 1,Graph the function f of x equals two x cubed minus five x squared plus three x minus one and find the x-intercepts or zeros of the polynomial.," f(x) = 2x^3 - 5x^2 + 3x - 1, x=1.829" 3 | 2,Let p of x be equal to two x cubed minus fifteen x squared plus twenty-nine x minus twenty. Graph p of x. ,y= 2x^3-15x^2+29x-20 4 | 3,Let p of x equals two x cubed minus fifteen x squared plus twenty nine x minus twenty. Graph p of x. ,p(x) =2x^3 - 15x^2+29x-20 5 | 4,Let f of x equals three times the quantity x plus four squared. Find the y intercept of f of x and graph it., y = 3(x+4)^2 6 | 5,"Given the equation y equals x to the fourth power minus three x cubed plus two x squared plus x minus one, graph the polynomial function and determine the number of zeros it has.",y=x^(4)-3x^(3)+2x^(2)+x-1 7 | 6,The polynomial function g of x equals x cubed minus 4x squared plus 5x minus 2 has a zero at x equals 2. Find the other zeros and plot the function.,g(x) = x^3 - 4x^2 + 5x - 2 8 | 7,We want to find the roots of the polynomial p of x equals the quantity two x squared plus seven x plus five times the quantity x minus three. Plot all the zeros of this polynomial,"p(x) = (2x^2+7x+5)(x-3), x=-2.5, x = -1, x = 3" 9 | 8,"Graph the polynomial with zeros at x equals zero, negative one, and three.",p(x) = x(x+1)(x-3) 10 | 9,Write a polynomial of least degree with roots two and negative two and graph it,p(x) = (x+2)(x-2) -------------------------------------------------------------------------------- /test/single_turn/graph_quad_eqns.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph the system of equations: Equation one is y equals x. Equation two is y equals x squared minus three x. Determine the coordinates of the intersection point, if any.","y = x, y = x^2 - 3x, (0,0), (4,4)" 3 | 1,"Graph y equals two x plus three, then graph y equals x squared minus two x, and finally find the intersections.","y=2x+3, y=x^2-2x, (-0.646, 1.708), (4.646, 12,292)" 4 | 2,The system of equations consists of two equations. The first equation is y equals three x minus two. The second equation is y equals negative two x squared plus five x plus one.,"y = 3x - 2, y = -2x^2 + 5x + 1, (1.823, 3,469), (-0.823, -4.469)" 5 | 3,Graph the system of equations: Equation 1 is y equals x squared minus four. Equation 2 is y equals negative two x plus three. Find the intersections,"y = x^2 - 4, y = -2x + 3, (-3.828, 10.657), (1.828, -0.657)" 6 | 4,"The system of equations consists of two equations. The first equation is y equals two x plus five, and the second equation is y equals x squared plus three x minus two. Find the intersections","y = 2x + 5, y = x^2 + 3x - 2, (-3.193, -1.385), (2.193, 9.385)" 7 | 5,The system of equations consists of two equations. The first equation is y equals x squared minus x. The second equation is y equals negative three x plus two. Find the intersections," y = x^2 - x, y = -3x + 2, (-2.732, 10.196), (0.732, -0.196)" 8 | 6,"Graph the system of equations: 9 | Equation 1: y equals two x squared minus three x plus one 10 | Equation 2: y equals three x plus two. Find the intersections","y = 2x^2 - 3x + 1, y=3x+2, (3.158, 11.475), (-0.158, 1.525)" 11 | 7,The system of equations consists of two equations. The first equation is y equals negative x squared plus 2x plus 3. The second equation is y equals 4x minus 1. Find the intersections,"y = -x^2 + 2x + 3, y = 4x-1, (-3.236, -13.944), (1.236, 3.944)" 12 | 8,The system of equations consists of two equations. The first equation is y equals x squared plus 2x minus 1. The second equation is y equals negative 2x plus 5. Find the intersections,"y = x^2 + 2x - 1, y= -2x+5, (-5.162, 15.325), (1.162, 2.675)" 13 | 9,Graph the system of equations: Equation 1 is y equals 2x plus 1. Equation 2 is y equals x squared minus 3x. Find the intersections,"y = 2x + 1, y = x^2-3x, (-0.193, 0.615), (5.193, 11.385)" 14 | 10,"Graph and solve the following system of equations: the quantity x minus two squared plus the quantity y minus three squared equals sixteen, and x plus y minus one equals zero","(x-2)^2 + (y-3)^2 = 16, x+y-1 = 0, (-2, 3), (2, -1)" 15 | 11,Function f is defined as f of x equals 1 over two x and function g is defined as g of x equals x squared. Determine the x coordinate of their intersection.,"f(x)=1/(2x), g(x)=x^2, x=0.794" 16 | 12,"How many points of intersection does the given system of equations have? y equals one minus x squared, y equals two minus x","y=1-x^2, y=2-x" -------------------------------------------------------------------------------- /test/single_turn/intercepts.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph two x cubed minus five x squared plus three x minus one and find the x intercepts of the polynomial.,"y = 2x^3 - 5x^2 + 3x - 1, (1.829, 0)" 3 | 1,Graph p of x equals two x cubed plus fifteen x squared plus twenty-nine x minus twenty and find the x-intercepts of the function.,"p(x)=2x^3 + 15x^2+29x-20 , (0.533, 0)" 4 | 2,Sketch the function y equals x to the power of four minus three x cubed plus two x squared plus x minus one and determine the points where the graph intersects the y-axis.,"y = x^4 - 3x^3 + 2x^2 + x - 1, (0, -1)" 5 | 3,Draw a polynomial with the least possible degree that has roots 2 and -2.,p(x) = (x+2)(x-2) 6 | 4,Construct two x cubed minus fifteen x squared plus twenty-nine x minus twenty and list the imaginary roots.,"y=2x^3-15x^2+29x-20 , (1.25+(.661)i, 0), (1.25-(.661)i, 0)" 7 | 5,Expand the expression (c+3)(c-1) and find the values of c that make the expression equal to zero.,"y=(x+3)(x-1), (1, 0), (-3, 0)" 8 | 6,"Write a polynomial with roots 0, negative one, and three.",p(x) = x(x+1)(x-3) 9 | 7,Draw x cubed minus two x squared plus five x minus 7 and list out the x-intercepts.,"p(x) = x^3-2x^2+5x-7 , (1.604, 0)" 10 | 8,Find the y-intercept of sine of two x minus pi.,"y = sin(2x-\pi), (0, 0)" 11 | 9,"What is the asymptote of one divided by the quantity five x plus three, all added to four?","y=1/(5x+3)+4, y=4" -------------------------------------------------------------------------------- /test/single_turn/intersections_of_lines.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph y equals two x minus two and x equals four. Find the intersection.,"y=2x-2, x=4, (4, 6)" 3 | 1,Graph the system y equals five x plus two and y equals negative x plus eight. Show where the lines intersect.,"y=5x+2, y=-x+8, (1, 7)" 4 | 2,"Graph eight x minus four y equals sixteen and eight x plus four y equals sixteen, and show their intersection.","8x-4y=16, 8x+4y=16, (2,0)" 5 | 3,Graph the line with a slope of six and a y-intercept of four. Graph the line with a slope of two and a y-intercept of negative four. Find their intersection.,"y = 6x + 4, y = 2x - 4, (-2, -8)" 6 | 4,Graph the functions y equals x and y equals x squared minus 3x. Find their intersections.,"y = x, y = x^2 - 3x, (0,0), (4,4)" 7 | 5,Graph y equals x and y equals x squared minus six. Find the intersection.,"y=x, y=x^2 - 6, (3, 3), (-2, -2)" 8 | 6,Graph x plus y equals five and y equals x squared plus x plus five. Find the intersections.," x + y = 5, y = x^2 + x + 5, (0, 5), (-2, 7)" 9 | 7,"First, graph the equation y equals two x plus three. Then, graph the equation y equals x squared minus two x. Finally, find the points where the two graphs intersect.","y=2x+3, y=x^2-2x, (4.646, 12.292), (-0.646, 1.708)" 10 | 8,Find the intersection of y equals four x squared and y equals three x plus one.,"y=4x^2, y=3x+1, (1, 4)" 11 | 9,Find the intersections of y equals two x squared plus five and y equals six x plus one.,"y=2x^2 + 5, y=6x + 1, (1, 7), (2, 13)" -------------------------------------------------------------------------------- /test/single_turn/inverse_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Consider the function f of x equals three x minus four. Find the inverse function inverse f of x, and graph both f of x and inverse f of x on the same coordinate plane. ","y = (x+4)/3, y=3x-4" 3 | 1,"Find the inverse function of f of x equals two over x, and plot both f of x and its inverse function on the same coordinate plane.",y = 2/x 4 | 2,Find the inverse function of f of x equals x cubed plus two and graph both f of x and its inverse on the same coordinate plane.,"y = (x-2)^{1/3}, y = x^3 + 2" 5 | 3,"To complete this task, you need to find the inverse function of f of x equals square root of the quantity two x plus three, which is denoted as inverse f of x. Then, you need to plot both f od x and inverse f of x on the same set of axes.","y = (x^2-3)/2, y=\sqrt{2x+3}" 6 | 4,"To complete this task, you need to find the inverse function of f of x equals negative five x plus seven. Then, you need to graph both f of x and inverse f of x on the same coordinate plane.","y = (-x+7)/5, y = -5x+7" 7 | 5,"Find the inverse function of f of x equals e to the power of the quantity five x plus four minus one, and graph both f of x and its inverse on the same set of axes.","y = (\ln{x+1}-4)/5, y = e^{5x+4}-1" 8 | 6,"Consider the function f of x equals one divided by the quantity x minus two. Determine the inverse function f inverse of x, and graph both f of x and f inverse of x on the same coordinate plane.","y = 1/x+2, y=1/(x-2)" 9 | 7,"Find the inverse function of f of x equals logarithm base three of x, and plot both f of x and its inverse function on the same set of axes.","y = 3^x, y = \log_3{x}" 10 | 8,"Find the inverse function of f of x equals natural logarithm of open parenthesis four x squared minus one close parenthesis, and graph both f of x and its inverse on the same coordinate plane.","y = +-\sqrt{e^x+1}/2, y=\ln{4x^2-1}" 11 | 9,Graph the sine function and its inverse on the same axes. ,y = sin^{-1}(x) -------------------------------------------------------------------------------- /test/single_turn/linear_and_nonlinear_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph the function f of x equals two x plus one and determine its x-intercept, y-intercept, and any asymptotes.","f(x)=2x+1, (-0.5, 0), (0, 1)" 3 | 1,"Graph the function f of x equals x squared minus four and find its x-intercepts, y-intercept, and any asymptotes. Also, determine if the graph has a maximum or minimum point.","f(x) = x^2 - 4, (0, -4)" 4 | 2,"Graph the function f of x equals negative three x plus two and identify the x-intercept, y-intercept, and any asymptotes.","f(x) = -3x + 2, (2/3,0), (0,2)" 5 | 3,"Graph the function f of x equals the quantity x plus 2 times the quantity x minus 3. Identify the x-intercepts, y-intercept, any asymptotes, and the minimum or maximum point.","f(x) = (x + 2)(x - 3), (-2,0), (3,0), (0,-6), (1/2,-25/4)" 6 | 4,"Graph the function f of x equals one over the quantity x minus four. Identify the x-intercept, y-intercept, and any asymptotes.","f(x)=1/(x-4), (0,-1/4), x=4, y=0" 7 | 5,"Graph the function f of x equals x cubed minus four x squared plus two x minus 1. Identify the x-intercepts, y-intercept, any asymptotes, and the minimum or maximum point.",f(x) = x^3 - 4x^2 + 2x - 1 8 | 6,"Graph the function f of x equals square root of x on a coordinate plane. Identify the x-intercept, the y-intercept, and any asymptotes. ","f(x) = \sqrt{x}, (0,0), (0,0)" 9 | 7,"Graph the function f of x equals two x squared plus three x plus one and determine the x-intercepts, y-intercept, any asymptotes, and the minimum or maximum point."," f(x) = 2x^2 + 3x + 1, (-1, 0), (-0.5, 0), (-0.75, -0.125), (0, 1)" 10 | 8,"Graph the function f of x equals e to the power of x plus four and find the x-intercept, y-intercept, and any asymptotes.","f(x) = e^{x}+4, y=4, (0, 5)" 11 | 9,"Graph the function f of x equals open parenthesis x minus one close parenthesis squared minus three. Identify the x-intercepts, y-intercept, any asymptotes, and the minimum or maximum point.","f(x) = (x - 1)^2 - 3, (-0.732, 0), (2.732, 0), (1, -3), (0, -2)" -------------------------------------------------------------------------------- /test/single_turn/linear_equation_systems.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Graph the system of equations y equals x plus 3 and y equals two-fifths x, and then provide the solution.","y=x+3, y=(2/5)x, (-5, -2)" 3 | 1,"Graph the equations y equals two x minus two and x equals four. Then, find the point where the two lines intersect and type the solution.","y=2x-2, x=4, (4, 6)" 4 | 2,Graph the system of equations y equals five x plus two and y equals negative x plus eight. Find the solution to the system of equations.,"y=5x+2, y=-x+8, (1, 7)" 5 | 3,Graph eight x minus four y equals sixteen and eight x plus four y equals sixteen. Find the solution to the system of equations.,"8x-4y=16, 8x+4y=16, (2,0)" 6 | 4,Graph y = x -4 and 5y-6x = 8. Find the solution. ,"5y-6x=8, y = x-4, (-28, -32)" 7 | 5,Graph 7x - y = 3 and x + y= 5. Find the intersection,"7x - y = 3, x + y= 5, (1, 4)" 8 | 6,"Maria buys apples and bananas at the supermarket. She buys 15 fruits in total, and the number of apples is twice the number of bananas. Write a system of equations to find the number of apples, x, and the number of bananas, y, she bought. ","x + y = 15, x = 2y, (10, 5)" 9 | 7,"A movie theater sells adult tickets for $10 and child tickets for $6. One day, the theater sold 120 tickets and made $960 from the sales. With x as the number of adult tickets and y as the number of child tickets, graph a system of equations to show how many tickets of each type were sold. ","x + y = 120, 10x + 6y = 960, (60, 60)" 10 | 8,A chemist has a solution that is 10% salt and another solution that is 40% salt. She wants to obtain 100 liters of a 25% salt solution. How many liters of each solution should she mix together? Use x for number of liters of the 10% solution and y for number of liters of the 40% solution. ,"x + y = 100, .10x + .40y = .25*100, (50, 50)" 11 | 9,"A school is selling hamburgers and hot dogs to raise money. Each hamburger sells for $3 and each hot dog sells for $5. The school wants to raise exactly $800, and they plan to sell 200 items. How many hamburgers and hot dogs should they sell to meet their goals? Use x for hamburgers and y for hot dogs. ","x + y = 200, 3x + 5y = 800, (100, 100)" -------------------------------------------------------------------------------- /test/single_turn/linear_inequalities.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,A salesperson is paid $100 per week and $3 for each additional sale. She wants to make at least $200 this week. Graph an inequality showing the number of sales she must make to meet her goal. ,200 <= 100 + 3x 3 | 1,Graph 5x + y < 400. ,5x + y < 400 4 | 2,Graph the inequality x over six plus y over nine is greater than five. ,x/6 + y/9 > 5 5 | 3,Graph the inequality y is greater than or equal to seven x minus two. ,y >= 7x - 2 6 | 4,"Michael has a $50 gift card to a restaurant that sells burritos and tacos. He cannot spend more than the value of the gift card. At the restaurant, burritos cost $7 and tacos cost $4. With burritos as x and tacos as y, graph the inequality showing how many burritos and tacos he can buy with his gift card. ",50 >= 7x + 4y 7 | 5,Graph four x plus eight y is less than twenty-four.,4x + 8y < 24 8 | 6,Graph the solution to two x is less than four ,2x < 4 9 | 7,"Johnathan runs a store selling knitted clothing. He has 5000 yards of yarn to use. A hat takes 150 yards of yarn to knit, and a shirt takes 1000 yards. With number of hats as x and number of shirts as y, graph an inequality showing the number of hats and shirts Johnathan can knit with the amount of yarn he has. ",5000 >= 150x + 1000y 10 | 8,"Jennifer is moving all the books in her office. She has 200 books to move. A small box can hold 20 books, while a large box can hold 50. With number of small boxes as x and number of large boxes as y, graph the inequality showing how many boxes she needs to move her books. ",200 <= 20x + 50y 11 | 9,Graph y < 7x-90,y < 7x-90 -------------------------------------------------------------------------------- /test/single_turn/linear_inequalities_2.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph y < 3x + 10 and y > 8x - 9,"y < 3x + 10, y > 8x - 9" 3 | 1,Graph the system of inequalities by plotting x greater than or equal to two and y less than two.," x>=2, y<2" 4 | 2,"Solve the system of linear inequalities: y is less than or equal to two x minus three, y is greater than or equal to negative three, and y is less than or equal to negative one point two five x plus two point five."," y <= 2x-3, y>= -3, y<= -1.25x + 2.5" 5 | 3,"Solve for the system: ""y is greater than x minus two, and y is less than or equal to two x plus two."""," y > x-2, y<= 2x+2" 6 | 4,"Solve the system of linear inequalities: two x minus five y is less than or equal to three, y minus three x is less than or equal to one","2x-5y <= 3, y-3x <= 1" 7 | 5,Graph 5x + 9y > 10 and y < 30,"5x + 9y > 10, y < 30" 8 | 6,"Find the greatest integer that satisfies the inequality negative two times the quantity three x plus two is greater than x plus ten, or two x is less than or equal to negative eight."," -2(3x+2)>x+10, 2x <= -8" 9 | 7,Find an integer solution to the inequality 'y is less than three-fourths x plus three' and 'y is less than or equal to negative two x minus one'.,"y<3/4x+3, y<= -2x-1" 10 | 8,"Alex wants to make at least $300 this month. He makes $15/hr working as a babysitter and $10/hr working at an ice cream shop. He cannot work more than 25 hours this month. With x as the hours worked as a babysitter and y as the hours worked at the ice cream shop, graph the set of points that represent the number of hours Alex can work this month. ","x+y <= 25, 15x + 10y >= 300" 11 | 9,"Jamie earns a base salary of $2000 per month. He makes $60 per computer sold, and $90 per tablet sold. He cannot sell more than 30 items in a month. If Jamie wants to make at least $4000 this month, how many computers and tablets can he sell this month? Graph this relationship using x for number of computers and y for number of tablets. ","x + y <= 30, 2000 + 60x + 90y >= 4000" -------------------------------------------------------------------------------- /test/single_turn/local_optima.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph the parabola y equals negative one over twenty times the quantity x minus three squared plus six. Determine and state the equation of the maxima,"y=-1/20(x-3)^2+6 , (3, 6)" 3 | 1,Find the local minima or maxima of y equals x squared minus x,"f(x) = x^2-x, (0.5, -0.25)" 4 | 2,For what value of x does h of x equals x to the fifth plus x to the fourth have a relative maximum?,"h(x)=x^5+x^4, -0.8" 5 | 3,For what value of x does f of x equals x cubed minus two x squred minus four x plus eight have a relative minimum?,"f(x)=x^3-2x^2-4x+8, 2" 6 | 4,Consider the function f of x equals x cubed minus six x squared plus nine x plus four. Graph the function and identify all local minima and maxima," f(x) = x^3 - 6x^2 + 9x + 4, (1, 8), (3, 4)" 7 | 5,"For the function g of x equals two x to the power of four minus four x cubed minus four x squared, determine the intervals on which the function is increasing or decreasing and identify any local minima or maxima","g(x) = 2x^4 - 4x^3 - 4x^2, (2, -16), (-0.5, -0.375)" 8 | 6,"Given the function h of x equals four x cubed minus two x squared minus six x plus two, find the x-coordinate(s) of the local minima and maxima. Sketch the graph of the function to verify your answers.","h(x) = 4x^3 - 2x^2 - 6x + 2, (-0.56, 4.03), (0.893, -2.104)" 9 | 7,Graph the function f of x equals x to the power of four minus four x squared plus three and locate all local minima and maxima. State whether each point is a minimum or maximum and provide the corresponding x-values," f(x) = x^4 - 4x^2 + 3, (-1.414, -1), (0, 3), (1.414, -1)" 10 | 8,"Determine the local minima and maxima of the function g of x equals three x cubed minus nine x squared minus two x plus four by analyzing its graph. Also, indicate whether each point is a minimum or maximum","g(x) = 3x^3 - 9x^2 - 2x + 4 , (-0.106, 4.107), (2.106, -12.107)" 11 | 9,Find the local extrema of y equals nine x to the fifth plus four x to the fourth plus x squared,"y=9x^5+4x^4+x^2, (-0.52, .221), (0, 0)" -------------------------------------------------------------------------------- /test/single_turn/proportional_relationships.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Graph y equals two point five x.,y=2.5x 3 | 1,Graph y equals three point five x.,y=3.5x 4 | 2,Graph y equals four x.,y=4x 5 | 3,Graph y equals ten x.,y=10x 6 | 4,Graph y equals x over ten. ,y = x/10 7 | 5,"A car travels 35 miles on one gallon of gasoline. Graph the relationship between gallons of gas in the car's tank, x, and distance in miles the car can travel, y. ",y=35x 8 | 6,"A recipe for chocolate chips requires 3 cups of flour to make 24 cookies. There is a proportional relationship between the number of cups of flour, x, and the number of cookies made, y. Graph this relationship. ",y=8x 9 | 7,"1 US dollar is equivalent to 0.9 euros. With x representing number of dollars and y representing number of euros, write an equation describing the proportional relationship between dollars and euros. ",y = 0.9x 10 | 8,"A runner runs 5 kilometers in 25 minutes. With minutes as x and kilometers as y, graph the relationship between minutes run and kilometers traveled if the runner stays at the same speed. ",y = x/5 11 | 9,"A garden hose fills a bucket with 2 gallons of water in 1 minute. There is a proportional relationship between minutes passed, x, and gallons in the bucket, y. Graph this relationship. ",y = 2x -------------------------------------------------------------------------------- /test/single_turn/rigid_transformations.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Plot point A, which has coordinates negative two and one, and its image A-prime, which is the result of reflecting A across the x-axis.","y = 0, (-2, 1), (-2, -1)" 3 | 1,"The task is to find the image C prime of point C with coordinates -2 and 9 under a reflection over the line y equals 1 minus x. After finding C prime, plot both C prime and C on a graph.","y=1-x, (-2, 9), (-8, 3)" 4 | 2,"Plot the rectangle with coordinates negative three, three; five, three; five, negative three; negative three, negative three and its reflection over the line y equals x minus five.","polygon((-3, 3), (5, 3), (5, -3), (-3, -3)), polygon((8, -8), (2, -8), (2, 0), (8, 0)), y = x - 5" 5 | 3,Quadrilateral EFGH has coordinates negative one six three eight two two negative two three. Apply a translation moving EFGH to the left six units and down ten units. Plot EFGH and its image. ,"polygon((-1, 6), (3, 8), (2, 2), (-2, 3)), polygon((-7, -4), (-3, -2), (-4, -8), (-8, -7))" 6 | 4,"Figure P has coordinates negative two, negative two, negative three, negative seven, negative six, negative two. Rotate P counterclockwise about the origin by 90 degrees. Plot P and its image. ","polygon((-2, -2), (-3, -7), (-6, -2)), polygon((2, -2), (7, -3), (2, -6))" 7 | 5,"Plot point P with coordinates three, five and its image obtained by rotating it clockwise by ninety degrees about the origin.","(3, 5), (5, -3)" 8 | 6,"Dilate point D about the origin with a scale factor of three. Point D has coordinates negative two, zero. Please plot point D and its image.","(-2, 0), (-6, 0)" 9 | 7,"Dilate point A, which has coordinates ten, eleven, about point P, which has coordinates twelve, twelve, by a scale factor of three. Please plot point A, the image of A after dilation, and point P.","(10, 11), (12, 12), (6, 9)" 10 | 8,"Triangle ABC has coordinates fourteen, one, two, nine, six, thirteen. Dilate ABC about center ten, five by a scale factor of one fourth. Plot ABC, the image of ABC, and the center of dilation.","(10, 5), polygon((14, 1), (2, 9), (6, 13)), polygon((11, 4), (8, 6), (9, 7))" 11 | 9,"Reflect (2, 2) across the y-axis. ","(2, 2), (-2, 2)" -------------------------------------------------------------------------------- /test/single_turn/transform_shapes.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Reflect the point two, one across the x-axis","(-2, 1), (-2, -1), y=0" 3 | 1,Dilate a circle with a radius of two units by a factor of four.,x^2 + y^2 = 64 4 | 2,"Shift a circle centered at eight, three to the left by six and down one.",(x-2)^2 + (y-2)^2 = 1 5 | 3,"Plot rectangle EFGH with coordinates negative three, three; five, three; five, negative three; negative three, negative three and its reflection over the line y equals x minus five.","polygon((-3, 3), (5, 3), (5, -3), (-3, -3)), polygon((8, -8), (2, -8), (2, 0), (8, 0))" 6 | 4,"Plot the triangle with vertices at negative two, negative two, negative three, negative seven, and negative six, negative two on a graph. Then, rotate the triangle counterclockwise by ninety degrees about the origin and plot the new image on the same graph.","polygon((-2, -2), (-3, -7), (-6, -2)), polygon((2, -2), (7, -3), (2, -6))" 7 | 5,"Stretch a circle centered at one, zero by a factor of ten.",(x-1)^2 + y^2 = 100 8 | 6,"Compress the circle centered at two, six with a radius of nine by a factor of three.",(x-2)^2 + (y-6)^2 = 9 9 | 7,"Translate a circle of radius ten centered at (five, five) by three units to the right can be spoken as ""Shift a circle with a radius of ten and centered at (five, five) three units to the right.""",(x-8)^2 + (y-5)^2 = 100 10 | 8,Move a circle of radius one half up seven units.,x^2 + (y-7)^2 = 1/4 11 | 9,Shrink a circle with a radius of eight by a factor of two.,x^2 + y^2 = 16 -------------------------------------------------------------------------------- /test/single_turn/transformations_of_functions.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,Reflect y equals five x minus four across the y-axis.,y = -5x-4 3 | 1,Shift x squared down by four and to the right by three.,y=(x-3)^2-4 4 | 2,Reflect the function of x cubed along the y-axis and then shift it up by three units.,y=3-x^3 5 | 3,Horizontally squash the absolute value of x minus 8 by a factor of 4.,y=abs(4x)-8 6 | 4,"Move x to the power of one-third up by four, then scale it vertically by a factor of one-half.",y=(1/2)x^{1/3}+4 7 | 5,"Shift absolute value of x to the right by five, reflect it across the x-axis, then shift it down by two, and finally reflect it across the y-axis.",y= -abs (-x-5)-2 8 | 6,Shift x to the power of one-half by four units to the right and then reflect it across the y-axis.,y=\sqrt{(-x-4)} 9 | 7,"Stretch two times the quantity of x minus four, plus four, vertically by four.",y=2(4x-4)+4 10 | 8,Reflect the function log of the quantity x plus five minus one along the x-axis and the y-axis.,y=1-\log{5-x} 11 | 9,Translate x squared horizontally to the left by three.,y=(x+3)^2 -------------------------------------------------------------------------------- /test/single_turn/transformations_of_functions_2.csv: -------------------------------------------------------------------------------- 1 | id,query,ground truth 2 | 0,"Given that h of x equals negative open parenthesis x minus 1 close parenthesis squared minus 1, graph f of x equals h of x minus 4. ",h(x) = -(x-1)^2-5 3 | 1,"Given that h of x equals negative open parenthesis x minus 1 close parenthesis squared minus 1, graph f of x equals h of the quantity x minus six. ",h(x) = -(x-7)^2-1 4 | 2,"Graph g of x equals negative f of x, where f of x equals the cube root of the quantity x minus 2.",g(x)= -(x-2)^{1/3} 5 | 3,"Graph g of x equals f of negative x, where f of x equals negative two times the logarithm base two of the quantity x plus one, plus three.",g(x) = -2\log_2{1-x}+3 6 | 4,"Graph negative f of negative x, where f of x equals negative two times the logarithm base two of the quantity x plus one, plus three.",g(x) = 2\log_2{1-x}-3 7 | 5,Graph two times f of x where f of x equals x squared minus 2x minus 1.,g(x) = 2(x^2-2x-1) 8 | 6,"Given f of x equals the absolute value of x minus eight, graph g of x equals f of 4x ",g(x) = |4x|-8 9 | 7,"Find g of x, where g of x is the reflection across the x-axis of f of x equals negative three times the absolute value of the quantity x plus seven plus four.",g(x) = 3|x+7|-4 10 | 8,"Find g(x), which is the translation 2 units right and 17 units up of f of x equals 3 times the absolute value of the quantity x minus 8.",g(x)=3|x-10|+17 11 | 9,Consider the function f of x equals x squared. Apply a horizontal translation by replacing f of x with f of the quantity x plus three. Sketch the new graph and identify the transformation. ,(x+3)^2 12 | 10,"For all real values of x, if f of x equals the quantity x minus three cubed and g of x equals the quantity x plus three squared, what is f of x minus g of x? ",y=(x-3)^3-(x+3)^2 --------------------------------------------------------------------------------