Support screenshot by URL for all paying customers
This commit is contained in:
parent
e9140c331b
commit
ab15aff021
@ -11,4 +11,7 @@ SHOULD_MOCK_AI_RESPONSE = bool(os.environ.get("MOCK", False))
|
|||||||
IS_PROD = os.environ.get("IS_PROD", False)
|
IS_PROD = os.environ.get("IS_PROD", False)
|
||||||
|
|
||||||
# Hosted version only
|
# Hosted version only
|
||||||
|
|
||||||
|
PLATFORM_SCREENSHOTONE_API_KEY = os.environ.get("PLATFORM_SCREENSHOTONE_API_KEY", "")
|
||||||
|
|
||||||
BACKEND_SAAS_URL = os.environ.get("BACKEND_SAAS_URL", "")
|
BACKEND_SAAS_URL = os.environ.get("BACKEND_SAAS_URL", "")
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import base64
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import httpx
|
import httpx
|
||||||
|
from config import PLATFORM_SCREENSHOTONE_API_KEY
|
||||||
|
|
||||||
|
from routes.saas_utils import does_user_have_subscription_credits
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -12,10 +15,30 @@ def bytes_to_data_url(image_bytes: bytes, mime_type: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
async def capture_screenshot(
|
async def capture_screenshot(
|
||||||
target_url: str, api_key: str, device: str = "desktop"
|
target_url: str, api_key: str | None, auth_token: str, device: str = "desktop"
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
api_base_url = "https://api.screenshotone.com/take"
|
api_base_url = "https://api.screenshotone.com/take"
|
||||||
|
|
||||||
|
# Get auth token
|
||||||
|
if not auth_token:
|
||||||
|
raise Exception("No auth token with capture_screenshot")
|
||||||
|
|
||||||
|
# If API key is not passed in, only use the platform ScreenshotOne API key if the user is a subscriber
|
||||||
|
if not api_key:
|
||||||
|
res = await does_user_have_subscription_credits(auth_token)
|
||||||
|
if res.status == "not_subscriber":
|
||||||
|
raise Exception(
|
||||||
|
"capture_screenshot - User is not subscriber and has no API key"
|
||||||
|
)
|
||||||
|
elif res.status == "subscriber_has_credits":
|
||||||
|
api_key = PLATFORM_SCREENSHOTONE_API_KEY
|
||||||
|
elif res.status == "subscriber_has_no_credits":
|
||||||
|
raise Exception("capture_screenshot - User has no credits")
|
||||||
|
else:
|
||||||
|
raise Exception(
|
||||||
|
"capture_screenshot - Unknown error occurred when checking subscription credits"
|
||||||
|
)
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
"access_key": api_key,
|
"access_key": api_key,
|
||||||
"url": target_url,
|
"url": target_url,
|
||||||
@ -44,7 +67,8 @@ async def capture_screenshot(
|
|||||||
|
|
||||||
class ScreenshotRequest(BaseModel):
|
class ScreenshotRequest(BaseModel):
|
||||||
url: str
|
url: str
|
||||||
apiKey: str
|
apiKey: str | None
|
||||||
|
authToken: str
|
||||||
|
|
||||||
|
|
||||||
class ScreenshotResponse(BaseModel):
|
class ScreenshotResponse(BaseModel):
|
||||||
@ -56,9 +80,10 @@ async def app_screenshot(request: ScreenshotRequest):
|
|||||||
# Extract the URL from the request body
|
# Extract the URL from the request body
|
||||||
url = request.url
|
url = request.url
|
||||||
api_key = request.apiKey
|
api_key = request.apiKey
|
||||||
|
auth_token = request.authToken
|
||||||
|
|
||||||
# TODO: Add error handling
|
# TODO: Add error handling
|
||||||
image_bytes = await capture_screenshot(url, api_key=api_key)
|
image_bytes = await capture_screenshot(url, api_key=api_key, auth_token=auth_token)
|
||||||
|
|
||||||
# Convert the image bytes to a data url
|
# Convert the image bytes to a data url
|
||||||
data_url = bytes_to_data_url(image_bytes, "image/png")
|
data_url = bytes_to_data_url(image_bytes, "image/png")
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { HTTP_BACKEND_URL } from "../config";
|
|||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { Input } from "./ui/input";
|
import { Input } from "./ui/input";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useStore } from "../store/store";
|
||||||
|
import { useAuth } from "@clerk/clerk-react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
screenshotOneApiKey: string | null;
|
screenshotOneApiKey: string | null;
|
||||||
@ -13,28 +15,31 @@ export function UrlInputSection({ doCreate, screenshotOneApiKey }: Props) {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [referenceUrl, setReferenceUrl] = useState("");
|
const [referenceUrl, setReferenceUrl] = useState("");
|
||||||
|
|
||||||
|
// Hosted version only
|
||||||
|
const subscriberTier = useStore((state) => state.subscriberTier);
|
||||||
|
const { getToken } = useAuth();
|
||||||
|
|
||||||
async function takeScreenshot() {
|
async function takeScreenshot() {
|
||||||
if (!screenshotOneApiKey) {
|
if (!referenceUrl) {
|
||||||
toast.error(
|
return toast.error("Please enter a URL");
|
||||||
"Please add a ScreenshotOne API key in the Settings dialog. This is optional - you can also drag/drop and upload images directly.",
|
|
||||||
{ duration: 8000 }
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!referenceUrl) {
|
if (!screenshotOneApiKey && subscriberTier === "free") {
|
||||||
toast.error("Please enter a URL");
|
return toast.error(
|
||||||
return;
|
"Please upgrade to a paid plan to use the screenshot feature."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (referenceUrl) {
|
if (referenceUrl) {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
const authToken = await getToken();
|
||||||
const response = await fetch(`${HTTP_BACKEND_URL}/api/screenshot`, {
|
const response = await fetch(`${HTTP_BACKEND_URL}/api/screenshot`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
url: referenceUrl,
|
url: referenceUrl,
|
||||||
apiKey: screenshotOneApiKey,
|
apiKey: screenshotOneApiKey,
|
||||||
|
authToken,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user