apify-haystack 0.1.3__tar.gz → 0.1.4__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.
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/PKG-INFO +3 -2
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/README.md +2 -1
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/pyproject.toml +2 -1
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/apify_dataset.py +45 -9
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/crawl_and_process_data.py +1 -0
- apify_haystack-0.1.4/src/apify_haystack/examples/instagram_comments_analysis.py +85 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/LICENSE +0 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/__init__.py +0 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/constants.py +0 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/apify_actor_call.py +0 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/apify_dataset_load.py +0 -0
- {apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/rag_with_crawled_website.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: apify_haystack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Apify-haystack integration
|
|
5
5
|
Home-page: https://apify.com
|
|
6
6
|
License: Apache-2.0
|
|
@@ -97,7 +97,8 @@ See other examples in the [examples directory](https://github.com/apify/apify-ha
|
|
|
97
97
|
- Load a dataset from Apify and convert it to a Haystack Document
|
|
98
98
|
- Call [Website Content Crawler](https://apify.com/apify/website-content-crawler) and convert the data into the Haystack Documents
|
|
99
99
|
- Crawl websites, retrieve text content, and store it in the `InMemoryDocumentStore`
|
|
100
|
-
- Retrieval-Augmented Generation (RAG): Extracting text from a website & question answering
|
|
100
|
+
- Retrieval-Augmented Generation (RAG): Extracting text from a website & question answering <a href="https://colab.research.google.com/github/deepset-ai/haystack-cookbook/blob/main/notebooks/apify_haystack_rag.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
|
|
101
|
+
- Analyze Your Instagram Comments’ Vibe with Apify and Haystack
|
|
101
102
|
|
|
102
103
|
## Support
|
|
103
104
|
|
|
@@ -68,7 +68,8 @@ See other examples in the [examples directory](https://github.com/apify/apify-ha
|
|
|
68
68
|
- Load a dataset from Apify and convert it to a Haystack Document
|
|
69
69
|
- Call [Website Content Crawler](https://apify.com/apify/website-content-crawler) and convert the data into the Haystack Documents
|
|
70
70
|
- Crawl websites, retrieve text content, and store it in the `InMemoryDocumentStore`
|
|
71
|
-
- Retrieval-Augmented Generation (RAG): Extracting text from a website & question answering
|
|
71
|
+
- Retrieval-Augmented Generation (RAG): Extracting text from a website & question answering <a href="https://colab.research.google.com/github/deepset-ai/haystack-cookbook/blob/main/notebooks/apify_haystack_rag.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
|
|
72
|
+
- Analyze Your Instagram Comments’ Vibe with Apify and Haystack
|
|
72
73
|
|
|
73
74
|
## Support
|
|
74
75
|
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "apify_haystack"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.4"
|
|
8
8
|
description = "Apify-haystack integration"
|
|
9
9
|
authors = ["Apify Technologies s.r.o. <support@apify.com>"]
|
|
10
10
|
homepage = "https://apify.com"
|
|
@@ -55,6 +55,7 @@ pytest = "~8.3.0"
|
|
|
55
55
|
pytest-cov = "~5.0.0"
|
|
56
56
|
ruff = "~0.5.0"
|
|
57
57
|
setuptools = "~70.3.0" # setuptools are used by pytest, but not explicitly required
|
|
58
|
+
black = "^24.8.0"
|
|
58
59
|
|
|
59
60
|
[tool.ruff]
|
|
60
61
|
line-length = 120
|
|
@@ -78,7 +78,7 @@ class ApifyDatasetFromActorCall:
|
|
|
78
78
|
self,
|
|
79
79
|
actor_id: str,
|
|
80
80
|
dataset_mapping_function: Callable[[dict], Document],
|
|
81
|
-
run_input: dict,
|
|
81
|
+
run_input: dict | None = None,
|
|
82
82
|
*,
|
|
83
83
|
build: str | None = None,
|
|
84
84
|
memory_mbytes: int | None = None,
|
|
@@ -89,10 +89,12 @@ class ApifyDatasetFromActorCall:
|
|
|
89
89
|
|
|
90
90
|
Args:
|
|
91
91
|
actor_id (str): The ID or name of the Actor on the Apify platform.
|
|
92
|
-
run_input (Dict): The input object of the Actor that you're trying to run.
|
|
93
92
|
dataset_mapping_function (Callable): A function that takes a single
|
|
94
93
|
dictionary (an Apify dataset item) and converts it to an
|
|
95
94
|
instance of the Document class.
|
|
95
|
+
run_input (dict, optional): The input parameters for the Actor you want to run. This can be provided
|
|
96
|
+
either in the `run` method or during the class instantiation. If specified in both places,
|
|
97
|
+
the inputs will be merged.
|
|
96
98
|
build (str, optional): Optionally specifies the actor build to run.
|
|
97
99
|
It can be either a build tag or build number.
|
|
98
100
|
memory_mbytes (int, optional): Optional memory limit for the run, in megabytes.
|
|
@@ -118,16 +120,33 @@ class ApifyDatasetFromActorCall:
|
|
|
118
120
|
if httpx_client := getattr(self.client.http_client, "httpx_client", None):
|
|
119
121
|
httpx_client.headers["user-agent"] += f"; {HAYSTACK_ATTRIBUTE_USER_AGENT}"
|
|
120
122
|
|
|
121
|
-
@component.output_types(documents=list[Document])
|
|
122
|
-
def run(self): # type: ignore[no-untyped-def] # noqa: ANN201
|
|
123
|
+
@component.output_types(documents=list[Document]) # type: ignore[misc]
|
|
124
|
+
def run(self, run_input: dict | None = None): # type: ignore[no-untyped-def] # noqa: ANN201
|
|
123
125
|
"""Run an Actor on the Apify platform and wait for results to be ready.
|
|
124
126
|
|
|
127
|
+
Args:
|
|
128
|
+
run_input (dict, optional): The input parameters for the Actor you want to run. This can be provided
|
|
129
|
+
either in the `run` method or during the class instantiation. If specified in both places,
|
|
130
|
+
the inputs will be merged.
|
|
131
|
+
|
|
132
|
+
Example:
|
|
133
|
+
.. code-block:: python
|
|
134
|
+
|
|
135
|
+
actor = ApifyDatasetFromActorCall(
|
|
136
|
+
actor_id="apify/website-content-crawler",
|
|
137
|
+
run_input={ "maxCrawlPages": 5 }
|
|
138
|
+
)
|
|
139
|
+
dataset = actor.run(run_input={ "startUrls": [{"url": "https://haystack.deepset.ai/"}] })
|
|
140
|
+
|
|
125
141
|
Type-hint note: the output is not type-hinted, otherwise linting complains
|
|
126
142
|
that `run` method is not haystack a component
|
|
127
143
|
"""
|
|
144
|
+
if not (run_input := _merge_inputs(run_input, self.run_input)):
|
|
145
|
+
raise ValueError("Please provide the run_input either in the constructor or in the run method.")
|
|
146
|
+
|
|
128
147
|
if not (
|
|
129
148
|
actor_call := self.client.actor(self.actor_id).call(
|
|
130
|
-
run_input=
|
|
149
|
+
run_input=run_input,
|
|
131
150
|
build=self.build,
|
|
132
151
|
memory_mbytes=self.memory_mbytes,
|
|
133
152
|
timeout_secs=self.timeout_secs,
|
|
@@ -156,7 +175,7 @@ class ApifyDatasetFromTaskCall:
|
|
|
156
175
|
self,
|
|
157
176
|
task_id: str,
|
|
158
177
|
dataset_mapping_function: Callable[[dict], Document],
|
|
159
|
-
task_input: dict,
|
|
178
|
+
task_input: dict | None = None,
|
|
160
179
|
*,
|
|
161
180
|
build: str | None = None,
|
|
162
181
|
memory_mbytes: int | None = None,
|
|
@@ -167,10 +186,12 @@ class ApifyDatasetFromTaskCall:
|
|
|
167
186
|
|
|
168
187
|
Args:
|
|
169
188
|
task_id (str): The ID or name of the Actor on the Apify platform.
|
|
170
|
-
task_input (Dict): The input object of the Actor that you're trying to run.
|
|
171
189
|
dataset_mapping_function (Callable): A function that takes a single
|
|
172
190
|
dictionary (an Apify dataset item) and converts it to an
|
|
173
191
|
instance of the Document class.
|
|
192
|
+
task_input (dict, optional): The input parameters for the Actor you want to run. This can be provided
|
|
193
|
+
either in the `run` method or during the class instantiation. If specified in both places,
|
|
194
|
+
the inputs will be merged.
|
|
174
195
|
build (str, optional): Optionally specifies the Actor build to run.
|
|
175
196
|
It can be either a build tag or build number.
|
|
176
197
|
memory_mbytes (int, optional): Optional memory limit for the run, in megabytes.
|
|
@@ -196,13 +217,22 @@ class ApifyDatasetFromTaskCall:
|
|
|
196
217
|
if httpx_client := getattr(self.client.http_client, "httpx_client", None):
|
|
197
218
|
httpx_client.headers["user-agent"] += f"; {HAYSTACK_ATTRIBUTE_USER_AGENT}"
|
|
198
219
|
|
|
199
|
-
@component.output_types(documents=list[Document])
|
|
200
|
-
def run(self): # type: ignore[no-untyped-def] # noqa: ANN201
|
|
220
|
+
@component.output_types(documents=list[Document]) # type: ignore[misc]
|
|
221
|
+
def run(self, task_input: dict | None = None): # type: ignore[no-untyped-def] # noqa: ANN201
|
|
201
222
|
"""Run an Actor on the Apify platform and wait for results to be ready.
|
|
202
223
|
|
|
224
|
+
Args:
|
|
225
|
+
task_input (dict, optional): The input parameters for the Actor you want to run. This can be provided
|
|
226
|
+
either in the `run` method or during the class instantiation. If specified in both places,
|
|
227
|
+
the inputs will be merged.
|
|
228
|
+
|
|
203
229
|
Type-hint note: the output is not type-hinted, otherwise linting complains
|
|
204
230
|
that `run` method is not haystack a component
|
|
205
231
|
"""
|
|
232
|
+
task_input = task_input or self.task_input
|
|
233
|
+
if not task_input:
|
|
234
|
+
raise ValueError("Please provide the task_input either in the constructor or in the run method.")
|
|
235
|
+
|
|
206
236
|
if not (
|
|
207
237
|
actor_call := self.client.task(self.task_id).call(
|
|
208
238
|
task_input=self.task_input,
|
|
@@ -221,3 +251,9 @@ class ApifyDatasetFromTaskCall:
|
|
|
221
251
|
dataset_mapping_function=self.dataset_mapping_function,
|
|
222
252
|
)
|
|
223
253
|
return loader.run()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _merge_inputs(input1: dict | None, input2: dict | None) -> dict | None:
|
|
257
|
+
if input1 and input2:
|
|
258
|
+
return input1 | input2
|
|
259
|
+
return input1 or input2
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Analyze Your Instagram Comments' Vibe with Apify and Haystack
|
|
3
|
+
|
|
4
|
+
This script demonstrates how to extract comments from an Instagram post using Apify's Instagram Scraper.
|
|
5
|
+
The content is processed using the Haystack pipeline and the vibe of the comments is analyzed using the LLM model.
|
|
6
|
+
|
|
7
|
+
URL = "https://www.instagram.com/p/C_a9jcRuJZZ/" # @tiffintech on How to easily keep up with tech?
|
|
8
|
+
|
|
9
|
+
Expected output:
|
|
10
|
+
......
|
|
11
|
+
Overall, the Instagram post seems to be generating positive energy and high engagement. The comments are filled with
|
|
12
|
+
emojis like 😍, 😂, ❤️, 🙏🏿, and 🙌 which show excitement and enthusiasm .....
|
|
13
|
+
.... Overall, the engagement patterns suggest that the post is vibrating with high energy and positivity.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from haystack import Document, Pipeline
|
|
19
|
+
from haystack.components.builders import PromptBuilder
|
|
20
|
+
from haystack.components.generators import OpenAIGenerator
|
|
21
|
+
from haystack.components.preprocessors import DocumentCleaner
|
|
22
|
+
|
|
23
|
+
from apify_haystack import ApifyDatasetFromActorCall
|
|
24
|
+
|
|
25
|
+
os.environ["APIFY_API_TOKEN"] = "YOUR-APIFY-API-TOKEN"
|
|
26
|
+
os.environ["OPENAI_API_KEY"] = "YOUR-OPENAI-API-KEY"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def dataset_mapping_function(dataset_item: dict) -> Document:
|
|
30
|
+
return Document(
|
|
31
|
+
content=dataset_item.get("text"),
|
|
32
|
+
meta={"ownerUsername": dataset_item.get("ownerUsername")},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
document_loader = ApifyDatasetFromActorCall(
|
|
37
|
+
actor_id="apify/instagram-comment-scraper",
|
|
38
|
+
run_input={"resultsLimit": 50},
|
|
39
|
+
dataset_mapping_function=dataset_mapping_function,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
prompt = """
|
|
43
|
+
Analyze these Instagram comments to determine if the post is generating positive energy, excitement,
|
|
44
|
+
or high engagement. Focus on sentiment, emotional tone, and engagement patterns to conclude if
|
|
45
|
+
the post is 'vibrating' with high energy. Be concise."
|
|
46
|
+
|
|
47
|
+
Context:
|
|
48
|
+
{% for document in documents %}
|
|
49
|
+
{{ document.content }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
|
|
52
|
+
Analysis:
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
cleaner = DocumentCleaner(
|
|
56
|
+
remove_empty_lines=True,
|
|
57
|
+
remove_extra_whitespaces=True,
|
|
58
|
+
remove_repeated_substrings=True,
|
|
59
|
+
)
|
|
60
|
+
prompt_builder = PromptBuilder(template=prompt)
|
|
61
|
+
generator = OpenAIGenerator(model="gpt-3.5-turbo")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
pipe = Pipeline()
|
|
65
|
+
pipe.add_component("loader", document_loader)
|
|
66
|
+
pipe.add_component("cleaner", cleaner)
|
|
67
|
+
pipe.add_component("prompt_builder", prompt_builder)
|
|
68
|
+
pipe.add_component("llm", generator)
|
|
69
|
+
pipe.connect("loader", "cleaner")
|
|
70
|
+
pipe.connect("cleaner", "prompt_builder")
|
|
71
|
+
pipe.connect("prompt_builder", "llm")
|
|
72
|
+
|
|
73
|
+
print("Vibe analysis:\n")
|
|
74
|
+
|
|
75
|
+
url1 = "https://www.instagram.com/p/C_a9jcRuJZZ/" # @tiffintech on How to easily keep up with tech?
|
|
76
|
+
print(f"\nScraping Instagram comments for: {url1} and running analysis (it might take around 30-60 secs) ...\n")
|
|
77
|
+
|
|
78
|
+
res = pipe.run({"loader": {"run_input": {"directUrls": [url1]}}})
|
|
79
|
+
print("Analysis:", res.get("llm", {}).get("replies", ["No response"])[0])
|
|
80
|
+
|
|
81
|
+
url2 = "https://www.instagram.com/p/C_RgBzogufK/" # @maharishis on Affordable Care Act
|
|
82
|
+
print(f"\nScraping Instagram comments for: {url2} and running analysis (it might take around 30-60 secs)... \n")
|
|
83
|
+
|
|
84
|
+
res = pipe.run({"loader": {"run_input": {"directUrls": [url2]}}})
|
|
85
|
+
print("Analysis:", res.get("llm", {}).get("replies", ["No response"])[0])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/apify_actor_call.py
RENAMED
|
File without changes
|
{apify_haystack-0.1.3 → apify_haystack-0.1.4}/src/apify_haystack/examples/apify_dataset_load.py
RENAMED
|
File without changes
|
|
File without changes
|