Skip to content

Commit cae784b

Browse files
lanbytescursoragent
andcommitted
Add TwexAPI Haystack components for tweet search and timelines.
Co-authored-by: Cursor <cursoragent@cursor.com>
0 parents  commit cae784b

26 files changed

Lines changed: 3022 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
test:
14+
name: Python ${{ matrix.python-version }}
15+
runs-on: ubuntu-24.04
16+
timeout-minutes: 20
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
python-version:
21+
- "3.10"
22+
- "3.11"
23+
- "3.12"
24+
- "3.13"
25+
steps:
26+
- uses: actions/checkout@v4
27+
with:
28+
persist-credentials: false
29+
- uses: astral-sh/setup-uv@v6
30+
- uses: actions/setup-python@v5
31+
with:
32+
python-version: ${{ matrix.python-version }}
33+
- run: uv sync --dev
34+
- run: uv run ruff format --check .
35+
- run: uv run ruff check .
36+
- run: uv run pytest

.github/workflows/publish.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types:
6+
- published
7+
8+
permissions: {}
9+
10+
jobs:
11+
publish:
12+
if: github.event.release.prerelease == false
13+
runs-on: ubuntu-24.04
14+
environment: pypi
15+
permissions:
16+
contents: read
17+
id-token: write
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
ref: ${{ github.event.release.tag_name }}
22+
persist-credentials: false
23+
- uses: astral-sh/setup-uv@v6
24+
- uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.13"
27+
- run: uv sync --dev
28+
- run: uv run pytest
29+
- run: uv build
30+
- uses: pypa/gh-action-pypi-publish@release/v1
31+
with:
32+
packages-dir: dist/

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.venv/
2+
__pycache__/
3+
.pytest_cache/
4+
.ruff_cache/
5+
dist/
6+
build/
7+
*.egg-info/
8+
.coverage
9+
htmlcov/
10+
.DS_Store
11+
.env

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
- First release with TwexAPI tweet search and user timeline Haystack components.

CODE_OF_CONDUCT.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Code of Conduct
2+
3+
Be respectful. Do not harass maintainers, contributors, or users.
4+
5+
Unacceptable behavior includes harassment, hate speech, and posting secrets or personal data.
6+
7+
Report issues on GitHub. Maintainers may remove comments, close issues, or block accounts that violate this policy.
8+
9+
This project is not affiliated with X Corp.

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Contributing
2+
3+
- Open an issue for bugs or missing components.
4+
- Keep PRs small. Do not add endpoints that are not in the TwexAPI OpenAPI.
5+
- Do not commit API keys or `.env` files.
6+
- Run `uv run ruff check .` and `uv run pytest` before opening a PR.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 TwexAPI
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Twitter search and user timeline components for Haystack
2+
3+
TwexAPI is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.
4+
5+
Search Twitter and fetch public user timelines in Haystack RAG pipelines. Each TwexAPI result becomes a Haystack `Document`.
6+
7+
## Components
8+
9+
| Task | Haystack component | TwexAPI route | Output |
10+
| --- | --- | --- | --- |
11+
| Search tweets for RAG | `TwexApiTweetSearch` | `POST /twitter/advanced_search/page` | Matching posts as `Document` objects |
12+
| Retrieve a user's timeline | `TwexApiUserTweetsFetcher` | `POST /twitter/{screen_name}/timeline/page` | Recent user posts as `Document` objects |
13+
14+
```python
15+
from haystack_integrations.components.websearch.x_api_scraper import (
16+
TwexApiTweetSearch,
17+
TwexApiUserTweetsFetcher,
18+
)
19+
```
20+
21+
Both components read `X_API_SCRAPER_KEY` by default and accept a Haystack `Secret`. They send `Authorization: Bearer`. Set `base_url` for another TwexAPI-compatible endpoint. Results include `documents`, `links`, `has_more`, and `next_cursor`.
22+
23+
Search returns up to 20 tweets per page. Timeline `top_k` maps to the page `count` (1-100). Use REST or an SDK for follower pagination or approved posting.
24+
25+
## Install
26+
27+
```bash
28+
pip install x-api-scraper-haystack
29+
```
30+
31+
## Build a Haystack RAG pipeline with Twitter search
32+
33+
### Search posts
34+
35+
```python
36+
from haystack import Pipeline
37+
from haystack.utils import Secret
38+
from haystack_integrations.components.websearch.x_api_scraper import TwexApiTweetSearch
39+
40+
search = TwexApiTweetSearch(api_key=Secret.from_env_var("X_API_SCRAPER_KEY"), top_k=10)
41+
42+
pipeline = Pipeline()
43+
pipeline.add_component("x_search", search)
44+
45+
result = pipeline.run({"x_search": {"query": "haystack ai"}})
46+
documents = result["x_search"]["documents"]
47+
```
48+
49+
### Fetch user posts
50+
51+
```python
52+
from haystack.utils import Secret
53+
from haystack_integrations.components.websearch.x_api_scraper import (
54+
TwexApiUserTweetsFetcher,
55+
)
56+
57+
fetcher = TwexApiUserTweetsFetcher(api_key=Secret.from_env_var("X_API_SCRAPER_KEY"))
58+
59+
result = fetcher.run(screen_name="elonmusk")
60+
documents = result["documents"]
61+
```
62+
63+
## Document mapping
64+
65+
Each tweet becomes a Haystack `Document` with this mapping.
66+
67+
- `Document.content`: `full_text` or `text`, or an empty string when both are missing
68+
- `Document.meta["endpoint"]`: `search` or `timeline`
69+
- `Document.meta`: available `id`, `url`, and `created_at` source values
70+
- `Document.meta["author"]`: available author identity and verification data
71+
- `Document.meta`: available like, retweet, reply, quote, view, and bookmark counts
72+
73+
## License
74+
75+
MIT. TwexAPI is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.

SECURITY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Security
2+
3+
Do not file public issues that include API keys, cookies, `auth_token` values, or personal data.
4+
5+
Report suspected vulnerabilities privately through GitHub Security Advisories on this repository.

examples/search_pipeline.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from haystack import Pipeline
2+
from haystack.utils import Secret
3+
4+
from haystack_integrations.components.websearch.x_api_scraper import TwexApiTweetSearch
5+
6+
search = TwexApiTweetSearch(api_key=Secret.from_env_var("X_API_SCRAPER_KEY"), top_k=10)
7+
8+
pipeline = Pipeline()
9+
pipeline.add_component("x_search", search)
10+
11+
result = pipeline.run({"x_search": {"query": "haystack ai"}})
12+
print(result["x_search"]["documents"])

0 commit comments

Comments
 (0)