Skip to content

Commit

Permalink
Merge pull request #48 from monkey-patch-sdk/demo/only-food
Browse files Browse the repository at this point in the history
Demo/only food
  • Loading branch information
MichaelSel authored Nov 10, 2023
2 parents 2b0ff6f + 24fe5bd commit e3af12c
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 46 deletions.
1 change: 0 additions & 1 deletion .env

This file was deleted.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions .idea/monkeyFunctions.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 0 additions & 15 deletions apps/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

# Configure sys path to include src dir for monkey patching
sys.path.append("../src")
from monkey import Monkey

from dotenv import load_dotenv

Expand All @@ -30,22 +29,8 @@
allow_headers=["*"],
)


app.include_router(router)

# origins = [CLIENT_URL]
# if APP_ENV != "production":
# origins.append("https://demo.paperplane.ai")

# app.add_middleware(
# CORSMiddleware,
# allow_origins=origins,
# allow_credentials=True,
# allow_methods=["*"],
# allow_headers=["authorization", "x-app-version"],
# )


if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
# uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True, log_config=log_config)
7 changes: 6 additions & 1 deletion apps/controllers/food_controller.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from typing import List, Dict
from services.food_service import specific_ratings, recommended_dishes
from services.food_service import (
specific_ratings,
recommended_dishes,
test_specific_ratings,
)


def get_ratings(reviews: List[str]) -> Dict[str, int]:
test_specific_ratings()
rating = specific_ratings(reviews)
return rating.model_dump()

Expand Down
32 changes: 32 additions & 0 deletions apps/extenders/yelp_scraper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import json
import os

from apify_client import ApifyClient

# Initialize the ApifyClient with your API token
APIFY_KEY = os.getenv("APIFY_API_KEY")
client = ApifyClient(APIFY_KEY)


def yelp_scraper(url: str):
# Prepare the Actor input
run_input = {
"debugLog": False,
"directUrls": [url],
"maxImages": 0,
"proxy": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]},
"reviewLimit": 20,
"reviewsLanguage": "ALL",
"scrapeReviewerName": False,
"scrapeReviewerUrl": False,
"searchLimit": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("yin/yelp-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
items = client.dataset(run["defaultDatasetId"]).get_items_as_bytes()
items = json.loads(items)

return items
12 changes: 10 additions & 2 deletions apps/routers/food_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@
@router.get("/")
async def analyze_reviews(url: str):
reviews = get_yelp_reviews(url)
max_reviews = 20
if len(reviews) == 0:
return {
"message": "error",
}
if len(reviews) > max_reviews:
reviews = reviews[:max_reviews]

ratings = get_ratings(reviews)
best_dishes = get_best_dishes(reviews)
# best_dishes = get_best_dishes(reviews)
return {
"message": "success",
"ratings": ratings,
"best_dishes": best_dishes,
# "best_dishes": best_dishes,
}
103 changes: 81 additions & 22 deletions apps/services/food_service.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,105 @@
from pydantic import Field, BaseModel
from typing import List, Annotated, Dict
from monkey import Monkey

from monkey_patch.monkey import Monkey

import openai
import requests
from bs4 import BeautifulSoup

# from dotenv import load_dotenv
import os

from extenders.yelp_scraper import yelp_scraper

# load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")


from zenrows import ZenRowsClient

client = ZenRowsClient(os.getenv("ZENROWS_API_KEY"))


class RatingItem(BaseModel):
rating: int = Field(int, ge=1, le=10)
confidence: int = Field(
int, ge=1, le=10, description="How confident are you in your answer?"
)


class RatingModel(BaseModel):
food: int = Annotated[
Field(..., ge=1, le=10), "The food-only rating based on the provided reviews"
]
service: int = Annotated[
Field(..., ge=1, le=10), "The service-only rating based on the provided reviews"
]
atmosphere: int = Annotated[
Field(..., ge=1, le=10),
"The atmosphere-only rating based on the provided reviews",
]
location: int = Annotated[
Field(..., ge=1, le=10),
"The location-only rating based on the provided reviews",
]
food: RatingItem = Field(..., description="The food-only rating")
service: RatingItem = Field(..., description="The service-only rating")
atmosphere: RatingItem = Field(..., description="The atmosphere-only rating")
location: RatingItem = Field(..., description="The location-only rating")


@Monkey.patch
def specific_ratings(reviews: List[str]) -> RatingModel:
"""
based on the reviews, separately rate (from 1 to 10) the following aspects:
- food
rating: 1-10
confidence: 1-10
- service
rating: 1-10
confidence: 1-10
- atmosphere
rating: 1-10
confidence: 1-10
- location
- overall
rating: 1-10
confidence: 1-10
"""


@Monkey.align
def test_specific_ratings():
"""We can test the function as normal using Pytest or Unittest"""
assert specific_ratings(["The food was great"]) == RatingModel(
food=RatingItem(rating=10, confidence=10),
service=RatingItem(rating=5, confidence=1),
atmosphere=RatingItem(rating=5, confidence=1),
location=RatingItem(rating=5, confidence=1),
)
assert specific_ratings(["The service was great"]) == RatingModel(
food=RatingItem(rating=5, confidence=1),
service=RatingItem(rating=10, confidence=10),
atmosphere=RatingItem(rating=5, confidence=1),
location=RatingItem(rating=5, confidence=1),
)
assert specific_ratings(
[
"The atmosphere was kinda average, the location was really nice, and the service was shitty"
]
) == RatingModel(
food=RatingItem(rating=5, confidence=1),
service=RatingItem(rating=1, confidence=10),
atmosphere=RatingItem(rating=5, confidence=10),
location=RatingItem(rating=10, confidence=10),
)
assert specific_ratings(
[
"The food was the worst I've ever had, the service is a little slow but not bad, the atmosphere was really nice but kinda loud, and the location was perfect except that it was a little hard to find parking"
]
) == RatingModel(
food=RatingItem(rating=1, confidence=10),
service=RatingItem(rating=4, confidence=10),
atmosphere=RatingItem(rating=7, confidence=10),
location=RatingItem(rating=9, confidence=10),
)
assert specific_ratings(
[
"The food was the best I've ever had",
"The food was the worst I've ever had",
]
) == RatingModel(
food=RatingItem(rating=5, confidence=5),
service=RatingItem(rating=5, confidence=1),
atmosphere=RatingItem(rating=5, confidence=1),
location=RatingItem(rating=5, confidence=1),
)


@Monkey.patch
Expand All @@ -59,9 +114,13 @@ def test_recommended_dishes():
"""We can test the function as normal using Pytest or Unittest"""


def get_yelp_reviews(yelp_url: str) -> List[str]:
response = requests.get(yelp_url)
soup = BeautifulSoup(response.text, "html.parser")
# get all "p" tags with class beginning with comment__
reviews = soup.find_all("p", class_=lambda x: x and x.startswith("comment__"))
return [review.text for review in reviews]
def get_yelp_reviews(business_id_or_alias: str) -> List[str]:
url = f"https://www.yelp.com/biz/{business_id_or_alias}"

params = {"autoparse": "true"}
response = client.get(url, params=params)
if "review" not in response.json():
return []
res_json = response.json()["review"]
reviews = [review["description"] for review in res_json]
return reviews
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ flake8==6.1.0
black==23.10.0
mypy==1.6.1
beautifulsoup4==4.12.2
apify_client
zenrows
monkey-patch.py

0 comments on commit e3af12c

Please sign in to comment.