player2 0.0.1__py3-none-any.whl
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.
- player2/__init__.py +1 -0
- player2/core.py +130 -0
- player2-0.0.1.dist-info/METADATA +62 -0
- player2-0.0.1.dist-info/RECORD +6 -0
- player2-0.0.1.dist-info/WHEEL +5 -0
- player2-0.0.1.dist-info/top_level.txt +1 -0
player2/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .core import APIClient
|
player2/core.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import threading
|
|
3
|
+
import requests
|
|
4
|
+
from typing import Optional, Dict, Any, List
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class APIClient:
|
|
8
|
+
def __init__(self, game_id: str, base_url: Optional[str] = None):
|
|
9
|
+
self.game_id = game_id
|
|
10
|
+
|
|
11
|
+
# Fallback for base_url if not provided
|
|
12
|
+
if not base_url:
|
|
13
|
+
self.base_url = "http://127.0.0.1:4315/v1"
|
|
14
|
+
else:
|
|
15
|
+
self.base_url = base_url
|
|
16
|
+
|
|
17
|
+
# Automatically fetch the p2Key upon initialization
|
|
18
|
+
self.p2_key = self._login()
|
|
19
|
+
|
|
20
|
+
# Start the background health check loop
|
|
21
|
+
self._start_health_checker()
|
|
22
|
+
|
|
23
|
+
def _login(self) -> str:
|
|
24
|
+
login_url = f"http://localhost:4315/v1/login/web/{self.game_id}"
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
response = requests.post(login_url, json={})
|
|
28
|
+
response.raise_for_status()
|
|
29
|
+
data = response.json()
|
|
30
|
+
return data["p2Key"]
|
|
31
|
+
except requests.exceptions.RequestException as e:
|
|
32
|
+
raise RuntimeError(f"Login failed: {e}")
|
|
33
|
+
|
|
34
|
+
def _start_health_checker(self):
|
|
35
|
+
"""Starts a background thread that pings the health endpoint every 60 seconds."""
|
|
36
|
+
|
|
37
|
+
def health_loop():
|
|
38
|
+
health_url = "http://127.0.0.1:4315/v1/health"
|
|
39
|
+
while True:
|
|
40
|
+
try:
|
|
41
|
+
requests.get(health_url, timeout=5)
|
|
42
|
+
except requests.exceptions.RequestException:
|
|
43
|
+
pass
|
|
44
|
+
time.sleep(60)
|
|
45
|
+
|
|
46
|
+
thread = threading.Thread(target=health_loop, daemon=True)
|
|
47
|
+
thread.start()
|
|
48
|
+
|
|
49
|
+
def chat(self, user: str, system: Optional[str] = None, stream: bool = False) -> str:
|
|
50
|
+
endpoint = f"{self.base_url}/chat/completions"
|
|
51
|
+
|
|
52
|
+
messages: List[Dict[str, str]] = [
|
|
53
|
+
{"role": "user", "content": user}
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
if system is not None:
|
|
57
|
+
messages.insert(0, {"role": "system", "content": system})
|
|
58
|
+
|
|
59
|
+
payload = {
|
|
60
|
+
"messages": messages,
|
|
61
|
+
"stream": stream
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
headers = {
|
|
65
|
+
"Authorization": f"Bearer {self.p2_key}"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
response = requests.post(endpoint, json=payload, headers=headers)
|
|
70
|
+
response.raise_for_status()
|
|
71
|
+
data = response.json()
|
|
72
|
+
|
|
73
|
+
return data["choices"][0]["message"]["content"]
|
|
74
|
+
|
|
75
|
+
except requests.exceptions.HTTPError as e:
|
|
76
|
+
error_body = e.response.text if e.response else "No error body"
|
|
77
|
+
raise RuntimeError(f"API request failed with status {e.response.status_code}: {error_body}")
|
|
78
|
+
except requests.exceptions.RequestException as e:
|
|
79
|
+
raise RuntimeError(f"Network error occurred: {e}")
|
|
80
|
+
except (KeyError, IndexError) as e:
|
|
81
|
+
raise RuntimeError(f"Unexpected response format from API: {e}")
|
|
82
|
+
|
|
83
|
+
def speak(
|
|
84
|
+
self,
|
|
85
|
+
text: str,
|
|
86
|
+
instructions: Optional[str] = "Speak with a sad tone",
|
|
87
|
+
voice_gender: str = "female",
|
|
88
|
+
voice_language: str = "en_US",
|
|
89
|
+
voice_ids: Optional[List[str]] = None,
|
|
90
|
+
speed: float = 1.0,
|
|
91
|
+
audio_format: str = "mp3",
|
|
92
|
+
play_in_app: bool = True
|
|
93
|
+
) -> Dict[str, Any]:
|
|
94
|
+
"""Sends a Text-to-Speech request to the local TTS endpoint."""
|
|
95
|
+
tts_url = "http://127.0.0.1:4315/v1/tts/speak"
|
|
96
|
+
|
|
97
|
+
# Use default voice ID from your curl example if none provided
|
|
98
|
+
if voice_ids is None:
|
|
99
|
+
voice_ids = ["01955d76-ed5b-73e0-a88d-cbeb3c5b499d"]
|
|
100
|
+
|
|
101
|
+
payload: Dict[str, Any] = {
|
|
102
|
+
"audio_format": audio_format,
|
|
103
|
+
"play_in_app": play_in_app,
|
|
104
|
+
"speed": speed,
|
|
105
|
+
"text": text,
|
|
106
|
+
"voice_gender": voice_gender,
|
|
107
|
+
"voice_ids": voice_ids,
|
|
108
|
+
"voice_language": voice_language
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Add advanced voice instructions if provided
|
|
112
|
+
if instructions is not None:
|
|
113
|
+
payload["advanced_voice"] = {
|
|
114
|
+
"instructions": instructions
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
headers = {
|
|
118
|
+
"accept": "application/json",
|
|
119
|
+
"Content-Type": "application/json"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
response = requests.post(tts_url, json=payload, headers=headers)
|
|
124
|
+
response.raise_for_status()
|
|
125
|
+
return response.json()
|
|
126
|
+
except requests.exceptions.HTTPError as e:
|
|
127
|
+
error_body = e.response.text if e.response else "No error body"
|
|
128
|
+
raise RuntimeError(f"TTS request failed with status {e.response.status_code}: {error_body}")
|
|
129
|
+
except requests.exceptions.RequestException as e:
|
|
130
|
+
raise RuntimeError(f"TTS network error occurred: {e}")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: player2
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A lightweight client for Player2
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: requests
|
|
11
|
+
|
|
12
|
+
# Local API Client
|
|
13
|
+
|
|
14
|
+
A lightweight Python client designed to easily interact with Player2 Local Endpoints.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Install the package via pip:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install player2
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### 1. Initialize the Client
|
|
27
|
+
|
|
28
|
+
When initializing the client, pass your `game_id`. It will automatically handle web login to fetch authorization keys and spin up a background health-check loop.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from player2 import APIClient
|
|
32
|
+
|
|
33
|
+
client = APIClient(game_id="your_game_id") # Get the gameID from the player2 website
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Chat Completions
|
|
37
|
+
|
|
38
|
+
Send user queries with optional system instructions:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
response = client.chat(
|
|
42
|
+
user="Hello, how are you doing today?",
|
|
43
|
+
system="You are a helpful and witty assistant."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
print(response)
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Text-to-Speech (TTS)
|
|
51
|
+
|
|
52
|
+
Trigger speech generation locally:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
tts_response = client.speak(
|
|
56
|
+
text="Hello, how are you doing today?",
|
|
57
|
+
instructions="Speak with a cheerful tone",
|
|
58
|
+
speed=1.0
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
print(tts_response)
|
|
62
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
player2/__init__.py,sha256=PsI5TL5RCdziUikX_zfngmRAE2GRX3ljIirRtjfmJmg,27
|
|
2
|
+
player2/core.py,sha256=CHDrKHaFH4LqsXkJTZDUqaJa0SBZFKn9Y5PZd1-dUF0,4547
|
|
3
|
+
player2-0.0.1.dist-info/METADATA,sha256=DvoMgHTiFojpZjBWUbB7tL879QkNSnJLqjHhojP6woQ,1319
|
|
4
|
+
player2-0.0.1.dist-info/WHEEL,sha256=a-udL2m4V_6Yn8b-uKzWb12RjRxwwMo6ohYFM24tpaY,91
|
|
5
|
+
player2-0.0.1.dist-info/top_level.txt,sha256=LykiWt7T8bwUYs9MFcsnmZZVlXTPqfVJbkzk-rtW9d4,8
|
|
6
|
+
player2-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
player2
|