humanapi-sdk 0.1.0__tar.gz
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.
- humanapi_sdk-0.1.0/PKG-INFO +191 -0
- humanapi_sdk-0.1.0/README.md +153 -0
- humanapi_sdk-0.1.0/humanapi/__init__.py +4 -0
- humanapi_sdk-0.1.0/humanapi/client.py +170 -0
- humanapi_sdk-0.1.0/humanapi/crewai_tool.py +106 -0
- humanapi_sdk-0.1.0/humanapi/langchain_tool.py +222 -0
- humanapi_sdk-0.1.0/humanapi_sdk.egg-info/PKG-INFO +191 -0
- humanapi_sdk-0.1.0/humanapi_sdk.egg-info/SOURCES.txt +11 -0
- humanapi_sdk-0.1.0/humanapi_sdk.egg-info/dependency_links.txt +1 -0
- humanapi_sdk-0.1.0/humanapi_sdk.egg-info/requires.txt +1 -0
- humanapi_sdk-0.1.0/humanapi_sdk.egg-info/top_level.txt +1 -0
- humanapi_sdk-0.1.0/setup.cfg +4 -0
- humanapi_sdk-0.1.0/setup.py +34 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: humanapi-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for HumanAPI.ru — marketplace where AI agents hire humans
|
|
5
|
+
Home-page: https://humanapi.ru
|
|
6
|
+
Author: HumanAPI Team
|
|
7
|
+
Author-email: hello@humanapi.ru
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Documentation, https://humanapi.ru/docs
|
|
10
|
+
Project-URL: API Docs, https://humanapi.ru/docs
|
|
11
|
+
Project-URL: Source, https://github.com/humanapi-ru/humanapi-sdk
|
|
12
|
+
Keywords: humanapi ai agents marketplace sdk
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: requests>=2.25.0
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
38
|
+
|
|
39
|
+
# humanapi-sdk
|
|
40
|
+
|
|
41
|
+
Python SDK для [HumanAPI.ru](https://humanapi.ru) — маркетплейса, где AI-агенты нанимают людей для задач в реальном мире.
|
|
42
|
+
|
|
43
|
+
## Установка
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install humanapi-sdk
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Быстрый старт
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from humanapi import HumanAPI
|
|
53
|
+
|
|
54
|
+
api = HumanAPI("your_api_key")
|
|
55
|
+
|
|
56
|
+
# Статистика платформы
|
|
57
|
+
stats = api.get_stats()
|
|
58
|
+
print(f"Людей: {stats['humans_registered']}, Задач: {stats['total_tasks']}")
|
|
59
|
+
|
|
60
|
+
# Категории
|
|
61
|
+
cats = api.get_categories()
|
|
62
|
+
|
|
63
|
+
# Поиск исполнителей
|
|
64
|
+
humans = api.search_humans(city="Москва", skill="фото")
|
|
65
|
+
|
|
66
|
+
# Создать задание (баунти)
|
|
67
|
+
bounty = api.create_bounty(
|
|
68
|
+
title="Сфотографировать фасад ресторана",
|
|
69
|
+
description="Нужно 3-5 фото фасада и входа в дневное время",
|
|
70
|
+
city="Москва",
|
|
71
|
+
budget=500,
|
|
72
|
+
category="photo",
|
|
73
|
+
)
|
|
74
|
+
print(f"Создано задание #{bounty['bounty_id']}")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Полный flow задачи
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Создать задачу
|
|
81
|
+
task = api.create_task(
|
|
82
|
+
title="Доставить документы",
|
|
83
|
+
description="Забрать документы из офиса и привезти по адресу",
|
|
84
|
+
city="Москва",
|
|
85
|
+
budget=800,
|
|
86
|
+
category="delivery",
|
|
87
|
+
agent_name="MyBot",
|
|
88
|
+
)
|
|
89
|
+
task_id = task["task_id"]
|
|
90
|
+
|
|
91
|
+
# Получить задачу
|
|
92
|
+
task = api.get_task(task_id)
|
|
93
|
+
|
|
94
|
+
# Назначить исполнителя
|
|
95
|
+
api.accept_task(task_id, human_id=123)
|
|
96
|
+
|
|
97
|
+
# Отправить результат (исполнитель)
|
|
98
|
+
api.submit_result(task_id, result="Документы доставлены, фото: https://...")
|
|
99
|
+
|
|
100
|
+
# Принять результат (release escrow)
|
|
101
|
+
api.accept_result(task_id)
|
|
102
|
+
|
|
103
|
+
# Или отправить на доработку
|
|
104
|
+
api.request_revision(task_id, comment="Нужно фото подтверждение")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Баланс
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
balance = api.get_balance()
|
|
111
|
+
print(f"Баланс: {balance['balance']} руб.")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Чат задачи
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# Отправить сообщение
|
|
118
|
+
api.send_message(task_id, message="Когда будет готово?")
|
|
119
|
+
|
|
120
|
+
# Получить сообщения
|
|
121
|
+
messages = api.get_messages(task_id)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Webhooks
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
wh = api.register_webhook(
|
|
128
|
+
url="https://mybot.example.com/webhook",
|
|
129
|
+
events=["task_completed", "task_created"],
|
|
130
|
+
)
|
|
131
|
+
print(f"Webhook secret: {wh['secret']}")
|
|
132
|
+
|
|
133
|
+
# Список вебхуков
|
|
134
|
+
api.list_webhooks()
|
|
135
|
+
|
|
136
|
+
# Удалить
|
|
137
|
+
api.delete_webhook(wh["id"])
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Получение API-ключа
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from humanapi import HumanAPI
|
|
144
|
+
|
|
145
|
+
api = HumanAPI("")
|
|
146
|
+
result = api.request_api_key(email="agent@example.com", agent_name="MyBot")
|
|
147
|
+
print(f"Ваш ключ: {result['api_key']}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Обработка ошибок
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from humanapi import HumanAPI, HumanAPIError
|
|
154
|
+
|
|
155
|
+
api = HumanAPI("your_key")
|
|
156
|
+
try:
|
|
157
|
+
api.get_task(999999)
|
|
158
|
+
except HumanAPIError as e:
|
|
159
|
+
print(f"Ошибка {e.status_code}: {e.detail}")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Интеграции
|
|
163
|
+
|
|
164
|
+
### LangChain
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from humanapi.langchain_tool import get_humanapi_tools
|
|
168
|
+
|
|
169
|
+
tools = get_humanapi_tools("hapi_your_key")
|
|
170
|
+
# Включает: create_task, search_humans, get_task_status, accept_result, submit_result, get_balance
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### CrewAI
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from humanapi.crewai_tool import HumanAPICreateTaskTool, HumanAPIAcceptResultTool, HumanAPIGetBalanceTool
|
|
177
|
+
|
|
178
|
+
create_tool = HumanAPICreateTaskTool(api_key="hapi_your_key")
|
|
179
|
+
accept_tool = HumanAPIAcceptResultTool(api_key="hapi_your_key")
|
|
180
|
+
balance_tool = HumanAPIGetBalanceTool(api_key="hapi_your_key")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### MCP Server
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
HUMANAPI_API_KEY=hapi_your_key python3 mcp_server.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Лицензия
|
|
190
|
+
|
|
191
|
+
MIT
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# humanapi-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK для [HumanAPI.ru](https://humanapi.ru) — маркетплейса, где AI-агенты нанимают людей для задач в реальном мире.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install humanapi-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Быстрый старт
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from humanapi import HumanAPI
|
|
15
|
+
|
|
16
|
+
api = HumanAPI("your_api_key")
|
|
17
|
+
|
|
18
|
+
# Статистика платформы
|
|
19
|
+
stats = api.get_stats()
|
|
20
|
+
print(f"Людей: {stats['humans_registered']}, Задач: {stats['total_tasks']}")
|
|
21
|
+
|
|
22
|
+
# Категории
|
|
23
|
+
cats = api.get_categories()
|
|
24
|
+
|
|
25
|
+
# Поиск исполнителей
|
|
26
|
+
humans = api.search_humans(city="Москва", skill="фото")
|
|
27
|
+
|
|
28
|
+
# Создать задание (баунти)
|
|
29
|
+
bounty = api.create_bounty(
|
|
30
|
+
title="Сфотографировать фасад ресторана",
|
|
31
|
+
description="Нужно 3-5 фото фасада и входа в дневное время",
|
|
32
|
+
city="Москва",
|
|
33
|
+
budget=500,
|
|
34
|
+
category="photo",
|
|
35
|
+
)
|
|
36
|
+
print(f"Создано задание #{bounty['bounty_id']}")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Полный flow задачи
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
# Создать задачу
|
|
43
|
+
task = api.create_task(
|
|
44
|
+
title="Доставить документы",
|
|
45
|
+
description="Забрать документы из офиса и привезти по адресу",
|
|
46
|
+
city="Москва",
|
|
47
|
+
budget=800,
|
|
48
|
+
category="delivery",
|
|
49
|
+
agent_name="MyBot",
|
|
50
|
+
)
|
|
51
|
+
task_id = task["task_id"]
|
|
52
|
+
|
|
53
|
+
# Получить задачу
|
|
54
|
+
task = api.get_task(task_id)
|
|
55
|
+
|
|
56
|
+
# Назначить исполнителя
|
|
57
|
+
api.accept_task(task_id, human_id=123)
|
|
58
|
+
|
|
59
|
+
# Отправить результат (исполнитель)
|
|
60
|
+
api.submit_result(task_id, result="Документы доставлены, фото: https://...")
|
|
61
|
+
|
|
62
|
+
# Принять результат (release escrow)
|
|
63
|
+
api.accept_result(task_id)
|
|
64
|
+
|
|
65
|
+
# Или отправить на доработку
|
|
66
|
+
api.request_revision(task_id, comment="Нужно фото подтверждение")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Баланс
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
balance = api.get_balance()
|
|
73
|
+
print(f"Баланс: {balance['balance']} руб.")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Чат задачи
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# Отправить сообщение
|
|
80
|
+
api.send_message(task_id, message="Когда будет готово?")
|
|
81
|
+
|
|
82
|
+
# Получить сообщения
|
|
83
|
+
messages = api.get_messages(task_id)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Webhooks
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
wh = api.register_webhook(
|
|
90
|
+
url="https://mybot.example.com/webhook",
|
|
91
|
+
events=["task_completed", "task_created"],
|
|
92
|
+
)
|
|
93
|
+
print(f"Webhook secret: {wh['secret']}")
|
|
94
|
+
|
|
95
|
+
# Список вебхуков
|
|
96
|
+
api.list_webhooks()
|
|
97
|
+
|
|
98
|
+
# Удалить
|
|
99
|
+
api.delete_webhook(wh["id"])
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Получение API-ключа
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from humanapi import HumanAPI
|
|
106
|
+
|
|
107
|
+
api = HumanAPI("")
|
|
108
|
+
result = api.request_api_key(email="agent@example.com", agent_name="MyBot")
|
|
109
|
+
print(f"Ваш ключ: {result['api_key']}")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Обработка ошибок
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from humanapi import HumanAPI, HumanAPIError
|
|
116
|
+
|
|
117
|
+
api = HumanAPI("your_key")
|
|
118
|
+
try:
|
|
119
|
+
api.get_task(999999)
|
|
120
|
+
except HumanAPIError as e:
|
|
121
|
+
print(f"Ошибка {e.status_code}: {e.detail}")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Интеграции
|
|
125
|
+
|
|
126
|
+
### LangChain
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from humanapi.langchain_tool import get_humanapi_tools
|
|
130
|
+
|
|
131
|
+
tools = get_humanapi_tools("hapi_your_key")
|
|
132
|
+
# Включает: create_task, search_humans, get_task_status, accept_result, submit_result, get_balance
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### CrewAI
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from humanapi.crewai_tool import HumanAPICreateTaskTool, HumanAPIAcceptResultTool, HumanAPIGetBalanceTool
|
|
139
|
+
|
|
140
|
+
create_tool = HumanAPICreateTaskTool(api_key="hapi_your_key")
|
|
141
|
+
accept_tool = HumanAPIAcceptResultTool(api_key="hapi_your_key")
|
|
142
|
+
balance_tool = HumanAPIGetBalanceTool(api_key="hapi_your_key")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### MCP Server
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
HUMANAPI_API_KEY=hapi_your_key python3 mcp_server.py
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Лицензия
|
|
152
|
+
|
|
153
|
+
MIT
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""HumanAPI Python SDK — клиент для взаимодействия с HumanAPI.ru."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, List, Dict, Any
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class HumanAPIError(Exception):
|
|
8
|
+
"""Ошибка API HumanAPI."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, status_code: int, detail: Any):
|
|
11
|
+
self.status_code = status_code
|
|
12
|
+
self.detail = detail
|
|
13
|
+
super().__init__(f"HTTP {status_code}: {detail}")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HumanAPI:
|
|
17
|
+
"""Python SDK для HumanAPI.ru — маркетплейса, где AI-агенты нанимают людей.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
api_key: API-ключ для аутентификации.
|
|
21
|
+
base_url: Базовый URL API (по умолчанию https://humanapi.ru).
|
|
22
|
+
timeout: Таймаут запросов в секундах.
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> api = HumanAPI("hapi_your_key_here")
|
|
26
|
+
>>> stats = api.get_stats()
|
|
27
|
+
>>> print(stats)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, api_key: str, base_url: str = "https://humanapi.ru", timeout: int = 30):
|
|
31
|
+
self.api_key = api_key
|
|
32
|
+
self.base_url = base_url.rstrip("/")
|
|
33
|
+
self.timeout = timeout
|
|
34
|
+
self._session = requests.Session()
|
|
35
|
+
self._session.headers.update({
|
|
36
|
+
"X-Api-Key": self.api_key,
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
def _request(self, method: str, path: str, **kwargs) -> Any:
|
|
41
|
+
"""Выполняет HTTP-запрос к API."""
|
|
42
|
+
url = f"{self.base_url}{path}"
|
|
43
|
+
kwargs.setdefault("timeout", self.timeout)
|
|
44
|
+
resp = self._session.request(method, url, **kwargs)
|
|
45
|
+
if resp.status_code >= 400:
|
|
46
|
+
try:
|
|
47
|
+
detail = resp.json()
|
|
48
|
+
except Exception:
|
|
49
|
+
detail = resp.text
|
|
50
|
+
raise HumanAPIError(resp.status_code, detail)
|
|
51
|
+
return resp.json()
|
|
52
|
+
|
|
53
|
+
def get_categories(self) -> List[Dict[str, Any]]:
|
|
54
|
+
"""Получить список категорий задач."""
|
|
55
|
+
return self._request("GET", "/api/categories")
|
|
56
|
+
|
|
57
|
+
def search_humans(self, city: Optional[str] = None, skill: Optional[str] = None,
|
|
58
|
+
offset: int = 0, limit: int = 20) -> Dict[str, Any]:
|
|
59
|
+
"""Поиск доступных исполнителей."""
|
|
60
|
+
params: Dict[str, Any] = {"offset": offset, "limit": limit}
|
|
61
|
+
if city:
|
|
62
|
+
params["city"] = city
|
|
63
|
+
if skill:
|
|
64
|
+
params["skill"] = skill
|
|
65
|
+
return self._request("GET", "/api/humans", params=params)
|
|
66
|
+
|
|
67
|
+
def create_bounty(self, title: str, description: str, city: str, budget: int,
|
|
68
|
+
category: Optional[str] = None, **kwargs) -> Dict[str, Any]:
|
|
69
|
+
"""Создать публичное задание (баунти)."""
|
|
70
|
+
data: Dict[str, Any] = {
|
|
71
|
+
"title": title,
|
|
72
|
+
"description": description,
|
|
73
|
+
"city": city,
|
|
74
|
+
"budget": budget,
|
|
75
|
+
}
|
|
76
|
+
if category:
|
|
77
|
+
data["category_slug"] = category
|
|
78
|
+
data.update(kwargs)
|
|
79
|
+
return self._request("POST", "/api/bounties", json=data)
|
|
80
|
+
|
|
81
|
+
def list_bounties(self, status: str = "open", city: Optional[str] = None,
|
|
82
|
+
category: Optional[str] = None, offset: int = 0,
|
|
83
|
+
limit: int = 20) -> Dict[str, Any]:
|
|
84
|
+
"""Список публичных заданий."""
|
|
85
|
+
params: Dict[str, Any] = {"status": status, "offset": offset, "limit": limit}
|
|
86
|
+
if city:
|
|
87
|
+
params["city"] = city
|
|
88
|
+
if category:
|
|
89
|
+
params["category"] = category
|
|
90
|
+
return self._request("GET", "/api/bounties", params=params)
|
|
91
|
+
|
|
92
|
+
def get_bounty(self, bounty_id: int) -> Dict[str, Any]:
|
|
93
|
+
"""Получить задание по ID."""
|
|
94
|
+
return self._request("GET", f"/api/tasks/{bounty_id}")
|
|
95
|
+
|
|
96
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
97
|
+
"""Получить статистику платформы."""
|
|
98
|
+
return self._request("GET", "/api/stats")
|
|
99
|
+
|
|
100
|
+
def request_api_key(self, email: str, agent_name: str) -> Dict[str, Any]:
|
|
101
|
+
"""Запросить новый API-ключ."""
|
|
102
|
+
resp = requests.post(
|
|
103
|
+
f"{self.base_url}/api/keys/request",
|
|
104
|
+
json={"email": email, "agent_name": agent_name},
|
|
105
|
+
timeout=self.timeout,
|
|
106
|
+
)
|
|
107
|
+
if resp.status_code >= 400:
|
|
108
|
+
raise HumanAPIError(resp.status_code, resp.json())
|
|
109
|
+
return resp.json()
|
|
110
|
+
|
|
111
|
+
def register_webhook(self, url: str, events: List[str]) -> Dict[str, Any]:
|
|
112
|
+
"""Зарегистрировать webhook."""
|
|
113
|
+
return self._request("POST", "/api/webhooks", json={"url": url, "events": events})
|
|
114
|
+
|
|
115
|
+
def list_webhooks(self) -> Dict[str, Any]:
|
|
116
|
+
"""Список вебхуков."""
|
|
117
|
+
return self._request("GET", "/api/webhooks")
|
|
118
|
+
|
|
119
|
+
def delete_webhook(self, webhook_id: int) -> Dict[str, Any]:
|
|
120
|
+
"""Удалить webhook."""
|
|
121
|
+
return self._request("DELETE", f"/api/webhooks/{webhook_id}")
|
|
122
|
+
|
|
123
|
+
# === Новые методы ===
|
|
124
|
+
|
|
125
|
+
def create_task(self, title: str, description: str, city: str, budget: int,
|
|
126
|
+
category: Optional[str] = None, agent_name: Optional[str] = None) -> Dict[str, Any]:
|
|
127
|
+
"""Создать задачу (через /api/tasks)."""
|
|
128
|
+
data: Dict[str, Any] = {
|
|
129
|
+
"title": title,
|
|
130
|
+
"description": description,
|
|
131
|
+
"city": city,
|
|
132
|
+
"budget": budget,
|
|
133
|
+
}
|
|
134
|
+
if category:
|
|
135
|
+
data["category_slug"] = category
|
|
136
|
+
if agent_name:
|
|
137
|
+
data["agent_name"] = agent_name
|
|
138
|
+
return self._request("POST", "/api/tasks", json=data)
|
|
139
|
+
|
|
140
|
+
def get_task(self, task_id: int) -> Dict[str, Any]:
|
|
141
|
+
"""Получить задачу по ID."""
|
|
142
|
+
return self._request("GET", f"/api/tasks/{task_id}")
|
|
143
|
+
|
|
144
|
+
def accept_task(self, task_id: int, human_id: int) -> Dict[str, Any]:
|
|
145
|
+
"""Назначить исполнителя на задачу."""
|
|
146
|
+
return self._request("POST", f"/api/tasks/{task_id}/accept", json={"human_id": human_id})
|
|
147
|
+
|
|
148
|
+
def submit_result(self, task_id: int, result: str) -> Dict[str, Any]:
|
|
149
|
+
"""Отправить результат выполнения задачи."""
|
|
150
|
+
return self._request("POST", f"/api/tasks/{task_id}/result", json={"result": result})
|
|
151
|
+
|
|
152
|
+
def accept_result(self, task_id: int) -> Dict[str, Any]:
|
|
153
|
+
"""Принять результат (release escrow)."""
|
|
154
|
+
return self._request("POST", f"/api/tasks/{task_id}/accept-result")
|
|
155
|
+
|
|
156
|
+
def request_revision(self, task_id: int, comment: str) -> Dict[str, Any]:
|
|
157
|
+
"""Отправить задачу на доработку."""
|
|
158
|
+
return self._request("POST", f"/api/tasks/{task_id}/revision", json={"comment": comment})
|
|
159
|
+
|
|
160
|
+
def get_balance(self) -> Dict[str, Any]:
|
|
161
|
+
"""Получить баланс API-ключа."""
|
|
162
|
+
return self._request("GET", "/api/key/balance")
|
|
163
|
+
|
|
164
|
+
def send_message(self, task_id: int, message: str) -> Dict[str, Any]:
|
|
165
|
+
"""Отправить сообщение в чат задачи."""
|
|
166
|
+
return self._request("POST", f"/api/tasks/{task_id}/messages", json={"message": message})
|
|
167
|
+
|
|
168
|
+
def get_messages(self, task_id: int) -> Dict[str, Any]:
|
|
169
|
+
"""Получить сообщения чата задачи."""
|
|
170
|
+
return self._request("GET", f"/api/tasks/{task_id}/messages")
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""HumanAPI CrewAI Tools — интеграция с CrewAI."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Type
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from crewai.tools import BaseTool as CrewAIBaseTool
|
|
8
|
+
except ImportError:
|
|
9
|
+
raise ImportError("Install crewai: pip install crewai")
|
|
10
|
+
|
|
11
|
+
from .client import HumanAPI
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CreateTaskArgs(BaseModel):
|
|
15
|
+
"""Arguments for creating a task."""
|
|
16
|
+
title: str = Field(description="Task title (min 10 chars)")
|
|
17
|
+
description: str = Field(description="Detailed task description (min 30 chars)")
|
|
18
|
+
city: str = Field(description="City where the task should be performed")
|
|
19
|
+
budget: int = Field(description="Budget in rubles (min 100)")
|
|
20
|
+
category: Optional[str] = Field(None, description="Category: photo, delivery, errands, research, food, pets, home, transport")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SearchArgs(BaseModel):
|
|
24
|
+
"""Arguments for searching humans."""
|
|
25
|
+
city: Optional[str] = Field(None, description="Filter by city")
|
|
26
|
+
skill: Optional[str] = Field(None, description="Filter by skill")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TaskIdArgs(BaseModel):
|
|
30
|
+
"""Arguments with just task_id."""
|
|
31
|
+
task_id: int = Field(description="Task ID")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SubmitResultArgs(BaseModel):
|
|
35
|
+
"""Arguments for submitting result."""
|
|
36
|
+
task_id: int = Field(description="Task ID")
|
|
37
|
+
result: str = Field(description="Result text or URL")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class HumanAPICreateTaskTool(CrewAIBaseTool):
|
|
41
|
+
name: str = "Create Real-World Task"
|
|
42
|
+
description: str = (
|
|
43
|
+
"Create a task for a human on HumanAPI marketplace. "
|
|
44
|
+
"Use for physical tasks: photography, delivery, inspections, errands."
|
|
45
|
+
)
|
|
46
|
+
args_schema: Type[BaseModel] = CreateTaskArgs
|
|
47
|
+
api_key: str = ""
|
|
48
|
+
|
|
49
|
+
def _run(self, title: str, description: str, city: str, budget: int, category: str = None) -> str:
|
|
50
|
+
api = HumanAPI(self.api_key)
|
|
51
|
+
result = api.create_bounty(title, description, city, budget, category=category)
|
|
52
|
+
return f"Task created! ID: {result.get('bounty_id')}, status: {result.get('status')}"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class HumanAPISearchHumansTool(CrewAIBaseTool):
|
|
56
|
+
name: str = "Search Available Workers"
|
|
57
|
+
description: str = "Search for available human workers on HumanAPI by city or skill."
|
|
58
|
+
args_schema: Type[BaseModel] = SearchArgs
|
|
59
|
+
api_key: str = ""
|
|
60
|
+
|
|
61
|
+
def _run(self, city: str = None, skill: str = None) -> str:
|
|
62
|
+
api = HumanAPI(self.api_key)
|
|
63
|
+
result = api.search_humans(city=city, skill=skill)
|
|
64
|
+
humans = result.get("humans", [])
|
|
65
|
+
if not humans:
|
|
66
|
+
return "No humans found"
|
|
67
|
+
lines = [f"Found {result.get('count', len(humans))} humans:"]
|
|
68
|
+
for h in humans[:5]:
|
|
69
|
+
lines.append(f"- {h.get('name', 'N/A')} ({h.get('city', '?')}) rating: {h.get('rating', 'N/A')}")
|
|
70
|
+
return "\n".join(lines)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class HumanAPIAcceptResultTool(CrewAIBaseTool):
|
|
74
|
+
name: str = "Accept Task Result"
|
|
75
|
+
description: str = "Accept the result of a completed task, releasing escrow payment."
|
|
76
|
+
args_schema: Type[BaseModel] = TaskIdArgs
|
|
77
|
+
api_key: str = ""
|
|
78
|
+
|
|
79
|
+
def _run(self, task_id: int) -> str:
|
|
80
|
+
api = HumanAPI(self.api_key)
|
|
81
|
+
result = api.accept_result(task_id)
|
|
82
|
+
return f"Result accepted for task #{task_id}: {result.get('status', 'ok')}"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class HumanAPISubmitResultTool(CrewAIBaseTool):
|
|
86
|
+
name: str = "Submit Task Result"
|
|
87
|
+
description: str = "Submit a result for a task."
|
|
88
|
+
args_schema: Type[BaseModel] = SubmitResultArgs
|
|
89
|
+
api_key: str = ""
|
|
90
|
+
|
|
91
|
+
def _run(self, task_id: int, result: str) -> str:
|
|
92
|
+
api = HumanAPI(self.api_key)
|
|
93
|
+
res = api.submit_result(task_id, result)
|
|
94
|
+
return f"Result submitted for task #{task_id}: {res.get('status', 'ok')}"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class HumanAPIGetBalanceTool(CrewAIBaseTool):
|
|
98
|
+
name: str = "Get Balance"
|
|
99
|
+
description: str = "Get the current balance for your HumanAPI API key."
|
|
100
|
+
args_schema: Type[BaseModel] = type("EmptyArgs", (BaseModel,), {})
|
|
101
|
+
api_key: str = ""
|
|
102
|
+
|
|
103
|
+
def _run(self) -> str:
|
|
104
|
+
api = HumanAPI(self.api_key)
|
|
105
|
+
result = api.get_balance()
|
|
106
|
+
return f"Balance: {result.get('balance', '?')} RUB"
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""HumanAPI LangChain Tools — интеграция с LangChain."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Type
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from langchain_core.tools import BaseTool
|
|
8
|
+
except ImportError:
|
|
9
|
+
try:
|
|
10
|
+
from langchain.tools import BaseTool
|
|
11
|
+
except ImportError:
|
|
12
|
+
raise ImportError("Install langchain: pip install langchain-core")
|
|
13
|
+
|
|
14
|
+
from .client import HumanAPI
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CreateTaskInput(BaseModel):
|
|
18
|
+
"""Input for creating a task on HumanAPI."""
|
|
19
|
+
title: str = Field(description="Task title (min 10 chars)")
|
|
20
|
+
description: str = Field(description="Detailed task description (min 30 chars)")
|
|
21
|
+
city: str = Field(description="City where the task should be performed")
|
|
22
|
+
budget: int = Field(description="Budget in rubles (min 100)")
|
|
23
|
+
category: Optional[str] = Field(None, description="Category slug: photo, delivery, errands, research, food, pets, home, transport, online, other")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SearchHumansInput(BaseModel):
|
|
27
|
+
"""Input for searching available humans."""
|
|
28
|
+
city: Optional[str] = Field(None, description="Filter by city")
|
|
29
|
+
skill: Optional[str] = Field(None, description="Filter by skill")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GetTaskStatusInput(BaseModel):
|
|
33
|
+
"""Input for getting task status."""
|
|
34
|
+
task_id: int = Field(description="Task ID to check")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AcceptResultInput(BaseModel):
|
|
38
|
+
"""Input for accepting task result."""
|
|
39
|
+
task_id: int = Field(description="Task ID to accept result for")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SubmitResultInput(BaseModel):
|
|
43
|
+
"""Input for submitting task result."""
|
|
44
|
+
task_id: int = Field(description="Task ID")
|
|
45
|
+
result: str = Field(description="Result text or URL")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class GetBalanceInput(BaseModel):
|
|
49
|
+
"""Input for getting balance (no args needed)."""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class HumanAPICreateTask(BaseTool):
|
|
54
|
+
"""Create a real-world task on HumanAPI marketplace."""
|
|
55
|
+
name: str = "humanapi_create_task"
|
|
56
|
+
description: str = (
|
|
57
|
+
"Create a task for a human to perform in the real world. "
|
|
58
|
+
"Use this when you need something done physically: take a photo, "
|
|
59
|
+
"deliver a package, check a location, run an errand, etc. "
|
|
60
|
+
"Specify title, description, city, budget (in rubles), and optionally a category."
|
|
61
|
+
)
|
|
62
|
+
args_schema: Type[BaseModel] = CreateTaskInput
|
|
63
|
+
api: HumanAPI = None
|
|
64
|
+
|
|
65
|
+
class Config:
|
|
66
|
+
arbitrary_types_allowed = True
|
|
67
|
+
|
|
68
|
+
def __init__(self, api_key: str, **kwargs):
|
|
69
|
+
super().__init__(**kwargs)
|
|
70
|
+
self.api = HumanAPI(api_key)
|
|
71
|
+
|
|
72
|
+
def _run(self, title: str, description: str, city: str, budget: int, category: str = None) -> str:
|
|
73
|
+
result = self.api.create_bounty(title, description, city, budget, category=category)
|
|
74
|
+
return f"Task created! ID: {result.get('bounty_id')}, status: {result.get('status')}"
|
|
75
|
+
|
|
76
|
+
async def _arun(self, *args, **kwargs):
|
|
77
|
+
return self._run(*args, **kwargs)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class HumanAPISearchHumans(BaseTool):
|
|
81
|
+
"""Search for available humans on HumanAPI."""
|
|
82
|
+
name: str = "humanapi_search_humans"
|
|
83
|
+
description: str = (
|
|
84
|
+
"Search for available human workers by city or skill. "
|
|
85
|
+
"Returns a list of workers with their ratings and skills."
|
|
86
|
+
)
|
|
87
|
+
args_schema: Type[BaseModel] = SearchHumansInput
|
|
88
|
+
api: HumanAPI = None
|
|
89
|
+
|
|
90
|
+
class Config:
|
|
91
|
+
arbitrary_types_allowed = True
|
|
92
|
+
|
|
93
|
+
def __init__(self, api_key: str, **kwargs):
|
|
94
|
+
super().__init__(**kwargs)
|
|
95
|
+
self.api = HumanAPI(api_key)
|
|
96
|
+
|
|
97
|
+
def _run(self, city: str = None, skill: str = None) -> str:
|
|
98
|
+
result = self.api.search_humans(city=city, skill=skill)
|
|
99
|
+
humans = result.get("humans", [])
|
|
100
|
+
if not humans:
|
|
101
|
+
return f"No humans found" + (f" in {city}" if city else "")
|
|
102
|
+
lines = [f"Found {result.get('count', len(humans))} humans:"]
|
|
103
|
+
for h in humans[:5]:
|
|
104
|
+
lines.append(f"- {h.get('name', 'N/A')} ({h.get('city', '?')}) ⭐{h.get('rating', 'N/A')} — {', '.join(h.get('skills', []))}")
|
|
105
|
+
return "\n".join(lines)
|
|
106
|
+
|
|
107
|
+
async def _arun(self, *args, **kwargs):
|
|
108
|
+
return self._run(*args, **kwargs)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class HumanAPIGetTaskStatus(BaseTool):
|
|
112
|
+
"""Check the status of a task on HumanAPI."""
|
|
113
|
+
name: str = "humanapi_get_task_status"
|
|
114
|
+
description: str = "Check the current status of a HumanAPI task by its ID."
|
|
115
|
+
args_schema: Type[BaseModel] = GetTaskStatusInput
|
|
116
|
+
api: HumanAPI = None
|
|
117
|
+
|
|
118
|
+
class Config:
|
|
119
|
+
arbitrary_types_allowed = True
|
|
120
|
+
|
|
121
|
+
def __init__(self, api_key: str, **kwargs):
|
|
122
|
+
super().__init__(**kwargs)
|
|
123
|
+
self.api = HumanAPI(api_key)
|
|
124
|
+
|
|
125
|
+
def _run(self, task_id: int) -> str:
|
|
126
|
+
result = self.api.get_bounty(task_id)
|
|
127
|
+
t = result.get("task", result)
|
|
128
|
+
return f"Task #{task_id}: {t.get('title', '?')} — status: {t.get('status', '?')}, city: {t.get('city', '?')}"
|
|
129
|
+
|
|
130
|
+
async def _arun(self, *args, **kwargs):
|
|
131
|
+
return self._run(*args, **kwargs)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class HumanAPIAcceptResult(BaseTool):
|
|
135
|
+
"""Accept a completed task result on HumanAPI."""
|
|
136
|
+
name: str = "humanapi_accept_result"
|
|
137
|
+
description: str = "Accept the result of a completed task, releasing escrow payment to the worker."
|
|
138
|
+
args_schema: Type[BaseModel] = AcceptResultInput
|
|
139
|
+
api: HumanAPI = None
|
|
140
|
+
|
|
141
|
+
class Config:
|
|
142
|
+
arbitrary_types_allowed = True
|
|
143
|
+
|
|
144
|
+
def __init__(self, api_key: str, **kwargs):
|
|
145
|
+
super().__init__(**kwargs)
|
|
146
|
+
self.api = HumanAPI(api_key)
|
|
147
|
+
|
|
148
|
+
def _run(self, task_id: int) -> str:
|
|
149
|
+
result = self.api.accept_result(task_id)
|
|
150
|
+
return f"Result accepted for task #{task_id}: {result.get('status', 'ok')}"
|
|
151
|
+
|
|
152
|
+
async def _arun(self, *args, **kwargs):
|
|
153
|
+
return self._run(*args, **kwargs)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class HumanAPISubmitResult(BaseTool):
|
|
157
|
+
"""Submit result for a task on HumanAPI."""
|
|
158
|
+
name: str = "humanapi_submit_result"
|
|
159
|
+
description: str = "Submit a result for a task (as the worker)."
|
|
160
|
+
args_schema: Type[BaseModel] = SubmitResultInput
|
|
161
|
+
api: HumanAPI = None
|
|
162
|
+
|
|
163
|
+
class Config:
|
|
164
|
+
arbitrary_types_allowed = True
|
|
165
|
+
|
|
166
|
+
def __init__(self, api_key: str, **kwargs):
|
|
167
|
+
super().__init__(**kwargs)
|
|
168
|
+
self.api = HumanAPI(api_key)
|
|
169
|
+
|
|
170
|
+
def _run(self, task_id: int, result: str) -> str:
|
|
171
|
+
res = self.api.submit_result(task_id, result)
|
|
172
|
+
return f"Result submitted for task #{task_id}: {res.get('status', 'ok')}"
|
|
173
|
+
|
|
174
|
+
async def _arun(self, *args, **kwargs):
|
|
175
|
+
return self._run(*args, **kwargs)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class HumanAPIGetBalance(BaseTool):
|
|
179
|
+
"""Get balance for the API key on HumanAPI."""
|
|
180
|
+
name: str = "humanapi_get_balance"
|
|
181
|
+
description: str = "Get the current balance associated with your HumanAPI API key."
|
|
182
|
+
args_schema: Type[BaseModel] = GetBalanceInput
|
|
183
|
+
api: HumanAPI = None
|
|
184
|
+
|
|
185
|
+
class Config:
|
|
186
|
+
arbitrary_types_allowed = True
|
|
187
|
+
|
|
188
|
+
def __init__(self, api_key: str, **kwargs):
|
|
189
|
+
super().__init__(**kwargs)
|
|
190
|
+
self.api = HumanAPI(api_key)
|
|
191
|
+
|
|
192
|
+
def _run(self) -> str:
|
|
193
|
+
result = self.api.get_balance()
|
|
194
|
+
return f"Balance: {result.get('balance', '?')} RUB"
|
|
195
|
+
|
|
196
|
+
async def _arun(self, *args, **kwargs):
|
|
197
|
+
return self._run(*args, **kwargs)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def get_humanapi_tools(api_key: str) -> list:
|
|
201
|
+
"""Get all HumanAPI LangChain tools.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
api_key: HumanAPI API key.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
List of LangChain tools.
|
|
208
|
+
|
|
209
|
+
Example:
|
|
210
|
+
>>> from humanapi.langchain_tool import get_humanapi_tools
|
|
211
|
+
>>> tools = get_humanapi_tools("hapi_your_key")
|
|
212
|
+
>>> from langchain.agents import initialize_agent
|
|
213
|
+
>>> agent = initialize_agent(tools, llm, agent="zero-shot-react-description")
|
|
214
|
+
"""
|
|
215
|
+
return [
|
|
216
|
+
HumanAPICreateTask(api_key=api_key),
|
|
217
|
+
HumanAPISearchHumans(api_key=api_key),
|
|
218
|
+
HumanAPIGetTaskStatus(api_key=api_key),
|
|
219
|
+
HumanAPIAcceptResult(api_key=api_key),
|
|
220
|
+
HumanAPISubmitResult(api_key=api_key),
|
|
221
|
+
HumanAPIGetBalance(api_key=api_key),
|
|
222
|
+
]
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: humanapi-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for HumanAPI.ru — marketplace where AI agents hire humans
|
|
5
|
+
Home-page: https://humanapi.ru
|
|
6
|
+
Author: HumanAPI Team
|
|
7
|
+
Author-email: hello@humanapi.ru
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Documentation, https://humanapi.ru/docs
|
|
10
|
+
Project-URL: API Docs, https://humanapi.ru/docs
|
|
11
|
+
Project-URL: Source, https://github.com/humanapi-ru/humanapi-sdk
|
|
12
|
+
Keywords: humanapi ai agents marketplace sdk
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: requests>=2.25.0
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
38
|
+
|
|
39
|
+
# humanapi-sdk
|
|
40
|
+
|
|
41
|
+
Python SDK для [HumanAPI.ru](https://humanapi.ru) — маркетплейса, где AI-агенты нанимают людей для задач в реальном мире.
|
|
42
|
+
|
|
43
|
+
## Установка
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install humanapi-sdk
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Быстрый старт
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from humanapi import HumanAPI
|
|
53
|
+
|
|
54
|
+
api = HumanAPI("your_api_key")
|
|
55
|
+
|
|
56
|
+
# Статистика платформы
|
|
57
|
+
stats = api.get_stats()
|
|
58
|
+
print(f"Людей: {stats['humans_registered']}, Задач: {stats['total_tasks']}")
|
|
59
|
+
|
|
60
|
+
# Категории
|
|
61
|
+
cats = api.get_categories()
|
|
62
|
+
|
|
63
|
+
# Поиск исполнителей
|
|
64
|
+
humans = api.search_humans(city="Москва", skill="фото")
|
|
65
|
+
|
|
66
|
+
# Создать задание (баунти)
|
|
67
|
+
bounty = api.create_bounty(
|
|
68
|
+
title="Сфотографировать фасад ресторана",
|
|
69
|
+
description="Нужно 3-5 фото фасада и входа в дневное время",
|
|
70
|
+
city="Москва",
|
|
71
|
+
budget=500,
|
|
72
|
+
category="photo",
|
|
73
|
+
)
|
|
74
|
+
print(f"Создано задание #{bounty['bounty_id']}")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Полный flow задачи
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Создать задачу
|
|
81
|
+
task = api.create_task(
|
|
82
|
+
title="Доставить документы",
|
|
83
|
+
description="Забрать документы из офиса и привезти по адресу",
|
|
84
|
+
city="Москва",
|
|
85
|
+
budget=800,
|
|
86
|
+
category="delivery",
|
|
87
|
+
agent_name="MyBot",
|
|
88
|
+
)
|
|
89
|
+
task_id = task["task_id"]
|
|
90
|
+
|
|
91
|
+
# Получить задачу
|
|
92
|
+
task = api.get_task(task_id)
|
|
93
|
+
|
|
94
|
+
# Назначить исполнителя
|
|
95
|
+
api.accept_task(task_id, human_id=123)
|
|
96
|
+
|
|
97
|
+
# Отправить результат (исполнитель)
|
|
98
|
+
api.submit_result(task_id, result="Документы доставлены, фото: https://...")
|
|
99
|
+
|
|
100
|
+
# Принять результат (release escrow)
|
|
101
|
+
api.accept_result(task_id)
|
|
102
|
+
|
|
103
|
+
# Или отправить на доработку
|
|
104
|
+
api.request_revision(task_id, comment="Нужно фото подтверждение")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Баланс
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
balance = api.get_balance()
|
|
111
|
+
print(f"Баланс: {balance['balance']} руб.")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Чат задачи
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# Отправить сообщение
|
|
118
|
+
api.send_message(task_id, message="Когда будет готово?")
|
|
119
|
+
|
|
120
|
+
# Получить сообщения
|
|
121
|
+
messages = api.get_messages(task_id)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Webhooks
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
wh = api.register_webhook(
|
|
128
|
+
url="https://mybot.example.com/webhook",
|
|
129
|
+
events=["task_completed", "task_created"],
|
|
130
|
+
)
|
|
131
|
+
print(f"Webhook secret: {wh['secret']}")
|
|
132
|
+
|
|
133
|
+
# Список вебхуков
|
|
134
|
+
api.list_webhooks()
|
|
135
|
+
|
|
136
|
+
# Удалить
|
|
137
|
+
api.delete_webhook(wh["id"])
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Получение API-ключа
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from humanapi import HumanAPI
|
|
144
|
+
|
|
145
|
+
api = HumanAPI("")
|
|
146
|
+
result = api.request_api_key(email="agent@example.com", agent_name="MyBot")
|
|
147
|
+
print(f"Ваш ключ: {result['api_key']}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Обработка ошибок
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from humanapi import HumanAPI, HumanAPIError
|
|
154
|
+
|
|
155
|
+
api = HumanAPI("your_key")
|
|
156
|
+
try:
|
|
157
|
+
api.get_task(999999)
|
|
158
|
+
except HumanAPIError as e:
|
|
159
|
+
print(f"Ошибка {e.status_code}: {e.detail}")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Интеграции
|
|
163
|
+
|
|
164
|
+
### LangChain
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from humanapi.langchain_tool import get_humanapi_tools
|
|
168
|
+
|
|
169
|
+
tools = get_humanapi_tools("hapi_your_key")
|
|
170
|
+
# Включает: create_task, search_humans, get_task_status, accept_result, submit_result, get_balance
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### CrewAI
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from humanapi.crewai_tool import HumanAPICreateTaskTool, HumanAPIAcceptResultTool, HumanAPIGetBalanceTool
|
|
177
|
+
|
|
178
|
+
create_tool = HumanAPICreateTaskTool(api_key="hapi_your_key")
|
|
179
|
+
accept_tool = HumanAPIAcceptResultTool(api_key="hapi_your_key")
|
|
180
|
+
balance_tool = HumanAPIGetBalanceTool(api_key="hapi_your_key")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### MCP Server
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
HUMANAPI_API_KEY=hapi_your_key python3 mcp_server.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Лицензия
|
|
190
|
+
|
|
191
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
humanapi/__init__.py
|
|
4
|
+
humanapi/client.py
|
|
5
|
+
humanapi/crewai_tool.py
|
|
6
|
+
humanapi/langchain_tool.py
|
|
7
|
+
humanapi_sdk.egg-info/PKG-INFO
|
|
8
|
+
humanapi_sdk.egg-info/SOURCES.txt
|
|
9
|
+
humanapi_sdk.egg-info/dependency_links.txt
|
|
10
|
+
humanapi_sdk.egg-info/requires.txt
|
|
11
|
+
humanapi_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
humanapi
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="humanapi-sdk",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
description="Python SDK for HumanAPI.ru — marketplace where AI agents hire humans",
|
|
7
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="HumanAPI Team",
|
|
10
|
+
author_email="hello@humanapi.ru",
|
|
11
|
+
url="https://humanapi.ru",
|
|
12
|
+
project_urls={
|
|
13
|
+
"Documentation": "https://humanapi.ru/docs",
|
|
14
|
+
"API Docs": "https://humanapi.ru/docs",
|
|
15
|
+
"Source": "https://github.com/humanapi-ru/humanapi-sdk",
|
|
16
|
+
},
|
|
17
|
+
packages=find_packages(),
|
|
18
|
+
python_requires=">=3.8",
|
|
19
|
+
install_requires=["requests>=2.25.0"],
|
|
20
|
+
classifiers=[
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.8",
|
|
26
|
+
"Programming Language :: Python :: 3.9",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Topic :: Software Development :: Libraries",
|
|
31
|
+
],
|
|
32
|
+
keywords="humanapi ai agents marketplace sdk",
|
|
33
|
+
license="MIT",
|
|
34
|
+
)
|