roast-api 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +21 -0
- package/README.md +27 -1
- package/composer.json +30 -0
- package/index.html +26 -1
- package/package.json +1 -1
- package/pyproject.toml +32 -0
- package/roast_api/__init__.py +29 -0
- package/roast_api/__pycache__/__init__.cpython-312.pyc +0 -0
- package/roast_api/__pycache__/client.cpython-312.pyc +0 -0
- package/roast_api/client.py +89 -0
- package/src/RaaS.php +133 -0
|
@@ -28,3 +28,24 @@ jobs:
|
|
|
28
28
|
files: |
|
|
29
29
|
api/client.js
|
|
30
30
|
postman/roast-as-a-service.postman_collection.json
|
|
31
|
+
|
|
32
|
+
publish-pypi:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
- uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: '3.x'
|
|
40
|
+
|
|
41
|
+
- name: Install build tools
|
|
42
|
+
run: pip install build twine
|
|
43
|
+
|
|
44
|
+
- name: Build package
|
|
45
|
+
run: python -m build
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
run: twine upload dist/*
|
|
49
|
+
env:
|
|
50
|
+
TWINE_USERNAME: __token__
|
|
51
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
<img src="https://hits.sh/maijied.github.io/roast-as-a-service.svg?view=today-total&style=flat-square&label=visitors&color=ec4899&labelColor=020617" alt="Visitor Count" />
|
|
8
8
|
<a href="https://www.npmjs.com/package/roast-api"><img src="https://img.shields.io/npm/v/roast-api?style=flat-square&color=f97316&labelColor=020617" alt="npm version" /></a>
|
|
9
9
|
<a href="https://www.npmjs.com/package/roast-api"><img src="https://img.shields.io/npm/dm/roast-api?style=flat-square&color=ec4899&labelColor=020617" alt="npm downloads" /></a>
|
|
10
|
+
<a href="https://pypi.org/project/roast-api/"><img src="https://img.shields.io/pypi/v/roast-api?style=flat-square&color=3b82f6&labelColor=020617" alt="PyPI version" /></a>
|
|
11
|
+
<a href="https://packagist.org/packages/maizied/roast-api"><img src="https://img.shields.io/packagist/v/maizied/roast-api?style=flat-square&color=10b981&labelColor=020617" alt="Packagist version" /></a>
|
|
10
12
|
<a href="https://github.com/Maijied/roast-as-a-service/actions/workflows/deploy.yml"><img src="https://github.com/Maijied/roast-as-a-service/actions/workflows/deploy.yml/badge.svg" alt="Deploy to GitHub Pages" /></a>
|
|
11
13
|
</p>
|
|
12
14
|
|
|
@@ -66,7 +68,31 @@ Load the client SDK directly in your browser:
|
|
|
66
68
|
</script>
|
|
67
69
|
```
|
|
68
70
|
|
|
69
|
-
### 3.
|
|
71
|
+
### 3. Install via Composer (PHP)
|
|
72
|
+
```bash
|
|
73
|
+
composer require maizied/roast-api
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```php
|
|
77
|
+
use Maizied\RoastApi\RaaS;
|
|
78
|
+
|
|
79
|
+
$roast = RaaS::getRandomRoast(['lang' => 'en']);
|
|
80
|
+
echo $roast['text'];
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 4. Install via pip (Python)
|
|
84
|
+
```bash
|
|
85
|
+
pip install roast-api
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from roast_api import get_random_roast
|
|
90
|
+
|
|
91
|
+
roast = get_random_roast(lang='en')
|
|
92
|
+
print(roast['text'])
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 5. Direct Fetch
|
|
70
96
|
Or just fetch the JSON files directly:
|
|
71
97
|
|
|
72
98
|
```javascript
|
package/composer.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "maizied/roast-api",
|
|
3
|
+
"description": "A PHP client for RaaS — Roast as a Service. CDN-served static JSON API for developer roasts.",
|
|
4
|
+
"type": "library",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"authors": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Maizied",
|
|
9
|
+
"email": "mdshuvo40@gmail.com"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://maijied.github.io/roast-as-a-service/",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"roast",
|
|
15
|
+
"api",
|
|
16
|
+
"developer",
|
|
17
|
+
"humor",
|
|
18
|
+
"fun",
|
|
19
|
+
"cdn"
|
|
20
|
+
],
|
|
21
|
+
"require": {
|
|
22
|
+
"php": ">=7.4"
|
|
23
|
+
},
|
|
24
|
+
"autoload": {
|
|
25
|
+
"psr-4": {
|
|
26
|
+
"Maizied\\RoastApi\\": "src/"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"minimum-stability": "stable"
|
|
30
|
+
}
|
package/index.html
CHANGED
|
@@ -53,6 +53,12 @@
|
|
|
53
53
|
<a href="https://www.npmjs.com/package/roast-api" target="_blank"><img
|
|
54
54
|
src="https://img.shields.io/npm/dm/roast-api?style=flat-square&color=ec4899&labelColor=020617"
|
|
55
55
|
alt="npm downloads" /></a>
|
|
56
|
+
<a href="https://pypi.org/project/roast-api/" target="_blank"><img
|
|
57
|
+
src="https://img.shields.io/pypi/v/roast-api?style=flat-square&color=3b82f6&labelColor=020617"
|
|
58
|
+
alt="PyPI version" /></a>
|
|
59
|
+
<a href="https://packagist.org/packages/maizied/roast-api" target="_blank"><img
|
|
60
|
+
src="https://img.shields.io/packagist/v/maizied/roast-api?style=flat-square&color=10b981&labelColor=020617"
|
|
61
|
+
alt="Packagist version" /></a>
|
|
56
62
|
<a href="https://github.com/Maijied/roast-as-a-service" target="_blank"><img
|
|
57
63
|
src="https://img.shields.io/github/stars/Maijied/roast-as-a-service?style=flat-square&color=f97316&labelColor=020617"
|
|
58
64
|
alt="GitHub stars" /></a>
|
|
@@ -163,8 +169,27 @@ RaaS.getRandomRoast({ lang: 'en' })
|
|
|
163
169
|
RaaS.getRandomRoast({ lang: 'bn', intensity: 2 })
|
|
164
170
|
.then(r => console.log(r.text));
|
|
165
171
|
</script></code></pre>
|
|
172
|
+
<div class="code-card">
|
|
173
|
+
<h3>Composer (PHP)</h3>
|
|
174
|
+
<pre><code>composer require maizied/roast-api
|
|
175
|
+
|
|
176
|
+
// Usage
|
|
177
|
+
use Maizied\RoastApi\RaaS;
|
|
178
|
+
|
|
179
|
+
$roast = RaaS::getRandomRoast(['lang' => 'en']);
|
|
180
|
+
echo $roast['text'];</code></pre>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="code-card">
|
|
183
|
+
<h3>pip (Python)</h3>
|
|
184
|
+
<pre><code>pip install roast-api
|
|
185
|
+
|
|
186
|
+
# Usage
|
|
187
|
+
from roast_api import get_random_roast
|
|
188
|
+
|
|
189
|
+
roast = get_random_roast(lang='en')
|
|
190
|
+
print(roast['text'])</code></pre>
|
|
191
|
+
</div>
|
|
166
192
|
</div>
|
|
167
|
-
</div>
|
|
168
193
|
</section>
|
|
169
194
|
|
|
170
195
|
<section class="section">
|
package/package.json
CHANGED
package/pyproject.toml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "roast-api"
|
|
7
|
+
version = "1.4.0"
|
|
8
|
+
description = "A Python client for RaaS — Roast as a Service. CDN-served static JSON API for developer roasts."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.7"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Maizied", email = "mdshuvo40@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["roast", "api", "developer", "humor", "fun", "cdn"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"requests>=2.20.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://maijied.github.io/roast-as-a-service/"
|
|
29
|
+
Repository = "https://github.com/Maijied/roast-as-a-service"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
include = ["roast_api*"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RaaS — Roast as a Service Python Client
|
|
3
|
+
|
|
4
|
+
A lightweight Python client for fetching developer roasts from the
|
|
5
|
+
RaaS static JSON API hosted on GitHub Pages.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from roast_api import get_random_roast, get_all_roasts
|
|
9
|
+
|
|
10
|
+
roast = get_random_roast(lang='en')
|
|
11
|
+
print(roast['text'])
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from roast_api.client import (
|
|
15
|
+
get_random_roast,
|
|
16
|
+
get_all_roasts,
|
|
17
|
+
get_manifest,
|
|
18
|
+
get_shard,
|
|
19
|
+
clear_cache,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__version__ = "1.4.0"
|
|
23
|
+
__all__ = [
|
|
24
|
+
"get_random_roast",
|
|
25
|
+
"get_all_roasts",
|
|
26
|
+
"get_manifest",
|
|
27
|
+
"get_shard",
|
|
28
|
+
"clear_cache",
|
|
29
|
+
]
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RaaS Python Client — core logic.
|
|
3
|
+
|
|
4
|
+
Fetches roasts from the static JSON API on GitHub Pages,
|
|
5
|
+
with in-memory caching and optional filtering.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import random
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
|
|
13
|
+
BASE_URL = "https://maijied.github.io/roast-as-a-service/api"
|
|
14
|
+
|
|
15
|
+
# In-memory caches
|
|
16
|
+
_manifest_cache: Optional[Dict[str, Any]] = None
|
|
17
|
+
_shard_cache: Dict[str, Dict[str, Any]] = {}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_manifest() -> Dict[str, Any]:
|
|
21
|
+
"""Fetch and cache the API manifest."""
|
|
22
|
+
global _manifest_cache
|
|
23
|
+
if _manifest_cache is not None:
|
|
24
|
+
return _manifest_cache
|
|
25
|
+
|
|
26
|
+
url = f"{BASE_URL}/manifest.json"
|
|
27
|
+
resp = requests.get(url, timeout=10)
|
|
28
|
+
resp.raise_for_status()
|
|
29
|
+
_manifest_cache = resp.json()
|
|
30
|
+
return _manifest_cache
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_shard(lang: str = "en", shard: int = 1) -> Dict[str, Any]:
|
|
34
|
+
"""Fetch and cache a specific language shard."""
|
|
35
|
+
key = f"{lang}-{shard}"
|
|
36
|
+
if key in _shard_cache:
|
|
37
|
+
return _shard_cache[key]
|
|
38
|
+
|
|
39
|
+
url = f"{BASE_URL}/{lang}/roasts-{lang}-{shard}.json"
|
|
40
|
+
resp = requests.get(url, timeout=10)
|
|
41
|
+
resp.raise_for_status()
|
|
42
|
+
_shard_cache[key] = resp.json()
|
|
43
|
+
return _shard_cache[key]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_random_roast(
|
|
47
|
+
lang: str = "en",
|
|
48
|
+
intensity: Optional[int] = None,
|
|
49
|
+
max_length: Optional[int] = None,
|
|
50
|
+
) -> Dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
Get a random roast.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
lang: Language code ('en' or 'bn'). Default: 'en'.
|
|
56
|
+
intensity: Filter by intensity (1–3). Default: None (any).
|
|
57
|
+
max_length: Maximum text length. Default: None (any).
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
A dict with keys: id, text, intensity, length.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
ValueError: If no roasts match the given filters.
|
|
64
|
+
"""
|
|
65
|
+
data = get_shard(lang)
|
|
66
|
+
roasts: List[Dict[str, Any]] = data.get("roasts", [])
|
|
67
|
+
|
|
68
|
+
if intensity is not None:
|
|
69
|
+
roasts = [r for r in roasts if r.get("intensity") == intensity]
|
|
70
|
+
if max_length is not None:
|
|
71
|
+
roasts = [r for r in roasts if r.get("length", 0) <= max_length]
|
|
72
|
+
|
|
73
|
+
if not roasts:
|
|
74
|
+
raise ValueError("No roasts match the given filters.")
|
|
75
|
+
|
|
76
|
+
return random.choice(roasts)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_all_roasts(lang: str = "en") -> List[Dict[str, Any]]:
|
|
80
|
+
"""Get all roasts for a language."""
|
|
81
|
+
data = get_shard(lang)
|
|
82
|
+
return data.get("roasts", [])
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def clear_cache() -> None:
|
|
86
|
+
"""Clear the in-memory caches."""
|
|
87
|
+
global _manifest_cache, _shard_cache
|
|
88
|
+
_manifest_cache = None
|
|
89
|
+
_shard_cache = {}
|
package/src/RaaS.php
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Maizied\RoastApi;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RaaS — Roast as a Service PHP Client
|
|
7
|
+
*
|
|
8
|
+
* A lightweight PHP client for fetching developer roasts from the
|
|
9
|
+
* RaaS static JSON API hosted on GitHub Pages.
|
|
10
|
+
*
|
|
11
|
+
* @package maizied/roast-api
|
|
12
|
+
* @author Maizied <mdshuvo40@gmail.com>
|
|
13
|
+
* @license MIT
|
|
14
|
+
* @link https://maijied.github.io/roast-as-a-service/
|
|
15
|
+
*/
|
|
16
|
+
class RaaS
|
|
17
|
+
{
|
|
18
|
+
private const BASE_URL = 'https://maijied.github.io/roast-as-a-service/api';
|
|
19
|
+
|
|
20
|
+
/** @var array|null In-memory manifest cache */
|
|
21
|
+
private static ?array $manifestCache = null;
|
|
22
|
+
|
|
23
|
+
/** @var array<string, array> In-memory shard cache */
|
|
24
|
+
private static array $shardCache = [];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Fetch the API manifest.
|
|
28
|
+
*
|
|
29
|
+
* @return array Decoded manifest data
|
|
30
|
+
* @throws \RuntimeException If the fetch fails
|
|
31
|
+
*/
|
|
32
|
+
public static function getManifest(): array
|
|
33
|
+
{
|
|
34
|
+
if (self::$manifestCache !== null) {
|
|
35
|
+
return self::$manifestCache;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
$url = self::BASE_URL . '/manifest.json';
|
|
39
|
+
$json = @file_get_contents($url);
|
|
40
|
+
|
|
41
|
+
if ($json === false) {
|
|
42
|
+
throw new \RuntimeException("Failed to fetch manifest from {$url}");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
self::$manifestCache = json_decode($json, true);
|
|
46
|
+
return self::$manifestCache;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Fetch a specific shard.
|
|
51
|
+
*
|
|
52
|
+
* @param string $lang Language code (e.g., 'en', 'bn')
|
|
53
|
+
* @param int $shard Shard number (default: 1)
|
|
54
|
+
* @return array Decoded shard data
|
|
55
|
+
* @throws \RuntimeException If the fetch fails
|
|
56
|
+
*/
|
|
57
|
+
public static function getShard(string $lang = 'en', int $shard = 1): array
|
|
58
|
+
{
|
|
59
|
+
$key = "{$lang}-{$shard}";
|
|
60
|
+
|
|
61
|
+
if (isset(self::$shardCache[$key])) {
|
|
62
|
+
return self::$shardCache[$key];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
$url = self::BASE_URL . "/{$lang}/roasts-{$lang}-{$shard}.json";
|
|
66
|
+
$json = @file_get_contents($url);
|
|
67
|
+
|
|
68
|
+
if ($json === false) {
|
|
69
|
+
throw new \RuntimeException("Failed to fetch shard from {$url}");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
self::$shardCache[$key] = json_decode($json, true);
|
|
73
|
+
return self::$shardCache[$key];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get a random roast.
|
|
78
|
+
*
|
|
79
|
+
* @param array $options {
|
|
80
|
+
* @type string $lang Language code ('en' or 'bn'). Default: 'en'.
|
|
81
|
+
* @type int $intensity Filter by intensity (1–3). Default: null (any).
|
|
82
|
+
* @type int $maxLength Maximum text length. Default: null (any).
|
|
83
|
+
* }
|
|
84
|
+
* @return array Roast object with keys: id, text, intensity, length
|
|
85
|
+
* @throws \RuntimeException If fetch fails or no roasts match filters
|
|
86
|
+
*/
|
|
87
|
+
public static function getRandomRoast(array $options = []): array
|
|
88
|
+
{
|
|
89
|
+
$lang = $options['lang'] ?? 'en';
|
|
90
|
+
$intensity = $options['intensity'] ?? null;
|
|
91
|
+
$maxLength = $options['maxLength'] ?? null;
|
|
92
|
+
|
|
93
|
+
$shard = self::getShard($lang);
|
|
94
|
+
$roasts = $shard['roasts'] ?? [];
|
|
95
|
+
|
|
96
|
+
// Apply filters
|
|
97
|
+
if ($intensity !== null) {
|
|
98
|
+
$roasts = array_filter($roasts, fn($r) => ($r['intensity'] ?? 0) === $intensity);
|
|
99
|
+
}
|
|
100
|
+
if ($maxLength !== null) {
|
|
101
|
+
$roasts = array_filter($roasts, fn($r) => ($r['length'] ?? 0) <= $maxLength);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
$roasts = array_values($roasts);
|
|
105
|
+
|
|
106
|
+
if (empty($roasts)) {
|
|
107
|
+
throw new \RuntimeException('No roasts match the given filters.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return $roasts[array_rand($roasts)];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get all roasts for a language.
|
|
115
|
+
*
|
|
116
|
+
* @param string $lang Language code. Default: 'en'.
|
|
117
|
+
* @return array List of roast objects
|
|
118
|
+
*/
|
|
119
|
+
public static function getAllRoasts(string $lang = 'en'): array
|
|
120
|
+
{
|
|
121
|
+
$shard = self::getShard($lang);
|
|
122
|
+
return $shard['roasts'] ?? [];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Clear the in-memory cache.
|
|
127
|
+
*/
|
|
128
|
+
public static function clearCache(): void
|
|
129
|
+
{
|
|
130
|
+
self::$manifestCache = null;
|
|
131
|
+
self::$shardCache = [];
|
|
132
|
+
}
|
|
133
|
+
}
|