loopuman 1.0.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.
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: loopuman
3
+ Version: 1.0.0
4
+ Summary: The Human API for AI - Give your AI agents instant access to humans
5
+ Home-page: https://github.com/loopuman/loopuman-python
6
+ Author: Loopuman
7
+ Author-email: hello@loopuman.com
8
+ Keywords: ai human-in-the-loop microtasks langchain agents
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Requires-Python: >=3.7
15
+ Requires-Dist: requests>=2.25.0
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: classifier
19
+ Dynamic: home-page
20
+ Dynamic: keywords
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
@@ -0,0 +1,88 @@
1
+ # Loopuman Python SDK
2
+
3
+ **The Human API for AI** - Give your AI agents instant access to humans.
4
+
5
+ ## Installation
6
+ ```bash
7
+ pip install loopuman
8
+ ```
9
+
10
+ ## Quick Start
11
+ ```python
12
+ from loopuman import Loopuman
13
+
14
+ client = Loopuman(api_key="your_key")
15
+
16
+ # Ask a human and wait for response
17
+ result = client.ask("Is this content appropriate for children?")
18
+ print(result.response) # "Yes" or "No" from human
19
+ ```
20
+
21
+ ## Use Cases
22
+
23
+ ### Content Moderation
24
+ ```python
25
+ result = client.ask(
26
+ question="Is this image appropriate?",
27
+ context="Image shows: a sunset over mountains",
28
+ budget_cents=25
29
+ )
30
+ ```
31
+
32
+ ### Fact Verification
33
+ ```python
34
+ result = client.ask(
35
+ question="Is this claim accurate: 'The Eiffel Tower is 300m tall'",
36
+ budget_cents=50
37
+ )
38
+ ```
39
+
40
+ ### AI Agent Oversight
41
+ ```python
42
+ # Before sending an important message
43
+ result = client.ask(
44
+ question=f"Should I send this message? '{draft_message}'",
45
+ budget_cents=30
46
+ )
47
+ if "yes" in result.response.lower():
48
+ send_message(draft_message)
49
+ ```
50
+
51
+ ## LangChain Integration
52
+ ```python
53
+ from loopuman.langchain_tool import LoopumanTool
54
+ from langchain.agents import initialize_agent
55
+
56
+ tool = LoopumanTool(api_key="your_key")
57
+ agent = initialize_agent([tool], llm, agent="zero-shot-react-description")
58
+
59
+ # Agent can now ask humans for help
60
+ response = agent.run("Verify if this product review is genuine: '...'")
61
+ ```
62
+
63
+ ## Async Tasks (with webhooks)
64
+ ```python
65
+ # Create task and receive webhook when complete
66
+ task = client.create_task(
67
+ title="Review this document",
68
+ description="Check for errors",
69
+ budget_cents=100,
70
+ webhook_url="https://your-app.com/webhook"
71
+ )
72
+
73
+ print(f"Task created: {task.id}")
74
+ # Your webhook will receive the result when a human completes it
75
+ ```
76
+
77
+ ## Pricing
78
+
79
+ - Minimum: $0.10 per task
80
+ - Typical: $0.25 - $1.00 per task
81
+ - You pay budget + 20% platform fee
82
+ - Workers receive budget - 20%
83
+
84
+ ## Links
85
+
86
+ - Website: https://loopuman.com
87
+ - API Docs: https://loopuman.com/docs
88
+ - Dashboard: https://loopuman.com/dashboard
@@ -0,0 +1,263 @@
1
+ """
2
+ Loopuman Python SDK
3
+ The Human API for AI - Give your AI agents instant access to humans
4
+
5
+ Usage:
6
+ from loopuman import Loopuman
7
+
8
+ client = Loopuman(api_key="your_key")
9
+
10
+ # Synchronous - waits for human response
11
+ result = client.ask("Is this content appropriate?", budget_cents=50)
12
+ print(result.response)
13
+
14
+ # Async - returns immediately, check later
15
+ task = client.create_task("Review this document", budget_cents=100)
16
+ # ... later ...
17
+ result = client.get_result(task.id)
18
+ """
19
+
20
+ import requests
21
+ from dataclasses import dataclass
22
+ from typing import Optional, List, Dict, Any
23
+
24
+ __version__ = "1.0.0"
25
+
26
+ @dataclass
27
+ class TaskResult:
28
+ status: str # "completed", "timeout", "pending"
29
+ task_id: str
30
+ response: Optional[str] = None
31
+ worker_id: Optional[str] = None
32
+ completed_in_seconds: Optional[int] = None
33
+
34
+ @dataclass
35
+ class Task:
36
+ id: str
37
+ title: str
38
+ status: str
39
+ budget: int
40
+
41
+ class LoopumanError(Exception):
42
+ """Base exception for Loopuman errors"""
43
+ pass
44
+
45
+ class Loopuman:
46
+ """
47
+ Loopuman client - The Human API for AI
48
+
49
+ Args:
50
+ api_key: Your Loopuman API key
51
+ base_url: API base URL (default: https://api.loopuman.com)
52
+ """
53
+
54
+ def __init__(self, api_key: str, base_url: str = "https://api.loopuman.com"):
55
+ self.api_key = api_key
56
+ self.base_url = base_url.rstrip("/")
57
+ self._session = requests.Session()
58
+ self._session.headers.update({
59
+ "X-API-Key": api_key,
60
+ "Content-Type": "application/json"
61
+ })
62
+
63
+ def ask(
64
+ self,
65
+ question: str,
66
+ context: str = "",
67
+ budget_cents: int = 50,
68
+ timeout_seconds: int = 300,
69
+ auto_approve: bool = True
70
+ ) -> TaskResult:
71
+ """
72
+ Ask a human a question and wait for the response.
73
+
74
+ This is a synchronous call - it blocks until a human responds
75
+ or the timeout is reached.
76
+
77
+ Args:
78
+ question: The question to ask
79
+ context: Additional context for the human
80
+ budget_cents: Payment in cents (min 10, typical 25-100)
81
+ timeout_seconds: Max time to wait (default 5 minutes)
82
+ auto_approve: Auto-approve the submission (default True)
83
+
84
+ Returns:
85
+ TaskResult with the human's response
86
+
87
+ Example:
88
+ result = client.ask("Is this image appropriate?")
89
+ if result.status == "completed":
90
+ print(f"Human said: {result.response}")
91
+ """
92
+ response = self._session.post(
93
+ f"{self.base_url}/api/v1/tasks/sync",
94
+ json={
95
+ "title": question,
96
+ "description": context,
97
+ "budget": budget_cents,
98
+ "timeout_seconds": timeout_seconds,
99
+ "auto_approve": auto_approve
100
+ }
101
+ )
102
+
103
+ if response.status_code != 200:
104
+ raise LoopumanError(f"API error: {response.text}")
105
+
106
+ data = response.json()
107
+ return TaskResult(
108
+ status=data.get("status", "error"),
109
+ task_id=data.get("task_id", ""),
110
+ response=data.get("response"),
111
+ worker_id=data.get("worker_id"),
112
+ completed_in_seconds=data.get("completed_in_seconds")
113
+ )
114
+
115
+ def create_task(
116
+ self,
117
+ title: str,
118
+ description: str = "",
119
+ category: str = "ai_training",
120
+ budget_cents: int = 50,
121
+ webhook_url: Optional[str] = None
122
+ ) -> Task:
123
+ """
124
+ Create a task asynchronously.
125
+
126
+ Use this when you don't need to wait for the response inline.
127
+ You can check for results later or receive a webhook.
128
+
129
+ Args:
130
+ title: Task title
131
+ description: Task description
132
+ category: Task category (default: ai_training)
133
+ budget_cents: Payment in cents
134
+ webhook_url: URL to receive completion webhook
135
+
136
+ Returns:
137
+ Task object with the task ID
138
+ """
139
+ payload = {
140
+ "tasks": [{
141
+ "title": title,
142
+ "description": description,
143
+ "category": category,
144
+ "budget": budget_cents
145
+ }]
146
+ }
147
+ if webhook_url:
148
+ payload["webhook_url"] = webhook_url
149
+
150
+ response = self._session.post(
151
+ f"{self.base_url}/api/v1/tasks/bulk",
152
+ json=payload
153
+ )
154
+
155
+ if response.status_code != 200:
156
+ raise LoopumanError(f"API error: {response.text}")
157
+
158
+ data = response.json()
159
+ task_id = data.get("task_ids", [None])[0]
160
+
161
+ return Task(
162
+ id=task_id,
163
+ title=title,
164
+ status="active",
165
+ budget=budget_cents
166
+ )
167
+
168
+ def get_result(self, task_id: str) -> Optional[TaskResult]:
169
+ """
170
+ Check if a task has been completed.
171
+
172
+ Args:
173
+ task_id: The task ID to check
174
+
175
+ Returns:
176
+ TaskResult if completed, None if still pending
177
+ """
178
+ response = self._session.get(
179
+ f"{self.base_url}/api/v1/tasks/{task_id}"
180
+ )
181
+
182
+ if response.status_code != 200:
183
+ raise LoopumanError(f"API error: {response.text}")
184
+
185
+ data = response.json()
186
+ if data.get("submissions"):
187
+ sub = data["submissions"][0]
188
+ return TaskResult(
189
+ status="completed",
190
+ task_id=task_id,
191
+ response=sub.get("content"),
192
+ worker_id=sub.get("worker_id")
193
+ )
194
+
195
+ return None
196
+
197
+ def bulk_create(
198
+ self,
199
+ tasks: List[Dict[str, Any]],
200
+ webhook_url: Optional[str] = None
201
+ ) -> Dict[str, Any]:
202
+ """
203
+ Create multiple tasks at once.
204
+
205
+ Args:
206
+ tasks: List of task dicts with title, description, budget
207
+ webhook_url: URL to receive completion webhooks
208
+
209
+ Returns:
210
+ Dict with batch_id and task_ids
211
+
212
+ Example:
213
+ result = client.bulk_create([
214
+ {"title": "Review image 1", "budget": 25},
215
+ {"title": "Review image 2", "budget": 25},
216
+ ])
217
+ """
218
+ payload = {"tasks": tasks}
219
+ if webhook_url:
220
+ payload["webhook_url"] = webhook_url
221
+
222
+ response = self._session.post(
223
+ f"{self.base_url}/api/v1/tasks/bulk",
224
+ json=payload
225
+ )
226
+
227
+ if response.status_code != 200:
228
+ raise LoopumanError(f"API error: {response.text}")
229
+
230
+ return response.json()
231
+
232
+
233
+ # LangChain Tool Integration
234
+ def get_langchain_tool():
235
+ """
236
+ Get a LangChain-compatible tool for human-in-the-loop.
237
+
238
+ Usage:
239
+ from loopuman import get_langchain_tool
240
+
241
+ human_tool = get_langchain_tool()
242
+ agent = initialize_agent([human_tool, ...], llm)
243
+ """
244
+ try:
245
+ from langchain.tools import Tool
246
+ except ImportError:
247
+ raise ImportError("langchain is required: pip install langchain")
248
+
249
+ import os
250
+ client = Loopuman(api_key=os.environ.get("LOOPUMAN_API_KEY", ""))
251
+
252
+ def ask_human(query: str) -> str:
253
+ """Ask a human for help with verification or judgment."""
254
+ result = client.ask(query, timeout_seconds=300)
255
+ if result.status == "completed":
256
+ return result.response
257
+ return f"No human responded. Task ID: {result.task_id}"
258
+
259
+ return Tool(
260
+ name="AskHuman",
261
+ func=ask_human,
262
+ description="Ask a human for help with verification, judgment, or subjective evaluation. Use when AI is uncertain or needs human oversight."
263
+ )
@@ -0,0 +1,61 @@
1
+ """
2
+ LangChain integration for Loopuman
3
+
4
+ Usage:
5
+ from loopuman.langchain_tool import LoopumanTool
6
+
7
+ tool = LoopumanTool(api_key="your_key")
8
+ agent = initialize_agent([tool], llm)
9
+ """
10
+
11
+ import os
12
+ from typing import Optional
13
+
14
+ try:
15
+ from langchain.tools import BaseTool
16
+ from pydantic import Field
17
+ except ImportError:
18
+ raise ImportError("langchain is required: pip install langchain")
19
+
20
+ from . import Loopuman
21
+
22
+ class LoopumanTool(BaseTool):
23
+ """LangChain tool that gives agents access to human workers."""
24
+
25
+ name: str = "ask_human"
26
+ description: str = """Ask a human worker to help with a task.
27
+ Use this tool when you need:
28
+ - Verification of facts or content
29
+ - Subjective judgment (is this appropriate, offensive, accurate?)
30
+ - Real-world information (what's at this location?)
31
+ - Human oversight for important decisions
32
+
33
+ Input should be a clear question or task description.
34
+ Returns the human's response as a string."""
35
+
36
+ client: Loopuman = Field(default=None, exclude=True)
37
+ budget_cents: int = 50
38
+ timeout_seconds: int = 300
39
+
40
+ def __init__(self, api_key: Optional[str] = None, **kwargs):
41
+ super().__init__(**kwargs)
42
+ key = api_key or os.environ.get("LOOPUMAN_API_KEY")
43
+ if not key:
44
+ raise ValueError("LOOPUMAN_API_KEY required")
45
+ self.client = Loopuman(api_key=key)
46
+
47
+ def _run(self, query: str) -> str:
48
+ """Execute the tool."""
49
+ result = self.client.ask(
50
+ question=query,
51
+ budget_cents=self.budget_cents,
52
+ timeout_seconds=self.timeout_seconds
53
+ )
54
+
55
+ if result.status == "completed":
56
+ return result.response
57
+ return f"No human responded within {self.timeout_seconds}s. Task ID: {result.task_id}"
58
+
59
+ async def _arun(self, query: str) -> str:
60
+ """Async not implemented yet."""
61
+ return self._run(query)
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: loopuman
3
+ Version: 1.0.0
4
+ Summary: The Human API for AI - Give your AI agents instant access to humans
5
+ Home-page: https://github.com/loopuman/loopuman-python
6
+ Author: Loopuman
7
+ Author-email: hello@loopuman.com
8
+ Keywords: ai human-in-the-loop microtasks langchain agents
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Requires-Python: >=3.7
15
+ Requires-Dist: requests>=2.25.0
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: classifier
19
+ Dynamic: home-page
20
+ Dynamic: keywords
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
@@ -0,0 +1,9 @@
1
+ README.md
2
+ setup.py
3
+ loopuman/__init__.py
4
+ loopuman/langchain_tool.py
5
+ loopuman.egg-info/PKG-INFO
6
+ loopuman.egg-info/SOURCES.txt
7
+ loopuman.egg-info/dependency_links.txt
8
+ loopuman.egg-info/requires.txt
9
+ loopuman.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ loopuman
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,21 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="loopuman",
5
+ version="1.0.0",
6
+ description="The Human API for AI - Give your AI agents instant access to humans",
7
+ author="Loopuman",
8
+ author_email="hello@loopuman.com",
9
+ url="https://github.com/loopuman/loopuman-python",
10
+ packages=find_packages(),
11
+ install_requires=["requests>=2.25.0"],
12
+ python_requires=">=3.7",
13
+ classifiers=[
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
19
+ ],
20
+ keywords="ai human-in-the-loop microtasks langchain agents",
21
+ )