# Project export: RecovARy

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Welcome to RecovARy, our Augmented Reality solution solving rehab and physical therapy for patients who recently suffered from a stroke.
- Devpost: https://devpost.com/software/recovary
- GitHub: https://github.com/pranavi-ch/recovARy-agents
- Demo: https://github.com/ppilli1/RecovARy
- Result: winner (Snap: Dream it. Build it.; Fetch.ai: Agentic Track Prize)
- Team: 0 GitHub contributor(s) — 

## Devpost submission (written by the team)

### Inspiration

We were inspired to build RecovARy after attending Physical Therapy for the last few weeks. One of us was diagnosed with muscle spasms in their neck. After being diagnosed with muscle knots by experienced doctors, they were told the only way to fix this challenging and painful obstacle was to increase mobility in their body. Although their story involved muscle spasms, I designed this app to take it a step further, for patients who require mobility after having a stroke. A stroke, if you aren't aware, damages brain cells due to a reduced blood flow to the brain, and thus, one of many things in the body that are affected are regular movement and mobility. Therefore, we created this app with two distinct AR games, allowing a patient to choose from either Wall Tennis or 3D Fruit Ninja.

### What it does

Our app essentially contains two video games: Wall Tennis focuses on restoring a patient's arm power, including movement in the arms, shoulders, and wrists, and we calculate a patient's hitting speed to see how much mobility they are gaining in their arms; Fruit Ninja focuses on hand-eye coordination and calculates a patient's reaction time.

### How we built it

We built this app using the following technologies: Snap Inc. Spectacles, Lens Studio, Fetch.ai, Groq, Xano, and React JS

### Challenges we ran into

A couple of challenges that I ran into was trying to change the entire concept of Wall Tennis into Squash. However, I noticed that the game was turning more into Virtual Reality, meaning I couldn't see the real world around me anymore and rather was completely immersed in the lens' objects instead of partially. Therefore, I changed the game back to Wall Tennis.

### Accomplishments we're proud of

We were proud of not only being able to develop these two video games but also being able to fetch two data values from Lens Studio (hitting speed from Wall Tennis and reaction time from Fruit Ninja) to calculate and analyze a patient's data to create an accurate and effective report for doctors/physical therapists to see how much mobility their patient is gaining.

### What we learned

We learned how to work together fight through obstacles, and even create a fully fleshed-out product given our limited time frame.

### What's next

We would love to create a wider variety of games for patients to choose from, perhaps focusing on other parts of mobility than just hitting speed from the arm, and reaction time calculating a patient's reaction time. Another game we had in mind was inspired by Valorant's shooting range, where several objects would spawn in random locations and the patient would get a limited time (a split second) to hit the object before it disappeared.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 25 recognized source files, 31 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (37 of 37)

```
.DS_Store
age_and_gender_agent.py
agent.py
agents_communication.py
body_parts_impacted_agent.py
game_mock_agent.py
incident_type_agent.py
patient_data.json
personalized_weekly_plan.txt
poetry.lock
pyproject.toml
reaction_time_recovery_agent.py
recovery-dashboard/.gitignore
recovery-dashboard/package.json
recovery-dashboard/public/index.html
recovery-dashboard/public/manifest.json
recovery-dashboard/public/personalized_weekly_plan.txt
recovery-dashboard/public/robots.txt
recovery-dashboard/public/t.txt
recovery-dashboard/README.md
recovery-dashboard/src/App.css
recovery-dashboard/src/App.js
recovery-dashboard/src/App.test.js
recovery-dashboard/src/components/RecoveryPlan.js
recovery-dashboard/src/components/SnapGameData.js
recovery-dashboard/src/index.css
recovery-dashboard/src/index.js
recovery-dashboard/src/reportWebVitals.js
recovery-dashboard/src/setupTests.js
remote_agents_sigmar.py
remote_agents_slaanesh.py
server.py
snap_game_agent.py
speed_recovery_agent.py
t.txt
uagent-address.py
wrapper_agent.py
```

### Dependencies

- pyproject.toml: chatgpt-block@^0.1.6
- recovery-dashboard/package.json: @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, axios@^1.7.7, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, recharts@^2.13.0, web-vitals@^2.1.4

### Recent commits (newest first)

- agents, removed api keys

## Key source files (fetched from GitHub, selected and truncated for size)

### pyproject.toml

```
[tool.poetry]
name = "agent-demo"
version = "0.1.0"
description = "trying out fetch ai for the first time"
authors = ["Pranavi"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
chatgpt-block = "^0.1.6"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

```

### recovery-dashboard/package.json

```
{
  "name": "recovery-dashboard",
  "version": "0.1.0",
  "proxy": "http://localhost:8006",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.7.7",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "recharts": "^2.13.0",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### server.py

```python
from flask import Flask
from flask_cors import CORS
import wrapper_agent
import asyncio
app = Flask(__name__)


CORS(app, resources={r"/data": {"origins": "http://localhost:3000"}})
CORS(app, resources={r"/data": {"origins": "http://localhost:3000"}}, supports_credentials=True)


@app.route('/data', methods=['POST'])
def tr():
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    loop.run_until_complete(wrapper_agent.generate_groq_combined_plan)
    return "LOL"

if __name__ == '__main__':
    app.run(port=5173, use_reloader=False, threaded=True)
```

### recovery-dashboard/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### recovery-dashboard/src/App.js

```javascript
import React, { useEffect, useState } from "react";
import './App.css';

// Single image URL (replace this with your actual image URL)
const imageUrl = "./img2.jpeg";

// Function to fetch and parse the text file
const fetchApiText = async () => {
  try {
    // Path to the text file
    const textFileUrl = '/personalized_weekly_plan.txt';  // Ensure the file is placed in the public folder

    // Perform the fetch request to load the text file
    const response = await fetch(textFileUrl);

    // Check if the response is successful
    if (!response.ok) {
      throw new Error('Failed to load the text file');
    }

    // Parse the text file content
    const text = await response.text();

    return text;  // Return the text content of the file
  } catch (error) {
    console.error('Error fetching the text file:', error);
    return 'Error fetching the text file';
  }
};

// Typing effect function
const useTypingEffect = (text, speed) => {
  const [displayedText, setDisplayedText] = useState("");
  const [isCursorVisible, setIsCursorVisible] = useState(true);

  useEffect(() => {
    let index = 0;
    const interval = setInterval(() => {
      if (index < text.length) {
        setDisplayedText((prev) => prev + text.charAt(index));
        index++;
      } else {
        clearInterval(interval);
      }
    }, speed);

    const cursorInterval = setInterval(() => {
      setIsCursorVisible((prev) => !prev);
    }, 500); // Blinking cursor every 500ms

    return () => {
      clearInterval(interval);
      clearInterval(cursorInterval);
    };
  }, [text, speed]);

  return { displayedText, isCursorVisible };
};

function App() {
  const [apiText, setApiText] = useState("");
  const { displayedText, isCursorVisible } = useTypingEffect(apiText, 50); // Adjust speed as needed

  useEffect(() => {
    const fetchText = async () => {
      const text = await fetchApiText();
      setApiText(text);
    };

    fetchText();
  }, []);

  // Handle displayed text with line breaks
  const formattedText = displayedText.split('<br />').map((line, index) => (
    <span key={index}>
      {line}
      <br />
    </span>
  ));

  return (
    <div className="App">
      <header className="header">
        <img
          src="./logo4.png" // Replace with your logo URL
          alt="Logo"
          className="logo"
        />
      </header>

      <div className="main-container">
        <div className="image-section">
          <img src={imageUrl} alt="Your Content" className="image" />
        </div>
        <div className="text-section">
          <h2></h2>
          <p>
            {formattedText}
            {isCursorVisible && <span className="cursor">|</span>}
          </p>
        </div>
      </div>
    </div>
  );
}

export default App;

```

### agent.py

```python
from uagents import Agent, Context

agent = Agent(name="alice", seed="secret_seed_phrase")
@agent.on_event("startup")
async def introduce_agent(ctx: Context):
    ctx.logger.info(f"Hello, I'm agent {agent.name} and my address is {agent.address}.")
 
if __name__ == "__main__":
    agent.run()
```

### uagent-address.py

```python
from uagents import Agent, Context
 
agent = Agent(name="alice", seed="alice recovery phrase")
 
@agent.on_event("startup")
async def introduce_agent(ctx: Context):
    ctx.logger.info(f"Hello, I'm agent {agent.name} and my address is {agent.address}.")
 
if __name__ == "__main__":
    agent.run()
```

### remote_agents_slaanesh.py

```python
from uagents.setup import fund_agent_if_low
from uagents import Agent, Context, Model
 
class Message(Model):
    message: str
 
slaanesh = Agent(
    name="slaanesh",
    port=8001,
    seed="slaanesh secret phrase",
    endpoint=["http://127.0.0.1:8001/submit"],
)
 
fund_agent_if_low(slaanesh.wallet.address())
 
@slaanesh.on_message(model=Message)
async def message_handler(ctx: Context, sender: str, msg: Message):
    ctx.logger.info(f"Received message from {sender}: {msg.message}")
 
    await ctx.send(sender, Message(message="hello there sigmar"))
 
if __name__ == "__main__":
    slaanesh.run()
```

### reaction_time_recovery_agent.py

```python
# Define a model to receive reaction time data
from uagents import Agent, Bureau, Context, Model

class ReactionTimeData(Model):
    reaction_time_data: list

# Create an agent to handle reaction time data
reaction_time_agent = Agent(name="reaction_time_agent", seed="reaction recovery phrase")

# Simulate the end of the game where reaction time data is sent to the reaction time agent
@reaction_time_agent.on_message(model=ReactionTimeData)
async def analyze_reaction_time_data(ctx: Context, sender: str, msg: ReactionTimeData):
    # Log the received reaction time data array
    ctx.logger.info(f"Received reaction time data from {sender}: {msg.reaction_time_data}")
    print(f"Reaction time data from game: {msg.reaction_time_data}")  # Print for now

```

### speed_recovery_agent.py

```python
from uagents import Agent, Bureau, Context, Model

# Define a model to receive the game data (array of speed)
class GameData(Model):
    speed_data: list

# Create an agent to handle the speed data
analyzer_agent = Agent(name="analyzer", seed="analyzer recovery phrase")

# Simulate the end of the game where speed data is sent to the analyzer agent
@analyzer_agent.on_message(model=GameData)
async def analyze_speed_data(ctx: Context, sender: str, msg: GameData):
    # Log the received speed data array
    ctx.logger.info(f"Received speed data from {sender}: {msg.speed_data}")
    print(f"Speed data from game: {msg.speed_data}")  # Print for now

# Bureau setup to manage the agent(s)
bureau = Bureau()
bureau.add(analyzer_agent)

if __name__ == "__main__":
    # Start the bureau with the analyzer agent
    bureau.run()




```

[15 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]