Skip to content

Commit 3e56fea

Browse files
committed
fix: Add DeepNews endpoint
1 parent d62fc2a commit 3e56fea

3 files changed

Lines changed: 180 additions & 0 deletions

File tree

asknews_sdk/api/chat.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
WebSearchResponse,
1515
)
1616
from asknews_sdk.dto.common import PaginatedResponse
17+
from asknews_sdk.dto.deepnews import (
18+
CreateDeepNewsRequest,
19+
CreateDeepNewsResponse,
20+
CreateDeepNewsResponseStream,
21+
)
1722
from asknews_sdk.response import EventSource
1823

1924

@@ -444,6 +449,73 @@ def list_alert_logs(
444449
)
445450
return PaginatedResponse[AlertLog].model_validate(response.content)
446451

452+
def get_deep_news(
453+
self,
454+
messages: List[Dict[str, str]],
455+
model: Literal[
456+
"claude-3-7-sonnet-latest",
457+
"deepseek",
458+
"o3-mini",
459+
] = "deepseek",
460+
stream: bool = False,
461+
inline_citations: Literal["markdown_link", "numbered", "none"] = "markdown_link",
462+
append_references: bool = True,
463+
asknews_watermark: bool = True,
464+
journalist_mode: bool = True,
465+
conversational_awareness: bool = False,
466+
filter_params: Optional[Dict] = None,
467+
sources: List[str] = None,
468+
search_depth: int = 3,
469+
max_depth: int = 5,
470+
*,
471+
http_headers: Optional[Dict] = None,
472+
) -> Union[CreateDeepNewsResponse, Iterator[CreateDeepNewsResponseStream]]:
473+
"""
474+
Get deep news research!
475+
476+
https://docs.asknews.app/en/reference#post-/v1/openai/chat/deepnews
477+
"""
478+
response = self.client.request(
479+
method="POST",
480+
endpoint="/v1/chat/deepnews",
481+
body=CreateDeepNewsRequest(
482+
messages=messages,
483+
model=model,
484+
stream=stream,
485+
inline_citations=inline_citations,
486+
append_references=append_references,
487+
asknews_watermark=asknews_watermark,
488+
journalist_mode=journalist_mode,
489+
conversational_awareness=conversational_awareness,
490+
filter_params=filter_params,
491+
sources=sources if sources else ["asknews"],
492+
search_depth=search_depth,
493+
max_depth=max_depth,
494+
).model_dump(mode="json"),
495+
headers={
496+
**(http_headers or {}),
497+
"Content-Type": CreateDeepNewsRequest.__content_type__,
498+
},
499+
accept=[
500+
(CreateDeepNewsResponse.__content_type__, 1.0),
501+
(CreateDeepNewsResponseStream.__content_type__, 1.0),
502+
],
503+
stream=stream,
504+
stream_type="lines",
505+
)
506+
507+
if stream:
508+
509+
def _stream():
510+
for event in EventSource.from_api_response(response):
511+
if event.content == "[DONE]":
512+
break
513+
yield CreateDeepNewsResponseStream.model_validate_json(event.content)
514+
515+
return _stream()
516+
else:
517+
return CreateDeepNewsResponse.model_validate(response.content)
518+
447519

448520
class AsyncChatAPI(BaseAPI):
449521
"""

asknews_sdk/dto/chat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ class WebSearchResult(BaseModel):
135135
published: str
136136
key_points: List[str]
137137
raw_text: str = ""
138+
as_string_key: Optional[str] = None
138139

139140

140141
class WebSearchResponse(BaseModel):

asknews_sdk/dto/deepnews.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Dict, List, Literal, Optional, Union
4+
5+
from pydantic import BaseModel, ConfigDict, Field
6+
from typing_extensions import Annotated
7+
8+
from asknews_sdk.dto.base import BaseSchema
9+
from asknews_sdk.dto.chat import WebSearchResult
10+
from asknews_sdk.dto.news import SearchResponseDictItem
11+
12+
13+
class DeepNewsSources(BaseModel):
14+
news: Annotated[List[SearchResponseDictItem], Field(title="News")]
15+
web: Annotated[List[WebSearchResult], Field(title="Web")]
16+
17+
18+
class CreateDeepNewsRequestMessage(BaseModel):
19+
role: Annotated[str, Field(title="Role")]
20+
content: Annotated[str, Field(title="Content")]
21+
name: Annotated[Optional[str], Field(None, title="Name")]
22+
function_call: Annotated[Optional[Dict[str, Any]], Field(None, title="Function Call")]
23+
24+
25+
class CreateDeepNewsResponseChoice(BaseModel):
26+
index: Annotated[int, Field(title="Index")]
27+
message: CreateDeepNewsRequestMessage
28+
finish_reason: Annotated[Optional[str], Field(None, title="Finish Reason")]
29+
30+
31+
class CreateDeepNewsResponseStreamChoice(BaseModel):
32+
index: Annotated[int, Field(title="Index")]
33+
delta: CreateDeepNewsRequestMessage
34+
finish_reason: Annotated[Optional[str], Field(None, title="Finish Reason")]
35+
36+
37+
class CreateDeepNewsResponseUsage(BaseModel):
38+
prompt_tokens: Annotated[int, Field(title="Prompt Tokens")]
39+
completion_tokens: Annotated[int, Field(title="Completion Tokens")]
40+
total_tokens: Annotated[int, Field(title="Total Tokens")]
41+
42+
43+
class CreateDeepNewsRequest(BaseSchema):
44+
model_config = ConfigDict(
45+
extra="allow",
46+
)
47+
model: Annotated[Optional[str], Field("deepseek", title="Model")]
48+
messages: Annotated[List[CreateDeepNewsRequestMessage], Field(title="Messages")]
49+
temperature: Annotated[Optional[float], Field(0.9, title="Temperature")]
50+
top_p: Annotated[Optional[float], Field(1.0, title="Top P")]
51+
n: Annotated[Optional[int], Field(1, title="N")]
52+
stream: Annotated[Optional[bool], Field(False, title="Stream")]
53+
stop: Annotated[Optional[Union[str, List[str]]], Field(None, title="Stop")]
54+
max_tokens: Annotated[Optional[int], Field(9999, title="Max Tokens")]
55+
presence_penalty: Annotated[Optional[int], Field(0, title="Presence Penalty")]
56+
frequency_penalty: Annotated[Optional[int], Field(0, title="Frequency Penalty")]
57+
user: Annotated[Optional[str], Field(None, title="User")]
58+
inline_citations: Annotated[
59+
Optional[Literal["markdown_link", "numbered", "none"]],
60+
Field("markdown_link", title="Type of inline citation formatting."),
61+
]
62+
journalist_mode: Annotated[
63+
Optional[bool],
64+
Field(
65+
True,
66+
title=(
67+
"Activate journalist mode, with improved alignment for making claims"
68+
"with supporting evidence. Improved journalistic style."
69+
),
70+
),
71+
]
72+
asknews_watermark: Annotated[
73+
Optional[bool], Field(True, title='Append "Generated by AskNews AI" watermark')
74+
]
75+
append_references: Annotated[Optional[bool], Field(True, title="Append References or not")]
76+
conversational_awareness: Annotated[
77+
Optional[bool], Field(False, title="Conversational Awareness")
78+
]
79+
filter_params: Annotated[
80+
Optional[Dict[str, Any]],
81+
Field(None, title="Any filter param available on the /news endpoint."),
82+
]
83+
sources: Annotated[Optional[List[str]], Field(["asknews"], title="Sources")]
84+
search_depth: Annotated[Optional[int], Field(2, title="Search Depth")]
85+
max_depth: Annotated[Optional[int], Field(4, title="Max Depth")]
86+
87+
88+
class CreateDeepNewsResponse(BaseSchema):
89+
id: Annotated[str, Field(title="Id")]
90+
created: Annotated[int, Field(title="Created")]
91+
object: Annotated[Optional[str], Field("chat.completion", title="Object")]
92+
model: Annotated[Optional[str], Field("deepseek", title="Model")]
93+
usage: CreateDeepNewsResponseUsage
94+
choices: Annotated[List[CreateDeepNewsResponseChoice], Field(title="Choices")]
95+
sources: Annotated[DeepNewsSources, Field(title="Sources")]
96+
97+
98+
class CreateDeepNewsResponseStream(BaseSchema):
99+
__content_type__ = "text/event-stream"
100+
101+
id: Annotated[str, Field(title="Id")]
102+
created: Annotated[int, Field(title="Created")]
103+
object: Annotated[Optional[str], Field("chat.completion.chunk", title="Object")]
104+
model: Annotated[Optional[str], Field("deepseek", title="Model")]
105+
usage: CreateDeepNewsResponseUsage
106+
choices: Annotated[List[CreateDeepNewsResponseStreamChoice], Field(title="Choices")]
107+
sources: Annotated[DeepNewsSources, Field(title="Sources")]

0 commit comments

Comments
 (0)