Skip to content

Commit

Permalink
fix conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
yu23ki14 committed Nov 2, 2024
2 parents 550be18 + 62a6d39 commit 3e17ab7
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
BirdXplorer is software that helps users explore community notes data on X
(formerly known as Twitter).

## Example Usecase

See [example](./docs/example.md)

## Development

### Requirements
Expand Down
12 changes: 6 additions & 6 deletions api/birdxplorer_api/routers/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ def get_notes(
@router.get("/posts", description=V1DataPostsDocs.description, response_model=PostListResponse)
def get_posts(
request: Request,
post_id: Union[List[PostId], None] = Query(default=None, **V1DataPostsDocs.params["post_id"]),
note_id: Union[List[NoteId], None] = Query(default=None, **V1DataPostsDocs.params["note_id"]),
post_ids: Union[List[PostId], None] = Query(default=None),
note_ids: Union[List[NoteId], None] = Query(default=None),
created_at_from: Union[None, TwitterTimestamp, str] = Query(
default=None, **V1DataPostsDocs.params["created_at_from"]
),
Expand All @@ -270,8 +270,8 @@ def get_posts(
created_at_to = ensure_twitter_timestamp(created_at_to)
posts = list(
storage.get_posts(
post_ids=post_id,
note_ids=note_id,
post_ids=post_ids,
note_ids=note_ids,
start=created_at_from,
end=created_at_to,
search_text=search_text,
Expand All @@ -283,8 +283,8 @@ def get_posts(
)

total_count = storage.get_number_of_posts(
post_ids=post_id,
note_ids=note_id,
post_ids=post_ids,
note_ids=note_ids,
start=created_at_from,
end=created_at_to,
search_text=search_text,
Expand Down
10 changes: 5 additions & 5 deletions api/tests/routers/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_posts_get_limit_and_offset(client: TestClient, post_samples: List[Post]


def test_posts_get_has_post_id_filter(client: TestClient, post_samples: List[Post]) -> None:
response = client.get(f"/api/v1/data/posts/?postId={post_samples[0].post_id},{post_samples[2].post_id}")
response = client.get(f"/api/v1/data/posts/?postIds={post_samples[0].post_id},{post_samples[2].post_id}")
assert response.status_code == 200
res_json = response.json()
assert res_json == {
Expand All @@ -57,7 +57,7 @@ def test_posts_get_has_post_id_filter(client: TestClient, post_samples: List[Pos


def test_posts_get_has_note_id_filter(client: TestClient, post_samples: List[Post], note_samples: List[Note]) -> None:
response = client.get(f"/api/v1/data/posts/?noteId={','.join([n.note_id for n in note_samples])}")
response = client.get(f"/api/v1/data/posts/?noteIds={','.join([n.note_id for n in note_samples])}")
assert response.status_code == 200
res_json = response.json()
assert res_json == {"data": [json.loads(post_samples[0].model_dump_json())], "meta": {"next": None, "prev": None}}
Expand Down Expand Up @@ -123,7 +123,7 @@ def test_posts_get_timestamp_out_of_range(client: TestClient, post_samples: List


def test_posts_get_with_media_by_default(client: TestClient, post_samples: List[Post]) -> None:
response = client.get("/api/v1/data/posts/?postId=2234567890123456791")
response = client.get("/api/v1/data/posts/?postIds=2234567890123456791")

assert response.status_code == 200
res_json_default = response.json()
Expand All @@ -134,7 +134,7 @@ def test_posts_get_with_media_by_default(client: TestClient, post_samples: List[


def test_posts_get_with_media_true(client: TestClient, post_samples: List[Post]) -> None:
response = client.get("/api/v1/data/posts/?postId=2234567890123456791&media=true")
response = client.get("/api/v1/data/posts/?postIds=2234567890123456791&media=true")

assert response.status_code == 200
res_json_default = response.json()
Expand All @@ -146,7 +146,7 @@ def test_posts_get_with_media_true(client: TestClient, post_samples: List[Post])

def test_posts_get_with_media_false(client: TestClient, post_samples: List[Post]) -> None:
expected_post = post_samples[1].model_copy(update={"media_details": []})
response = client.get("/api/v1/data/posts/?postId=2234567890123456791&media=false")
response = client.get("/api/v1/data/posts/?postIds=2234567890123456791&media=false")

assert response.status_code == 200
res_json_default = response.json()
Expand Down
50 changes: 50 additions & 0 deletions docs/example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# BirdXplorer の 使用例

## API仕様の閲覧

API 仕様は、[Swagger UI](https://birdxplorer.onrender.com/docs) で閲覧できます。

また、[OpenAPI Spec](https://birdxplorer.onrender.com/openapi.json) も提供しています。

> [!TIP]
> OpenAPI Specification から API リクエスト用のコードを生成するライブラリを使用することで、
> API の入出力をコード上で安全に扱えることがあります。
## 特定のトピックのコミュニティノートと、そのトピックに関連するツイートを取得する

BirdXplorer では、コミュニティノートのトピックを AI で推定して分類しています。
この分類の候補は、 `/api/v1/data/topics` で取得できます。

ここでは、トピック: テクノロジー (topicId: 51) について、そのコミュニティノート500件とコミュニティノートに関連するツイートを取得する例を示します。

```python
#!python3.10
import json

import requests

# AI で推定 / 分類した際に 「テクノロジー」 と判定されたコミュニティノートを取得するための id
# その他の種類は `https://birdxplorer.onrender.com/api/v1/data/topics` で取得できます
TECHNOLOGY_TOPIC_ID = 51

offset = 0
expected_data_amount = 500 # 最大で 1000 まで指定できます

tech_notes_res = requests.get(
f"https://birdxplorer.onrender.com/api/v1/data/notes?offset={offset}&limit={expected_data_amount}&topic_ids={TECHNOLOGY_TOPIC_ID}&language=ja"
)
tech_notes = tech_notes_res.json()["data"]

# コミュニティノート と X の Post は 1:1 で対応しています
tech_post_ids = list(map(lambda x: x["postId"], tech_notes))
post_ids = ",".join(tech_post_ids)

posts_res = requests.get(
f"https://birdxplorer.onrender.com/api/v1/data/posts?post_ids={post_ids}&limit={expected_data_amount}"
)
tech_posts = posts_res.json()["data"]


with open("tech_posts.json", "w") as f:
f.write(json.dumps(tech_posts, ensure_ascii=False, indent=2))
```

0 comments on commit 3e17ab7

Please sign in to comment.