Skip to content

Commit 5155d78

Browse files
feat(api): add ai detect tool endpoint
1 parent fe810b2 commit 5155d78

7 files changed

Lines changed: 189 additions & 4 deletions

File tree

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 31
1+
configured_endpoints: 32
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/writerai%2Fwriter-a0e83ebfd81856b538d16c7a41ccdc11687ee558e1435a40f3bb7e0d6e1ab7c8.yml
33
openapi_spec_hash: 8ac62303a9158c13f344975cb0786bc6
4-
config_hash: 1f6d0bf7309d0007e28ab85b89a0de85
4+
config_hash: b1d3b26784527ee46af49c1bb9e93193

api.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,16 @@ Methods:
162162
Types:
163163

164164
```python
165-
from writerai.types import ToolContextAwareSplittingResponse, ToolParsePdfResponse
165+
from writerai.types import (
166+
ToolAIDetectResponse,
167+
ToolContextAwareSplittingResponse,
168+
ToolParsePdfResponse,
169+
)
166170
```
167171

168172
Methods:
169173

174+
- <code title="post /v1/tools/ai-detect">client.tools.<a href="./src/writerai/resources/tools/tools.py">ai_detect</a>(\*\*<a href="src/writerai/types/tool_ai_detect_params.py">params</a>) -> <a href="./src/writerai/types/tool_ai_detect_response.py">ToolAIDetectResponse</a></code>
170175
- <code title="post /v1/tools/context-aware-splitting">client.tools.<a href="./src/writerai/resources/tools/tools.py">context_aware_splitting</a>(\*\*<a href="src/writerai/types/tool_context_aware_splitting_params.py">params</a>) -> <a href="./src/writerai/types/tool_context_aware_splitting_response.py">ToolContextAwareSplittingResponse</a></code>
171176
- <code title="post /v1/tools/pdf-parser/{file_id}">client.tools.<a href="./src/writerai/resources/tools/tools.py">parse_pdf</a>(file_id, \*\*<a href="src/writerai/types/tool_parse_pdf_params.py">params</a>) -> <a href="./src/writerai/types/tool_parse_pdf_response.py">ToolParsePdfResponse</a></code>
172177

src/writerai/resources/tools/tools.py

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import httpx
88

9-
from ...types import tool_parse_pdf_params, tool_context_aware_splitting_params
9+
from ...types import tool_ai_detect_params, tool_parse_pdf_params, tool_context_aware_splitting_params
1010
from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
1111
from ..._utils import maybe_transform, async_maybe_transform
1212
from ..._compat import cached_property
@@ -26,6 +26,7 @@
2626
async_to_streamed_response_wrapper,
2727
)
2828
from ..._base_client import make_request_options
29+
from ...types.tool_ai_detect_response import ToolAIDetectResponse
2930
from ...types.tool_parse_pdf_response import ToolParsePdfResponse
3031
from ...types.tool_context_aware_splitting_response import ToolContextAwareSplittingResponse
3132

@@ -56,6 +57,43 @@ def with_streaming_response(self) -> ToolsResourceWithStreamingResponse:
5657
"""
5758
return ToolsResourceWithStreamingResponse(self)
5859

60+
def ai_detect(
61+
self,
62+
*,
63+
input: str,
64+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
65+
# The extra values given here take precedence over values defined on the client or passed to this method.
66+
extra_headers: Headers | None = None,
67+
extra_query: Query | None = None,
68+
extra_body: Body | None = None,
69+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
70+
) -> ToolAIDetectResponse:
71+
"""Detects if content is AI- or human-generated, with a confidence score.
72+
73+
Content
74+
must have at least 350 characters
75+
76+
Args:
77+
input: The content to determine if it is AI- or human-generated. Content must have at
78+
least 350 characters.
79+
80+
extra_headers: Send extra headers
81+
82+
extra_query: Add additional query parameters to the request
83+
84+
extra_body: Add additional JSON properties to the request
85+
86+
timeout: Override the client-level default timeout for this request, in seconds
87+
"""
88+
return self._post(
89+
"/v1/tools/ai-detect",
90+
body=maybe_transform({"input": input}, tool_ai_detect_params.ToolAIDetectParams),
91+
options=make_request_options(
92+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
93+
),
94+
cast_to=ToolAIDetectResponse,
95+
)
96+
5997
def context_aware_splitting(
6098
self,
6199
*,
@@ -164,6 +202,43 @@ def with_streaming_response(self) -> AsyncToolsResourceWithStreamingResponse:
164202
"""
165203
return AsyncToolsResourceWithStreamingResponse(self)
166204

205+
async def ai_detect(
206+
self,
207+
*,
208+
input: str,
209+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
210+
# The extra values given here take precedence over values defined on the client or passed to this method.
211+
extra_headers: Headers | None = None,
212+
extra_query: Query | None = None,
213+
extra_body: Body | None = None,
214+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
215+
) -> ToolAIDetectResponse:
216+
"""Detects if content is AI- or human-generated, with a confidence score.
217+
218+
Content
219+
must have at least 350 characters
220+
221+
Args:
222+
input: The content to determine if it is AI- or human-generated. Content must have at
223+
least 350 characters.
224+
225+
extra_headers: Send extra headers
226+
227+
extra_query: Add additional query parameters to the request
228+
229+
extra_body: Add additional JSON properties to the request
230+
231+
timeout: Override the client-level default timeout for this request, in seconds
232+
"""
233+
return await self._post(
234+
"/v1/tools/ai-detect",
235+
body=await async_maybe_transform({"input": input}, tool_ai_detect_params.ToolAIDetectParams),
236+
options=make_request_options(
237+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
238+
),
239+
cast_to=ToolAIDetectResponse,
240+
)
241+
167242
async def context_aware_splitting(
168243
self,
169244
*,
@@ -252,6 +327,9 @@ class ToolsResourceWithRawResponse:
252327
def __init__(self, tools: ToolsResource) -> None:
253328
self._tools = tools
254329

330+
self.ai_detect = to_raw_response_wrapper(
331+
tools.ai_detect,
332+
)
255333
self.context_aware_splitting = to_raw_response_wrapper(
256334
tools.context_aware_splitting,
257335
)
@@ -268,6 +346,9 @@ class AsyncToolsResourceWithRawResponse:
268346
def __init__(self, tools: AsyncToolsResource) -> None:
269347
self._tools = tools
270348

349+
self.ai_detect = async_to_raw_response_wrapper(
350+
tools.ai_detect,
351+
)
271352
self.context_aware_splitting = async_to_raw_response_wrapper(
272353
tools.context_aware_splitting,
273354
)
@@ -284,6 +365,9 @@ class ToolsResourceWithStreamingResponse:
284365
def __init__(self, tools: ToolsResource) -> None:
285366
self._tools = tools
286367

368+
self.ai_detect = to_streamed_response_wrapper(
369+
tools.ai_detect,
370+
)
287371
self.context_aware_splitting = to_streamed_response_wrapper(
288372
tools.context_aware_splitting,
289373
)
@@ -300,6 +384,9 @@ class AsyncToolsResourceWithStreamingResponse:
300384
def __init__(self, tools: AsyncToolsResource) -> None:
301385
self._tools = tools
302386

387+
self.ai_detect = async_to_streamed_response_wrapper(
388+
tools.ai_detect,
389+
)
303390
self.context_aware_splitting = async_to_streamed_response_wrapper(
304391
tools.context_aware_splitting,
305392
)

src/writerai/types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@
4141
from .graph_delete_response import GraphDeleteResponse as GraphDeleteResponse
4242
from .graph_question_params import GraphQuestionParams as GraphQuestionParams
4343
from .graph_update_response import GraphUpdateResponse as GraphUpdateResponse
44+
from .tool_ai_detect_params import ToolAIDetectParams as ToolAIDetectParams
4445
from .tool_parse_pdf_params import ToolParsePdfParams as ToolParsePdfParams
4546
from .vision_analyze_params import VisionAnalyzeParams as VisionAnalyzeParams
4647
from .chat_completion_choice import ChatCompletionChoice as ChatCompletionChoice
4748
from .application_list_params import ApplicationListParams as ApplicationListParams
4849
from .chat_completion_message import ChatCompletionMessage as ChatCompletionMessage
4950
from .question_response_chunk import QuestionResponseChunk as QuestionResponseChunk
51+
from .tool_ai_detect_response import ToolAIDetectResponse as ToolAIDetectResponse
5052
from .tool_parse_pdf_response import ToolParsePdfResponse as ToolParsePdfResponse
5153
from .completion_create_params import CompletionCreateParams as CompletionCreateParams
5254
from .application_list_response import ApplicationListResponse as ApplicationListResponse
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Required, TypedDict
6+
7+
__all__ = ["ToolAIDetectParams"]
8+
9+
10+
class ToolAIDetectParams(TypedDict, total=False):
11+
input: Required[str]
12+
"""The content to determine if it is AI- or human-generated.
13+
14+
Content must have at least 350 characters.
15+
"""
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from typing_extensions import Literal
4+
5+
from .._models import BaseModel
6+
7+
__all__ = ["ToolAIDetectResponse"]
8+
9+
10+
class ToolAIDetectResponse(BaseModel):
11+
label: Literal["fake", "real"]
12+
13+
score: float

tests/api_resources/test_tools.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from writerai import Writer, AsyncWriter
1111
from tests.utils import assert_matches_type
1212
from writerai.types import (
13+
ToolAIDetectResponse,
1314
ToolParsePdfResponse,
1415
ToolContextAwareSplittingResponse,
1516
)
@@ -20,6 +21,37 @@
2021
class TestTools:
2122
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
2223

24+
@parametrize
25+
def test_method_ai_detect(self, client: Writer) -> None:
26+
tool = client.tools.ai_detect(
27+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
28+
)
29+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
30+
31+
@parametrize
32+
def test_raw_response_ai_detect(self, client: Writer) -> None:
33+
response = client.tools.with_raw_response.ai_detect(
34+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
35+
)
36+
37+
assert response.is_closed is True
38+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
39+
tool = response.parse()
40+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
41+
42+
@parametrize
43+
def test_streaming_response_ai_detect(self, client: Writer) -> None:
44+
with client.tools.with_streaming_response.ai_detect(
45+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
46+
) as response:
47+
assert not response.is_closed
48+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
49+
50+
tool = response.parse()
51+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
52+
53+
assert cast(Any, response.is_closed) is True
54+
2355
@parametrize
2456
def test_method_context_aware_splitting(self, client: Writer) -> None:
2557
tool = client.tools.context_aware_splitting(
@@ -100,6 +132,37 @@ def test_path_params_parse_pdf(self, client: Writer) -> None:
100132
class TestAsyncTools:
101133
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
102134

135+
@parametrize
136+
async def test_method_ai_detect(self, async_client: AsyncWriter) -> None:
137+
tool = await async_client.tools.ai_detect(
138+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
139+
)
140+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
141+
142+
@parametrize
143+
async def test_raw_response_ai_detect(self, async_client: AsyncWriter) -> None:
144+
response = await async_client.tools.with_raw_response.ai_detect(
145+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
146+
)
147+
148+
assert response.is_closed is True
149+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
150+
tool = await response.parse()
151+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
152+
153+
@parametrize
154+
async def test_streaming_response_ai_detect(self, async_client: AsyncWriter) -> None:
155+
async with async_client.tools.with_streaming_response.ai_detect(
156+
input="AI and ML continue to be at the forefront of technological advancements. In 2025, we can expect more sophisticated AI systems that can handle complex tasks with greater efficiency. AI will play a crucial role in various sectors, including healthcare, finance, and manufacturing. For instance, AI-powered diagnostic tools will become more accurate, helping doctors detect diseases at an early stage. In finance, AI algorithms will enhance fraud detection and risk management.",
157+
) as response:
158+
assert not response.is_closed
159+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
160+
161+
tool = await response.parse()
162+
assert_matches_type(ToolAIDetectResponse, tool, path=["response"])
163+
164+
assert cast(Any, response.is_closed) is True
165+
103166
@parametrize
104167
async def test_method_context_aware_splitting(self, async_client: AsyncWriter) -> None:
105168
tool = await async_client.tools.context_aware_splitting(

0 commit comments

Comments
 (0)