From 67979475677f4ec494d3752105fa9ba836c30c3b Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Tue, 7 Jan 2025 14:00:04 +0100 Subject: [PATCH 1/9] removed examples --- examples/anthropic/.env.example | 1 - .../code_generator_graph_anthropic.py | 59 --- examples/anthropic/custom_graph_anthropic.py | 94 ---- .../anthropic/depth_search_graph_anthropic.py | 28 -- .../anthropic/document_scraper_anthropic.py | 42 -- examples/anthropic/inputs/books.xml | 120 ------ examples/anthropic/inputs/example.json | 182 -------- .../anthropic/inputs/plain_html_example.txt | 105 ----- examples/anthropic/inputs/username.csv | 7 - examples/anthropic/json_scraper_anthropic.py | 43 -- .../anthropic/json_scraper_multi_anthropic.py | 35 -- examples/anthropic/rate_limit_anthropic.py | 47 -- .../anthropic/scrape_plain_text_anthropic.py | 52 --- .../anthropic/script_generator_anthropic.py | 42 -- .../script_multi_generator_anthropic.py | 51 --- examples/anthropic/search_graph_anthropic.py | 43 -- .../search_graph_schema_anthropic.py | 44 -- .../anthropic/search_link_graph_anthropic.py | 45 -- examples/anthropic/smart_scraper_anthropic.py | 41 -- .../anthropic/smart_scraper_lite_anthropic.py | 32 -- .../smart_scraper_multi_anthropic.py | 56 --- .../smart_scraper_multi_concat_anthropic.py | 38 -- .../smart_scraper_multi_lite_anthropic.py | 35 -- .../smart_scraper_schema_anthropic.py | 51 --- examples/anthropic/xml_scraper_anthropic.py | 55 --- .../xml_scraper_graph_multi_anthropic.py | 55 --- examples/azure/code_generator_graph_azure.py | 57 --- examples/azure/csv_scraper_azure.py | 56 --- .../azure/csv_scraper_graph_multi_azure.py | 55 --- examples/azure/depth_search_graph_azure.py | 28 -- examples/azure/document_scraper_azure.py | 44 -- examples/azure/inputs/books.xml | 120 ------ examples/azure/inputs/example.json | 182 -------- examples/azure/inputs/username.csv | 7 - examples/azure/json_scraper_azure.py | 45 -- examples/azure/json_scraper_multi_azure.py | 38 -- examples/azure/rate_limit_azure.py | 56 --- examples/azure/scrape_plain_text_azure.py | 54 --- examples/azure/script_generator_azure.py | 43 -- .../azure/script_multi_generator_azure.py | 52 --- examples/azure/search_graph_azure.py | 51 --- examples/azure/search_graph_schema_azure.py | 60 --- examples/azure/search_link_graph_azure.py | 45 -- examples/azure/smart_scraper_azure.py | 44 -- examples/azure/smart_scraper_lite_azure.py | 31 -- examples/azure/smart_scraper_multi_azure.py | 38 -- .../azure/smart_scraper_multi_concat_azure.py | 38 -- .../azure/smart_scraper_multi_lite_azure.py | 35 -- examples/azure/smart_scraper_schema_azure.py | 49 --- examples/azure/xml_scraper_azure.py | 46 -- .../azure/xml_scraper_graph_multi_azure.py | 56 --- examples/bedrock/.env.example | 4 - examples/bedrock/README.md | 3 - .../bedrock/code_generator_graph_bedrock.py | 60 --- examples/bedrock/csv_scraper_bedrock.py | 50 --- .../csv_scraper_graph_multi_bedrock.py | 56 --- examples/bedrock/custom_graph_bedrock.py | 125 ------ .../bedrock/depth_search_graph_bedrock.py | 25 -- examples/bedrock/document_scraper_bedrock.py | 42 -- examples/bedrock/inputs/books.xml | 120 ------ examples/bedrock/inputs/example.json | 38 -- .../bedrock/inputs/plain_html_example.txt | 105 ----- examples/bedrock/inputs/username.csv | 6 - examples/bedrock/json_scraper_bedrock.py | 57 --- .../bedrock/json_scraper_multi_bedrock.py | 32 -- examples/bedrock/rate_limit_bedrock.py | 44 -- examples/bedrock/scrape_plain_text_bedrock.py | 54 --- examples/bedrock/scrapegraphai_bedrock.png | Bin 82480 -> 0 bytes examples/bedrock/script_generator_bedrock.py | 43 -- .../bedrock/script_multi_generator_bedrock.py | 48 --- examples/bedrock/search_graph_bedrock.py | 27 -- .../bedrock/search_graph_schema_bedrock.py | 54 --- examples/bedrock/search_link_graph_bedrock.py | 40 -- examples/bedrock/smart_scraper_bedrock.py | 42 -- .../bedrock/smart_scraper_lite_bedrock.py | 26 -- .../bedrock/smart_scraper_multi_bedrock.py | 34 -- .../smart_scraper_multi_concat_bedrock.py | 35 -- .../smart_scraper_multi_lite_bedrock.py | 29 -- .../bedrock/smart_scraper_schema_bedrock.py | 52 --- examples/bedrock/xml_scraper_bedrock.py | 58 --- .../xml_scraper_graph_multi_bedrock.py | 56 --- .../benchmarks/GenerateScraper/.env.example | 1 - examples/benchmarks/GenerateScraper/Readme.md | 43 -- .../GenerateScraper/benchmark_docker.py | 0 .../GenerateScraper/benchmark_groq.py | 61 --- .../GenerateScraper/benchmark_llama3.py | 57 --- .../GenerateScraper/benchmark_mistral.py | 62 --- .../GenerateScraper/benchmark_openai_gpt35.py | 53 --- .../GenerateScraper/benchmark_openai_gpt4.py | 53 --- .../GenerateScraper/inputs/example_1.txt | 105 ----- .../GenerateScraper/inputs/example_2.txt | 400 ------------------ examples/benchmarks/SmartScraper/.env.example | 1 - examples/benchmarks/SmartScraper/Readme.md | 42 -- .../SmartScraper/benchmark_docker.py | 51 --- .../benchmarks/SmartScraper/benchmark_groq.py | 57 --- .../SmartScraper/benchmark_llama3.py | 53 --- .../SmartScraper/benchmark_mistral.py | 54 --- .../SmartScraper/benchmark_openai_gpt35.py | 52 --- .../SmartScraper/benchmark_openai_gpt4.py | 53 --- .../SmartScraper/benchmark_openai_gpt4o.py | 53 --- .../SmartScraper/inputs/example_1.txt | 105 ----- .../SmartScraper/inputs/example_2.txt | 400 ------------------ examples/benchmarks/readme.md | 4 - examples/deepseek/.env.example | 1 - .../deepseek/code_generator_graph_deepseek.py | 59 --- examples/deepseek/csv_scraper_deepseek.py | 56 --- .../csv_scraper_graph_multi_deepseek.py | 56 --- .../deepseek/depth_search_graph_deepseek.py | 30 -- .../deepseek/document_scraper_deepseek.py | 44 -- examples/deepseek/inputs/books.xml | 120 ------ examples/deepseek/inputs/example.json | 182 -------- examples/deepseek/inputs/username.csv | 7 - examples/deepseek/json_scraper_deepseek.py | 46 -- .../deepseek/json_scraper_multi_deepseek.py | 37 -- examples/deepseek/rate_limit_deepseek.py | 47 -- .../deepseek/scrape_plain_text_deepseek.py | 54 --- .../deepseek/script_generator_deepseek.py | 44 -- .../script_multi_generator_deepseek.py | 53 --- examples/deepseek/search_graph_deepseek.py | 35 -- .../deepseek/search_graph_schema_deepseek.py | 60 --- .../deepseek/search_link_graph_deepseek.py | 46 -- examples/deepseek/smart_scraper_deepseek.py | 44 -- .../deepseek/smart_scraper_lite_deepseek.py | 31 -- .../smart_scraper_multi_concat_deepseek.py | 41 -- .../deepseek/smart_scraper_multi_deepseek.py | 41 -- .../smart_scraper_multi_lite_deepseek.py | 35 -- .../deepseek/smart_scraper_schema_deepseek.py | 58 --- examples/deepseek/xml_scraper_deepseek.py | 59 --- .../xml_scraper_graph_multi_deepseek.py | 57 --- examples/ernie/code_generator_graph_ernie.py | 61 --- examples/ernie/csv_scraper_ernie.py | 57 --- examples/ernie/custom_graph_ernie.py | 106 ----- examples/ernie/depth_search_graph_ernie.py | 26 -- .../ernie/document_scraper_anthropic_ernie.py | 39 -- examples/ernie/inputs/books.xml | 120 ------ examples/ernie/inputs/example.json | 182 -------- examples/ernie/inputs/plain_html_example.txt | 105 ----- examples/ernie/inputs/username.csv | 7 - examples/ernie/json_scraper_ernie.py | 43 -- examples/ernie/rate_limit_ernie.py | 47 -- examples/ernie/scrape_plain_text_ernie.py | 54 --- examples/ernie/script_generator_ernie.py | 43 -- .../ernie/script_multi_generator_ernie.py | 49 --- examples/ernie/search_graph_ernie.py | 33 -- examples/ernie/search_link_graph_ernie.py | 42 -- examples/ernie/smart_scraper_ernie.py | 40 -- examples/ernie/smart_scraper_lite_ernie.py | 31 -- .../ernie/smart_scraper_multi_concat_ernie.py | 35 -- examples/ernie/smart_scraper_multi_ernie.py | 41 -- .../ernie/smart_scraper_multi_lite_ernie.py | 35 -- examples/ernie/smart_scraper_schema_ernie.py | 54 --- examples/ernie/speech_graph_ernie.py | 58 --- examples/ernie/xml_scraper_ernie.py | 61 --- examples/extras/.env.example | 4 - .../extras/Savedscreenshots/test_image.jpeg | Bin 178104 -> 0 bytes examples/extras/authenticated_playwright.py | 93 ---- examples/extras/browser_base_integration.py | 49 --- examples/extras/chromium_selenium.py | 119 ------ examples/extras/cond_smartscraper_usage.py | 38 -- examples/extras/conditional_usage.py | 41 -- examples/extras/custom_prompt.py | 50 --- examples/extras/example.yml | 15 - examples/extras/force_mode.py | 54 --- examples/extras/html_mode.py | 49 --- examples/extras/load_yml.py | 32 -- examples/extras/no_cut.py | 43 -- examples/extras/proxy_rotation.py | 48 --- examples/extras/rag_caching.py | 46 -- examples/extras/reasoning.py | 46 -- examples/extras/scrape_do.py | 40 -- examples/extras/screenshot_scaping.py | 32 -- examples/extras/serch_graph_scehma.py | 43 -- examples/extras/slow_mo.py | 48 --- examples/extras/undected_playwright.py | 47 -- examples/fireworks/.env.example | 1 - .../code_generator_graph_fireworks.py | 60 --- examples/fireworks/csv_scraper_fireworks.py | 57 --- .../csv_scraper_graph_multi_fireworks.py | 57 --- examples/fireworks/custom_graph_fireworks.py | 98 ----- .../fireworks/depth_search_graph_fireworks.py | 30 -- .../document_scraper_anthropic_fireworks.py | 44 -- examples/fireworks/inputs/books.xml | 120 ------ examples/fireworks/inputs/example.json | 182 -------- .../fireworks/inputs/plain_html_example.txt | 105 ----- examples/fireworks/inputs/username.csv | 7 - .../fireworks/json_scraper_fireworkspy.py | 47 -- .../fireworks/json_scraper_multi_fireworks.py | 39 -- examples/fireworks/rate_limit_fireworks.py | 49 --- .../fireworks/scrape_plain_text_fireworks.py | 54 --- .../fireworks/script_generator_fireworks.py | 47 -- .../script_generator_schema_fireworks.py | 60 --- .../script_multi_generator_fireworks.py | 52 --- examples/fireworks/search_graph_fireworks.py | 36 -- .../search_graph_schema_fireworks.py | 62 --- .../fireworks/search_link_graph_fireworks.py | 47 -- examples/fireworks/smart_scraper_fireworks.py | 46 -- .../fireworks/smart_scraper_lite_fireworks.py | 31 -- .../smart_scraper_multi_concat_fireworks.py | 37 -- .../smart_scraper_multi_fireworks.py | 40 -- .../smart_scraper_multi_lite_fireworks.py | 35 -- .../smart_scraper_schema_fireworks.py | 49 --- examples/fireworks/xml_scraper_fireworks.py | 58 --- .../xml_scraper_graph_multi_fireworks.py | 58 --- examples/google_genai/.env.example | 1 - .../code_generator_graph_gemini.py | 59 --- examples/google_genai/csv_scraper_gemini.py | 52 --- .../csv_scraper_graph_multi_gemini.py | 56 --- .../google_genai/depth_search_graph_gemini.py | 30 -- .../google_genai/document_scraper_gemini.py | 41 -- examples/google_genai/inputs/books.xml | 120 ------ examples/google_genai/inputs/example.json | 182 -------- .../inputs/plain_html_example.txt | 105 ----- examples/google_genai/inputs/username.csv | 7 - examples/google_genai/json_scraper_gemini.py | 46 -- .../google_genai/json_scraper_multi_gemini.py | 38 -- examples/google_genai/rate_limit_gemini.py | 46 -- examples/google_genai/readme.md | 1 - .../google_genai/scrape_plain_text_gemini.py | 56 --- examples/google_genai/scrape_xml_gemini.py | 56 --- .../google_genai/script_generator_gemini.py | 44 -- .../script_multi_generator_gemini.py | 53 --- examples/google_genai/search_graph_gemini.py | 41 -- .../search_graph_schema_gemini.py | 58 --- .../google_genai/search_link_graph_gemini.py | 44 -- examples/google_genai/smart_scraper_gemini.py | 44 -- .../smart_scraper_lite_google_genai.py | 31 -- .../smart_scraper_multi_concat_gemini.py | 39 -- .../smart_scraper_multi_gemini.py | 39 -- .../smart_scraper_multi_lite_gemini.py | 0 .../smart_scraper_multi_lite_google_genai.py | 34 -- .../smart_scraper_schema_gemini.py | 56 --- examples/google_genai/xml_scraper_gemini.py | 57 --- .../xml_scraper_graph_multi_gemini.py | 57 --- examples/google_vertexai/.env.example | 1 - .../code_generator_graph_vertex.py | 60 --- .../google_vertexai/csv_scraper_gemini.py | 53 --- .../csv_scraper_graph_multi_gemini.py | 57 --- .../google_vertexai/custom_graph_gemini.py | 84 ---- .../depth_search_graph_gemini.py | 30 -- .../document_scraper_vertex.py | 41 -- examples/google_vertexai/inputs/books.xml | 120 ------ examples/google_vertexai/inputs/example.json | 182 -------- .../inputs/plain_html_example.txt | 105 ----- examples/google_vertexai/inputs/username.csv | 7 - .../google_vertexai/json_scraper_gemini.py | 46 -- .../json_scraper_multi_gemini.py | 38 -- examples/google_vertexai/rate_limit_gemini.py | 47 -- examples/google_vertexai/readme.md | 1 - .../scrape_plain_text_gemini.py | 56 --- examples/google_vertexai/scrape_xml_gemini.py | 57 --- .../script_generator_gemini.py | 46 -- .../script_multi_generator_gemini.py | 54 --- .../google_vertexai/search_graph_gemini.py | 42 -- .../search_graph_schema_gemini.py | 61 --- .../search_link_graph_gemini.py | 44 -- .../google_vertexai/smart_scraper_gemini.py | 44 -- .../smart_scraper_lite_google_vertexai.py | 33 -- .../smart_scraper_multi_concat_gemini.py | 36 -- .../smart_scraper_multi_gemini.py | 39 -- ...mart_scraper_multi_lite_google_vertexai.py | 35 -- .../smart_scraper_multi_lite_vertex.py | 47 -- .../smart_scraper_schema_gemini.py | 56 --- .../google_vertexai/xml_scraper_gemini.py | 57 --- .../xml_scraper_graph_multi_gemini.py | 57 --- examples/groq/.env.example | 2 - examples/groq/code_generator_graph_groq.py | 60 --- examples/groq/csv_scraper_graph_multi_groq.py | 58 --- examples/groq/csv_scraper_groq.py | 57 --- examples/groq/custom_graph_groq.py | 99 ----- examples/groq/depth_search_graph_groq.py | 31 -- examples/groq/document_scraper_groq.py | 45 -- examples/groq/inputs/books.xml | 120 ------ examples/groq/inputs/example.json | 182 -------- examples/groq/inputs/plain_html_example.txt | 105 ----- examples/groq/inputs/username.csv | 7 - examples/groq/json_scraper_groq.py | 49 --- examples/groq/json_scraper_multi_groq.py | 38 -- examples/groq/rate_limit_groq.py | 48 --- examples/groq/scrape_plain_text_groq.py | 57 --- examples/groq/script_generator_groq.py | 44 -- examples/groq/script_multi_generator_groq.py | 55 --- examples/groq/search_graph_groq.py | 40 -- examples/groq/search_graph_schema_groq.py | 62 --- examples/groq/search_link_graph_groq.py | 47 -- examples/groq/smart_scraper_groq.py | 45 -- examples/groq/smart_scraper_lite_groq.py | 31 -- .../groq/smart_scraper_multi_concat_groq.py | 41 -- examples/groq/smart_scraper_multi_groq.py | 41 -- .../groq/smart_scraper_multi_lite_groq.py | 35 -- examples/groq/smart_scraper_schema_groq.py | 59 --- examples/groq/xml_scraper_graph_multi_groq.py | 59 --- examples/groq/xml_scraper_groq.py | 60 --- .../code_generator_graph_huggingfacehub.py | 71 ---- .../csv_scraper_graph_multi_huggingfacehub.py | 68 --- .../csv_scraper_huggingfacehub.py | 70 --- .../custom_graph_huggingfacehub.py | 121 ------ .../depth_search_graph_huggingfacehub.py | 38 -- .../document_scraper_huggingfacehub.py | 57 --- examples/huggingfacehub/inputs/books.xml | 120 ------ examples/huggingfacehub/inputs/example.json | 182 -------- .../inputs/plain_html_example.txt | 105 ----- examples/huggingfacehub/inputs/username.csv | 7 - .../json_scraper_huggingfacehub.py | 59 --- .../json_scraper_multi_huggingfacehub.py | 45 -- .../scrape_plain_text_huggingfacehub.py | 68 --- .../script_generator_huggingfacehub.py | 60 --- .../script_multi_generator_huggingfacehub.py | 66 --- .../search_graph_huggingfacehub.py | 55 --- .../search_link_graph_huggingfacehub.py | 53 --- .../smart_scraper_huggingfacehub.py | 58 --- .../smart_scraper_lite_huggingfacehub.py | 31 -- ...art_scraper_multi_concat_huggingfacehub.py | 53 --- .../smart_scraper_multi_huggingfacehub.py | 48 --- ...smart_scraper_multi_lite_huggingfacehub.py | 34 -- ...smart_scraper_multi_lite_uhggingfacehub.py | 0 .../smart_scraper_schema_huggingfacehub.py | 67 --- .../xml_scraper_graph_multi_huggingfacehub.py | 67 --- .../xml_scraper_huggingfacehub.py | 68 --- .../integrations/indexify_node_example.py | 72 ---- .../code_generator_graph_ollama.py | 61 --- .../csv_scraper_graph_multi_ollama.py | 62 --- examples/local_models/csv_scraper_ollama.py | 62 --- examples/local_models/custom_graph_ollama.py | 101 ----- .../local_models/depth_search_graph_ollama.py | 32 -- .../local_models/document_scraper_ollama.py | 42 -- examples/local_models/inputs/books.xml | 120 ------ examples/local_models/inputs/example.json | 182 -------- .../inputs/plain_html_example.txt | 105 ----- examples/local_models/inputs/username.csv | 7 - .../local_models/json_scraper_multi_ollama.py | 36 -- examples/local_models/json_scraper_ollama.py | 59 --- examples/local_models/package-lock.json | 6 - examples/local_models/package.json | 1 - .../local_models/scrape_plain_text_ollama.py | 54 --- .../local_models/script_generator_ollama.py | 40 -- .../script_multi_generator_ollama.py | 55 --- examples/local_models/search_graph_ollama.py | 44 -- .../search_graph_schema_ollama.py | 58 --- .../local_models/search_link_graph_ollama.py | 51 --- .../local_models/smart_scraper_lite_ollama.py | 30 -- .../smart_scraper_multi_concat_ollama.py | 42 -- .../smart_scraper_multi_lite_ollama.py | 45 -- .../smart_scraper_multi_ollama.py | 39 -- .../smart_scraper_schema_ollama.py | 43 -- .../xml_scraper_graph_multi_ollama.py | 58 --- examples/local_models/xml_scraper_ollama.py | 58 --- examples/mistral/.env.example | 1 - .../mistral/code_generator_graph_mistral.py | 59 --- .../csv_scraper_graph_multi_mistral.py | 56 --- examples/mistral/csv_scraper_mistral.py | 57 --- examples/mistral/custom_graph_mistral.py | 108 ----- .../mistral/depth_search_graph_mistral.py | 30 -- examples/mistral/document_scraper_mistral.py | 43 -- examples/mistral/inputs/books.xml | 120 ------ examples/mistral/inputs/example.json | 182 -------- examples/mistral/inputs/markdown_example.md | 35 -- .../mistral/inputs/plain_html_example.txt | 105 ----- examples/mistral/inputs/username.csv | 7 - examples/mistral/json_scraper_mistral.py | 46 -- .../mistral/json_scraper_multi_mistral.py | 37 -- examples/mistral/md_scraper_mistral.py | 57 --- examples/mistral/rate_limit_mistral.py | 39 -- examples/mistral/readme.md | 1 - examples/mistral/scrape_plain_text_mistral.py | 54 --- examples/mistral/script_generator_mistral.py | 45 -- .../script_generator_schema_mistral.py | 61 --- .../mistral/script_multi_generator_mistral.py | 54 --- examples/mistral/search_graph_mistral.py | 35 -- .../mistral/search_graph_schema_mistral.py | 61 --- examples/mistral/search_link_graph_mistral.py | 42 -- .../mistral/smart_scraper_lite_mistral.py | 31 -- examples/mistral/smart_scraper_mistral.py | 36 -- .../smart_scraper_multi_concat_mistral.py | 38 -- .../smart_scraper_multi_lite_mistral.py | 35 -- .../mistral/smart_scraper_multi_mistral.py | 41 -- .../mistral/smart_scraper_schema_mistral.py | 50 --- .../xml_scraper_graph_multi_mistral.py | 57 --- examples/mistral/xml_scraper_mistral.py | 58 --- examples/model_instance/.env.example | 1 - .../smart_scraper_with_model_instace.py | 53 --- examples/moonshot/.env.example | 1 - .../moonshot/code_generator_graph_moonshot.py | 67 --- .../moonshot/document_scraper_moonshot.py | 43 -- examples/moonshot/readme.md | 1 - .../moonshot/smart_scraper_lite_moonshot.py | 31 -- .../smart_scraper_multi_concat_moonshot.py | 52 --- .../smart_scraper_multi_lite_moonshot.py | 34 -- .../moonshot/smart_scraper_with_moonshot.py | 54 --- .../nemotron/code_generator_graph_nemotron.py | 57 --- .../csv_scraper_graph_multi_nemotron.py | 54 --- examples/nemotron/csv_scraper_nemotron.py | 57 --- .../nemotron/depth_search_graph_nemotron.py | 30 -- .../nemotron/document_scraper_nemotron.py | 44 -- examples/nemotron/inputs/books.xml | 120 ------ examples/nemotron/inputs/example.json | 182 -------- examples/nemotron/inputs/markdown_example.md | 35 -- .../nemotron/inputs/plain_html_example.txt | 105 ----- examples/nemotron/inputs/username.csv | 7 - .../nemotron/json_scraper_multi_nemotron.py | 37 -- examples/nemotron/json_scraper_nemotron.py | 57 --- examples/nemotron/md_scraper_nemotron.py | 57 --- examples/nemotron/rate_limit_nemotron.py | 47 -- .../nemotron/scrape_plain_text_nemotron.py | 54 --- .../nemotron/script_generator_nemotron.py | 44 -- .../script_generator_schema_nemotron.py | 59 --- .../script_multi_generator_nemotron.py | 54 --- examples/nemotron/search_graph_nemotron.py | 35 -- .../nemotron/search_graph_schema_nemotron.py | 62 --- .../nemotron/search_link_graph_nemotron.py | 41 -- .../nemotron/smart_scraper_lite_nemotron.py | 32 -- .../smart_scraper_multi_concat_nemotron.py | 38 -- .../smart_scraper_multi_lite_nemotron.py | 46 -- .../nemotron/smart_scraper_multi_nemotron.py | 41 -- examples/nemotron/smart_scraper_nemotron.py | 45 -- .../nemotron/smart_scraper_schema_nemotron.py | 50 --- examples/nemotron/speech_graph_nemotron.py | 50 --- .../nemotron/xml_scraper_graph_nemotron.py | 60 --- examples/nemotron/xml_scraper_nemotron.py | 59 --- .../oneapi/code_generator_graph_oneapi.py | 60 --- .../oneapi/csv_scraper_graph_multi_oneapi.py | 56 --- examples/oneapi/csv_scraper_oneapi.py | 55 --- examples/oneapi/custom_graph_oneapi.py | 105 ----- examples/oneapi/depth_search_graph_onenapi.py | 31 -- examples/oneapi/document_scraper_oneapi.py | 42 -- examples/oneapi/inputs/books.xml | 120 ------ examples/oneapi/inputs/example.json | 182 -------- .../oneapi/inputs/plain_html_example copy.txt | 105 ----- examples/oneapi/inputs/plain_html_example.txt | 105 ----- examples/oneapi/inputs/username.csv | 7 - examples/oneapi/json_scraper_multi_oneapi.py | 33 -- examples/oneapi/json_scraper_oneapi.py | 53 --- examples/oneapi/rate_limit_oneapi.py | 41 -- examples/oneapi/scrape_plain_text_oneapi.py | 53 --- examples/oneapi/script_generator_oneapi.py | 43 -- .../oneapi/script_multi_generator_oneapi.py | 48 --- examples/oneapi/search_graph_oneapi.py | 29 -- examples/oneapi/search_graph_schema_oneapi.py | 55 --- examples/oneapi/smart_scraper_lite_oneapi.py | 32 -- .../smart_scraper_multi_concat_oneapi.py | 35 -- .../oneapi/smart_scraper_multi_lite_oneapi.py | 43 -- examples/oneapi/smart_scraper_multi_oneapi.py | 38 -- examples/oneapi/smart_scraper_oneapi.py | 38 -- .../oneapi/smart_scraper_schema_oneapi.py | 48 --- examples/oneapi/smartscraper_oneapi.py | 35 -- .../oneapi/xml_scraper_graph_multi_oneapi.py | 57 --- examples/oneapi/xml_scraper_oneapi.py | 58 --- examples/openai/.env.example | 1 - .../openai/code_generator_graph_openai.py | 59 --- .../openai/csv_scraper_graph_multi_openai.py | 55 --- examples/openai/csv_scraper_openai.py | 57 --- examples/openai/custom_graph_openai.py | 109 ----- examples/openai/document_scraper_openai.py | 39 -- examples/openai/inputs/books.xml | 120 ------ examples/openai/inputs/example.json | 182 -------- examples/openai/inputs/markdown_example.md | 35 -- examples/openai/inputs/plain_html_example.txt | 105 ----- examples/openai/inputs/username.csv | 7 - examples/openai/json_scraper_multi_openai.py | 37 -- examples/openai/json_scraper_openai.py | 57 --- examples/openai/md_scraper_openai.py | 57 --- examples/openai/omni_scraper_openai.py | 47 -- examples/openai/omni_search_openai.py | 45 -- examples/openai/rate_limit_openai.py | 48 --- examples/openai/readme.md | 1 - examples/openai/scrape_plain_text_openai.py | 54 --- examples/openai/screenshot_scraper.py | 37 -- examples/openai/script_generator_openai.py | 46 -- .../openai/script_generator_schema_openai.py | 60 --- .../openai/script_multi_generator_openai.py | 54 --- examples/openai/search_graph_schema_openai.py | 61 --- examples/openai/search_link_graph_openai.py | 42 -- examples/openai/smart_scraper_lite_openai.py | 32 -- .../smart_scraper_multi_concat_openai.py | 40 -- .../openai/smart_scraper_multi_lite_openai.py | 47 -- examples/openai/smart_scraper_multi_openai.py | 41 -- .../openai/smart_scraper_schema_openai.py | 50 --- .../openai/xml_scraper_graph_multi_openai.py | 58 --- examples/readme.md | 41 -- examples/scrapegraph-api/smart_scraper_api.py | 44 -- examples/single_node/fetch_node.py | 30 -- examples/single_node/image2text_node.py | 54 --- examples/single_node/kg_node.py | 79 ---- examples/single_node/robot_node.py | 49 --- examples/single_node/search_internet_node.py | 50 --- examples/together/.env.example | 1 - .../together/code_generator_graph_togehter.py | 60 --- .../csv_scraper_graph_multi_together.py | 56 --- examples/together/csv_scraper_together.py | 57 --- .../together/depth_search_graph_together.py | 30 -- .../together/document_scraper_together.py | 39 -- examples/together/inputs/books.xml | 120 ------ examples/together/inputs/example.json | 182 -------- examples/together/inputs/username.csv | 7 - .../together/json_scraper_multi_together.py | 38 -- examples/together/json_scraper_together.py | 57 --- examples/together/rate_limit_together.py | 47 -- .../together/scrape_plain_text_together.py | 55 --- .../together/script_generator_together.py | 44 -- .../script_multi_generator_together.py | 53 --- .../together/search_graph_schema_together.py | 61 --- examples/together/search_graph_together.py | 34 -- .../together/search_link_graph_together.py | 46 -- .../together/smart_scraper_lite_together.py | 1 - .../smart_scraper_multi_lite_together.py | 43 -- .../together/smart_scraper_multi_together.py | 40 -- .../together/smart_scraper_schema_together.py | 58 --- examples/together/smart_scraper_together.py | 44 -- .../xml_scraper_graph_multi_together.py | 58 --- examples/together/xml_scraper_together.py | 59 --- 509 files changed, 27661 deletions(-) delete mode 100644 examples/anthropic/.env.example delete mode 100644 examples/anthropic/code_generator_graph_anthropic.py delete mode 100644 examples/anthropic/custom_graph_anthropic.py delete mode 100644 examples/anthropic/depth_search_graph_anthropic.py delete mode 100644 examples/anthropic/document_scraper_anthropic.py delete mode 100644 examples/anthropic/inputs/books.xml delete mode 100644 examples/anthropic/inputs/example.json delete mode 100644 examples/anthropic/inputs/plain_html_example.txt delete mode 100644 examples/anthropic/inputs/username.csv delete mode 100644 examples/anthropic/json_scraper_anthropic.py delete mode 100644 examples/anthropic/json_scraper_multi_anthropic.py delete mode 100644 examples/anthropic/rate_limit_anthropic.py delete mode 100644 examples/anthropic/scrape_plain_text_anthropic.py delete mode 100644 examples/anthropic/script_generator_anthropic.py delete mode 100644 examples/anthropic/script_multi_generator_anthropic.py delete mode 100644 examples/anthropic/search_graph_anthropic.py delete mode 100644 examples/anthropic/search_graph_schema_anthropic.py delete mode 100644 examples/anthropic/search_link_graph_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_lite_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_multi_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_multi_concat_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_multi_lite_anthropic.py delete mode 100644 examples/anthropic/smart_scraper_schema_anthropic.py delete mode 100644 examples/anthropic/xml_scraper_anthropic.py delete mode 100644 examples/anthropic/xml_scraper_graph_multi_anthropic.py delete mode 100644 examples/azure/code_generator_graph_azure.py delete mode 100644 examples/azure/csv_scraper_azure.py delete mode 100644 examples/azure/csv_scraper_graph_multi_azure.py delete mode 100644 examples/azure/depth_search_graph_azure.py delete mode 100644 examples/azure/document_scraper_azure.py delete mode 100644 examples/azure/inputs/books.xml delete mode 100644 examples/azure/inputs/example.json delete mode 100644 examples/azure/inputs/username.csv delete mode 100644 examples/azure/json_scraper_azure.py delete mode 100644 examples/azure/json_scraper_multi_azure.py delete mode 100644 examples/azure/rate_limit_azure.py delete mode 100644 examples/azure/scrape_plain_text_azure.py delete mode 100644 examples/azure/script_generator_azure.py delete mode 100644 examples/azure/script_multi_generator_azure.py delete mode 100644 examples/azure/search_graph_azure.py delete mode 100644 examples/azure/search_graph_schema_azure.py delete mode 100644 examples/azure/search_link_graph_azure.py delete mode 100644 examples/azure/smart_scraper_azure.py delete mode 100644 examples/azure/smart_scraper_lite_azure.py delete mode 100644 examples/azure/smart_scraper_multi_azure.py delete mode 100644 examples/azure/smart_scraper_multi_concat_azure.py delete mode 100644 examples/azure/smart_scraper_multi_lite_azure.py delete mode 100644 examples/azure/smart_scraper_schema_azure.py delete mode 100644 examples/azure/xml_scraper_azure.py delete mode 100644 examples/azure/xml_scraper_graph_multi_azure.py delete mode 100644 examples/bedrock/.env.example delete mode 100644 examples/bedrock/README.md delete mode 100644 examples/bedrock/code_generator_graph_bedrock.py delete mode 100644 examples/bedrock/csv_scraper_bedrock.py delete mode 100644 examples/bedrock/csv_scraper_graph_multi_bedrock.py delete mode 100644 examples/bedrock/custom_graph_bedrock.py delete mode 100644 examples/bedrock/depth_search_graph_bedrock.py delete mode 100644 examples/bedrock/document_scraper_bedrock.py delete mode 100644 examples/bedrock/inputs/books.xml delete mode 100644 examples/bedrock/inputs/example.json delete mode 100644 examples/bedrock/inputs/plain_html_example.txt delete mode 100644 examples/bedrock/inputs/username.csv delete mode 100644 examples/bedrock/json_scraper_bedrock.py delete mode 100644 examples/bedrock/json_scraper_multi_bedrock.py delete mode 100644 examples/bedrock/rate_limit_bedrock.py delete mode 100644 examples/bedrock/scrape_plain_text_bedrock.py delete mode 100644 examples/bedrock/scrapegraphai_bedrock.png delete mode 100644 examples/bedrock/script_generator_bedrock.py delete mode 100644 examples/bedrock/script_multi_generator_bedrock.py delete mode 100644 examples/bedrock/search_graph_bedrock.py delete mode 100644 examples/bedrock/search_graph_schema_bedrock.py delete mode 100644 examples/bedrock/search_link_graph_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_lite_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_multi_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_multi_concat_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_multi_lite_bedrock.py delete mode 100644 examples/bedrock/smart_scraper_schema_bedrock.py delete mode 100644 examples/bedrock/xml_scraper_bedrock.py delete mode 100644 examples/bedrock/xml_scraper_graph_multi_bedrock.py delete mode 100644 examples/benchmarks/GenerateScraper/.env.example delete mode 100644 examples/benchmarks/GenerateScraper/Readme.md delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_docker.py delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_groq.py delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_llama3.py delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_mistral.py delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_openai_gpt35.py delete mode 100644 examples/benchmarks/GenerateScraper/benchmark_openai_gpt4.py delete mode 100644 examples/benchmarks/GenerateScraper/inputs/example_1.txt delete mode 100644 examples/benchmarks/GenerateScraper/inputs/example_2.txt delete mode 100644 examples/benchmarks/SmartScraper/.env.example delete mode 100644 examples/benchmarks/SmartScraper/Readme.md delete mode 100644 examples/benchmarks/SmartScraper/benchmark_docker.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_groq.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_llama3.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_mistral.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_openai_gpt35.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_openai_gpt4.py delete mode 100644 examples/benchmarks/SmartScraper/benchmark_openai_gpt4o.py delete mode 100644 examples/benchmarks/SmartScraper/inputs/example_1.txt delete mode 100644 examples/benchmarks/SmartScraper/inputs/example_2.txt delete mode 100644 examples/benchmarks/readme.md delete mode 100644 examples/deepseek/.env.example delete mode 100644 examples/deepseek/code_generator_graph_deepseek.py delete mode 100644 examples/deepseek/csv_scraper_deepseek.py delete mode 100644 examples/deepseek/csv_scraper_graph_multi_deepseek.py delete mode 100644 examples/deepseek/depth_search_graph_deepseek.py delete mode 100644 examples/deepseek/document_scraper_deepseek.py delete mode 100644 examples/deepseek/inputs/books.xml delete mode 100644 examples/deepseek/inputs/example.json delete mode 100644 examples/deepseek/inputs/username.csv delete mode 100644 examples/deepseek/json_scraper_deepseek.py delete mode 100644 examples/deepseek/json_scraper_multi_deepseek.py delete mode 100644 examples/deepseek/rate_limit_deepseek.py delete mode 100644 examples/deepseek/scrape_plain_text_deepseek.py delete mode 100644 examples/deepseek/script_generator_deepseek.py delete mode 100644 examples/deepseek/script_multi_generator_deepseek.py delete mode 100644 examples/deepseek/search_graph_deepseek.py delete mode 100644 examples/deepseek/search_graph_schema_deepseek.py delete mode 100644 examples/deepseek/search_link_graph_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_lite_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_multi_concat_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_multi_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_multi_lite_deepseek.py delete mode 100644 examples/deepseek/smart_scraper_schema_deepseek.py delete mode 100644 examples/deepseek/xml_scraper_deepseek.py delete mode 100644 examples/deepseek/xml_scraper_graph_multi_deepseek.py delete mode 100644 examples/ernie/code_generator_graph_ernie.py delete mode 100644 examples/ernie/csv_scraper_ernie.py delete mode 100644 examples/ernie/custom_graph_ernie.py delete mode 100644 examples/ernie/depth_search_graph_ernie.py delete mode 100644 examples/ernie/document_scraper_anthropic_ernie.py delete mode 100644 examples/ernie/inputs/books.xml delete mode 100644 examples/ernie/inputs/example.json delete mode 100644 examples/ernie/inputs/plain_html_example.txt delete mode 100644 examples/ernie/inputs/username.csv delete mode 100644 examples/ernie/json_scraper_ernie.py delete mode 100644 examples/ernie/rate_limit_ernie.py delete mode 100644 examples/ernie/scrape_plain_text_ernie.py delete mode 100644 examples/ernie/script_generator_ernie.py delete mode 100644 examples/ernie/script_multi_generator_ernie.py delete mode 100644 examples/ernie/search_graph_ernie.py delete mode 100644 examples/ernie/search_link_graph_ernie.py delete mode 100644 examples/ernie/smart_scraper_ernie.py delete mode 100644 examples/ernie/smart_scraper_lite_ernie.py delete mode 100644 examples/ernie/smart_scraper_multi_concat_ernie.py delete mode 100644 examples/ernie/smart_scraper_multi_ernie.py delete mode 100644 examples/ernie/smart_scraper_multi_lite_ernie.py delete mode 100644 examples/ernie/smart_scraper_schema_ernie.py delete mode 100644 examples/ernie/speech_graph_ernie.py delete mode 100644 examples/ernie/xml_scraper_ernie.py delete mode 100644 examples/extras/.env.example delete mode 100644 examples/extras/Savedscreenshots/test_image.jpeg delete mode 100644 examples/extras/authenticated_playwright.py delete mode 100644 examples/extras/browser_base_integration.py delete mode 100644 examples/extras/chromium_selenium.py delete mode 100644 examples/extras/cond_smartscraper_usage.py delete mode 100644 examples/extras/conditional_usage.py delete mode 100644 examples/extras/custom_prompt.py delete mode 100644 examples/extras/example.yml delete mode 100644 examples/extras/force_mode.py delete mode 100644 examples/extras/html_mode.py delete mode 100644 examples/extras/load_yml.py delete mode 100644 examples/extras/no_cut.py delete mode 100644 examples/extras/proxy_rotation.py delete mode 100644 examples/extras/rag_caching.py delete mode 100644 examples/extras/reasoning.py delete mode 100644 examples/extras/scrape_do.py delete mode 100644 examples/extras/screenshot_scaping.py delete mode 100644 examples/extras/serch_graph_scehma.py delete mode 100644 examples/extras/slow_mo.py delete mode 100644 examples/extras/undected_playwright.py delete mode 100644 examples/fireworks/.env.example delete mode 100644 examples/fireworks/code_generator_graph_fireworks.py delete mode 100644 examples/fireworks/csv_scraper_fireworks.py delete mode 100644 examples/fireworks/csv_scraper_graph_multi_fireworks.py delete mode 100644 examples/fireworks/custom_graph_fireworks.py delete mode 100644 examples/fireworks/depth_search_graph_fireworks.py delete mode 100644 examples/fireworks/document_scraper_anthropic_fireworks.py delete mode 100644 examples/fireworks/inputs/books.xml delete mode 100644 examples/fireworks/inputs/example.json delete mode 100644 examples/fireworks/inputs/plain_html_example.txt delete mode 100644 examples/fireworks/inputs/username.csv delete mode 100644 examples/fireworks/json_scraper_fireworkspy.py delete mode 100644 examples/fireworks/json_scraper_multi_fireworks.py delete mode 100644 examples/fireworks/rate_limit_fireworks.py delete mode 100644 examples/fireworks/scrape_plain_text_fireworks.py delete mode 100644 examples/fireworks/script_generator_fireworks.py delete mode 100644 examples/fireworks/script_generator_schema_fireworks.py delete mode 100644 examples/fireworks/script_multi_generator_fireworks.py delete mode 100644 examples/fireworks/search_graph_fireworks.py delete mode 100644 examples/fireworks/search_graph_schema_fireworks.py delete mode 100644 examples/fireworks/search_link_graph_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_lite_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_multi_concat_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_multi_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_multi_lite_fireworks.py delete mode 100644 examples/fireworks/smart_scraper_schema_fireworks.py delete mode 100644 examples/fireworks/xml_scraper_fireworks.py delete mode 100644 examples/fireworks/xml_scraper_graph_multi_fireworks.py delete mode 100644 examples/google_genai/.env.example delete mode 100644 examples/google_genai/code_generator_graph_gemini.py delete mode 100644 examples/google_genai/csv_scraper_gemini.py delete mode 100644 examples/google_genai/csv_scraper_graph_multi_gemini.py delete mode 100644 examples/google_genai/depth_search_graph_gemini.py delete mode 100644 examples/google_genai/document_scraper_gemini.py delete mode 100644 examples/google_genai/inputs/books.xml delete mode 100644 examples/google_genai/inputs/example.json delete mode 100644 examples/google_genai/inputs/plain_html_example.txt delete mode 100644 examples/google_genai/inputs/username.csv delete mode 100644 examples/google_genai/json_scraper_gemini.py delete mode 100644 examples/google_genai/json_scraper_multi_gemini.py delete mode 100644 examples/google_genai/rate_limit_gemini.py delete mode 100644 examples/google_genai/readme.md delete mode 100644 examples/google_genai/scrape_plain_text_gemini.py delete mode 100644 examples/google_genai/scrape_xml_gemini.py delete mode 100644 examples/google_genai/script_generator_gemini.py delete mode 100644 examples/google_genai/script_multi_generator_gemini.py delete mode 100644 examples/google_genai/search_graph_gemini.py delete mode 100644 examples/google_genai/search_graph_schema_gemini.py delete mode 100644 examples/google_genai/search_link_graph_gemini.py delete mode 100644 examples/google_genai/smart_scraper_gemini.py delete mode 100644 examples/google_genai/smart_scraper_lite_google_genai.py delete mode 100644 examples/google_genai/smart_scraper_multi_concat_gemini.py delete mode 100644 examples/google_genai/smart_scraper_multi_gemini.py delete mode 100644 examples/google_genai/smart_scraper_multi_lite_gemini.py delete mode 100644 examples/google_genai/smart_scraper_multi_lite_google_genai.py delete mode 100644 examples/google_genai/smart_scraper_schema_gemini.py delete mode 100644 examples/google_genai/xml_scraper_gemini.py delete mode 100644 examples/google_genai/xml_scraper_graph_multi_gemini.py delete mode 100644 examples/google_vertexai/.env.example delete mode 100644 examples/google_vertexai/code_generator_graph_vertex.py delete mode 100644 examples/google_vertexai/csv_scraper_gemini.py delete mode 100644 examples/google_vertexai/csv_scraper_graph_multi_gemini.py delete mode 100644 examples/google_vertexai/custom_graph_gemini.py delete mode 100644 examples/google_vertexai/depth_search_graph_gemini.py delete mode 100644 examples/google_vertexai/document_scraper_vertex.py delete mode 100644 examples/google_vertexai/inputs/books.xml delete mode 100644 examples/google_vertexai/inputs/example.json delete mode 100644 examples/google_vertexai/inputs/plain_html_example.txt delete mode 100644 examples/google_vertexai/inputs/username.csv delete mode 100644 examples/google_vertexai/json_scraper_gemini.py delete mode 100644 examples/google_vertexai/json_scraper_multi_gemini.py delete mode 100644 examples/google_vertexai/rate_limit_gemini.py delete mode 100644 examples/google_vertexai/readme.md delete mode 100644 examples/google_vertexai/scrape_plain_text_gemini.py delete mode 100644 examples/google_vertexai/scrape_xml_gemini.py delete mode 100644 examples/google_vertexai/script_generator_gemini.py delete mode 100644 examples/google_vertexai/script_multi_generator_gemini.py delete mode 100644 examples/google_vertexai/search_graph_gemini.py delete mode 100644 examples/google_vertexai/search_graph_schema_gemini.py delete mode 100644 examples/google_vertexai/search_link_graph_gemini.py delete mode 100644 examples/google_vertexai/smart_scraper_gemini.py delete mode 100644 examples/google_vertexai/smart_scraper_lite_google_vertexai.py delete mode 100644 examples/google_vertexai/smart_scraper_multi_concat_gemini.py delete mode 100644 examples/google_vertexai/smart_scraper_multi_gemini.py delete mode 100644 examples/google_vertexai/smart_scraper_multi_lite_google_vertexai.py delete mode 100644 examples/google_vertexai/smart_scraper_multi_lite_vertex.py delete mode 100644 examples/google_vertexai/smart_scraper_schema_gemini.py delete mode 100644 examples/google_vertexai/xml_scraper_gemini.py delete mode 100644 examples/google_vertexai/xml_scraper_graph_multi_gemini.py delete mode 100644 examples/groq/.env.example delete mode 100644 examples/groq/code_generator_graph_groq.py delete mode 100644 examples/groq/csv_scraper_graph_multi_groq.py delete mode 100644 examples/groq/csv_scraper_groq.py delete mode 100644 examples/groq/custom_graph_groq.py delete mode 100644 examples/groq/depth_search_graph_groq.py delete mode 100644 examples/groq/document_scraper_groq.py delete mode 100644 examples/groq/inputs/books.xml delete mode 100644 examples/groq/inputs/example.json delete mode 100644 examples/groq/inputs/plain_html_example.txt delete mode 100644 examples/groq/inputs/username.csv delete mode 100644 examples/groq/json_scraper_groq.py delete mode 100644 examples/groq/json_scraper_multi_groq.py delete mode 100644 examples/groq/rate_limit_groq.py delete mode 100644 examples/groq/scrape_plain_text_groq.py delete mode 100644 examples/groq/script_generator_groq.py delete mode 100644 examples/groq/script_multi_generator_groq.py delete mode 100644 examples/groq/search_graph_groq.py delete mode 100644 examples/groq/search_graph_schema_groq.py delete mode 100644 examples/groq/search_link_graph_groq.py delete mode 100644 examples/groq/smart_scraper_groq.py delete mode 100644 examples/groq/smart_scraper_lite_groq.py delete mode 100644 examples/groq/smart_scraper_multi_concat_groq.py delete mode 100644 examples/groq/smart_scraper_multi_groq.py delete mode 100644 examples/groq/smart_scraper_multi_lite_groq.py delete mode 100644 examples/groq/smart_scraper_schema_groq.py delete mode 100644 examples/groq/xml_scraper_graph_multi_groq.py delete mode 100644 examples/groq/xml_scraper_groq.py delete mode 100644 examples/huggingfacehub/code_generator_graph_huggingfacehub.py delete mode 100644 examples/huggingfacehub/csv_scraper_graph_multi_huggingfacehub.py delete mode 100644 examples/huggingfacehub/csv_scraper_huggingfacehub.py delete mode 100644 examples/huggingfacehub/custom_graph_huggingfacehub.py delete mode 100644 examples/huggingfacehub/depth_search_graph_huggingfacehub.py delete mode 100644 examples/huggingfacehub/document_scraper_huggingfacehub.py delete mode 100644 examples/huggingfacehub/inputs/books.xml delete mode 100644 examples/huggingfacehub/inputs/example.json delete mode 100644 examples/huggingfacehub/inputs/plain_html_example.txt delete mode 100644 examples/huggingfacehub/inputs/username.csv delete mode 100644 examples/huggingfacehub/json_scraper_huggingfacehub.py delete mode 100644 examples/huggingfacehub/json_scraper_multi_huggingfacehub.py delete mode 100644 examples/huggingfacehub/scrape_plain_text_huggingfacehub.py delete mode 100644 examples/huggingfacehub/script_generator_huggingfacehub.py delete mode 100644 examples/huggingfacehub/script_multi_generator_huggingfacehub.py delete mode 100644 examples/huggingfacehub/search_graph_huggingfacehub.py delete mode 100644 examples/huggingfacehub/search_link_graph_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_lite_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_multi_concat_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_multi_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_multi_lite_huggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_multi_lite_uhggingfacehub.py delete mode 100644 examples/huggingfacehub/smart_scraper_schema_huggingfacehub.py delete mode 100644 examples/huggingfacehub/xml_scraper_graph_multi_huggingfacehub.py delete mode 100644 examples/huggingfacehub/xml_scraper_huggingfacehub.py delete mode 100644 examples/integrations/indexify_node_example.py delete mode 100644 examples/local_models/code_generator_graph_ollama.py delete mode 100644 examples/local_models/csv_scraper_graph_multi_ollama.py delete mode 100644 examples/local_models/csv_scraper_ollama.py delete mode 100644 examples/local_models/custom_graph_ollama.py delete mode 100644 examples/local_models/depth_search_graph_ollama.py delete mode 100644 examples/local_models/document_scraper_ollama.py delete mode 100644 examples/local_models/inputs/books.xml delete mode 100644 examples/local_models/inputs/example.json delete mode 100644 examples/local_models/inputs/plain_html_example.txt delete mode 100644 examples/local_models/inputs/username.csv delete mode 100644 examples/local_models/json_scraper_multi_ollama.py delete mode 100644 examples/local_models/json_scraper_ollama.py delete mode 100644 examples/local_models/package-lock.json delete mode 100644 examples/local_models/package.json delete mode 100644 examples/local_models/scrape_plain_text_ollama.py delete mode 100644 examples/local_models/script_generator_ollama.py delete mode 100644 examples/local_models/script_multi_generator_ollama.py delete mode 100644 examples/local_models/search_graph_ollama.py delete mode 100644 examples/local_models/search_graph_schema_ollama.py delete mode 100644 examples/local_models/search_link_graph_ollama.py delete mode 100644 examples/local_models/smart_scraper_lite_ollama.py delete mode 100644 examples/local_models/smart_scraper_multi_concat_ollama.py delete mode 100644 examples/local_models/smart_scraper_multi_lite_ollama.py delete mode 100644 examples/local_models/smart_scraper_multi_ollama.py delete mode 100644 examples/local_models/smart_scraper_schema_ollama.py delete mode 100644 examples/local_models/xml_scraper_graph_multi_ollama.py delete mode 100644 examples/local_models/xml_scraper_ollama.py delete mode 100644 examples/mistral/.env.example delete mode 100644 examples/mistral/code_generator_graph_mistral.py delete mode 100644 examples/mistral/csv_scraper_graph_multi_mistral.py delete mode 100644 examples/mistral/csv_scraper_mistral.py delete mode 100644 examples/mistral/custom_graph_mistral.py delete mode 100644 examples/mistral/depth_search_graph_mistral.py delete mode 100644 examples/mistral/document_scraper_mistral.py delete mode 100644 examples/mistral/inputs/books.xml delete mode 100644 examples/mistral/inputs/example.json delete mode 100644 examples/mistral/inputs/markdown_example.md delete mode 100644 examples/mistral/inputs/plain_html_example.txt delete mode 100644 examples/mistral/inputs/username.csv delete mode 100644 examples/mistral/json_scraper_mistral.py delete mode 100644 examples/mistral/json_scraper_multi_mistral.py delete mode 100644 examples/mistral/md_scraper_mistral.py delete mode 100644 examples/mistral/rate_limit_mistral.py delete mode 100644 examples/mistral/readme.md delete mode 100644 examples/mistral/scrape_plain_text_mistral.py delete mode 100644 examples/mistral/script_generator_mistral.py delete mode 100644 examples/mistral/script_generator_schema_mistral.py delete mode 100644 examples/mistral/script_multi_generator_mistral.py delete mode 100644 examples/mistral/search_graph_mistral.py delete mode 100644 examples/mistral/search_graph_schema_mistral.py delete mode 100644 examples/mistral/search_link_graph_mistral.py delete mode 100644 examples/mistral/smart_scraper_lite_mistral.py delete mode 100644 examples/mistral/smart_scraper_mistral.py delete mode 100644 examples/mistral/smart_scraper_multi_concat_mistral.py delete mode 100644 examples/mistral/smart_scraper_multi_lite_mistral.py delete mode 100644 examples/mistral/smart_scraper_multi_mistral.py delete mode 100644 examples/mistral/smart_scraper_schema_mistral.py delete mode 100644 examples/mistral/xml_scraper_graph_multi_mistral.py delete mode 100644 examples/mistral/xml_scraper_mistral.py delete mode 100644 examples/model_instance/.env.example delete mode 100644 examples/model_instance/smart_scraper_with_model_instace.py delete mode 100644 examples/moonshot/.env.example delete mode 100644 examples/moonshot/code_generator_graph_moonshot.py delete mode 100644 examples/moonshot/document_scraper_moonshot.py delete mode 100644 examples/moonshot/readme.md delete mode 100644 examples/moonshot/smart_scraper_lite_moonshot.py delete mode 100644 examples/moonshot/smart_scraper_multi_concat_moonshot.py delete mode 100644 examples/moonshot/smart_scraper_multi_lite_moonshot.py delete mode 100644 examples/moonshot/smart_scraper_with_moonshot.py delete mode 100644 examples/nemotron/code_generator_graph_nemotron.py delete mode 100644 examples/nemotron/csv_scraper_graph_multi_nemotron.py delete mode 100644 examples/nemotron/csv_scraper_nemotron.py delete mode 100644 examples/nemotron/depth_search_graph_nemotron.py delete mode 100644 examples/nemotron/document_scraper_nemotron.py delete mode 100644 examples/nemotron/inputs/books.xml delete mode 100644 examples/nemotron/inputs/example.json delete mode 100644 examples/nemotron/inputs/markdown_example.md delete mode 100644 examples/nemotron/inputs/plain_html_example.txt delete mode 100644 examples/nemotron/inputs/username.csv delete mode 100644 examples/nemotron/json_scraper_multi_nemotron.py delete mode 100644 examples/nemotron/json_scraper_nemotron.py delete mode 100644 examples/nemotron/md_scraper_nemotron.py delete mode 100644 examples/nemotron/rate_limit_nemotron.py delete mode 100644 examples/nemotron/scrape_plain_text_nemotron.py delete mode 100644 examples/nemotron/script_generator_nemotron.py delete mode 100644 examples/nemotron/script_generator_schema_nemotron.py delete mode 100644 examples/nemotron/script_multi_generator_nemotron.py delete mode 100644 examples/nemotron/search_graph_nemotron.py delete mode 100644 examples/nemotron/search_graph_schema_nemotron.py delete mode 100644 examples/nemotron/search_link_graph_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_lite_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_multi_concat_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_multi_lite_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_multi_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_nemotron.py delete mode 100644 examples/nemotron/smart_scraper_schema_nemotron.py delete mode 100644 examples/nemotron/speech_graph_nemotron.py delete mode 100644 examples/nemotron/xml_scraper_graph_nemotron.py delete mode 100644 examples/nemotron/xml_scraper_nemotron.py delete mode 100644 examples/oneapi/code_generator_graph_oneapi.py delete mode 100644 examples/oneapi/csv_scraper_graph_multi_oneapi.py delete mode 100644 examples/oneapi/csv_scraper_oneapi.py delete mode 100644 examples/oneapi/custom_graph_oneapi.py delete mode 100644 examples/oneapi/depth_search_graph_onenapi.py delete mode 100644 examples/oneapi/document_scraper_oneapi.py delete mode 100644 examples/oneapi/inputs/books.xml delete mode 100644 examples/oneapi/inputs/example.json delete mode 100644 examples/oneapi/inputs/plain_html_example copy.txt delete mode 100644 examples/oneapi/inputs/plain_html_example.txt delete mode 100644 examples/oneapi/inputs/username.csv delete mode 100644 examples/oneapi/json_scraper_multi_oneapi.py delete mode 100644 examples/oneapi/json_scraper_oneapi.py delete mode 100644 examples/oneapi/rate_limit_oneapi.py delete mode 100644 examples/oneapi/scrape_plain_text_oneapi.py delete mode 100644 examples/oneapi/script_generator_oneapi.py delete mode 100644 examples/oneapi/script_multi_generator_oneapi.py delete mode 100644 examples/oneapi/search_graph_oneapi.py delete mode 100644 examples/oneapi/search_graph_schema_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_lite_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_multi_concat_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_multi_lite_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_multi_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_oneapi.py delete mode 100644 examples/oneapi/smart_scraper_schema_oneapi.py delete mode 100644 examples/oneapi/smartscraper_oneapi.py delete mode 100644 examples/oneapi/xml_scraper_graph_multi_oneapi.py delete mode 100644 examples/oneapi/xml_scraper_oneapi.py delete mode 100644 examples/openai/.env.example delete mode 100644 examples/openai/code_generator_graph_openai.py delete mode 100644 examples/openai/csv_scraper_graph_multi_openai.py delete mode 100644 examples/openai/csv_scraper_openai.py delete mode 100644 examples/openai/custom_graph_openai.py delete mode 100644 examples/openai/document_scraper_openai.py delete mode 100644 examples/openai/inputs/books.xml delete mode 100644 examples/openai/inputs/example.json delete mode 100644 examples/openai/inputs/markdown_example.md delete mode 100644 examples/openai/inputs/plain_html_example.txt delete mode 100644 examples/openai/inputs/username.csv delete mode 100644 examples/openai/json_scraper_multi_openai.py delete mode 100644 examples/openai/json_scraper_openai.py delete mode 100644 examples/openai/md_scraper_openai.py delete mode 100644 examples/openai/omni_scraper_openai.py delete mode 100644 examples/openai/omni_search_openai.py delete mode 100644 examples/openai/rate_limit_openai.py delete mode 100644 examples/openai/readme.md delete mode 100644 examples/openai/scrape_plain_text_openai.py delete mode 100644 examples/openai/screenshot_scraper.py delete mode 100644 examples/openai/script_generator_openai.py delete mode 100644 examples/openai/script_generator_schema_openai.py delete mode 100644 examples/openai/script_multi_generator_openai.py delete mode 100644 examples/openai/search_graph_schema_openai.py delete mode 100644 examples/openai/search_link_graph_openai.py delete mode 100644 examples/openai/smart_scraper_lite_openai.py delete mode 100644 examples/openai/smart_scraper_multi_concat_openai.py delete mode 100644 examples/openai/smart_scraper_multi_lite_openai.py delete mode 100644 examples/openai/smart_scraper_multi_openai.py delete mode 100644 examples/openai/smart_scraper_schema_openai.py delete mode 100644 examples/openai/xml_scraper_graph_multi_openai.py delete mode 100644 examples/readme.md delete mode 100644 examples/scrapegraph-api/smart_scraper_api.py delete mode 100644 examples/single_node/fetch_node.py delete mode 100644 examples/single_node/image2text_node.py delete mode 100644 examples/single_node/kg_node.py delete mode 100644 examples/single_node/robot_node.py delete mode 100644 examples/single_node/search_internet_node.py delete mode 100644 examples/together/.env.example delete mode 100644 examples/together/code_generator_graph_togehter.py delete mode 100644 examples/together/csv_scraper_graph_multi_together.py delete mode 100644 examples/together/csv_scraper_together.py delete mode 100644 examples/together/depth_search_graph_together.py delete mode 100644 examples/together/document_scraper_together.py delete mode 100644 examples/together/inputs/books.xml delete mode 100644 examples/together/inputs/example.json delete mode 100644 examples/together/inputs/username.csv delete mode 100644 examples/together/json_scraper_multi_together.py delete mode 100644 examples/together/json_scraper_together.py delete mode 100644 examples/together/rate_limit_together.py delete mode 100644 examples/together/scrape_plain_text_together.py delete mode 100644 examples/together/script_generator_together.py delete mode 100644 examples/together/script_multi_generator_together.py delete mode 100644 examples/together/search_graph_schema_together.py delete mode 100644 examples/together/search_graph_together.py delete mode 100644 examples/together/search_link_graph_together.py delete mode 100644 examples/together/smart_scraper_lite_together.py delete mode 100644 examples/together/smart_scraper_multi_lite_together.py delete mode 100644 examples/together/smart_scraper_multi_together.py delete mode 100644 examples/together/smart_scraper_schema_together.py delete mode 100644 examples/together/smart_scraper_together.py delete mode 100644 examples/together/xml_scraper_graph_multi_together.py delete mode 100644 examples/together/xml_scraper_together.py diff --git a/examples/anthropic/.env.example b/examples/anthropic/.env.example deleted file mode 100644 index 2789e380..00000000 --- a/examples/anthropic/.env.example +++ /dev/null @@ -1 +0,0 @@ -ANTHROPIC_API_KEY="YOUR ANTHROPIC API KEY" \ No newline at end of file diff --git a/examples/anthropic/code_generator_graph_anthropic.py b/examples/anthropic/code_generator_graph_anthropic.py deleted file mode 100644 index 71160b8c..00000000 --- a/examples/anthropic/code_generator_graph_anthropic.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -anthropic_key = os.getenv("ANTHROPIC_API_KEY") - -graph_config = { - "llm": { - "api_key":anthropic_key, - "model": "anthropic/claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/anthropic/custom_graph_anthropic.py b/examples/anthropic/custom_graph_anthropic.py deleted file mode 100644 index 6df51108..00000000 --- a/examples/anthropic/custom_graph_anthropic.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -import os -from dotenv import load_dotenv -from langchain_anthropic import ChatAnthropic -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, GenerateAnswerNode, RobotsNode -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatAnthropic(graph_config["llm"]) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/anthropic/depth_search_graph_anthropic.py b/examples/anthropic/depth_search_graph_anthropic.py deleted file mode 100644 index 565934ed..00000000 --- a/examples/anthropic/depth_search_graph_anthropic.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/anthropic/document_scraper_anthropic.py b/examples/anthropic/document_scraper_anthropic.py deleted file mode 100644 index a8f253be..00000000 --- a/examples/anthropic/document_scraper_anthropic.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - } -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/anthropic/inputs/books.xml b/examples/anthropic/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/anthropic/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/anthropic/inputs/example.json b/examples/anthropic/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/anthropic/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/anthropic/inputs/plain_html_example.txt b/examples/anthropic/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/anthropic/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
-
-
-
-

Projects

-

-
-
- -
-
-
- -
- \ No newline at end of file diff --git a/examples/anthropic/inputs/username.csv b/examples/anthropic/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/anthropic/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/anthropic/json_scraper_anthropic.py b/examples/anthropic/json_scraper_anthropic.py deleted file mode 100644 index fd5aa4e8..00000000 --- a/examples/anthropic/json_scraper_anthropic.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - } -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/anthropic/json_scraper_multi_anthropic.py b/examples/anthropic/json_scraper_multi_anthropic.py deleted file mode 100644 index d016439d..00000000 --- a/examples/anthropic/json_scraper_multi_anthropic.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/anthropic/rate_limit_anthropic.py b/examples/anthropic/rate_limit_anthropic.py deleted file mode 100644 index f9321770..00000000 --- a/examples/anthropic/rate_limit_anthropic.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper while setting an API rate limit. -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - - -# required environment variables in .env -# ANTHROPIC_API_KEY -load_dotenv() - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - "rate_limit": { - "requests_per_second": 1 - } - }, -} - -smart_scraper_graph = SmartScraperGraph( - prompt="""Don't say anything else. Output JSON only. List me all the events, with the following fields: company_name, event_name, event_start_date, event_start_time, - event_end_date, event_end_time, location, event_mode, event_category, - third_party_redirect, no_of_days, - time_in_hours, hosted_or_attending, refreshments_type, - registration_available, registration_link""", - # also accepts a string with the already downloaded HTML code - source="https://www.hmhco.com/event", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/anthropic/scrape_plain_text_anthropic.py b/examples/anthropic/scrape_plain_text_anthropic.py deleted file mode 100644 index fd8ebd1d..00000000 --- a/examples/anthropic/scrape_plain_text_anthropic.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/anthropic/script_generator_anthropic.py b/examples/anthropic/script_generator_anthropic.py deleted file mode 100644 index 8c9333e1..00000000 --- a/examples/anthropic/script_generator_anthropic.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/anthropic/script_multi_generator_anthropic.py b/examples/anthropic/script_multi_generator_anthropic.py deleted file mode 100644 index d47e60e9..00000000 --- a/examples/anthropic/script_multi_generator_anthropic.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/anthropic/search_graph_anthropic.py b/examples/anthropic/search_graph_anthropic.py deleted file mode 100644 index 0e1d7b45..00000000 --- a/examples/anthropic/search_graph_anthropic.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/anthropic/search_graph_schema_anthropic.py b/examples/anthropic/search_graph_schema_anthropic.py deleted file mode 100644 index 926e72ea..00000000 --- a/examples/anthropic/search_graph_schema_anthropic.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) diff --git a/examples/anthropic/search_link_graph_anthropic.py b/examples/anthropic/search_link_graph_anthropic.py deleted file mode 100644 index 70798cf3..00000000 --- a/examples/anthropic/search_link_graph_anthropic.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_openai import AzureChatOpenAI -from langchain_openai import AzureOpenAIEmbeddings - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/anthropic/smart_scraper_anthropic.py b/examples/anthropic/smart_scraper_anthropic.py deleted file mode 100644 index 7eb655d5..00000000 --- a/examples/anthropic/smart_scraper_anthropic.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -smart_scraper_graph = SmartScraperGraph( - prompt="""Don't say anything else. Output JSON only. List me all the events, with the following fields: company_name, event_name, event_start_date, event_start_time, - event_end_date, event_end_time, location, event_mode, event_category, - third_party_redirect, no_of_days, - time_in_hours, hosted_or_attending, refreshments_type, - registration_available, registration_link""", - # also accepts a string with the already downloaded HTML code - source="https://www.hmhco.com/event", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/anthropic/smart_scraper_lite_anthropic.py b/examples/anthropic/smart_scraper_lite_anthropic.py deleted file mode 100644 index 698623c6..00000000 --- a/examples/anthropic/smart_scraper_lite_anthropic.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/anthropic/smart_scraper_multi_anthropic.py b/examples/anthropic/smart_scraper_multi_anthropic.py deleted file mode 100644 index e4dc0aca..00000000 --- a/examples/anthropic/smart_scraper_multi_anthropic.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/anthropic/smart_scraper_multi_concat_anthropic.py b/examples/anthropic/smart_scraper_multi_concat_anthropic.py deleted file mode 100644 index d5c65a14..00000000 --- a/examples/anthropic/smart_scraper_multi_concat_anthropic.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/anthropic/smart_scraper_multi_lite_anthropic.py b/examples/anthropic/smart_scraper_multi_lite_anthropic.py deleted file mode 100644 index 7cf3c09d..00000000 --- a/examples/anthropic/smart_scraper_multi_lite_anthropic.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/anthropic/smart_scraper_schema_anthropic.py b/examples/anthropic/smart_scraper_schema_anthropic.py deleted file mode 100644 index 3cebd257..00000000 --- a/examples/anthropic/smart_scraper_schema_anthropic.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - schema=Projects, - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/anthropic/xml_scraper_anthropic.py b/examples/anthropic/xml_scraper_anthropic.py deleted file mode 100644 index 5568f0a3..00000000 --- a/examples/anthropic/xml_scraper_anthropic.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/anthropic/xml_scraper_graph_multi_anthropic.py b/examples/anthropic/xml_scraper_graph_multi_anthropic.py deleted file mode 100644 index 577e2e1d..00000000 --- a/examples/anthropic/xml_scraper_graph_multi_anthropic.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/code_generator_graph_azure.py b/examples/azure/code_generator_graph_azure.py deleted file mode 100644 index 7dc13602..00000000 --- a/examples/azure/code_generator_graph_azure.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/azure/csv_scraper_azure.py b/examples/azure/csv_scraper_azure.py deleted file mode 100644 index 5bc9ca50..00000000 --- a/examples/azure/csv_scraper_azure.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/csv_scraper_graph_multi_azure.py b/examples/azure/csv_scraper_graph_multi_azure.py deleted file mode 100644 index 0c599427..00000000 --- a/examples/azure/csv_scraper_graph_multi_azure.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/depth_search_graph_azure.py b/examples/azure/depth_search_graph_azure.py deleted file mode 100644 index 96ccc23e..00000000 --- a/examples/azure/depth_search_graph_azure.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -depth_search_graph_azure example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/azure/document_scraper_azure.py b/examples/azure/document_scraper_azure.py deleted file mode 100644 index 43f00678..00000000 --- a/examples/azure/document_scraper_azure.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/azure/inputs/books.xml b/examples/azure/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/azure/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/azure/inputs/example.json b/examples/azure/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/azure/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/azure/inputs/username.csv b/examples/azure/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/azure/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/azure/json_scraper_azure.py b/examples/azure/json_scraper_azure.py deleted file mode 100644 index 5224f9bb..00000000 --- a/examples/azure/json_scraper_azure.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -smart_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/json_scraper_multi_azure.py b/examples/azure/json_scraper_multi_azure.py deleted file mode 100644 index 93ac02e3..00000000 --- a/examples/azure/json_scraper_multi_azure.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/azure/rate_limit_azure.py b/examples/azure/rate_limit_azure.py deleted file mode 100644 index aa0f943d..00000000 --- a/examples/azure/rate_limit_azure.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - - -# required environment variable in .env -# AZURE_OPENAI_ENDPOINT -# AZURE_OPENAI_CHAT_DEPLOYMENT_NAME -# MODEL_NAME -# AZURE_OPENAI_API_KEY -# OPENAI_API_TYPE -# AZURE_OPENAI_API_VERSION -# AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME -load_dotenv() - - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o", - "rate_limit": { - "requests_per_second": 1 - }, - }, - "verbose": True, - "headless": False -} - -smart_scraper_graph = SmartScraperGraph( - prompt="""List me all the events, with the following fields: company_name, event_name, event_start_date, event_start_time, - event_end_date, event_end_time, location, event_mode, event_category, - third_party_redirect, no_of_days, - time_in_hours, hosted_or_attending, refreshments_type, - registration_available, registration_link""", - # also accepts a string with the already downloaded HTML code - source="https://www.hmhco.com/event", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/scrape_plain_text_azure.py b/examples/azure/scrape_plain_text_azure.py deleted file mode 100644 index 0beb1526..00000000 --- a/examples/azure/scrape_plain_text_azure.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/script_generator_azure.py b/examples/azure/script_generator_azure.py deleted file mode 100644 index 5eb40b1c..00000000 --- a/examples/azure/script_generator_azure.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/azure/script_multi_generator_azure.py b/examples/azure/script_multi_generator_azure.py deleted file mode 100644 index 6bb94051..00000000 --- a/examples/azure/script_multi_generator_azure.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/search_graph_azure.py b/examples/azure/search_graph_azure.py deleted file mode 100644 index 8c7d9a9e..00000000 --- a/examples/azure/search_graph_azure.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/search_graph_schema_azure.py b/examples/azure/search_graph_schema_azure.py deleted file mode 100644 index bc22f7bc..00000000 --- a/examples/azure/search_graph_schema_azure.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -from pydantic import BaseModel, Field - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/search_link_graph_azure.py b/examples/azure/search_link_graph_azure.py deleted file mode 100644 index 42ed07ad..00000000 --- a/examples/azure/search_link_graph_azure.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/azure/smart_scraper_azure.py b/examples/azure/smart_scraper_azure.py deleted file mode 100644 index 11643a6d..00000000 --- a/examples/azure/smart_scraper_azure.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -smart_scraper_graph = SmartScraperGraph( - prompt="""List me all the events, with the following fields: - company_name, event_name, event_start_date, event_start_time, - event_end_date, event_end_time, location, event_mode, event_category, - third_party_redirect, no_of_days, - time_in_hours, hosted_or_attending, refreshments_type, - registration_available, registration_link""", - # also accepts a string with the already downloaded HTML code - source="https://www.hmhco.com/event", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/smart_scraper_lite_azure.py b/examples/azure/smart_scraper_lite_azure.py deleted file mode 100644 index 335c4832..00000000 --- a/examples/azure/smart_scraper_lite_azure.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/smart_scraper_multi_azure.py b/examples/azure/smart_scraper_multi_azure.py deleted file mode 100644 index e066eaf1..00000000 --- a/examples/azure/smart_scraper_multi_azure.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/azure/smart_scraper_multi_concat_azure.py b/examples/azure/smart_scraper_multi_concat_azure.py deleted file mode 100644 index 072cb190..00000000 --- a/examples/azure/smart_scraper_multi_concat_azure.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/azure/smart_scraper_multi_lite_azure.py b/examples/azure/smart_scraper_multi_lite_azure.py deleted file mode 100644 index b9046d9f..00000000 --- a/examples/azure/smart_scraper_multi_lite_azure.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/azure/smart_scraper_schema_azure.py b/examples/azure/smart_scraper_schema_azure.py deleted file mode 100644 index 28d8b87e..00000000 --- a/examples/azure/smart_scraper_schema_azure.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -import json -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/azure/xml_scraper_azure.py b/examples/azure/xml_scraper_azure.py deleted file mode 100644 index cd53242c..00000000 --- a/examples/azure/xml_scraper_azure.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - - -# ************************************************ -# Initialize the model instances -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o" - }, - "verbose": True, - "headless": False -} - -smart_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/azure/xml_scraper_graph_multi_azure.py b/examples/azure/xml_scraper_graph_multi_azure.py deleted file mode 100644 index e7aaf382..00000000 --- a/examples/azure/xml_scraper_graph_multi_azure.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.environ["AZURE_OPENAI_KEY"], - "model": "azure_openai/gpt-4o", - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/.env.example b/examples/bedrock/.env.example deleted file mode 100644 index cd27769e..00000000 --- a/examples/bedrock/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -AWS_ACCESS_KEY_ID="..." -AWS_SECRET_ACCESS_KEY="..." -AWS_SESSION_TOKEN="..." -AWS_DEFAULT_REGION="..." \ No newline at end of file diff --git a/examples/bedrock/README.md b/examples/bedrock/README.md deleted file mode 100644 index 88edd82c..00000000 --- a/examples/bedrock/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This folder contains examples of how to use ScrapeGraphAI with [Amazon Bedrock](https://aws.amazon.com/bedrock/) ⛰️. The examples show how to extract information from websites and files using a natural language prompt. - -![](scrapegraphai_bedrock.png) \ No newline at end of file diff --git a/examples/bedrock/code_generator_graph_bedrock.py b/examples/bedrock/code_generator_graph_bedrock.py deleted file mode 100644 index 7a0561fe..00000000 --- a/examples/bedrock/code_generator_graph_bedrock.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/bedrock/csv_scraper_bedrock.py b/examples/bedrock/csv_scraper_bedrock.py deleted file mode 100644 index cf453ab3..00000000 --- a/examples/bedrock/csv_scraper_bedrock.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" - -import os -import json - -from dotenv import load_dotenv - -import pandas as pd - -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(json.dumps(result, indent=4)) - diff --git a/examples/bedrock/csv_scraper_graph_multi_bedrock.py b/examples/bedrock/csv_scraper_graph_multi_bedrock.py deleted file mode 100644 index b9dd7f6f..00000000 --- a/examples/bedrock/csv_scraper_graph_multi_bedrock.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" - -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/custom_graph_bedrock.py b/examples/bedrock/custom_graph_bedrock.py deleted file mode 100644 index d72f6999..00000000 --- a/examples/bedrock/custom_graph_bedrock.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -import json - -from dotenv import load_dotenv - -from langchain_aws import BedrockEmbeddings -from scrapegraphai.models import Bedrock -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import ( - FetchNode, - ParseNode, - RAGNode, - GenerateAnswerNode, - RobotsNode -) - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = Bedrock({ - 'model_id': graph_config["llm"]["model"].split("/")[-1], - 'model_kwargs': { - 'temperature': 0.0 - }}) -embedder = BedrockEmbeddings(model_id=graph_config["embeddings"]["model"].split("/")[-1]) - -# Define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) - -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) - -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) - -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "List me all the articles", - "url": "https://perinim.github.io/projects" -}) - -# Get the answer from the result -result = result.get("answer", "No answer found.") -print(json.dumps(result, indent=4)) diff --git a/examples/bedrock/depth_search_graph_bedrock.py b/examples/bedrock/depth_search_graph_bedrock.py deleted file mode 100644 index 243547a4..00000000 --- a/examples/bedrock/depth_search_graph_bedrock.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -depth_search_graph_opeani example -""" -from scrapegraphai.graphs import DepthSearchGraph - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/bedrock/document_scraper_bedrock.py b/examples/bedrock/document_scraper_bedrock.py deleted file mode 100644 index f9b99e1f..00000000 --- a/examples/bedrock/document_scraper_bedrock.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/bedrock/inputs/books.xml b/examples/bedrock/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/bedrock/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/bedrock/inputs/example.json b/examples/bedrock/inputs/example.json deleted file mode 100644 index d729b76a..00000000 --- a/examples/bedrock/inputs/example.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "quiz": { - "sport": { - "q1": { - "question": "Which one is correct team name in NBA?", - "options": [ - "New York Bulls", - "Los Angeles Kings", - "Golden State Warriros", - "Huston Rocket" - ], - "answer": "Huston Rocket" - } - }, - "maths": { - "q1": { - "question": "5 + 7 = ?", - "options": [ - "10", - "11", - "12", - "13" - ], - "answer": "12" - }, - "q2": { - "question": "12 - 8 = ?", - "options": [ - "1", - "2", - "3", - "4" - ], - "answer": "4" - } - } - } -} \ No newline at end of file diff --git a/examples/bedrock/inputs/plain_html_example.txt b/examples/bedrock/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/bedrock/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
-
-
-
-

Projects

-

-
-
- -
-
-
- -
- \ No newline at end of file diff --git a/examples/bedrock/inputs/username.csv b/examples/bedrock/inputs/username.csv deleted file mode 100644 index 8c039d7e..00000000 --- a/examples/bedrock/inputs/username.csv +++ /dev/null @@ -1,6 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith \ No newline at end of file diff --git a/examples/bedrock/json_scraper_bedrock.py b/examples/bedrock/json_scraper_bedrock.py deleted file mode 100644 index c34cb1bd..00000000 --- a/examples/bedrock/json_scraper_bedrock.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all questions and options in the math section, no answers.", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/json_scraper_multi_bedrock.py b/examples/bedrock/json_scraper_multi_bedrock.py deleted file mode 100644 index 5848ef17..00000000 --- a/examples/bedrock/json_scraper_multi_bedrock.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from scrapegraphai.graphs import JSONScraperMultiGraph - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/bedrock/rate_limit_bedrock.py b/examples/bedrock/rate_limit_bedrock.py deleted file mode 100644 index 98e2e3db..00000000 --- a/examples/bedrock/rate_limit_bedrock.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0, - "rate_limit": { - "requests_per_second": 1 - }, - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/scrape_plain_text_bedrock.py b/examples/bedrock/scrape_plain_text_bedrock.py deleted file mode 100644 index 1a89786e..00000000 --- a/examples/bedrock/scrape_plain_text_bedrock.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/scrapegraphai_bedrock.png b/examples/bedrock/scrapegraphai_bedrock.png deleted file mode 100644 index 918cf19132a7535f0f3ff42da574bb848597d1e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82480 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

+O%gEZ9lM|4joCCQ@)}VL!on5 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 diff --git a/examples/bedrock/script_generator_bedrock.py b/examples/bedrock/script_generator_bedrock.py deleted file mode 100644 index 4adb13f1..00000000 --- a/examples/bedrock/script_generator_bedrock.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/bedrock/script_multi_generator_bedrock.py b/examples/bedrock/script_multi_generator_bedrock.py deleted file mode 100644 index 2491a1f9..00000000 --- a/examples/bedrock/script_multi_generator_bedrock.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/search_graph_bedrock.py b/examples/bedrock/search_graph_bedrock.py deleted file mode 100644 index 6369f647..00000000 --- a/examples/bedrock/search_graph_bedrock.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/bedrock/search_graph_schema_bedrock.py b/examples/bedrock/search_graph_schema_bedrock.py deleted file mode 100644 index 55ad772c..00000000 --- a/examples/bedrock/search_graph_schema_bedrock.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Example of Search Graph -""" -from typing import List -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/search_link_graph_bedrock.py b/examples/bedrock/search_link_graph_bedrock.py deleted file mode 100644 index 64e62710..00000000 --- a/examples/bedrock/search_link_graph_bedrock.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/smart_scraper_bedrock.py b/examples/bedrock/smart_scraper_bedrock.py deleted file mode 100644 index d63f1ece..00000000 --- a/examples/bedrock/smart_scraper_bedrock.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/smart_scraper_lite_bedrock.py b/examples/bedrock/smart_scraper_lite_bedrock.py deleted file mode 100644 index 2bf0471c..00000000 --- a/examples/bedrock/smart_scraper_lite_bedrock.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/smart_scraper_multi_bedrock.py b/examples/bedrock/smart_scraper_multi_bedrock.py deleted file mode 100644 index 9de097b0..00000000 --- a/examples/bedrock/smart_scraper_multi_bedrock.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperMultiGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/bedrock/smart_scraper_multi_concat_bedrock.py b/examples/bedrock/smart_scraper_multi_concat_bedrock.py deleted file mode 100644 index 74c30a3f..00000000 --- a/examples/bedrock/smart_scraper_multi_concat_bedrock.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/bedrock/smart_scraper_multi_lite_bedrock.py b/examples/bedrock/smart_scraper_multi_lite_bedrock.py deleted file mode 100644 index 5cb26067..00000000 --- a/examples/bedrock/smart_scraper_multi_lite_bedrock.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/smart_scraper_schema_bedrock.py b/examples/bedrock/smart_scraper_schema_bedrock.py deleted file mode 100644 index 2829efec..00000000 --- a/examples/bedrock/smart_scraper_schema_bedrock.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from typing import List -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/bedrock/xml_scraper_bedrock.py b/examples/bedrock/xml_scraper_bedrock.py deleted file mode 100644 index 2110fc9f..00000000 --- a/examples/bedrock/xml_scraper_bedrock.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books. Skip the preamble.", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/bedrock/xml_scraper_graph_multi_bedrock.py b/examples/bedrock/xml_scraper_graph_multi_bedrock.py deleted file mode 100644 index ab7bd4ad..00000000 --- a/examples/bedrock/xml_scraper_graph_multi_bedrock.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "client": "client_name", - "model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0", - "temperature": 0.0 - }, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/benchmarks/GenerateScraper/.env.example b/examples/benchmarks/GenerateScraper/.env.example deleted file mode 100644 index 599a2397..00000000 --- a/examples/benchmarks/GenerateScraper/.env.example +++ /dev/null @@ -1 +0,0 @@ -OPENAI_APIKEY="your openai key here" \ No newline at end of file diff --git a/examples/benchmarks/GenerateScraper/Readme.md b/examples/benchmarks/GenerateScraper/Readme.md deleted file mode 100644 index 79201d22..00000000 --- a/examples/benchmarks/GenerateScraper/Readme.md +++ /dev/null @@ -1,43 +0,0 @@ -# Local models -# Local models -The two websites benchmark are: -- Example 1: https://perinim.github.io/projects -- Example 2: https://www.wired.com (at 17/4/2024) - -Both are strored locally as txt file in .txt format because in this way we do not have to think about the internet connection - -The time is measured in seconds - -The model runned for this benchmark is Mistral on Ollama with nomic-embed-text - -| Hardware | Model | Example 1 | Example 2 | -| ---------------------- | --------------------------------------- | --------- | --------- | -| Macbook 14' m1 pro | Mistral on Ollama with nomic-embed-text | 30.54s | 35.76s | -| Macbook m2 max | Mistral on Ollama with nomic-embed-text | | | -| Macbook 14' m1 pro
| Llama3 on Ollama with nomic-embed-text | 27.82s | 29.986s | -| Macbook m2 max
| Llama3 on Ollama with nomic-embed-text | | | - - -**Note**: the examples on Docker are not runned on other devices than the Macbook because the performance are to slow (10 times slower than Ollama). -# Performance on APIs services -### Example 1: personal portfolio -**URL**: https://perinim.github.io/projects -**Task**: List me all the projects with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| --------------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | 24.21 | 1892 | 1802 | 90 | 1 | 0.002883 | -| gpt-4-turbo-preview | 6.614 | 1936 | 1802 | 134 | 1 | 0.02204 | -| Grooq with nomic-embed-text | 6.71 | 2201 | 2024 | 177 | 1 | 0 | - -### Example 2: Wired -**URL**: https://www.wired.com -**Task**: List me all the articles with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| --------------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | | | | | | | -| gpt-4-turbo-preview | | | | | | | -| Grooq with nomic-embed-text | | | | | | | - - diff --git a/examples/benchmarks/GenerateScraper/benchmark_docker.py b/examples/benchmarks/GenerateScraper/benchmark_docker.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/benchmarks/GenerateScraper/benchmark_groq.py b/examples/benchmarks/GenerateScraper/benchmark_groq.py deleted file mode 100644 index bef4e8b6..00000000 --- a/examples/benchmarks/GenerateScraper/benchmark_groq.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "headless": False, - "library": "beautifoulsoup" -} - - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = ScriptCreatorGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/GenerateScraper/benchmark_llama3.py b/examples/benchmarks/GenerateScraper/benchmark_llama3.py deleted file mode 100644 index a80b2e71..00000000 --- a/examples/benchmarks/GenerateScraper/benchmark_llama3.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - # "model_tokens": 2000, # set context length arbitrarily, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "library": "beautifoulsoup" -} - - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = ScriptCreatorGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/GenerateScraper/benchmark_mistral.py b/examples/benchmarks/GenerateScraper/benchmark_mistral.py deleted file mode 100644 index 87219eb4..00000000 --- a/examples/benchmarks/GenerateScraper/benchmark_mistral.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("GPT4_KEY") - - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - # "model_tokens": 2000, # set context length arbitrarily, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "library": "beautifoulsoup" -} - - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = ScriptCreatorGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/GenerateScraper/benchmark_openai_gpt35.py b/examples/benchmarks/GenerateScraper/benchmark_openai_gpt35.py deleted file mode 100644 index 83ed3913..00000000 --- a/examples/benchmarks/GenerateScraper/benchmark_openai_gpt35.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = ScriptCreatorGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/GenerateScraper/benchmark_openai_gpt4.py b/examples/benchmarks/GenerateScraper/benchmark_openai_gpt4.py deleted file mode 100644 index 37791c29..00000000 --- a/examples/benchmarks/GenerateScraper/benchmark_openai_gpt4.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4-turbo-2024-04-09", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = ScriptCreatorGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/GenerateScraper/inputs/example_1.txt b/examples/benchmarks/GenerateScraper/inputs/example_1.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/benchmarks/GenerateScraper/inputs/example_1.txt +++ /dev/null @@ -1,105 +0,0 @@ - -

- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/benchmarks/GenerateScraper/inputs/example_2.txt b/examples/benchmarks/GenerateScraper/inputs/example_2.txt deleted file mode 100644 index b7810eed..00000000 --- a/examples/benchmarks/GenerateScraper/inputs/example_2.txt +++ /dev/null @@ -1,400 +0,0 @@ -WIRED - The Latest in Technology, Science, Culture and Business | WIRED
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
- WIRED - The Latest in Technology, Science, Culture and Business | WIRED -
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
-WIRED - The Latest in Technology, Science, Culture and Business | WIRED
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
\ No newline at end of file diff --git a/examples/benchmarks/SmartScraper/.env.example b/examples/benchmarks/SmartScraper/.env.example deleted file mode 100644 index 599a2397..00000000 --- a/examples/benchmarks/SmartScraper/.env.example +++ /dev/null @@ -1 +0,0 @@ -OPENAI_APIKEY="your openai key here" \ No newline at end of file diff --git a/examples/benchmarks/SmartScraper/Readme.md b/examples/benchmarks/SmartScraper/Readme.md deleted file mode 100644 index 9c9f9c37..00000000 --- a/examples/benchmarks/SmartScraper/Readme.md +++ /dev/null @@ -1,42 +0,0 @@ -# Local models -# Local models -The two websites benchmark are: -- Example 1: https://perinim.github.io/projects -- Example 2: https://www.wired.com (at 17/4/2024) - -Both are strored locally as txt file in .txt format because in this way we do not have to think about the internet connection - -| Hardware | Model | Example 1 | Example 2 | -| ---------------------- | --------------------------------------- | --------- | --------- | -| Macbook 14' m1 pro | Mistral on Ollama with nomic-embed-text | 16.291s | 38.74s | -| Macbook m2 max | Mistral on Ollama with nomic-embed-text | | | -| Macbook 14' m1 pro
| Llama3 on Ollama with nomic-embed-text | 12.88s | 13.84s | -| Macbook m2 max
| Llama3 on Ollama with nomic-embed-text | | | - -**Note**: the examples on Docker are not runned on other devices than the Macbook because the performance are to slow (10 times slower than Ollama). Indeed the results are the following: - -| Hardware | Example 1 | Example 2 | -| ------------------ | --------- | --------- | -| Macbook 14' m1 pro | 139.89 | Too long | -# Performance on APIs services -### Example 1: personal portfolio -**URL**: https://perinim.github.io/projects -**Task**: List me all the projects with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| ------------------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | 4.132s | 438 | 303 | 135 | 1 | 0.000724 | -| gpt-4-turbo-preview | 6.965s | 442 | 303 | 139 | 1 | 0.0072 | -| gpt-4-o | 4.446s | 444 | 305 | 139 | 1 | 0 | -| Grooq with nomic-embed-text
| 1.335s | 648 | 482 | 166 | 1 | 0 | - -### Example 2: Wired -**URL**: https://www.wired.com -**Task**: List me all the articles with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| ------------------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | 8.836s | 1167 | 726 | 441 | 1 | 0.001971 | -| gpt-4-turbo-preview | 21.53s | 1205 | 726 | 479 | 1 | 0.02163 | -| gpt-4-o | 15.27s | 1400 | 715 | 685 | 1 | 0 | -| Grooq with nomic-embed-text
| 3.82s | 2459 | 2192 | 267 | 1 | 0 | diff --git a/examples/benchmarks/SmartScraper/benchmark_docker.py b/examples/benchmarks/SmartScraper/benchmark_docker.py deleted file mode 100644 index e5754c4b..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_docker.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_groq.py b/examples/benchmarks/SmartScraper/benchmark_groq.py deleted file mode 100644 index e769ee52..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_groq.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_llama3.py b/examples/benchmarks/SmartScraper/benchmark_llama3.py deleted file mode 100644 index 2b182f20..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_llama3.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_mistral.py b/examples/benchmarks/SmartScraper/benchmark_mistral.py deleted file mode 100644 index 0e6e53e5..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_mistral.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_openai_gpt35.py b/examples/benchmarks/SmartScraper/benchmark_openai_gpt35.py deleted file mode 100644 index 659d2c78..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_openai_gpt35.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_openai_gpt4.py b/examples/benchmarks/SmartScraper/benchmark_openai_gpt4.py deleted file mode 100644 index a23901a9..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_openai_gpt4.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4-turbo", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/benchmark_openai_gpt4o.py b/examples/benchmarks/SmartScraper/benchmark_openai_gpt4o.py deleted file mode 100644 index 8b2da6d7..00000000 --- a/examples/benchmarks/SmartScraper/benchmark_openai_gpt4o.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ -files = ["inputs/example_1.txt", "inputs/example_2.txt"] -tasks = ["List me all the projects with their description.", - "List me all the articles with their description."] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -for i in range(0, 2): - with open(files[i], 'r', encoding="utf-8") as file: - text = file.read() - - smart_scraper_graph = SmartScraperGraph( - prompt=tasks[i], - source=text, - config=graph_config - ) - - result = smart_scraper_graph.run() - print(result) - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = smart_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) diff --git a/examples/benchmarks/SmartScraper/inputs/example_1.txt b/examples/benchmarks/SmartScraper/inputs/example_1.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/benchmarks/SmartScraper/inputs/example_1.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/benchmarks/SmartScraper/inputs/example_2.txt b/examples/benchmarks/SmartScraper/inputs/example_2.txt deleted file mode 100644 index b7810eed..00000000 --- a/examples/benchmarks/SmartScraper/inputs/example_2.txt +++ /dev/null @@ -1,400 +0,0 @@ -WIRED - The Latest in Technology, Science, Culture and Business | WIRED
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
- WIRED - The Latest in Technology, Science, Culture and Business | WIRED -
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
-WIRED - The Latest in Technology, Science, Culture and Business | WIRED
Skip to main content

WIRED

Book Excerpt

They Experimented on Themselves in Secret. What They Discovered Helped Win a War

The untold, top-secret story of the British researchers who found the key to keeping humans alive underwater—and helped make D-Day a success.
Business

Microsoft in the age of Satya Nadella

Originally published February 2015: More than five years before Microsoft invested its first $1 billion in OpenAI, its engineers were hard at work on something that they believed would transform consumer computing, and it wasn’t artificial intelligence.
\ No newline at end of file diff --git a/examples/benchmarks/readme.md b/examples/benchmarks/readme.md deleted file mode 100644 index ca672ad0..00000000 --- a/examples/benchmarks/readme.md +++ /dev/null @@ -1,4 +0,0 @@ -These 2 subfolders contain all the scripts and performance documents for the 2 graphs used for the scrapers. -In particular: -* __GenerateScraper__: contains the benchmarks for GenerateScraper class -* __SmartScraper__: contains the benchamrks for SmartScraper class \ No newline at end of file diff --git a/examples/deepseek/.env.example b/examples/deepseek/.env.example deleted file mode 100644 index 37511138..00000000 --- a/examples/deepseek/.env.example +++ /dev/null @@ -1 +0,0 @@ -DEEPSEEK_APIKEY="your api key" \ No newline at end of file diff --git a/examples/deepseek/code_generator_graph_deepseek.py b/examples/deepseek/code_generator_graph_deepseek.py deleted file mode 100644 index f78a42b6..00000000 --- a/examples/deepseek/code_generator_graph_deepseek.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/deepseek/csv_scraper_deepseek.py b/examples/deepseek/csv_scraper_deepseek.py deleted file mode 100644 index 6ef0ac92..00000000 --- a/examples/deepseek/csv_scraper_deepseek.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/deepseek/csv_scraper_graph_multi_deepseek.py b/examples/deepseek/csv_scraper_graph_multi_deepseek.py deleted file mode 100644 index 95474360..00000000 --- a/examples/deepseek/csv_scraper_graph_multi_deepseek.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/deepseek/depth_search_graph_deepseek.py b/examples/deepseek/depth_search_graph_deepseek.py deleted file mode 100644 index 064690a5..00000000 --- a/examples/deepseek/depth_search_graph_deepseek.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/deepseek/document_scraper_deepseek.py b/examples/deepseek/document_scraper_deepseek.py deleted file mode 100644 index e94826d3..00000000 --- a/examples/deepseek/document_scraper_deepseek.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/deepseek/inputs/books.xml b/examples/deepseek/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/deepseek/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/deepseek/inputs/example.json b/examples/deepseek/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/deepseek/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/deepseek/inputs/username.csv b/examples/deepseek/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/deepseek/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/deepseek/json_scraper_deepseek.py b/examples/deepseek/json_scraper_deepseek.py deleted file mode 100644 index d714c1db..00000000 --- a/examples/deepseek/json_scraper_deepseek.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/deepseek/json_scraper_multi_deepseek.py b/examples/deepseek/json_scraper_multi_deepseek.py deleted file mode 100644 index 893937cd..00000000 --- a/examples/deepseek/json_scraper_multi_deepseek.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/deepseek/rate_limit_deepseek.py b/examples/deepseek/rate_limit_deepseek.py deleted file mode 100644 index 16781f39..00000000 --- a/examples/deepseek/rate_limit_deepseek.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - "rate_limit": { - "requests_per_second": 1 - } - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/scrape_plain_text_deepseek.py b/examples/deepseek/scrape_plain_text_deepseek.py deleted file mode 100644 index 2b243d35..00000000 --- a/examples/deepseek/scrape_plain_text_deepseek.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/script_generator_deepseek.py b/examples/deepseek/script_generator_deepseek.py deleted file mode 100644 index 899c7a35..00000000 --- a/examples/deepseek/script_generator_deepseek.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/script_multi_generator_deepseek.py b/examples/deepseek/script_multi_generator_deepseek.py deleted file mode 100644 index 48ca2d20..00000000 --- a/examples/deepseek/script_multi_generator_deepseek.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/search_graph_deepseek.py b/examples/deepseek/search_graph_deepseek.py deleted file mode 100644 index 7a3baf0d..00000000 --- a/examples/deepseek/search_graph_deepseek.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/deepseek/search_graph_schema_deepseek.py b/examples/deepseek/search_graph_schema_deepseek.py deleted file mode 100644 index f5f20e25..00000000 --- a/examples/deepseek/search_graph_schema_deepseek.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/deepseek/search_link_graph_deepseek.py b/examples/deepseek/search_link_graph_deepseek.py deleted file mode 100644 index dac13737..00000000 --- a/examples/deepseek/search_link_graph_deepseek.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/deepseek/smart_scraper_deepseek.py b/examples/deepseek/smart_scraper_deepseek.py deleted file mode 100644 index 0eac94e8..00000000 --- a/examples/deepseek/smart_scraper_deepseek.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/smart_scraper_lite_deepseek.py b/examples/deepseek/smart_scraper_lite_deepseek.py deleted file mode 100644 index a70d76b0..00000000 --- a/examples/deepseek/smart_scraper_lite_deepseek.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("DEEPSEEK_API_KEY"), - "model": "deepseek/deepseek-coder-33b-instruct", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/smart_scraper_multi_concat_deepseek.py b/examples/deepseek/smart_scraper_multi_concat_deepseek.py deleted file mode 100644 index eeb1816c..00000000 --- a/examples/deepseek/smart_scraper_multi_concat_deepseek.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/deepseek/smart_scraper_multi_deepseek.py b/examples/deepseek/smart_scraper_multi_deepseek.py deleted file mode 100644 index 5923e302..00000000 --- a/examples/deepseek/smart_scraper_multi_deepseek.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/deepseek/smart_scraper_multi_lite_deepseek.py b/examples/deepseek/smart_scraper_multi_lite_deepseek.py deleted file mode 100644 index eb5eea01..00000000 --- a/examples/deepseek/smart_scraper_multi_lite_deepseek.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("DEEPSEEK_API_KEY"), - "model": "deepseek/deepseek-coder-33b-instruct", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/deepseek/smart_scraper_schema_deepseek.py b/examples/deepseek/smart_scraper_schema_deepseek.py deleted file mode 100644 index fd87fbdc..00000000 --- a/examples/deepseek/smart_scraper_schema_deepseek.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/deepseek/xml_scraper_deepseek.py b/examples/deepseek/xml_scraper_deepseek.py deleted file mode 100644 index d66b0eab..00000000 --- a/examples/deepseek/xml_scraper_deepseek.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/deepseek/xml_scraper_graph_multi_deepseek.py b/examples/deepseek/xml_scraper_graph_multi_deepseek.py deleted file mode 100644 index 2d190926..00000000 --- a/examples/deepseek/xml_scraper_graph_multi_deepseek.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -deepseek_key = os.getenv("DEEPSEEK_APIKEY") - -graph_config = { - "llm": { - "model": "deepseek/deepseek-chat", - "api_key": deepseek_key, - }, - "verbose": True, -} -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/ernie/code_generator_graph_ernie.py b/examples/ernie/code_generator_graph_ernie.py deleted file mode 100644 index 65b8e4b9..00000000 --- a/examples/ernie/code_generator_graph_ernie.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/ernie/csv_scraper_ernie.py b/examples/ernie/csv_scraper_ernie.py deleted file mode 100644 index 6f4335b6..00000000 --- a/examples/ernie/csv_scraper_ernie.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - } -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/ernie/custom_graph_ernie.py b/examples/ernie/custom_graph_ernie.py deleted file mode 100644 index a987560e..00000000 --- a/examples/ernie/custom_graph_ernie.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -from langchain_openai import OpenAIEmbeddings -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - } -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) -embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/ernie/depth_search_graph_ernie.py b/examples/ernie/depth_search_graph_ernie.py deleted file mode 100644 index 99470d8d..00000000 --- a/examples/ernie/depth_search_graph_ernie.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -depth_search_graph_opeani example -""" -from scrapegraphai.graphs import DepthSearchGraph - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/ernie/document_scraper_anthropic_ernie.py b/examples/ernie/document_scraper_anthropic_ernie.py deleted file mode 100644 index 74d91be1..00000000 --- a/examples/ernie/document_scraper_anthropic_ernie.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from scrapegraphai.graphs import DocumentScraperGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - } -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/ernie/inputs/books.xml b/examples/ernie/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/ernie/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/ernie/inputs/example.json b/examples/ernie/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/ernie/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/ernie/inputs/plain_html_example.txt b/examples/ernie/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/ernie/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/ernie/inputs/username.csv b/examples/ernie/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/ernie/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/ernie/json_scraper_ernie.py b/examples/ernie/json_scraper_ernie.py deleted file mode 100644 index 35324da2..00000000 --- a/examples/ernie/json_scraper_ernie.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - } -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/ernie/rate_limit_ernie.py b/examples/ernie/rate_limit_ernie.py deleted file mode 100644 index 043029a7..00000000 --- a/examples/ernie/rate_limit_ernie.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1, - "rate_limit": { - "requests_per_second": 1 - }, - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/scrape_plain_text_ernie.py b/examples/ernie/scrape_plain_text_ernie.py deleted file mode 100644 index dde49537..00000000 --- a/examples/ernie/scrape_plain_text_ernie.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/script_generator_ernie.py b/examples/ernie/script_generator_ernie.py deleted file mode 100644 index f518739c..00000000 --- a/examples/ernie/script_generator_ernie.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/script_multi_generator_ernie.py b/examples/ernie/script_multi_generator_ernie.py deleted file mode 100644 index 4b3c88f7..00000000 --- a/examples/ernie/script_multi_generator_ernie.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/search_graph_ernie.py b/examples/ernie/search_graph_ernie.py deleted file mode 100644 index ff9b3d8b..00000000 --- a/examples/ernie/search_graph_ernie.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Example of Search Graph -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/ernie/search_link_graph_ernie.py b/examples/ernie/search_link_graph_ernie.py deleted file mode 100644 index 645dd505..00000000 --- a/examples/ernie/search_link_graph_ernie.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/ernie/smart_scraper_ernie.py b/examples/ernie/smart_scraper_ernie.py deleted file mode 100644 index 4bbe608a..00000000 --- a/examples/ernie/smart_scraper_ernie.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/smart_scraper_lite_ernie.py b/examples/ernie/smart_scraper_lite_ernie.py deleted file mode 100644 index 5d3ba9d9..00000000 --- a/examples/ernie/smart_scraper_lite_ernie.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ERNIE_API_KEY"), - "model": "ernie/ernie-bot-4", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/smart_scraper_multi_concat_ernie.py b/examples/ernie/smart_scraper_multi_concat_ernie.py deleted file mode 100644 index 5be9898d..00000000 --- a/examples/ernie/smart_scraper_multi_concat_ernie.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "library": "beautifulsoup" -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/ernie/smart_scraper_multi_ernie.py b/examples/ernie/smart_scraper_multi_ernie.py deleted file mode 100644 index 4e44ab6a..00000000 --- a/examples/ernie/smart_scraper_multi_ernie.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/ernie/smart_scraper_multi_lite_ernie.py b/examples/ernie/smart_scraper_multi_lite_ernie.py deleted file mode 100644 index 777a760e..00000000 --- a/examples/ernie/smart_scraper_multi_lite_ernie.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ERNIE_API_KEY"), - "model": "ernie/ernie-bot-4", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/ernie/smart_scraper_schema_ernie.py b/examples/ernie/smart_scraper_schema_ernie.py deleted file mode 100644 index e9d9ab0a..00000000 --- a/examples/ernie/smart_scraper_schema_ernie.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import json -import os -from typing import Dict -from dotenv import load_dotenv -from pydantic import BaseModel -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ -class Project(BaseModel): - title: str - description: str - - -class Projects(BaseModel): - Projects: Dict[str, Project] - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config, -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/ernie/speech_graph_ernie.py b/examples/ernie/speech_graph_ernie.py deleted file mode 100644 index 0b4ed620..00000000 --- a/examples/ernie/speech_graph_ernie.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using SpeechSummaryGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SpeechGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define audio output path -# ************************************************ - -FILE_NAME = "website_summary.mp3" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -output_path = os.path.join(curr_dir, FILE_NAME) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "tts_model": { - "api_key": openai_key, - "model": "tts-1", - "voice": "alloy" - }, - "output_path": output_path, -} - -# ************************************************ -# Create the SpeechGraph instance and run it -# ************************************************ - -speech_graph = SpeechGraph( - prompt="Make a detailed audio summary of the projects.", - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = speech_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = speech_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/ernie/xml_scraper_ernie.py b/examples/ernie/xml_scraper_ernie.py deleted file mode 100644 index 90a1230a..00000000 --- a/examples/ernie/xml_scraper_ernie.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ernie/ernie-bot-turbo", - "ernie_client_id": "", - "ernie_client_secret": "", - "temperature": 0.1 - }, - "verbose":False, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/extras/.env.example b/examples/extras/.env.example deleted file mode 100644 index dc01444e..00000000 --- a/examples/extras/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -OPENAI_API_KEY="YOUR_OPENAI_API_KEY" -BROWSER_BASE_PROJECT_ID="YOUR_BROWSER_BASE_PROJECT_ID" -BROWSER_BASE_API_KEY="YOUR_BROWSERBASE_API_KEY" -SCRAPE_DO_API_KEY="YOUR_SCRAPE_DO_API_KEY" \ No newline at end of file diff --git a/examples/extras/Savedscreenshots/test_image.jpeg b/examples/extras/Savedscreenshots/test_image.jpeg deleted file mode 100644 index 159625bcec1cc5553bd03d7fb74b93f16b276bc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178104 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

%#7M@LBBE*~5>&Uo4=g|6{dXaD(YP-=*jQ>ZX< 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 MU(A154gA6QZ$zW>YybcN diff --git a/examples/extras/authenticated_playwright.py b/examples/extras/authenticated_playwright.py deleted file mode 100644 index a4926bc7..00000000 --- a/examples/extras/authenticated_playwright.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -Example leveraging a state file containing session cookies which -might be leveraged to authenticate to a website and scrape protected -content. -""" - -import os -import random -from dotenv import load_dotenv - -# import playwright so we can use it to create the state file -from playwright.async_api import async_playwright - -from scrapegraphai.graphs import OmniScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Leveraging Playwright external to the invocation of the graph to -# login and create the state file -# ************************************************ - - -# note this is just an example and probably won't actually work on -# LinkedIn, the implementation of the login is highly dependent on the website -async def do_login(): - async with async_playwright() as playwright: - browser = await playwright.chromium.launch( - timeout=30000, - headless=False, - slow_mo=random.uniform(500, 1500), - ) - page = await browser.new_page() - - # very basic implementation of a login, in reality it may be trickier - await page.goto("https://www.linkedin.com/login") - await page.get_by_label("Email or phone").fill("some_bloke@some_domain.com") - await page.get_by_label("Password").fill("test1234") - await page.get_by_role("button", name="Sign in").click() - await page.wait_for_timeout(3000) - - # assuming a successful login, we save the cookies to a file - await page.context.storage_state(path="./state.json") - - -async def main(): - await do_login() - - # ************************************************ - # Define the configuration for the graph - # ************************************************ - - openai_api_key = os.getenv("OPENAI_APIKEY") - - graph_config = { - "llm": { - "api_key": openai_api_key, - "model": "openai/gpt-4o", - }, - "max_images": 10, - "headless": False, - # provide the path to the state file - "storage_state": "./state.json", - } - - # ************************************************ - # Create the OmniScraperGraph instance and run it - # ************************************************ - - omni_scraper_graph = OmniScraperGraph( - prompt="List me all the projects with their description.", - source="https://www.linkedin.com/feed/", - config=graph_config, - ) - - # the storage_state is used to load the cookies from the state file - # so we are authenticated and able to scrape protected content - result = omni_scraper_graph.run() - print(result) - - # ************************************************ - # Get graph execution info - # ************************************************ - - graph_exec_info = omni_scraper_graph.get_execution_info() - print(prettify_exec_info(graph_exec_info)) - - -if __name__ == "__main__": - import asyncio - - asyncio.run(main()) diff --git a/examples/extras/browser_base_integration.py b/examples/extras/browser_base_integration.py deleted file mode 100644 index 7030e101..00000000 --- a/examples/extras/browser_base_integration.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "browser_base": { - "api_key": os.getenv("BROWSER_BASE_API_KEY"), - "project_id": os.getenv("BROWSER_BASE_PROJECT_ID"), - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/chromium_selenium.py b/examples/extras/chromium_selenium.py deleted file mode 100644 index fba530d4..00000000 --- a/examples/extras/chromium_selenium.py +++ /dev/null @@ -1,119 +0,0 @@ -import asyncio -import os -import json -from dotenv import load_dotenv -from scrapegraphai.docloaders.chromium import ChromiumLoader # Import your ChromiumLoader class -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -from aiohttp import ClientError - -# Load environment variables for API keys -load_dotenv() - -# ************************************************ -# Define function to analyze content with ScrapegraphAI -# ************************************************ -async def analyze_content_with_scrapegraph(content: str): - """ - Analyze scraped content using ScrapegraphAI. - - Args: - content (str): The scraped HTML or text content. - - Returns: - dict: The result from ScrapegraphAI analysis. - """ - try: - # Initialize ScrapegraphAI SmartScraperGraph - smart_scraper = SmartScraperGraph( - prompt="Summarize the main content of this webpage and extract any contact information.", - source=content, # Pass the content directly - config={ - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "verbose": True - } - ) - result = smart_scraper.run() - return result - except Exception as e: - print(f"❌ ScrapegraphAI analysis failed: {e}") - return {"error": str(e)} - -# ************************************************ -# Test scraper and ScrapegraphAI pipeline -# ************************************************ -async def test_scraper_with_analysis(scraper: ChromiumLoader, urls: list): - """ - Test scraper for the given backend and URLs, then analyze content with ScrapegraphAI. - - Args: - scraper (ChromiumLoader): The ChromiumLoader instance. - urls (list): A list of URLs to scrape. - """ - for url in urls: - try: - print(f"\n🔎 Scraping: {url} using {scraper.backend}...") - result = await scraper.scrape(url) - - if "Error" in result or not result.strip(): - print(f"❌ Failed to scrape {url}: {result}") - else: - print(f"✅ Successfully scraped {url}. Content (first 200 chars): {result[:200]}") - - # Pass scraped content to ScrapegraphAI for analysis - print("🤖 Analyzing content with ScrapegraphAI...") - analysis_result = await analyze_content_with_scrapegraph(result) - print("📝 Analysis Result:") - print(json.dumps(analysis_result, indent=4)) - - except ClientError as ce: - print(f"❌ Network error while scraping {url}: {ce}") - except Exception as e: - print(f"❌ Unexpected error while scraping {url}: {e}") - -# ************************************************ -# Main Execution -# ************************************************ -async def main(): - urls_to_scrape = [ - "https://example.com", - "https://www.python.org", - "https://invalid-url.test" - ] - - # Test with Playwright backend - print("\n--- Testing Playwright Backend ---") - try: - scraper_playwright_chromium = ChromiumLoader(urls=urls_to_scrape, backend="playwright", headless=True, browser_name = "chromium") - await test_scraper_with_analysis(scraper_playwright_chromium, urls_to_scrape) - - scraper_playwright_firefox = ChromiumLoader(urls=urls_to_scrape, backend="playwright", headless=True, browser_name = "firefox") - await test_scraper_with_analysis(scraper_playwright_firefox, urls_to_scrape) - except ImportError as ie: - print(f"❌ Playwright ImportError: {ie}") - except Exception as e: - print(f"❌ Error initializing Playwright ChromiumLoader: {e}") - - # Test with Selenium backend - print("\n--- Testing Selenium Backend ---") - try: - scraper_selenium_chromium = ChromiumLoader(urls=urls_to_scrape, backend="selenium", headless=True, browser_name = "chromium") - await test_scraper_with_analysis(scraper_selenium_chromium, urls_to_scrape) - - scraper_selenium_firefox = ChromiumLoader(urls=urls_to_scrape, backend="selenium", headless=True, browser_name = "firefox") - await test_scraper_with_analysis(scraper_selenium_firefox, urls_to_scrape) - except ImportError as ie: - print(f"❌ Selenium ImportError: {ie}") - except Exception as e: - print(f"❌ Error initializing Selenium ChromiumLoader: {e}") - -if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - print("❌ Program interrupted by user.") - except Exception as e: - print(f"❌ Program crashed: {e}") diff --git a/examples/extras/cond_smartscraper_usage.py b/examples/extras/cond_smartscraper_usage.py deleted file mode 100644 index 54c40712..00000000 --- a/examples/extras/cond_smartscraper_usage.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraperMultiConcatGraph with Groq -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("GROQ_APIKEY"), - "model": "groq/gemma-7b-it", - }, - "verbose": True, - "headless": True, - "reattempt": True #Setting this to True will allow the graph to reattempt the scraping process -} - -# ******************************************************* -# Create the SmartScraperMultiCondGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/extras/conditional_usage.py b/examples/extras/conditional_usage.py deleted file mode 100644 index d3152bed..00000000 --- a/examples/extras/conditional_usage.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraperMultiConcatGraph with Groq -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiCondGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source=[ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/extras/custom_prompt.py b/examples/extras/custom_prompt.py deleted file mode 100644 index 7def35a3..00000000 --- a/examples/extras/custom_prompt.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -prompt = "Some more info" - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, - "additional_info": prompt, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/example.yml b/examples/extras/example.yml deleted file mode 100644 index fd5713c7..00000000 --- a/examples/extras/example.yml +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", - # "base_url": "http://localhost:11434", - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - # "base_url": "http://localhost:11434", - }, - "verbose": true, - "headless": false -} \ No newline at end of file diff --git a/examples/extras/force_mode.py b/examples/extras/force_mode.py deleted file mode 100644 index 85593032..00000000 --- a/examples/extras/force_mode.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - # "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "force": True, - "caching": True -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/html_mode.py b/examples/extras/html_mode.py deleted file mode 100644 index 6e2670a0..00000000 --- a/examples/extras/html_mode.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -By default smart scraper converts in md format the -code. If you want to just use the original code, you have -to specify in the confi -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "html_mode": True, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/load_yml.py b/examples/extras/load_yml.py deleted file mode 100644 index 974ba4d5..00000000 --- a/examples/extras/load_yml.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import yaml -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -with open("example.yml", 'r') as file: - graph_config = yaml.safe_load(file) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the titles", - source="https://sport.sky.it/nba?gr=www", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/no_cut.py b/examples/extras/no_cut.py deleted file mode 100644 index 71bfad86..00000000 --- a/examples/extras/no_cut.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -This example shows how to do not process the html code in the fetch phase -""" - -import os, json -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": "s", - "model": "openai/gpt-3.5-turbo", - }, - "cut": False, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="Extract me the python code inside the page", - source="https://www.exploit-db.com/exploits/51447", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/proxy_rotation.py b/examples/extras/proxy_rotation.py deleted file mode 100644 index adfb87ed..00000000 --- a/examples/extras/proxy_rotation.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "API_KEY", - "model": "openai/gpt-3.5-turbo", - }, - "loader_kwargs": { - "proxy" : { - "server": "http:/**********", - "username": "********", - "password": "***", - }, - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/rag_caching.py b/examples/extras/rag_caching.py deleted file mode 100644 index df73d2b4..00000000 --- a/examples/extras/rag_caching.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, - "caching": True -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) \ No newline at end of file diff --git a/examples/extras/reasoning.py b/examples/extras/reasoning.py deleted file mode 100644 index 80e57faa..00000000 --- a/examples/extras/reasoning.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "reasoning": True, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/scrape_do.py b/examples/extras/scrape_do.py deleted file mode 100644 index 45026f21..00000000 --- a/examples/extras/scrape_do.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "scrape_do": { - "api_key": os.getenv("SCRAPE_DO_API_KEY"), - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects", - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/extras/screenshot_scaping.py b/examples/extras/screenshot_scaping.py deleted file mode 100644 index 439c2a0c..00000000 --- a/examples/extras/screenshot_scaping.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -example of scraping with screenshots -""" -import asyncio -from scrapegraphai.utils.screenshot_scraping import (take_screenshot, - select_area_with_opencv, - crop_image, detect_text) - -# STEP 1: Take a screenshot -image = asyncio.run(take_screenshot( - url="https://colab.google/", - save_path="Savedscreenshots/test_image.jpeg", - quality = 50 -)) - -# STEP 2 (Optional): Select an area of the image which you want to use for text detection. -LEFT, TOP, RIGHT, BOTTOM = select_area_with_opencv(image) -print("LEFT: ", LEFT, " TOP: ", TOP, " RIGHT: ", RIGHT, " BOTTOM: ", BOTTOM) - -# STEP 3 (Optional): Crop the image. -# Note: If any of the coordinates (LEFT, TOP, RIGHT, BOTTOM) is None, -# it will be set to the corresponding edge of the image. -cropped_image = crop_image(image, LEFT=LEFT, RIGHT=RIGHT,TOP=TOP,BOTTOM=BOTTOM) - -# STEP 4: Detect text -TEXT = detect_text( - cropped_image, # The image to detect text from - languages = ["en"] # The languages to detect text in -) - -print("DETECTED TEXT: ") -print(TEXT) diff --git a/examples/extras/serch_graph_scehma.py b/examples/extras/serch_graph_scehma.py deleted file mode 100644 index 66c47a33..00000000 --- a/examples/extras/serch_graph_scehma.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from pydantic import BaseModel, Field -from typing import List -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -class CeoName(BaseModel): - ceo_name: str = Field(description="The name and surname of the ceo") - -class Ceos(BaseModel): - names: List[CeoName] - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt=f"Who is the ceo of Appke?", - schema = Ceos, - config=graph_config, -) - -result = search_graph.run() -print(result) diff --git a/examples/extras/slow_mo.py b/examples/extras/slow_mo.py deleted file mode 100644 index 55b40cd7..00000000 --- a/examples/extras/slow_mo.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "loader_kwargs": { - "slow_mo": 10000 - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the titles", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) \ No newline at end of file diff --git a/examples/extras/undected_playwright.py b/examples/extras/undected_playwright.py deleted file mode 100644 index 999fe42e..00000000 --- a/examples/extras/undected_playwright.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False, - "backend": "undetected_chromedriver" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/.env.example b/examples/fireworks/.env.example deleted file mode 100644 index ab200215..00000000 --- a/examples/fireworks/.env.example +++ /dev/null @@ -1 +0,0 @@ -FIREWORKS_APIKEY="your fireworks api key" diff --git a/examples/fireworks/code_generator_graph_fireworks.py b/examples/fireworks/code_generator_graph_fireworks.py deleted file mode 100644 index e38c48a1..00000000 --- a/examples/fireworks/code_generator_graph_fireworks.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -import json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/fireworks/csv_scraper_fireworks.py b/examples/fireworks/csv_scraper_fireworks.py deleted file mode 100644 index c380f9bd..00000000 --- a/examples/fireworks/csv_scraper_fireworks.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "headless": False, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/fireworks/csv_scraper_graph_multi_fireworks.py b/examples/fireworks/csv_scraper_graph_multi_fireworks.py deleted file mode 100644 index 61518822..00000000 --- a/examples/fireworks/csv_scraper_graph_multi_fireworks.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/fireworks/custom_graph_fireworks.py b/examples/fireworks/custom_graph_fireworks.py deleted file mode 100644 index 518e9df3..00000000 --- a/examples/fireworks/custom_graph_fireworks.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -import os -from dotenv import load_dotenv -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, GenerateAnswerNode, RobotsNode -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) - -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/fireworks/depth_search_graph_fireworks.py b/examples/fireworks/depth_search_graph_fireworks.py deleted file mode 100644 index f467be9f..00000000 --- a/examples/fireworks/depth_search_graph_fireworks.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/fireworks/document_scraper_anthropic_fireworks.py b/examples/fireworks/document_scraper_anthropic_fireworks.py deleted file mode 100644 index 33f6c0d5..00000000 --- a/examples/fireworks/document_scraper_anthropic_fireworks.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/fireworks/inputs/books.xml b/examples/fireworks/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/fireworks/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/fireworks/inputs/example.json b/examples/fireworks/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/fireworks/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/fireworks/inputs/plain_html_example.txt b/examples/fireworks/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/fireworks/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -

- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/fireworks/inputs/username.csv b/examples/fireworks/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/fireworks/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/fireworks/json_scraper_fireworkspy.py b/examples/fireworks/json_scraper_fireworkspy.py deleted file mode 100644 index ef1b8264..00000000 --- a/examples/fireworks/json_scraper_fireworkspy.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/fireworks/json_scraper_multi_fireworks.py b/examples/fireworks/json_scraper_multi_fireworks.py deleted file mode 100644 index cd16c525..00000000 --- a/examples/fireworks/json_scraper_multi_fireworks.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/fireworks/rate_limit_fireworks.py b/examples/fireworks/rate_limit_fireworks.py deleted file mode 100644 index 813b6d5d..00000000 --- a/examples/fireworks/rate_limit_fireworks.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct", - "rate_limit": { - "requests_per_second": 1 - }, - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/scrape_plain_text_fireworks.py b/examples/fireworks/scrape_plain_text_fireworks.py deleted file mode 100644 index c82bdf15..00000000 --- a/examples/fireworks/scrape_plain_text_fireworks.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/script_generator_fireworks.py b/examples/fireworks/script_generator_fireworks.py deleted file mode 100644 index d195cbdc..00000000 --- a/examples/fireworks/script_generator_fireworks.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, - "library": "beautifulsoup" - -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/script_generator_schema_fireworks.py b/examples/fireworks/script_generator_schema_fireworks.py deleted file mode 100644 index 20e46fb7..00000000 --- a/examples/fireworks/script_generator_schema_fireworks.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "library": "beautifulsoup", -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config, - schema=Projects -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/fireworks/script_multi_generator_fireworks.py b/examples/fireworks/script_multi_generator_fireworks.py deleted file mode 100644 index c0f474dc..00000000 --- a/examples/fireworks/script_multi_generator_fireworks.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "library": "beautifulsoup", -} -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/search_graph_fireworks.py b/examples/fireworks/search_graph_fireworks.py deleted file mode 100644 index 72728a28..00000000 --- a/examples/fireworks/search_graph_fireworks.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "max_results": 2, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/fireworks/search_graph_schema_fireworks.py b/examples/fireworks/search_graph_schema_fireworks.py deleted file mode 100644 index bd54a69a..00000000 --- a/examples/fireworks/search_graph_schema_fireworks.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "max_results": 2, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/fireworks/search_link_graph_fireworks.py b/examples/fireworks/search_link_graph_fireworks.py deleted file mode 100644 index e71e2a4f..00000000 --- a/examples/fireworks/search_link_graph_fireworks.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "max_results": 2, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/fireworks/smart_scraper_fireworks.py b/examples/fireworks/smart_scraper_fireworks.py deleted file mode 100644 index 2ccac269..00000000 --- a/examples/fireworks/smart_scraper_fireworks.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/smart_scraper_lite_fireworks.py b/examples/fireworks/smart_scraper_lite_fireworks.py deleted file mode 100644 index 6c9a7745..00000000 --- a/examples/fireworks/smart_scraper_lite_fireworks.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("FIREWORKS_API_KEY"), - "model": "fireworks/llama-v2-70b-chat", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/fireworks/smart_scraper_multi_concat_fireworks.py b/examples/fireworks/smart_scraper_multi_concat_fireworks.py deleted file mode 100644 index c0da49a3..00000000 --- a/examples/fireworks/smart_scraper_multi_concat_fireworks.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/fireworks/smart_scraper_multi_fireworks.py b/examples/fireworks/smart_scraper_multi_fireworks.py deleted file mode 100644 index a75f9ab1..00000000 --- a/examples/fireworks/smart_scraper_multi_fireworks.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/fireworks/smart_scraper_multi_lite_fireworks.py b/examples/fireworks/smart_scraper_multi_lite_fireworks.py deleted file mode 100644 index 4ffaf6bb..00000000 --- a/examples/fireworks/smart_scraper_multi_lite_fireworks.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("FIREWORKS_API_KEY"), - "model": "fireworks/llama-v2-70b-chat", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/fireworks/smart_scraper_schema_fireworks.py b/examples/fireworks/smart_scraper_schema_fireworks.py deleted file mode 100644 index b576bc7d..00000000 --- a/examples/fireworks/smart_scraper_schema_fireworks.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) diff --git a/examples/fireworks/xml_scraper_fireworks.py b/examples/fireworks/xml_scraper_fireworks.py deleted file mode 100644 index 88673cf6..00000000 --- a/examples/fireworks/xml_scraper_fireworks.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/fireworks/xml_scraper_graph_multi_fireworks.py b/examples/fireworks/xml_scraper_graph_multi_fireworks.py deleted file mode 100644 index 1744325b..00000000 --- a/examples/fireworks/xml_scraper_graph_multi_fireworks.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -fireworks_api_key = os.getenv("FIREWORKS_APIKEY") - -graph_config = { - "llm": { - "api_key": fireworks_api_key, - "model": "fireworks/accounts/fireworks/models/mixtral-8x7b-instruct" - }, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/.env.example b/examples/google_genai/.env.example deleted file mode 100644 index fc0dacb0..00000000 --- a/examples/google_genai/.env.example +++ /dev/null @@ -1 +0,0 @@ -GOOGLE_APIKEY="your google api key" diff --git a/examples/google_genai/code_generator_graph_gemini.py b/examples/google_genai/code_generator_graph_gemini.py deleted file mode 100644 index 48ea9833..00000000 --- a/examples/google_genai/code_generator_graph_gemini.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/google_genai/csv_scraper_gemini.py b/examples/google_genai/csv_scraper_gemini.py deleted file mode 100644 index cb792169..00000000 --- a/examples/google_genai/csv_scraper_gemini.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the csv file -# ************************************************ - -text = pd.read_csv("inputs/username.csv") - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/csv_scraper_graph_multi_gemini.py b/examples/google_genai/csv_scraper_graph_multi_gemini.py deleted file mode 100644 index a7b252ee..00000000 --- a/examples/google_genai/csv_scraper_graph_multi_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/depth_search_graph_gemini.py b/examples/google_genai/depth_search_graph_gemini.py deleted file mode 100644 index 956341f4..00000000 --- a/examples/google_genai/depth_search_graph_gemini.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/google_genai/document_scraper_gemini.py b/examples/google_genai/document_scraper_gemini.py deleted file mode 100644 index efb22d68..00000000 --- a/examples/google_genai/document_scraper_gemini.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/google_genai/inputs/books.xml b/examples/google_genai/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/google_genai/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/google_genai/inputs/example.json b/examples/google_genai/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/google_genai/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/google_genai/inputs/plain_html_example.txt b/examples/google_genai/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/google_genai/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/google_genai/inputs/username.csv b/examples/google_genai/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/google_genai/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/google_genai/json_scraper_gemini.py b/examples/google_genai/json_scraper_gemini.py deleted file mode 100644 index 343f1d42..00000000 --- a/examples/google_genai/json_scraper_gemini.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/google_genai/json_scraper_multi_gemini.py b/examples/google_genai/json_scraper_multi_gemini.py deleted file mode 100644 index 573faa97..00000000 --- a/examples/google_genai/json_scraper_multi_gemini.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, - "library": "beautifulsoup" -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_genai/rate_limit_gemini.py b/examples/google_genai/rate_limit_gemini.py deleted file mode 100644 index f3e2c555..00000000 --- a/examples/google_genai/rate_limit_gemini.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - "rate_limit": { - "requests_per_second": 1 - } - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/readme.md b/examples/google_genai/readme.md deleted file mode 100644 index 7e06773d..00000000 --- a/examples/google_genai/readme.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains an example of how to use ScrapeGraph-AI with Gemini, a large language model (LLM) from Google AI. The example shows how to extract information from a website using a natural language prompt. \ No newline at end of file diff --git a/examples/google_genai/scrape_plain_text_gemini.py b/examples/google_genai/scrape_plain_text_gemini.py deleted file mode 100644 index f554cede..00000000 --- a/examples/google_genai/scrape_plain_text_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - "temperature": 0, - "streaming": True - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/scrape_xml_gemini.py b/examples/google_genai/scrape_xml_gemini.py deleted file mode 100644 index af8868ea..00000000 --- a/examples/google_genai/scrape_xml_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - "temperature": 0, - "streaming": True - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/script_generator_gemini.py b/examples/google_genai/script_generator_gemini.py deleted file mode 100644 index fdf61f87..00000000 --- a/examples/google_genai/script_generator_gemini.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -smart_scraper_graph = ScriptCreatorGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/script_multi_generator_gemini.py b/examples/google_genai/script_multi_generator_gemini.py deleted file mode 100644 index 3ef0e108..00000000 --- a/examples/google_genai/script_multi_generator_gemini.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/search_graph_gemini.py b/examples/google_genai/search_graph_gemini.py deleted file mode 100644 index d001b34d..00000000 --- a/examples/google_genai/search_graph_gemini.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - "temperature": 0, - "streaming": True - }, - "max_results": 5, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me all the regions of Italy.", - config=graph_config -) - -result = search_graph.run() -print(result) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/search_graph_schema_gemini.py b/examples/google_genai/search_graph_schema_gemini.py deleted file mode 100644 index c55854c5..00000000 --- a/examples/google_genai/search_graph_schema_gemini.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/search_link_graph_gemini.py b/examples/google_genai/search_link_graph_gemini.py deleted file mode 100644 index 084cea41..00000000 --- a/examples/google_genai/search_link_graph_gemini.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_genai/smart_scraper_gemini.py b/examples/google_genai/smart_scraper_gemini.py deleted file mode 100644 index cb59e34f..00000000 --- a/examples/google_genai/smart_scraper_gemini.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/smart_scraper_lite_google_genai.py b/examples/google_genai/smart_scraper_lite_google_genai.py deleted file mode 100644 index 9b776735..00000000 --- a/examples/google_genai/smart_scraper_lite_google_genai.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("GOOGLE_API_KEY"), - "model": "gemini-pro", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/smart_scraper_multi_concat_gemini.py b/examples/google_genai/smart_scraper_multi_concat_gemini.py deleted file mode 100644 index bf6ee544..00000000 --- a/examples/google_genai/smart_scraper_multi_concat_gemini.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_genai/smart_scraper_multi_gemini.py b/examples/google_genai/smart_scraper_multi_gemini.py deleted file mode 100644 index db721db9..00000000 --- a/examples/google_genai/smart_scraper_multi_gemini.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_genai/smart_scraper_multi_lite_gemini.py b/examples/google_genai/smart_scraper_multi_lite_gemini.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/google_genai/smart_scraper_multi_lite_google_genai.py b/examples/google_genai/smart_scraper_multi_lite_google_genai.py deleted file mode 100644 index e14e2ceb..00000000 --- a/examples/google_genai/smart_scraper_multi_lite_google_genai.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("GOOGLE_API_KEY"), - "model": "gemini-pro", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/smart_scraper_schema_gemini.py b/examples/google_genai/smart_scraper_schema_gemini.py deleted file mode 100644 index 7037dc08..00000000 --- a/examples/google_genai/smart_scraper_schema_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_genai/xml_scraper_gemini.py b/examples/google_genai/xml_scraper_gemini.py deleted file mode 100644 index 3c3dc342..00000000 --- a/examples/google_genai/xml_scraper_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/google_genai/xml_scraper_graph_multi_gemini.py b/examples/google_genai/xml_scraper_graph_multi_gemini.py deleted file mode 100644 index 15bc2485..00000000 --- a/examples/google_genai/xml_scraper_graph_multi_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_genai/gemini-pro", - }, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/.env.example b/examples/google_vertexai/.env.example deleted file mode 100644 index fc0dacb0..00000000 --- a/examples/google_vertexai/.env.example +++ /dev/null @@ -1 +0,0 @@ -GOOGLE_APIKEY="your google api key" diff --git a/examples/google_vertexai/code_generator_graph_vertex.py b/examples/google_vertexai/code_generator_graph_vertex.py deleted file mode 100644 index 28f40174..00000000 --- a/examples/google_vertexai/code_generator_graph_vertex.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/google_vertexai/csv_scraper_gemini.py b/examples/google_vertexai/csv_scraper_gemini.py deleted file mode 100644 index e5de1f17..00000000 --- a/examples/google_vertexai/csv_scraper_gemini.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" - -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the csv file -# ************************************************ - -text = pd.read_csv("inputs/username.csv") - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/csv_scraper_graph_multi_gemini.py b/examples/google_vertexai/csv_scraper_graph_multi_gemini.py deleted file mode 100644 index 1318acfb..00000000 --- a/examples/google_vertexai/csv_scraper_graph_multi_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" - -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/custom_graph_gemini.py b/examples/google_vertexai/custom_graph_gemini.py deleted file mode 100644 index 7feff114..00000000 --- a/examples/google_vertexai/custom_graph_gemini.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Example of custom graph using Gemini Google model -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.models import Gemini -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - "temperature": 0, - "streaming": True - }, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = Gemini(graph_config["llm"]) - -# define the nodes for the graph -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={"chunk_size": 4096} -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={"llm": llm_model}, -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={"llm": llm_model}, -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes={ - fetch_node, - parse_node, - rag_node, - generate_answer_node, - }, - edges={ - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - }, - entry_point=fetch_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "List me the projects with their description", - "url": "https://perinim.github.io/projects/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/google_vertexai/depth_search_graph_gemini.py b/examples/google_vertexai/depth_search_graph_gemini.py deleted file mode 100644 index 13bba630..00000000 --- a/examples/google_vertexai/depth_search_graph_gemini.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/google_vertexai/document_scraper_vertex.py b/examples/google_vertexai/document_scraper_vertex.py deleted file mode 100644 index 58f79a91..00000000 --- a/examples/google_vertexai/document_scraper_vertex.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/google_vertexai/inputs/books.xml b/examples/google_vertexai/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/google_vertexai/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/google_vertexai/inputs/example.json b/examples/google_vertexai/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/google_vertexai/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/google_vertexai/inputs/plain_html_example.txt b/examples/google_vertexai/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/google_vertexai/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/google_vertexai/inputs/username.csv b/examples/google_vertexai/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/google_vertexai/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/google_vertexai/json_scraper_gemini.py b/examples/google_vertexai/json_scraper_gemini.py deleted file mode 100644 index 8e9f5a9f..00000000 --- a/examples/google_vertexai/json_scraper_gemini.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/google_vertexai/json_scraper_multi_gemini.py b/examples/google_vertexai/json_scraper_multi_gemini.py deleted file mode 100644 index b9dc2e93..00000000 --- a/examples/google_vertexai/json_scraper_multi_gemini.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, - "library": "beautifulsoup" -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_vertexai/rate_limit_gemini.py b/examples/google_vertexai/rate_limit_gemini.py deleted file mode 100644 index c5f15a35..00000000 --- a/examples/google_vertexai/rate_limit_gemini.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - "rate_limit": { - "requests_per_second": 1 - } - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/readme.md b/examples/google_vertexai/readme.md deleted file mode 100644 index 7e06773d..00000000 --- a/examples/google_vertexai/readme.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains an example of how to use ScrapeGraph-AI with Gemini, a large language model (LLM) from Google AI. The example shows how to extract information from a website using a natural language prompt. \ No newline at end of file diff --git a/examples/google_vertexai/scrape_plain_text_gemini.py b/examples/google_vertexai/scrape_plain_text_gemini.py deleted file mode 100644 index b910330a..00000000 --- a/examples/google_vertexai/scrape_plain_text_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - "temperature": 0, - "streaming": True - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/scrape_xml_gemini.py b/examples/google_vertexai/scrape_xml_gemini.py deleted file mode 100644 index 0b6563a4..00000000 --- a/examples/google_vertexai/scrape_xml_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - "temperature": 0, - "streaming": True - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/script_generator_gemini.py b/examples/google_vertexai/script_generator_gemini.py deleted file mode 100644 index 83bcb978..00000000 --- a/examples/google_vertexai/script_generator_gemini.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -smart_scraper_graph = ScriptCreatorGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/script_multi_generator_gemini.py b/examples/google_vertexai/script_multi_generator_gemini.py deleted file mode 100644 index 8ab3564e..00000000 --- a/examples/google_vertexai/script_multi_generator_gemini.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, - "library": "beautifoulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/search_graph_gemini.py b/examples/google_vertexai/search_graph_gemini.py deleted file mode 100644 index 1c86f322..00000000 --- a/examples/google_vertexai/search_graph_gemini.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - "temperature": 0, - "streaming": True - }, - "max_results": 5, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me all the regions of Italy.", - config=graph_config -) - -result = search_graph.run() -print(result) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/search_graph_schema_gemini.py b/examples/google_vertexai/search_graph_schema_gemini.py deleted file mode 100644 index 54586c7e..00000000 --- a/examples/google_vertexai/search_graph_schema_gemini.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from dotenv import load_dotenv -load_dotenv() - -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -from pydantic import BaseModel, Field -from typing import List - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/search_link_graph_gemini.py b/examples/google_vertexai/search_link_graph_gemini.py deleted file mode 100644 index d351b843..00000000 --- a/examples/google_vertexai/search_link_graph_gemini.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/google_vertexai/smart_scraper_gemini.py b/examples/google_vertexai/smart_scraper_gemini.py deleted file mode 100644 index 4ed7c352..00000000 --- a/examples/google_vertexai/smart_scraper_gemini.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/smart_scraper_lite_google_vertexai.py b/examples/google_vertexai/smart_scraper_lite_google_vertexai.py deleted file mode 100644 index eca61bbb..00000000 --- a/examples/google_vertexai/smart_scraper_lite_google_vertexai.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "project": os.getenv("GOOGLE_CLOUD_PROJECT"), - "location": "us-central1", - "model": "text-bison@001", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/google_vertexai/smart_scraper_multi_concat_gemini.py b/examples/google_vertexai/smart_scraper_multi_concat_gemini.py deleted file mode 100644 index c6874ff6..00000000 --- a/examples/google_vertexai/smart_scraper_multi_concat_gemini.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_vertexai/smart_scraper_multi_gemini.py b/examples/google_vertexai/smart_scraper_multi_gemini.py deleted file mode 100644 index ffbd6f47..00000000 --- a/examples/google_vertexai/smart_scraper_multi_gemini.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os, json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/google_vertexai/smart_scraper_multi_lite_google_vertexai.py b/examples/google_vertexai/smart_scraper_multi_lite_google_vertexai.py deleted file mode 100644 index 5c293416..00000000 --- a/examples/google_vertexai/smart_scraper_multi_lite_google_vertexai.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "project": os.getenv("GOOGLE_CLOUD_PROJECT"), - "location": "us-central1", - "model": "text-bison@001", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/smart_scraper_multi_lite_vertex.py b/examples/google_vertexai/smart_scraper_multi_lite_vertex.py deleted file mode 100644 index 60ff3638..00000000 --- a/examples/google_vertexai/smart_scraper_multi_lite_vertex.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "project": os.getenv("GOOGLE_CLOUD_PROJECT"), - "location": "us-central1", - "model": "text-bison@001", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/smart_scraper_schema_gemini.py b/examples/google_vertexai/smart_scraper_schema_gemini.py deleted file mode 100644 index 541ce9aa..00000000 --- a/examples/google_vertexai/smart_scraper_schema_gemini.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" - -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.utils import prettify_exec_info -from scrapegraphai.graphs import SmartScraperGraph -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/google_vertexai/xml_scraper_gemini.py b/examples/google_vertexai/xml_scraper_gemini.py deleted file mode 100644 index de0e084f..00000000 --- a/examples/google_vertexai/xml_scraper_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/google_vertexai/xml_scraper_graph_multi_gemini.py b/examples/google_vertexai/xml_scraper_graph_multi_gemini.py deleted file mode 100644 index 3b7562d3..00000000 --- a/examples/google_vertexai/xml_scraper_graph_multi_gemini.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -gemini_key = os.getenv("GOOGLE_APIKEY") - -graph_config = { - "llm": { - "api_key": gemini_key, - "model": "google_vertexai/gemini-1.5-pro", - }, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/.env.example b/examples/groq/.env.example deleted file mode 100644 index c934d4fa..00000000 --- a/examples/groq/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -GROQ_APIKEY= "your groq key" -OPENAI_APIKEY="your openai api key" \ No newline at end of file diff --git a/examples/groq/code_generator_graph_groq.py b/examples/groq/code_generator_graph_groq.py deleted file mode 100644 index cf03d96c..00000000 --- a/examples/groq/code_generator_graph_groq.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/groq/csv_scraper_graph_multi_groq.py b/examples/groq/csv_scraper_graph_multi_groq.py deleted file mode 100644 index e0343f31..00000000 --- a/examples/groq/csv_scraper_graph_multi_groq.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/csv_scraper_groq.py b/examples/groq/csv_scraper_groq.py deleted file mode 100644 index 6c36b4c4..00000000 --- a/examples/groq/csv_scraper_groq.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, -} -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/custom_graph_groq.py b/examples/groq/custom_graph_groq.py deleted file mode 100644 index ea35137f..00000000 --- a/examples/groq/custom_graph_groq.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -import os -from dotenv import load_dotenv -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, GenerateAnswerNode, RobotsNode -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) - -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/groq/depth_search_graph_groq.py b/examples/groq/depth_search_graph_groq.py deleted file mode 100644 index 2d1ed8b1..00000000 --- a/examples/groq/depth_search_graph_groq.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/groq/document_scraper_groq.py b/examples/groq/document_scraper_groq.py deleted file mode 100644 index 53c64f73..00000000 --- a/examples/groq/document_scraper_groq.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/groq/inputs/books.xml b/examples/groq/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/groq/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/groq/inputs/example.json b/examples/groq/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/groq/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/groq/inputs/plain_html_example.txt b/examples/groq/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/groq/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/groq/inputs/username.csv b/examples/groq/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/groq/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/groq/json_scraper_groq.py b/examples/groq/json_scraper_groq.py deleted file mode 100644 index cac0f10d..00000000 --- a/examples/groq/json_scraper_groq.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/groq/json_scraper_multi_groq.py b/examples/groq/json_scraper_multi_groq.py deleted file mode 100644 index df3b9276..00000000 --- a/examples/groq/json_scraper_multi_groq.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "library": "beautifulsoup" -} -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/groq/rate_limit_groq.py b/examples/groq/rate_limit_groq.py deleted file mode 100644 index 8e59115f..00000000 --- a/examples/groq/rate_limit_groq.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0, - "rate_limit": { - "requests_per_second": 1 - } - }, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/scrape_plain_text_groq.py b/examples/groq/scrape_plain_text_groq.py deleted file mode 100644 index c4e4065d..00000000 --- a/examples/groq/scrape_plain_text_groq.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/script_generator_groq.py b/examples/groq/script_generator_groq.py deleted file mode 100644 index 08550044..00000000 --- a/examples/groq/script_generator_groq.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "library": "beautifulsoup" -} -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/groq/script_multi_generator_groq.py b/examples/groq/script_multi_generator_groq.py deleted file mode 100644 index 31f4041e..00000000 --- a/examples/groq/script_multi_generator_groq.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/search_graph_groq.py b/examples/groq/search_graph_groq.py deleted file mode 100644 index ec971e37..00000000 --- a/examples/groq/search_graph_groq.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/search_graph_schema_groq.py b/examples/groq/search_graph_schema_groq.py deleted file mode 100644 index ae0de3ee..00000000 --- a/examples/groq/search_graph_schema_groq.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/search_link_graph_groq.py b/examples/groq/search_link_graph_groq.py deleted file mode 100644 index 5d82f37f..00000000 --- a/examples/groq/search_link_graph_groq.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/smart_scraper_groq.py b/examples/groq/smart_scraper_groq.py deleted file mode 100644 index 4ac32678..00000000 --- a/examples/groq/smart_scraper_groq.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/smart_scraper_lite_groq.py b/examples/groq/smart_scraper_lite_groq.py deleted file mode 100644 index 5fe6022f..00000000 --- a/examples/groq/smart_scraper_lite_groq.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("GROQ_API_KEY"), - "model": "mixtral-8x7b-32768", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/smart_scraper_multi_concat_groq.py b/examples/groq/smart_scraper_multi_concat_groq.py deleted file mode 100644 index 79c262a1..00000000 --- a/examples/groq/smart_scraper_multi_concat_groq.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/groq/smart_scraper_multi_groq.py b/examples/groq/smart_scraper_multi_groq.py deleted file mode 100644 index fec8fbb5..00000000 --- a/examples/groq/smart_scraper_multi_groq.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/groq/smart_scraper_multi_lite_groq.py b/examples/groq/smart_scraper_multi_lite_groq.py deleted file mode 100644 index 9c8e4d1d..00000000 --- a/examples/groq/smart_scraper_multi_lite_groq.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("GROQ_API_KEY"), - "model": "mixtral-8x7b-32768", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/groq/smart_scraper_schema_groq.py b/examples/groq/smart_scraper_schema_groq.py deleted file mode 100644 index bfa7ed3b..00000000 --- a/examples/groq/smart_scraper_schema_groq.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/groq/xml_scraper_graph_multi_groq.py b/examples/groq/xml_scraper_graph_multi_groq.py deleted file mode 100644 index 09c7483f..00000000 --- a/examples/groq/xml_scraper_graph_multi_groq.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "headless": False -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/groq/xml_scraper_groq.py b/examples/groq/xml_scraper_groq.py deleted file mode 100644 index cb1ca8d7..00000000 --- a/examples/groq/xml_scraper_groq.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -groq_key = os.getenv("GROQ_APIKEY") - -graph_config = { - "llm": { - "model": "groq/gemma-7b-it", - "api_key": groq_key, - "temperature": 0 - }, - "verbose": True, - "headless": False -} -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/huggingfacehub/code_generator_graph_huggingfacehub.py b/examples/huggingfacehub/code_generator_graph_huggingfacehub.py deleted file mode 100644 index 4ff0d67e..00000000 --- a/examples/huggingfacehub/code_generator_graph_huggingfacehub.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": { - "model_instance": llm_model_instance - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/huggingfacehub/csv_scraper_graph_multi_huggingfacehub.py b/examples/huggingfacehub/csv_scraper_graph_multi_huggingfacehub.py deleted file mode 100644 index 48b04dab..00000000 --- a/examples/huggingfacehub/csv_scraper_graph_multi_huggingfacehub.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" - -import os -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/huggingfacehub/csv_scraper_huggingfacehub.py b/examples/huggingfacehub/csv_scraper_huggingfacehub.py deleted file mode 100644 index 18ce1194..00000000 --- a/examples/huggingfacehub/csv_scraper_huggingfacehub.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" - -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/huggingfacehub/custom_graph_huggingfacehub.py b/examples/huggingfacehub/custom_graph_huggingfacehub.py deleted file mode 100644 index 06b2f089..00000000 --- a/examples/huggingfacehub/custom_graph_huggingfacehub.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -import os -from dotenv import load_dotenv -from langchain_openai import OpenAIEmbeddings -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = OpenAI(graph_config["llm"]) -embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/huggingfacehub/depth_search_graph_huggingfacehub.py b/examples/huggingfacehub/depth_search_graph_huggingfacehub.py deleted file mode 100644 index 48df3e37..00000000 --- a/examples/huggingfacehub/depth_search_graph_huggingfacehub.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/huggingfacehub/document_scraper_huggingfacehub.py b/examples/huggingfacehub/document_scraper_huggingfacehub.py deleted file mode 100644 index 5992f077..00000000 --- a/examples/huggingfacehub/document_scraper_huggingfacehub.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -# ************************************************ -# Define the configuration for the graph -# ************************************************ -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/huggingfacehub/inputs/books.xml b/examples/huggingfacehub/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/huggingfacehub/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/huggingfacehub/inputs/example.json b/examples/huggingfacehub/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/huggingfacehub/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/huggingfacehub/inputs/plain_html_example.txt b/examples/huggingfacehub/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/huggingfacehub/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/huggingfacehub/inputs/username.csv b/examples/huggingfacehub/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/huggingfacehub/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/huggingfacehub/json_scraper_huggingfacehub.py b/examples/huggingfacehub/json_scraper_huggingfacehub.py deleted file mode 100644 index f8223711..00000000 --- a/examples/huggingfacehub/json_scraper_huggingfacehub.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/huggingfacehub/json_scraper_multi_huggingfacehub.py b/examples/huggingfacehub/json_scraper_multi_huggingfacehub.py deleted file mode 100644 index c029431e..00000000 --- a/examples/huggingfacehub/json_scraper_multi_huggingfacehub.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/huggingfacehub/scrape_plain_text_huggingfacehub.py b/examples/huggingfacehub/scrape_plain_text_huggingfacehub.py deleted file mode 100644 index 76d32cda..00000000 --- a/examples/huggingfacehub/scrape_plain_text_huggingfacehub.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/huggingfacehub/script_generator_huggingfacehub.py b/examples/huggingfacehub/script_generator_huggingfacehub.py deleted file mode 100644 index a3fcaaf4..00000000 --- a/examples/huggingfacehub/script_generator_huggingfacehub.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') -# ************************************************ -# Initialize the model instances -# ************************************************ - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/huggingfacehub/script_multi_generator_huggingfacehub.py b/examples/huggingfacehub/script_multi_generator_huggingfacehub.py deleted file mode 100644 index 0ee89189..00000000 --- a/examples/huggingfacehub/script_multi_generator_huggingfacehub.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/huggingfacehub/search_graph_huggingfacehub.py b/examples/huggingfacehub/search_graph_huggingfacehub.py deleted file mode 100644 index 7c4a0c43..00000000 --- a/examples/huggingfacehub/search_graph_huggingfacehub.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/huggingfacehub/search_link_graph_huggingfacehub.py b/examples/huggingfacehub/search_link_graph_huggingfacehub.py deleted file mode 100644 index 75b41282..00000000 --- a/examples/huggingfacehub/search_link_graph_huggingfacehub.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Example of Search Graph -""" -import os -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/huggingfacehub/smart_scraper_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_huggingfacehub.py deleted file mode 100644 index a50b574e..00000000 --- a/examples/huggingfacehub/smart_scraper_huggingfacehub.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - - -## required environment variable in .env -#HUGGINGFACEHUB_API_TOKEN -load_dotenv() - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') -# ************************************************ -# Initialize the model instances -# ************************************************ - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the events, with the following fields: company_name, event_name, event_start_date, event_start_time, event_end_date, event_end_time, location, event_mode, event_category, third_party_redirect, no_of_days, time_in_hours, hosted_or_attending, refreshments_type, registration_available, registration_link", - # also accepts a string with the already downloaded HTML code - source="https://www.hmhco.com/event", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - - diff --git a/examples/huggingfacehub/smart_scraper_lite_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_lite_huggingfacehub.py deleted file mode 100644 index 4faa8a47..00000000 --- a/examples/huggingfacehub/smart_scraper_lite_huggingfacehub.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("HUGGINGFACEHUB_API_TOKEN"), - "model": "huggingfacehub/meta-llama/Llama-2-70b-chat-hf", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/huggingfacehub/smart_scraper_multi_concat_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_multi_concat_huggingfacehub.py deleted file mode 100644 index 3f2d7135..00000000 --- a/examples/huggingfacehub/smart_scraper_multi_concat_huggingfacehub.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') -# ************************************************ -# Initialize the model instances -# ************************************************ - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/huggingfacehub/smart_scraper_multi_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_multi_huggingfacehub.py deleted file mode 100644 index 046883a2..00000000 --- a/examples/huggingfacehub/smart_scraper_multi_huggingfacehub.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os, json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/huggingfacehub/smart_scraper_multi_lite_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_multi_lite_huggingfacehub.py deleted file mode 100644 index 2d7a3a45..00000000 --- a/examples/huggingfacehub/smart_scraper_multi_lite_huggingfacehub.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("HUGGINGFACEHUB_API_TOKEN"), - "model": "huggingfacehub/meta-llama/Llama-2-70b-chat-hf", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/huggingfacehub/smart_scraper_multi_lite_uhggingfacehub.py b/examples/huggingfacehub/smart_scraper_multi_lite_uhggingfacehub.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/huggingfacehub/smart_scraper_schema_huggingfacehub.py b/examples/huggingfacehub/smart_scraper_schema_huggingfacehub.py deleted file mode 100644 index 31719697..00000000 --- a/examples/huggingfacehub/smart_scraper_schema_huggingfacehub.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper using Azure OpenAI Key -""" - -import os -from dotenv import load_dotenv -from typing import Dict - -from pydantic import BaseModel -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str - description: str - -class Projects(BaseModel): - Projects: Dict[str, Project] - -## required environment variable in .env -#HUGGINGFACEHUB_API_TOKEN -load_dotenv() - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') -# ************************************************ -# Initialize the model instances -# ************************************************ - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/huggingfacehub/xml_scraper_graph_multi_huggingfacehub.py b/examples/huggingfacehub/xml_scraper_graph_multi_huggingfacehub.py deleted file mode 100644 index 1a244b86..00000000 --- a/examples/huggingfacehub/xml_scraper_graph_multi_huggingfacehub.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" - -import os -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/huggingfacehub/xml_scraper_huggingfacehub.py b/examples/huggingfacehub/xml_scraper_huggingfacehub.py deleted file mode 100644 index ddd73b5f..00000000 --- a/examples/huggingfacehub/xml_scraper_huggingfacehub.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -from langchain_community.llms import HuggingFaceEndpoint -from langchain_community.embeddings import HuggingFaceInferenceAPIEmbeddings - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN') - -repo_id = "mistralai/Mistral-7B-Instruct-v0.2" - -llm_model_instance = HuggingFaceEndpoint( - repo_id=repo_id, max_length=128, temperature=0.5, token=HUGGINGFACEHUB_API_TOKEN -) - -embedder_model_instance = HuggingFaceInferenceAPIEmbeddings( - api_key=HUGGINGFACEHUB_API_TOKEN, model_name="sentence-transformers/all-MiniLM-l6-v2" -) - -graph_config = { - "llm": {"model_instance": llm_model_instance}, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/integrations/indexify_node_example.py b/examples/integrations/indexify_node_example.py deleted file mode 100644 index 61db52d2..00000000 --- a/examples/integrations/indexify_node_example.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" - -import os, json -from typing import List - -from dotenv import load_dotenv -load_dotenv() - -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.integrations import IndexifyNode - - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Image(BaseModel): - url: str = Field(description="The url of the image") - -class Images(BaseModel): - images: List[Image] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key":openai_key, - "model": "openai/gpt-3.5-turbo", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Define the custom nodes for the graph -# ************************************************ - -indexify_node = IndexifyNode( - input="answer & img_urls", - output=["is_indexed"], - node_config={ - "verbose": True - } -) - -# ************************************************ -# Create the SmartScraperGraph instance -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the images with their url", - source="https://giphy.com/", - schema=Images, - config=graph_config -) - -# Add the custom node to the graph -smart_scraper_graph.append_node(indexify_node) - -# ************************************************ -# Run the SmartScraperGraph -# ************************************************ - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=2)) diff --git a/examples/local_models/code_generator_graph_ollama.py b/examples/local_models/code_generator_graph_ollama.py deleted file mode 100644 index 46ab8ab3..00000000 --- a/examples/local_models/code_generator_graph_ollama.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", - "base_url": "http://localhost:11434", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/local_models/csv_scraper_graph_multi_ollama.py b/examples/local_models/csv_scraper_graph_multi_ollama.py deleted file mode 100644 index fb6bce51..00000000 --- a/examples/local_models/csv_scraper_graph_multi_ollama.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" - -import os -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", - }, - "verbose": True, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/csv_scraper_ollama.py b/examples/local_models/csv_scraper_ollama.py deleted file mode 100644 index 8d1edbd7..00000000 --- a/examples/local_models/csv_scraper_ollama.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" - -import os -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "embeddings": { - "model": "ollama/nomic-embed-text", - "temperature": 0, - "base_url": "http://localhost:11434", - }, - "verbose": True, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/custom_graph_ollama.py b/examples/local_models/custom_graph_ollama.py deleted file mode 100644 index c505d068..00000000 --- a/examples/local_models/custom_graph_ollama.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -import os -from langchain_openai import OpenAIEmbeddings -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - - "verbose": True, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) -embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) - -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/local_models/depth_search_graph_ollama.py b/examples/local_models/depth_search_graph_ollama.py deleted file mode 100644 index d0f960b5..00000000 --- a/examples/local_models/depth_search_graph_ollama.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/local_models/document_scraper_ollama.py b/examples/local_models/document_scraper_ollama.py deleted file mode 100644 index 6853a549..00000000 --- a/examples/local_models/document_scraper_ollama.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -document_scraper example -""" -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - "model_tokens": 4000, - }, - "verbose": True, - "headless": False, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) diff --git a/examples/local_models/inputs/books.xml b/examples/local_models/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/local_models/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/local_models/inputs/example.json b/examples/local_models/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/local_models/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/local_models/inputs/plain_html_example.txt b/examples/local_models/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/local_models/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/local_models/inputs/username.csv b/examples/local_models/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/local_models/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/local_models/json_scraper_multi_ollama.py b/examples/local_models/json_scraper_multi_ollama.py deleted file mode 100644 index e80bf5ec..00000000 --- a/examples/local_models/json_scraper_multi_ollama.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from scrapegraphai.graphs import JSONScraperMultiGraph - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - "model_tokens": 4000, - }, - "verbose": True, - "headless": False, -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/local_models/json_scraper_ollama.py b/examples/local_models/json_scraper_ollama.py deleted file mode 100644 index ca4eb32e..00000000 --- a/examples/local_models/json_scraper_ollama.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "verbose": True, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/package-lock.json b/examples/local_models/package-lock.json deleted file mode 100644 index 4159e5cf..00000000 --- a/examples/local_models/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "local_models", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/examples/local_models/package.json b/examples/local_models/package.json deleted file mode 100644 index 0967ef42..00000000 --- a/examples/local_models/package.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/local_models/scrape_plain_text_ollama.py b/examples/local_models/scrape_plain_text_ollama.py deleted file mode 100644 index fe24c2a9..00000000 --- a/examples/local_models/scrape_plain_text_ollama.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" - -import os -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/local_models/script_generator_ollama.py b/examples/local_models/script_generator_ollama.py deleted file mode 100644 index caa0455c..00000000 --- a/examples/local_models/script_generator_ollama.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0.5, - # "model_tokens": 2000, # set context length arbitrarily, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "library": "beautifoulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -smart_scraper_graph = ScriptCreatorGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/local_models/script_multi_generator_ollama.py b/examples/local_models/script_multi_generator_ollama.py deleted file mode 100644 index d94faba6..00000000 --- a/examples/local_models/script_multi_generator_ollama.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - # "model_tokens": 2000, # set context length arbitrarily, - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "library": "beautifoulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/local_models/search_graph_ollama.py b/examples/local_models/search_graph_ollama.py deleted file mode 100644 index 039ca00e..00000000 --- a/examples/local_models/search_graph_ollama.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - # "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "max_results": 5, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/search_graph_schema_ollama.py b/examples/local_models/search_graph_schema_ollama.py deleted file mode 100644 index fb87954f..00000000 --- a/examples/local_models/search_graph_schema_ollama.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -from pydantic import BaseModel, Field -from typing import List - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/mistral", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/search_link_graph_ollama.py b/examples/local_models/search_link_graph_ollama.py deleted file mode 100644 index 885b65e9..00000000 --- a/examples/local_models/search_link_graph_ollama.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from scrapegraphai.graphs import SearchLinkGraph -from scrapegraphai.utils import prettify_exec_info -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3.1:8b", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - - "verbose": True, - "headless": False, - "filter_config": { - "diff_domain_filter": True, - # "img_exts": ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp', '.ico'], - # "lang_indicators": ['lang=', '/fr', '/pt', '/es', '/de', '/jp', '/it'], - # "irrelevant_keywords": [ - # '/login', '/signup', '/register', '/contact', 'facebook.com', 'twitter.com', - # 'linkedin.com', 'instagram.com', '.js', '.css', '/wp-content/', '/wp-admin/', - # '/wp-includes/', '/wp-json/', '/wp-comments-post.php', ';amp', '/about', - # '/careers', '/jobs', '/privacy', '/terms', '/legal', '/faq', '/help', - # '.pdf', '.zip', '/news', '/files', '/downloads' - # ] - }, -} - -# ************************************************ -# Create the SearchLinkGraph instance and run it -# ************************************************ - -smart_scraper_graph = SearchLinkGraph( - source="https://sport.sky.it/nba?gr=www", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/local_models/smart_scraper_lite_ollama.py b/examples/local_models/smart_scraper_lite_ollama.py deleted file mode 100644 index 2cf6c402..00000000 --- a/examples/local_models/smart_scraper_lite_ollama.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper - -""" -import json -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", - "base_url": "http://localhost:11434", - }, - "verbose": True, - "headless": False -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/local_models/smart_scraper_multi_concat_ollama.py b/examples/local_models/smart_scraper_multi_concat_ollama.py deleted file mode 100644 index 665b5db4..00000000 --- a/examples/local_models/smart_scraper_multi_concat_ollama.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "verbose": True, - "headless": False -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/local_models/smart_scraper_multi_lite_ollama.py b/examples/local_models/smart_scraper_multi_lite_ollama.py deleted file mode 100644 index f09c4cb4..00000000 --- a/examples/local_models/smart_scraper_multi_lite_ollama.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import json -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/local_models/smart_scraper_multi_ollama.py b/examples/local_models/smart_scraper_multi_ollama.py deleted file mode 100644 index c9d49793..00000000 --- a/examples/local_models/smart_scraper_multi_ollama.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import json -from scrapegraphai.graphs import SmartScraperMultiGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - - "verbose": True, - "headless": False -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/local_models/smart_scraper_schema_ollama.py b/examples/local_models/smart_scraper_schema_ollama.py deleted file mode 100644 index 5a5b3cea..00000000 --- a/examples/local_models/smart_scraper_schema_ollama.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import json -from typing import List -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -graph_config = { - "llm": { - "model": "ollama/llama3.1", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - }, - "verbose": True, - "headless": False -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/local_models/xml_scraper_graph_multi_ollama.py b/examples/local_models/xml_scraper_graph_multi_ollama.py deleted file mode 100644 index 0494ff2c..00000000 --- a/examples/local_models/xml_scraper_graph_multi_ollama.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" - -import os -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - - "verbose": True, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/local_models/xml_scraper_ollama.py b/examples/local_models/xml_scraper_ollama.py deleted file mode 100644 index 50c4f8e7..00000000 --- a/examples/local_models/xml_scraper_ollama.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "ollama/llama3", - "temperature": 0, - # "model_tokens": 2000, # set context length arbitrarily - "base_url": "http://localhost:11434", - }, - "verbose": True, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/.env.example b/examples/mistral/.env.example deleted file mode 100644 index cca63d1d..00000000 --- a/examples/mistral/.env.example +++ /dev/null @@ -1 +0,0 @@ -MISTRAL_API_KEY="YOUR MISTRAL API KEY" diff --git a/examples/mistral/code_generator_graph_mistral.py b/examples/mistral/code_generator_graph_mistral.py deleted file mode 100644 index 19af9aef..00000000 --- a/examples/mistral/code_generator_graph_mistral.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/mistral/csv_scraper_graph_multi_mistral.py b/examples/mistral/csv_scraper_graph_multi_mistral.py deleted file mode 100644 index 608a8851..00000000 --- a/examples/mistral/csv_scraper_graph_multi_mistral.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/csv_scraper_mistral.py b/examples/mistral/csv_scraper_mistral.py deleted file mode 100644 index 6daa216c..00000000 --- a/examples/mistral/csv_scraper_mistral.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/custom_graph_mistral.py b/examples/mistral/custom_graph_mistral.py deleted file mode 100644 index bac1cd30..00000000 --- a/examples/mistral/custom_graph_mistral.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -import os -from dotenv import load_dotenv -from langchain_mistralai import ChatMistralAI, MistralAIEmbeddings -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatMistralAI(**graph_config["llm"]) -embedder = MistralAIEmbeddings(api_key=llm_model.mistral_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/mistral/depth_search_graph_mistral.py b/examples/mistral/depth_search_graph_mistral.py deleted file mode 100644 index ae18ffba..00000000 --- a/examples/mistral/depth_search_graph_mistral.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/mistral/document_scraper_mistral.py b/examples/mistral/document_scraper_mistral.py deleted file mode 100644 index aa75e9c4..00000000 --- a/examples/mistral/document_scraper_mistral.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/inputs/books.xml b/examples/mistral/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/mistral/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/mistral/inputs/example.json b/examples/mistral/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/mistral/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/mistral/inputs/markdown_example.md b/examples/mistral/inputs/markdown_example.md deleted file mode 100644 index 85088f29..00000000 --- a/examples/mistral/inputs/markdown_example.md +++ /dev/null @@ -1,35 +0,0 @@ -Marco Perini Toggle navigation - - * About - * Projects(current) - -Projects - -Competitions - - * CV - * ____ - -# Projects - - ![project thumbnail Rotary Pendulum RL -Open Source project aimed at controlling a real life rotary pendulum using RL -algorithms ](/projects/rotary-pendulum-rl/) - - ![project thumbnail DQN -Implementation from scratch Developed a Deep Q-Network algorithm to train a -simple and double pendulum ](https://github.com/PeriniM/DQN-SwingUp) - - ![project thumbnail Multi Agents HAED -University project which focuses on simulating a multi-agent system to perform -environment mapping. Agents, equipped with sensors, explore and record their -surroundings, considering uncertainties in their readings. -](https://github.com/PeriniM/Multi-Agents-HAED) - - ![project thumbnail Wireless ESC for Modular -Drones Modular drone architecture proposal and proof of concept. The project -received maximum grade. ](/projects/wireless-esc-drone/) - -© Copyright 2023 Marco Perini. Powered by Jekyll with -al-folio theme. Hosted by [GitHub -Pages](https://pages.github.com/). \ No newline at end of file diff --git a/examples/mistral/inputs/plain_html_example.txt b/examples/mistral/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/mistral/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/mistral/inputs/username.csv b/examples/mistral/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/mistral/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/mistral/json_scraper_mistral.py b/examples/mistral/json_scraper_mistral.py deleted file mode 100644 index 0b9be3ec..00000000 --- a/examples/mistral/json_scraper_mistral.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) diff --git a/examples/mistral/json_scraper_multi_mistral.py b/examples/mistral/json_scraper_multi_mistral.py deleted file mode 100644 index 1369eda7..00000000 --- a/examples/mistral/json_scraper_multi_mistral.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - } -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/md_scraper_mistral.py b/examples/mistral/md_scraper_mistral.py deleted file mode 100644 index 135f08ba..00000000 --- a/examples/mistral/md_scraper_mistral.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using DocumentScraperGraph from MD documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the MD file -# ************************************************ - -FILE_NAME = "inputs/markdown_example.md" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Create the DocumentScraperGraph instance and run it -# ************************************************ - -md_scraper_graph = DocumentScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = md_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = md_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/rate_limit_mistral.py b/examples/mistral/rate_limit_mistral.py deleted file mode 100644 index 4bc0f6fb..00000000 --- a/examples/mistral/rate_limit_mistral.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -import json -from scrapegraphai.graphs import SmartScraperGraph -from dotenv import load_dotenv - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("MISTRAL_API_KEY"), - "model": "mistralai/open-mistral-nemo", - "rate_limit": { - "requests_per_second": 1 - } - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/readme.md b/examples/mistral/readme.md deleted file mode 100644 index 6e13a97b..00000000 --- a/examples/mistral/readme.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains examples of how to use ScrapeGraph-AI with Mistral, an LLM provider. The examples show how to extract information from a website using a natural language prompt. \ No newline at end of file diff --git a/examples/mistral/scrape_plain_text_mistral.py b/examples/mistral/scrape_plain_text_mistral.py deleted file mode 100644 index 131747c6..00000000 --- a/examples/mistral/scrape_plain_text_mistral.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/mistral/script_generator_mistral.py b/examples/mistral/script_generator_mistral.py deleted file mode 100644 index 74a81b46..00000000 --- a/examples/mistral/script_generator_mistral.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/mistral/script_generator_schema_mistral.py b/examples/mistral/script_generator_schema_mistral.py deleted file mode 100644 index 3ad46685..00000000 --- a/examples/mistral/script_generator_schema_mistral.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info -from pydantic import BaseModel, Field -from typing import List - -load_dotenv() - -# ************************************************ -# Define the schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config, - schema=Projects -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/mistral/script_multi_generator_mistral.py b/examples/mistral/script_multi_generator_mistral.py deleted file mode 100644 index d5869c53..00000000 --- a/examples/mistral/script_multi_generator_mistral.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/mistral/search_graph_mistral.py b/examples/mistral/search_graph_mistral.py deleted file mode 100644 index 983733e0..00000000 --- a/examples/mistral/search_graph_mistral.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/mistral/search_graph_schema_mistral.py b/examples/mistral/search_graph_schema_mistral.py deleted file mode 100644 index 06a88ff7..00000000 --- a/examples/mistral/search_graph_schema_mistral.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/search_link_graph_mistral.py b/examples/mistral/search_link_graph_mistral.py deleted file mode 100644 index 45d0c5f0..00000000 --- a/examples/mistral/search_link_graph_mistral.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchLinkGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SearchLinkGraph instance and run it -# ************************************************ - -smart_scraper_graph = SearchLinkGraph( - source="https://sport.sky.it/nba?gr=www", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/mistral/smart_scraper_lite_mistral.py b/examples/mistral/smart_scraper_lite_mistral.py deleted file mode 100644 index 390371f9..00000000 --- a/examples/mistral/smart_scraper_lite_mistral.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("MISTRAL_API_KEY"), - "model": "mistral/mistral-medium", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/mistral/smart_scraper_mistral.py b/examples/mistral/smart_scraper_mistral.py deleted file mode 100644 index a2f82504..00000000 --- a/examples/mistral/smart_scraper_mistral.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("MISTRAL_API_KEY"), - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/smart_scraper_multi_concat_mistral.py b/examples/mistral/smart_scraper_multi_concat_mistral.py deleted file mode 100644 index 9cef8a16..00000000 --- a/examples/mistral/smart_scraper_multi_concat_mistral.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -graph_config = { - "llm": { - "api_key": os.getenv("MISTRAL_API_KEY"), - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/smart_scraper_multi_lite_mistral.py b/examples/mistral/smart_scraper_multi_lite_mistral.py deleted file mode 100644 index ce2d19bf..00000000 --- a/examples/mistral/smart_scraper_multi_lite_mistral.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("MISTRAL_API_KEY"), - "model": "mistral/mistral-medium", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/mistral/smart_scraper_multi_mistral.py b/examples/mistral/smart_scraper_multi_mistral.py deleted file mode 100644 index 7929f9cc..00000000 --- a/examples/mistral/smart_scraper_multi_mistral.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/mistral/smart_scraper_schema_mistral.py b/examples/mistral/smart_scraper_schema_mistral.py deleted file mode 100644 index 3b129a89..00000000 --- a/examples/mistral/smart_scraper_schema_mistral.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key":mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) diff --git a/examples/mistral/xml_scraper_graph_multi_mistral.py b/examples/mistral/xml_scraper_graph_multi_mistral.py deleted file mode 100644 index 6db20ebf..00000000 --- a/examples/mistral/xml_scraper_graph_multi_mistral.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key":mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/mistral/xml_scraper_mistral.py b/examples/mistral/xml_scraper_mistral.py deleted file mode 100644 index 6d551c22..00000000 --- a/examples/mistral/xml_scraper_mistral.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, - "verbose":False, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/model_instance/.env.example b/examples/model_instance/.env.example deleted file mode 100644 index c5a7ed85..00000000 --- a/examples/model_instance/.env.example +++ /dev/null @@ -1 +0,0 @@ -MOONLIGHT_API_KEY="YOUR MOONLIGHT API KEY" \ No newline at end of file diff --git a/examples/model_instance/smart_scraper_with_model_instace.py b/examples/model_instance/smart_scraper_with_model_instace.py deleted file mode 100644 index b362414f..00000000 --- a/examples/model_instance/smart_scraper_with_model_instace.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper and model_instace -""" - -import os, json -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info -from langchain_community.chat_models.moonshot import MoonshotChat -from dotenv import load_dotenv -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -llm_instance_config = { - "model": "moonshot-v1-8k", - "base_url": "https://api.moonshot.cn/v1", - "moonshot_api_key": os.getenv("MOONLIGHT_API_KEY"), -} - - -llm_model_instance = MoonshotChat(**llm_instance_config) - -graph_config = { - "llm": { - "model_instance": llm_model_instance, - "model_tokens": 10000 - }, - "verbose": True, - "headless": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/moonshot/.env.example b/examples/moonshot/.env.example deleted file mode 100644 index c5a7ed85..00000000 --- a/examples/moonshot/.env.example +++ /dev/null @@ -1 +0,0 @@ -MOONLIGHT_API_KEY="YOUR MOONLIGHT API KEY" \ No newline at end of file diff --git a/examples/moonshot/code_generator_graph_moonshot.py b/examples/moonshot/code_generator_graph_moonshot.py deleted file mode 100644 index 58e6182b..00000000 --- a/examples/moonshot/code_generator_graph_moonshot.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from langchain_community.chat_models.moonshot import MoonshotChat -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -llm_instance_config = { - "model": "moonshot-v1-8k", - "base_url": "https://api.moonshot.cn/v1", - "moonshot_api_key": os.getenv("MOONLIGHT_API_KEY"), -} - -llm_model_instance = MoonshotChat(**llm_instance_config) - -graph_config = { - "llm": { - "model_instance": llm_model_instance, - "model_tokens": 10000 - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/moonshot/document_scraper_moonshot.py b/examples/moonshot/document_scraper_moonshot.py deleted file mode 100644 index aa75e9c4..00000000 --- a/examples/moonshot/document_scraper_moonshot.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -mistral_key = os.getenv("MISTRAL_API_KEY") - -graph_config = { - "llm": { - "api_key": mistral_key, - "model": "mistralai/open-mistral-nemo", - }, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) diff --git a/examples/moonshot/readme.md b/examples/moonshot/readme.md deleted file mode 100644 index 6b9b2f21..00000000 --- a/examples/moonshot/readme.md +++ /dev/null @@ -1 +0,0 @@ -This folder offer an example of how to use ScrapeGraph-AI with Moonshot and SmartScraperGraph. More usage examples can refer to openai exapmles. \ No newline at end of file diff --git a/examples/moonshot/smart_scraper_lite_moonshot.py b/examples/moonshot/smart_scraper_lite_moonshot.py deleted file mode 100644 index 509027fb..00000000 --- a/examples/moonshot/smart_scraper_lite_moonshot.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/moonshot/smart_scraper_multi_concat_moonshot.py b/examples/moonshot/smart_scraper_multi_concat_moonshot.py deleted file mode 100644 index 1e652db4..00000000 --- a/examples/moonshot/smart_scraper_multi_concat_moonshot.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from langchain_community.chat_models.moonshot import MoonshotChat -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -llm_instance_config = { - "model": "moonshot-v1-8k", - "base_url": "https://api.moonshot.cn/v1", - "moonshot_api_key": os.getenv("MOONLIGHT_API_KEY"), -} - - -llm_model_instance = MoonshotChat(**llm_instance_config) - -graph_config = { - "llm": { - "model_instance": llm_model_instance, - "model_tokens": 10000 - }, - "verbose": True, - "headless": True, -} - - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/moonshot/smart_scraper_multi_lite_moonshot.py b/examples/moonshot/smart_scraper_multi_lite_moonshot.py deleted file mode 100644 index b3e2b7be..00000000 --- a/examples/moonshot/smart_scraper_multi_lite_moonshot.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("MOONSHOT_API_KEY"), - "model": "moonshot/moonshot-v1-8b", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/moonshot/smart_scraper_with_moonshot.py b/examples/moonshot/smart_scraper_with_moonshot.py deleted file mode 100644 index 28635ba3..00000000 --- a/examples/moonshot/smart_scraper_with_moonshot.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper and model_instace -""" -import os -import json -from langchain_community.chat_models.moonshot import MoonshotChat -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -llm_instance_config = { - "model": "moonshot-v1-8k", - "base_url": "https://api.moonshot.cn/v1", - "moonshot_api_key": os.getenv("MOONLIGHT_API_KEY"), -} - - -llm_model_instance = MoonshotChat(**llm_instance_config) - -graph_config = { - "llm": { - "model_instance": llm_model_instance, - "model_tokens": 10000 - }, - "verbose": True, - "headless": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/code_generator_graph_nemotron.py b/examples/nemotron/code_generator_graph_nemotron.py deleted file mode 100644 index 5ccd9d9f..00000000 --- a/examples/nemotron/code_generator_graph_nemotron.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_APIKEY"), - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/nemotron/csv_scraper_graph_multi_nemotron.py b/examples/nemotron/csv_scraper_graph_multi_nemotron.py deleted file mode 100644 index d5de6039..00000000 --- a/examples/nemotron/csv_scraper_graph_multi_nemotron.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -import pandas as pd -from dotenv import load_dotenv -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_APIKEY"), - "model": "nvidia/meta/llama3-70b-instruct", - } -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/csv_scraper_nemotron.py b/examples/nemotron/csv_scraper_nemotron.py deleted file mode 100644 index 2d527450..00000000 --- a/examples/nemotron/csv_scraper_nemotron.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/depth_search_graph_nemotron.py b/examples/nemotron/depth_search_graph_nemotron.py deleted file mode 100644 index edd80463..00000000 --- a/examples/nemotron/depth_search_graph_nemotron.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_KEY"), - "model": "claude-3-haiku-20240307", - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/nemotron/document_scraper_nemotron.py b/examples/nemotron/document_scraper_nemotron.py deleted file mode 100644 index 618047ee..00000000 --- a/examples/nemotron/document_scraper_nemotron.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/nemotron/inputs/books.xml b/examples/nemotron/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/nemotron/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/nemotron/inputs/example.json b/examples/nemotron/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/nemotron/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/nemotron/inputs/markdown_example.md b/examples/nemotron/inputs/markdown_example.md deleted file mode 100644 index 85088f29..00000000 --- a/examples/nemotron/inputs/markdown_example.md +++ /dev/null @@ -1,35 +0,0 @@ -Marco Perini Toggle navigation - - * About - * Projects(current) - -Projects - -Competitions - - * CV - * ____ - -# Projects - - ![project thumbnail Rotary Pendulum RL -Open Source project aimed at controlling a real life rotary pendulum using RL -algorithms ](/projects/rotary-pendulum-rl/) - - ![project thumbnail DQN -Implementation from scratch Developed a Deep Q-Network algorithm to train a -simple and double pendulum ](https://github.com/PeriniM/DQN-SwingUp) - - ![project thumbnail Multi Agents HAED -University project which focuses on simulating a multi-agent system to perform -environment mapping. Agents, equipped with sensors, explore and record their -surroundings, considering uncertainties in their readings. -](https://github.com/PeriniM/Multi-Agents-HAED) - - ![project thumbnail Wireless ESC for Modular -Drones Modular drone architecture proposal and proof of concept. The project -received maximum grade. ](/projects/wireless-esc-drone/) - -© Copyright 2023 Marco Perini. Powered by Jekyll with -al-folio theme. Hosted by [GitHub -Pages](https://pages.github.com/). \ No newline at end of file diff --git a/examples/nemotron/inputs/plain_html_example.txt b/examples/nemotron/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/nemotron/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/nemotron/inputs/username.csv b/examples/nemotron/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/nemotron/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/nemotron/json_scraper_multi_nemotron.py b/examples/nemotron/json_scraper_multi_nemotron.py deleted file mode 100644 index 846c7f48..00000000 --- a/examples/nemotron/json_scraper_multi_nemotron.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/nemotron/json_scraper_nemotron.py b/examples/nemotron/json_scraper_nemotron.py deleted file mode 100644 index a5479ca7..00000000 --- a/examples/nemotron/json_scraper_nemotron.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/md_scraper_nemotron.py b/examples/nemotron/md_scraper_nemotron.py deleted file mode 100644 index 8e925c03..00000000 --- a/examples/nemotron/md_scraper_nemotron.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using DocumentScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/markdown_example.md" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -# ************************************************ -# Create the DocumentScraperGraph instance and run it -# ************************************************ - -md_scraper_graph = DocumentScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = md_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = md_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/rate_limit_nemotron.py b/examples/nemotron/rate_limit_nemotron.py deleted file mode 100644 index 934c2036..00000000 --- a/examples/nemotron/rate_limit_nemotron.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_KEY"), - "model": "nvidia/meta/llama3-70b-instruct", - "rate_limit": { - "requests_per_second": 1 - } - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="Extract me the python code inside the page", - source="https://www.exploit-db.com/exploits/51447", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/scrape_plain_text_nemotron.py b/examples/nemotron/scrape_plain_text_nemotron.py deleted file mode 100644 index 315bae8e..00000000 --- a/examples/nemotron/scrape_plain_text_nemotron.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/script_generator_nemotron.py b/examples/nemotron/script_generator_nemotron.py deleted file mode 100644 index 2ff8176a..00000000 --- a/examples/nemotron/script_generator_nemotron.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/script_generator_schema_nemotron.py b/examples/nemotron/script_generator_schema_nemotron.py deleted file mode 100644 index 9516521a..00000000 --- a/examples/nemotron/script_generator_schema_nemotron.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from typing import List -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config, - schema=Projects -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/script_multi_generator_nemotron.py b/examples/nemotron/script_multi_generator_nemotron.py deleted file mode 100644 index 730fab8d..00000000 --- a/examples/nemotron/script_multi_generator_nemotron.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/search_graph_nemotron.py b/examples/nemotron/search_graph_nemotron.py deleted file mode 100644 index e57e9642..00000000 --- a/examples/nemotron/search_graph_nemotron.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/nemotron/search_graph_schema_nemotron.py b/examples/nemotron/search_graph_schema_nemotron.py deleted file mode 100644 index 64fbf047..00000000 --- a/examples/nemotron/search_graph_schema_nemotron.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/search_link_graph_nemotron.py b/examples/nemotron/search_link_graph_nemotron.py deleted file mode 100644 index 50dce11b..00000000 --- a/examples/nemotron/search_link_graph_nemotron.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchLinkGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_APIKEY"), - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SearchLinkGraph instance and run it -# ************************************************ - -smart_scraper_graph = SearchLinkGraph( - source="https://sport.sky.it/nba?gr=www", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/smart_scraper_lite_nemotron.py b/examples/nemotron/smart_scraper_lite_nemotron.py deleted file mode 100644 index 6c1d8528..00000000 --- a/examples/nemotron/smart_scraper_lite_nemotron.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_API_KEY"), - "model": "nemotron/nemotron-3.5-turbo", - "base_url": "http://127.0.0.1:3000/v1", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/smart_scraper_multi_concat_nemotron.py b/examples/nemotron/smart_scraper_multi_concat_nemotron.py deleted file mode 100644 index 3297fcbf..00000000 --- a/examples/nemotron/smart_scraper_multi_concat_nemotron.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_APIKEY"), - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/nemotron/smart_scraper_multi_lite_nemotron.py b/examples/nemotron/smart_scraper_multi_lite_nemotron.py deleted file mode 100644 index 7639d820..00000000 --- a/examples/nemotron/smart_scraper_multi_lite_nemotron.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_API_KEY"), - "model": "nemotron/nemotron-3-8b-chat", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/smart_scraper_multi_nemotron.py b/examples/nemotron/smart_scraper_multi_nemotron.py deleted file mode 100644 index 00306a96..00000000 --- a/examples/nemotron/smart_scraper_multi_nemotron.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/nemotron/smart_scraper_nemotron.py b/examples/nemotron/smart_scraper_nemotron.py deleted file mode 100644 index 10ad42b7..00000000 --- a/examples/nemotron/smart_scraper_nemotron.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("NEMOTRON_KEY"), - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="Extract me the python code inside the page", - source="https://www.exploit-db.com/exploits/51447", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/smart_scraper_schema_nemotron.py b/examples/nemotron/smart_scraper_schema_nemotron.py deleted file mode 100644 index 54dbce1f..00000000 --- a/examples/nemotron/smart_scraper_schema_nemotron.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key":nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) diff --git a/examples/nemotron/speech_graph_nemotron.py b/examples/nemotron/speech_graph_nemotron.py deleted file mode 100644 index 21f0d2b1..00000000 --- a/examples/nemotron/speech_graph_nemotron.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using SpeechSummaryGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SpeechGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define audio output path -# ************************************************ - -FILE_NAME = "website_summary.mp3" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -output_path = os.path.join(curr_dir, FILE_NAME) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, -} - -# ************************************************ -# Create the SpeechGraph instance and run it -# ************************************************ - -speech_graph = SpeechGraph( - prompt="Make a detailed audio summary of the projects.", - source="https://perinim.github.io/projects/", - config=graph_config, -) - -result = speech_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = speech_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/nemotron/xml_scraper_graph_nemotron.py b/examples/nemotron/xml_scraper_graph_nemotron.py deleted file mode 100644 index 753b0be5..00000000 --- a/examples/nemotron/xml_scraper_graph_nemotron.py +++ /dev/null @@ -1,60 +0,0 @@ -""" - -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key":nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/nemotron/xml_scraper_nemotron.py b/examples/nemotron/xml_scraper_nemotron.py deleted file mode 100644 index 5f7cb7d6..00000000 --- a/examples/nemotron/xml_scraper_nemotron.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -nemotron_key = os.getenv("NEMOTRON_APIKEY") - -graph_config = { - "llm": { - "api_key": nemotron_key, - "model": "nvidia/meta/llama3-70b-instruct", - }, - "verbose":False, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") - diff --git a/examples/oneapi/code_generator_graph_oneapi.py b/examples/oneapi/code_generator_graph_oneapi.py deleted file mode 100644 index 5f9808a3..00000000 --- a/examples/oneapi/code_generator_graph_oneapi.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) \ No newline at end of file diff --git a/examples/oneapi/csv_scraper_graph_multi_oneapi.py b/examples/oneapi/csv_scraper_graph_multi_oneapi.py deleted file mode 100644 index 7b5d8abd..00000000 --- a/examples/oneapi/csv_scraper_graph_multi_oneapi.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/oneapi/csv_scraper_oneapi.py b/examples/oneapi/csv_scraper_oneapi.py deleted file mode 100644 index a9fda090..00000000 --- a/examples/oneapi/csv_scraper_oneapi.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/oneapi/custom_graph_oneapi.py b/examples/oneapi/custom_graph_oneapi.py deleted file mode 100644 index 1e27dcf9..00000000 --- a/examples/oneapi/custom_graph_oneapi.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -from langchain_openai import OpenAIEmbeddings -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) -embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/oneapi/depth_search_graph_onenapi.py b/examples/oneapi/depth_search_graph_onenapi.py deleted file mode 100644 index 7a2e7f3e..00000000 --- a/examples/oneapi/depth_search_graph_onenapi.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/oneapi/document_scraper_oneapi.py b/examples/oneapi/document_scraper_oneapi.py deleted file mode 100644 index 99ffe295..00000000 --- a/examples/oneapi/document_scraper_oneapi.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -document_scraper example -""" -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/oneapi/inputs/books.xml b/examples/oneapi/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/oneapi/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/oneapi/inputs/example.json b/examples/oneapi/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/oneapi/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/oneapi/inputs/plain_html_example copy.txt b/examples/oneapi/inputs/plain_html_example copy.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/oneapi/inputs/plain_html_example copy.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/oneapi/inputs/plain_html_example.txt b/examples/oneapi/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/oneapi/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/oneapi/inputs/username.csv b/examples/oneapi/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/oneapi/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/oneapi/json_scraper_multi_oneapi.py b/examples/oneapi/json_scraper_multi_oneapi.py deleted file mode 100644 index fc1c4555..00000000 --- a/examples/oneapi/json_scraper_multi_oneapi.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from scrapegraphai.graphs import JSONScraperMultiGraph - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/oneapi/json_scraper_oneapi.py b/examples/oneapi/json_scraper_oneapi.py deleted file mode 100644 index 2f89fc50..00000000 --- a/examples/oneapi/json_scraper_oneapi.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/oneapi/rate_limit_oneapi.py b/examples/oneapi/rate_limit_oneapi.py deleted file mode 100644 index abd2f9c7..00000000 --- a/examples/oneapi/rate_limit_oneapi.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - "rate_limit": { - "requests_per_second": 1 - } - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the titles", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/scrape_plain_text_oneapi.py b/examples/oneapi/scrape_plain_text_oneapi.py deleted file mode 100644 index 268d2b0d..00000000 --- a/examples/oneapi/scrape_plain_text_oneapi.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/script_generator_oneapi.py b/examples/oneapi/script_generator_oneapi.py deleted file mode 100644 index 3876eb34..00000000 --- a/examples/oneapi/script_generator_oneapi.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/oneapi/script_multi_generator_oneapi.py b/examples/oneapi/script_multi_generator_oneapi.py deleted file mode 100644 index 42328744..00000000 --- a/examples/oneapi/script_multi_generator_oneapi.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/search_graph_oneapi.py b/examples/oneapi/search_graph_oneapi.py deleted file mode 100644 index b25cbfa6..00000000 --- a/examples/oneapi/search_graph_oneapi.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/oneapi/search_graph_schema_oneapi.py b/examples/oneapi/search_graph_schema_oneapi.py deleted file mode 100644 index 7fc44539..00000000 --- a/examples/oneapi/search_graph_schema_oneapi.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Example of Search Graph -""" -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -from pydantic import BaseModel, Field -from typing import List - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/oneapi/smart_scraper_lite_oneapi.py b/examples/oneapi/smart_scraper_lite_oneapi.py deleted file mode 100644 index b271acb3..00000000 --- a/examples/oneapi/smart_scraper_lite_oneapi.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("ONEAPI_API_KEY"), - "model": "oneapi/gpt-3.5-turbo", - "base_url": "http://127.0.0.1:3000/v1", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/smart_scraper_multi_concat_oneapi.py b/examples/oneapi/smart_scraper_multi_concat_oneapi.py deleted file mode 100644 index bbadbcfd..00000000 --- a/examples/oneapi/smart_scraper_multi_concat_oneapi.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import json -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/oneapi/smart_scraper_multi_lite_oneapi.py b/examples/oneapi/smart_scraper_multi_lite_oneapi.py deleted file mode 100644 index 8cf66dea..00000000 --- a/examples/oneapi/smart_scraper_multi_lite_oneapi.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/smart_scraper_multi_oneapi.py b/examples/oneapi/smart_scraper_multi_oneapi.py deleted file mode 100644 index 37b7b6e8..00000000 --- a/examples/oneapi/smart_scraper_multi_oneapi.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" - -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/oneapi/smart_scraper_oneapi.py b/examples/oneapi/smart_scraper_oneapi.py deleted file mode 100644 index 30b12aa3..00000000 --- a/examples/oneapi/smart_scraper_oneapi.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the titles", - # also accepts a string with the already downloaded HTML code - source="https://www.wired.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/oneapi/smart_scraper_schema_oneapi.py b/examples/oneapi/smart_scraper_schema_oneapi.py deleted file mode 100644 index 0c011bb6..00000000 --- a/examples/oneapi/smart_scraper_schema_oneapi.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper and OneAPI -""" -from typing import List -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ********************************************* - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config, - schema=Projects -) - -# ************************************************ -# Get graph execution info -# ************************************************ -result = smart_scraper_graph.run() -print(result) -print(prettify_exec_info(result)) diff --git a/examples/oneapi/smartscraper_oneapi.py b/examples/oneapi/smartscraper_oneapi.py deleted file mode 100644 index f0783782..00000000 --- a/examples/oneapi/smartscraper_oneapi.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ********************************************* - -graph_config = { - "llm": { - "api_key": "***************************", - "model": "oneapi/qwen-turbo", - "base_url": "http://127.0.0.1:3000/v1", # 设置 OneAPI URL - } -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="该网站为XXXXX,请提取出标题、发布时间、发布来源以及内容摘要,并以中文回答。", - # 也可以使用已下载的 HTML 代码的字符串 - source="http://XXXX", - config=graph_config -) - -# ************************************************ -# Get graph execution info -# ************************************************ -result = smart_scraper_graph.run() -print(result) -print(prettify_exec_info(result)) diff --git a/examples/oneapi/xml_scraper_graph_multi_oneapi.py b/examples/oneapi/xml_scraper_graph_multi_oneapi.py deleted file mode 100644 index b459fdd3..00000000 --- a/examples/oneapi/xml_scraper_graph_multi_oneapi.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/oneapi/xml_scraper_oneapi.py b/examples/oneapi/xml_scraper_oneapi.py deleted file mode 100644 index 7ea7fad5..00000000 --- a/examples/oneapi/xml_scraper_oneapi.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("ONEAPI_KEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-3.5-turbo", - }, - "verbose":False, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/.env.example b/examples/openai/.env.example deleted file mode 100644 index afa13602..00000000 --- a/examples/openai/.env.example +++ /dev/null @@ -1 +0,0 @@ -OPENAI_API_KEY="YOUR OPENAI API KEY" \ No newline at end of file diff --git a/examples/openai/code_generator_graph_openai.py b/examples/openai/code_generator_graph_openai.py deleted file mode 100644 index a9a2ea56..00000000 --- a/examples/openai/code_generator_graph_openai.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key":openai_key, - "model": "openai/gpt-4o-mini", - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/openai/csv_scraper_graph_multi_openai.py b/examples/openai/csv_scraper_graph_multi_openai.py deleted file mode 100644 index 6ed33c90..00000000 --- a/examples/openai/csv_scraper_graph_multi_openai.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/csv_scraper_openai.py b/examples/openai/csv_scraper_openai.py deleted file mode 100644 index d9527b86..00000000 --- a/examples/openai/csv_scraper_openai.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/custom_graph_openai.py b/examples/openai/custom_graph_openai.py deleted file mode 100644 index 00fecfdd..00000000 --- a/examples/openai/custom_graph_openai.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -Example of custom graph using existing nodes -""" -import os -from dotenv import load_dotenv -from langchain_openai import OpenAIEmbeddings -from langchain_openai import ChatOpenAI -from scrapegraphai.graphs import BaseGraph -from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") -graph_config = { - "llm": { - "api_key": openai_key, - "model": "gpt-4o", - }, -} - -# ************************************************ -# Define the graph nodes -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) -embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) - -# define the nodes for the graph -robot_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={ - "llm_model": llm_model, - "force_scraping": True, - "verbose": True, - } -) - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "verbose": True, - "headless": True, - } -) -parse_node = ParseNode( - input="doc", - output=["parsed_doc"], - node_config={ - "chunk_size": 4096, - "verbose": True, - } -) -rag_node = RAGNode( - input="user_prompt & (parsed_doc | doc)", - output=["relevant_chunks"], - node_config={ - "llm_model": llm_model, - "embedder_model": embedder, - "verbose": True, - } -) -generate_answer_node = GenerateAnswerNode( - input="user_prompt & (relevant_chunks | parsed_doc | doc)", - output=["answer"], - node_config={ - "llm_model": llm_model, - "verbose": True, - } -) - -# ************************************************ -# Create the graph by defining the connections -# ************************************************ - -graph = BaseGraph( - nodes=[ - robot_node, - fetch_node, - parse_node, - rag_node, - generate_answer_node, - ], - edges=[ - (robot_node, fetch_node), - (fetch_node, parse_node), - (parse_node, rag_node), - (rag_node, generate_answer_node) - ], - entry_point=robot_node -) - -# ************************************************ -# Execute the graph -# ************************************************ - -result, execution_info = graph.execute({ - "user_prompt": "Describe the content", - "url": "https://example.com/" -}) - -# get the answer from the result -result = result.get("answer", "No answer found.") -print(result) diff --git a/examples/openai/document_scraper_openai.py b/examples/openai/document_scraper_openai.py deleted file mode 100644 index f9475446..00000000 --- a/examples/openai/document_scraper_openai.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - } -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/openai/inputs/books.xml b/examples/openai/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/openai/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/openai/inputs/example.json b/examples/openai/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/openai/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/openai/inputs/markdown_example.md b/examples/openai/inputs/markdown_example.md deleted file mode 100644 index 85088f29..00000000 --- a/examples/openai/inputs/markdown_example.md +++ /dev/null @@ -1,35 +0,0 @@ -Marco Perini Toggle navigation - - * About - * Projects(current) - -Projects - -Competitions - - * CV - * ____ - -# Projects - - ![project thumbnail Rotary Pendulum RL -Open Source project aimed at controlling a real life rotary pendulum using RL -algorithms ](/projects/rotary-pendulum-rl/) - - ![project thumbnail DQN -Implementation from scratch Developed a Deep Q-Network algorithm to train a -simple and double pendulum ](https://github.com/PeriniM/DQN-SwingUp) - - ![project thumbnail Multi Agents HAED -University project which focuses on simulating a multi-agent system to perform -environment mapping. Agents, equipped with sensors, explore and record their -surroundings, considering uncertainties in their readings. -](https://github.com/PeriniM/Multi-Agents-HAED) - - ![project thumbnail Wireless ESC for Modular -Drones Modular drone architecture proposal and proof of concept. The project -received maximum grade. ](/projects/wireless-esc-drone/) - -© Copyright 2023 Marco Perini. Powered by Jekyll with -al-folio theme. Hosted by [GitHub -Pages](https://pages.github.com/). \ No newline at end of file diff --git a/examples/openai/inputs/plain_html_example.txt b/examples/openai/inputs/plain_html_example.txt deleted file mode 100644 index 78f814ae..00000000 --- a/examples/openai/inputs/plain_html_example.txt +++ /dev/null @@ -1,105 +0,0 @@ - -
- - -
-
-
- - -
- \ No newline at end of file diff --git a/examples/openai/inputs/username.csv b/examples/openai/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/openai/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/openai/json_scraper_multi_openai.py b/examples/openai/json_scraper_multi_openai.py deleted file mode 100644 index f7cb528a..00000000 --- a/examples/openai/json_scraper_multi_openai.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Module for showing how PDFScraper multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - } -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/openai/json_scraper_openai.py b/examples/openai/json_scraper_openai.py deleted file mode 100644 index 891ec32a..00000000 --- a/examples/openai/json_scraper_openai.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/md_scraper_openai.py b/examples/openai/md_scraper_openai.py deleted file mode 100644 index 118e7d59..00000000 --- a/examples/openai/md_scraper_openai.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using DocumentScraperGraph from MD documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the MD file -# ************************************************ - -FILE_NAME = "inputs/markdown_example.md" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the DocumentScraperGraph instance and run it -# ************************************************ - -md_scraper_graph = DocumentScraperGraph( - prompt="List me all the projects", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = md_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = md_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/omni_scraper_openai.py b/examples/openai/omni_scraper_openai.py deleted file mode 100644 index 61da3b6a..00000000 --- a/examples/openai/omni_scraper_openai.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using OmniScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import OmniScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": True, - "max_images": 5 -} - -# ************************************************ -# Create the OmniScraperGraph instance and run it -# ************************************************ - -omni_scraper_graph = OmniScraperGraph( - prompt="List me all the projects with their titles and image links and descriptions.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = omni_scraper_graph.run() -print(json.dumps(result, indent=2)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = omni_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/omni_search_openai.py b/examples/openai/omni_search_openai.py deleted file mode 100644 index a6fdb266..00000000 --- a/examples/openai/omni_search_openai.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -Example of OmniSearchGraph -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import OmniSearchGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "max_results": 2, - "max_images": 1, - "verbose": True, -} - -# ************************************************ -# Create the OmniSearchGraph instance and run it -# ************************************************ - -omni_search_graph = OmniSearchGraph( - prompt="List me all Chioggia's famous dishes and describe their pictures.", - config=graph_config -) - -result = omni_search_graph.run() -print(json.dumps(result, indent=2)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = omni_search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/rate_limit_openai.py b/examples/openai/rate_limit_openai.py deleted file mode 100644 index 9455e798..00000000 --- a/examples/openai/rate_limit_openai.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" - -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - "rate_limit": { - "requests_per_second": 1 - } - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me what does the company do, the name and a contact email.", - source="https://scrapegraphai.com/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/readme.md b/examples/openai/readme.md deleted file mode 100644 index 9a517ac6..00000000 --- a/examples/openai/readme.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains an example of how to use ScrapeGraph-AI with OpenAI, an artificial intelligence platform. The examples show how to extract information from a website using a natural language prompt. \ No newline at end of file diff --git a/examples/openai/scrape_plain_text_openai.py b/examples/openai/scrape_plain_text_openai.py deleted file mode 100644 index 27a65663..00000000 --- a/examples/openai/scrape_plain_text_openai.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/screenshot_scraper.py b/examples/openai/screenshot_scraper.py deleted file mode 100644 index f5576b64..00000000 --- a/examples/openai/screenshot_scraper.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import ScreenshotScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the ScreenshotScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = ScreenshotScraperGraph( - prompt="List me all the projects", - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/openai/script_generator_openai.py b/examples/openai/script_generator_openai.py deleted file mode 100644 index 611acc57..00000000 --- a/examples/openai/script_generator_openai.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "library": "beautifulsoup", - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = ScriptCreatorGraph( - prompt="List me all the news with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/script_generator_schema_openai.py b/examples/openai/script_generator_schema_openai.py deleted file mode 100644 index adb646d1..00000000 --- a/examples/openai/script_generator_schema_openai.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o" - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config, - schema=Projects -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/openai/script_multi_generator_openai.py b/examples/openai/script_multi_generator_openai.py deleted file mode 100644 index 19eacf66..00000000 --- a/examples/openai/script_multi_generator_openai.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "library": "beautifulsoup", - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/search_graph_schema_openai.py b/examples/openai/search_graph_schema_openai.py deleted file mode 100644 index 3109cc79..00000000 --- a/examples/openai/search_graph_schema_openai.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Example of Search Graph -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o" - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/openai/search_link_graph_openai.py b/examples/openai/search_link_graph_openai.py deleted file mode 100644 index f7436159..00000000 --- a/examples/openai/search_link_graph_openai.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchLinkGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SearchLinkGraph instance and run it -# ************************************************ - -smart_scraper_graph = SearchLinkGraph( - source="https://sport.sky.it/nba?gr=www", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/smart_scraper_lite_openai.py b/examples/openai/smart_scraper_lite_openai.py deleted file mode 100644 index 5de725bb..00000000 --- a/examples/openai/smart_scraper_lite_openai.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -smart_scraper_lite_graph = SmartScraperLiteGraph( - prompt="Who is Marco Perini?", - source="https://perinim.github.io/", - config=graph_config -) - -result = smart_scraper_lite_graph.run() -print(json.dumps(result, indent=4)) - -graph_exec_info = smart_scraper_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/openai/smart_scraper_multi_concat_openai.py b/examples/openai/smart_scraper_multi_concat_openai.py deleted file mode 100644 index 650971f1..00000000 --- a/examples/openai/smart_scraper_multi_concat_openai.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiConcatGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiConcatGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/openai/smart_scraper_multi_lite_openai.py b/examples/openai/smart_scraper_multi_lite_openai.py deleted file mode 100644 index 69eeafc7..00000000 --- a/examples/openai/smart_scraper_multi_lite_openai.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "api_key": os.getenv("OPENAI_API_KEY"), - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/openai/smart_scraper_multi_openai.py b/examples/openai/smart_scraper_multi_openai.py deleted file mode 100644 index ba889c96..00000000 --- a/examples/openai/smart_scraper_multi_openai.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/openai/smart_scraper_schema_openai.py b/examples/openai/smart_scraper_schema_openai.py deleted file mode 100644 index 32e8891a..00000000 --- a/examples/openai/smart_scraper_schema_openai.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with schema -""" -import os -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import SmartScraperGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "openai/gpt-4o-mini", - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) diff --git a/examples/openai/xml_scraper_graph_multi_openai.py b/examples/openai/xml_scraper_graph_multi_openai.py deleted file mode 100644 index 3604489b..00000000 --- a/examples/openai/xml_scraper_graph_multi_openai.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key":openai_key, - "model": "openai/gpt-4o", - }, - "verbose": True, - "headless": False, -} -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/readme.md b/examples/readme.md deleted file mode 100644 index 3d3501fb..00000000 --- a/examples/readme.md +++ /dev/null @@ -1,41 +0,0 @@ -# Benchmark analysis -# Local models -The two websites benchmark are: -- Example 1: https://perinim.github.io/projects -- Example 2: https://www.wired.com (at 17/4/2024) - -Both are strored locally as txt file in .txt format because in this way we do not have to think about the internet connection - -The time is measured in seconds - -The model runned for this benchmark is Mistral on Ollama with nomic-embed-text - -| Hardware | Example 1 | Example 2 | -| ----------------------- | --------- | --------- | -| Macbook pro 14' m1 | 11.60s | 26.61s | -| Macbook pro 16' m2 max | 8.05s | 12.17s | - -**Note**: the examples on Docker are not runned on other devices than the Macbook because the performance are to slow (10 times slower than Ollama). Indeed the results are the following: - -| Hardware | Example 1 | Example 2 | -| ------------------ | --------- | --------- | -| Macbook 14' m1 pro | 139.89 | Too long | -# Performance on APIs services -### Example 1: personal portfolio -**URL**: https://perinim.github.io/projects -**Task**: List me all the projects with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| ------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | 25.22 | 445 | 272 | 173 | 1 | 0.000754 | -| gpt-4-turbo-preview | 9.53 | 449 | 272 | 177 | 1 | 0.00803 | - -### Example 2: Wired -**URL**: https://www.wired.com -**Task**: List me all the articles with their description. - -| Name | Execution time (seconds) | total_tokens | prompt_tokens | completion_tokens | successful_requests | total_cost_USD | -| ------------------- | ------------------------ | ------------ | ------------- | ----------------- | ------------------- | -------------- | -| gpt-3.5-turbo | 25.89 | 445 | 272 | 173 | 1 | 0.000754 | -| gpt-4-turbo-preview | 64.70 | 3573 | 2199 | 1374 | 1 | 0.06321 | - diff --git a/examples/scrapegraph-api/smart_scraper_api.py b/examples/scrapegraph-api/smart_scraper_api.py deleted file mode 100644 index 8a292ee9..00000000 --- a/examples/scrapegraph-api/smart_scraper_api.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -graph_config = { - "llm": { - "model": "scrapegraphai/smart-scraper", - "api_key": os.getenv("SCRAPEGRAPH_API_KEY") - }, - "verbose": True, - "headless": False, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="Extract me all the articles", - source="https://www.wired.com", - config=graph_config -) - -result = smart_scraper_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/single_node/fetch_node.py b/examples/single_node/fetch_node.py deleted file mode 100644 index ed2de2e0..00000000 --- a/examples/single_node/fetch_node.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -from scrapegraphai.nodes import FetchNode - -# ************************************************ -# Define the node -# ************************************************ - - -fetch_node = FetchNode( - input="url | local_dir", - output=["doc"], - node_config={ - "headless": False - } -) - -# ************************************************ -# Test the node -# ************************************************ - -state = { - "url": "https://twitter.com/home" -} - -result = fetch_node.execute(state) - -print(result) diff --git a/examples/single_node/image2text_node.py b/examples/single_node/image2text_node.py deleted file mode 100644 index 0f691e8a..00000000 --- a/examples/single_node/image2text_node.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -Example of ImageToTextNode -""" - -import os -from dotenv import load_dotenv -from scrapegraphai.nodes import ImageToTextNode -from scrapegraphai.models import OpenAIImageToText - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "gpt-4o", - "temperature": 0, - }, -} - -# ************************************************ -# Define the node -# ************************************************ - -llm_model = OpenAIImageToText(graph_config["llm"]) - -image_to_text_node = ImageToTextNode( - input="img_url", - output=["img_desc"], - node_config={ - "llm_model": llm_model, - "headless": False - } -) - -# ************************************************ -# Test the node -# ************************************************ - -state = { - "img_url": [ - "https://perinim.github.io/assets/img/rotary_pybullet.jpg", - "https://perinim.github.io/assets/img/value-policy-heatmaps.jpg", - ], -} - -result = image_to_text_node.execute(state) - -print(result) diff --git a/examples/single_node/kg_node.py b/examples/single_node/kg_node.py deleted file mode 100644 index 37d1d9a4..00000000 --- a/examples/single_node/kg_node.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Example of knowledge graph node -""" - -import os -from langchain_openai import ChatOpenAI -from scrapegraphai.nodes import KnowledgeGraphNode - -job_postings = { - "Job Postings": { - "Company A": [ - { - "title": "Software Engineer", - "description": "Develop and maintain software applications.", - "location": "New York, NY", - "date_posted": "2024-05-01", - "requirements": ["Python", "Django", "REST APIs"] - }, - { - "title": "Data Scientist", - "description": "Analyze and interpret complex data.", - "location": "San Francisco, CA", - "date_posted": "2024-05-05", - "requirements": ["Python", "Machine Learning", "SQL"] - } - ], - "Company B": [ - { - "title": "Project Manager", - "description": "Manage software development projects.", - "location": "Boston, MA", - "date_posted": "2024-04-20", - "requirements": ["Project Management", "Agile", "Scrum"] - } - ] - } -} - - - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -openai_key = os.getenv("OPENAI_APIKEY") - -graph_config = { - "llm": { - "api_key": openai_key, - "model": "gpt-4o", - "temperature": 0, - }, - "verbose": True, -} - -# ************************************************ -# Define the node -# ************************************************ - -llm_model = ChatOpenAI(graph_config["llm"]) - -robots_node = KnowledgeGraphNode( - input="user_prompt & answer_dict", - output=["is_scrapable"], - node_config={"llm_model": llm_model} -) - -# ************************************************ -# Test the node -# ************************************************ - -state = { - "user_prompt": "What are the job postings?", - "answer_dict": job_postings -} - -result = robots_node.execute(state) - -print(result) diff --git a/examples/single_node/robot_node.py b/examples/single_node/robot_node.py deleted file mode 100644 index dcb70e3d..00000000 --- a/examples/single_node/robot_node.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -from langchain_community.chat_models import ChatOllama -from scrapegraphai.nodes import RobotsNode - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "llama3", - "temperature": 0, - "streaming": True - }, - "embeddings": { - "model": "nomic-embed-text", - "temperature": 0, - # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - } -} - -# ************************************************ -# Define the node -# ************************************************ - -llm_model = ChatOllama(graph_config["llm"]) - -robots_node = RobotsNode( - input="url", - output=["is_scrapable"], - node_config={"llm_model": llm_model, - "headless": False - } -) - -# ************************************************ -# Test the node -# ************************************************ - -state = { - "url": "https://twitter.com/home" -} - -result = robots_node.execute(state) - -print(result) diff --git a/examples/single_node/search_internet_node.py b/examples/single_node/search_internet_node.py deleted file mode 100644 index c998cdd1..00000000 --- a/examples/single_node/search_internet_node.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Example of custom graph using existing nodes -""" - -from langchain_community.chat_models import ChatOllama -from scrapegraphai.nodes import SearchInternetNode - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "llama3", - "temperature": 0, - "streaming": True - }, - "search_engine": "google", - "max_results": 3, - "verbose": True -} - -# ************************************************ -# Define the node -# ************************************************ - -llm_model = ChatOllama(graph_config["llm"]) - -search_node = SearchInternetNode( - input="user_input", - output=["search_results"], - node_config={ - "llm_model": llm_model, - "search_engine": graph_config["search_engine"], - "max_results": graph_config["max_results"], - "verbose": graph_config["verbose"] - } -) - -# ************************************************ -# Test the node -# ************************************************ - -state = { - "user_input": "What is the capital of France?" -} - -result = search_node.execute(state) - -print(result) diff --git a/examples/together/.env.example b/examples/together/.env.example deleted file mode 100644 index 7004713a..00000000 --- a/examples/together/.env.example +++ /dev/null @@ -1 +0,0 @@ -TOGETHER_APIKEY="your api key" \ No newline at end of file diff --git a/examples/together/code_generator_graph_togehter.py b/examples/together/code_generator_graph_togehter.py deleted file mode 100644 index aefbeba4..00000000 --- a/examples/together/code_generator_graph_togehter.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Basic example of scraping pipeline using Code Generator with schema -""" - -import os, json -from typing import List -from dotenv import load_dotenv -from pydantic import BaseModel, Field -from scrapegraphai.graphs import CodeGeneratorGraph - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_KEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, - "headless": False, - "reduction": 2, - "max_iterations": { - "overall": 10, - "syntax": 3, - "execution": 3, - "validation": 3, - "semantic": 3 - }, - "output_file_name": "extracted_data.py" -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -code_generator_graph = CodeGeneratorGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = code_generator_graph.run() -print(result) diff --git a/examples/together/csv_scraper_graph_multi_together.py b/examples/together/csv_scraper_graph_multi_together.py deleted file mode 100644 index beee56c1..00000000 --- a/examples/together/csv_scraper_graph_multi_together.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} -# ************************************************ -# Create the CSVScraperMultiGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperMultiGraph( - prompt="List me all the last names", - source=[str(text), str(text)], - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/csv_scraper_together.py b/examples/together/csv_scraper_together.py deleted file mode 100644 index 5d1a3474..00000000 --- a/examples/together/csv_scraper_together.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using CSVScraperGraph from CSV documents -""" -import os -from dotenv import load_dotenv -import pandas as pd -from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the CSV file -# ************************************************ - -FILE_NAME = "inputs/username.csv" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -text = pd.read_csv(file_path) - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} -# ************************************************ -# Create the CSVScraperGraph instance and run it -# ************************************************ - -csv_scraper_graph = CSVScraperGraph( - prompt="List me all the last names", - source=str(text), # Pass the content of the file, not the file object - config=graph_config -) - -result = csv_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/depth_search_graph_together.py b/examples/together/depth_search_graph_together.py deleted file mode 100644 index fb7b4d9e..00000000 --- a/examples/together/depth_search_graph_together.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -depth_search_graph_opeani example -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import DepthSearchGraph - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, - "headless": False, - "depth": 2, - "only_inside_links": False, -} - -search_graph = DepthSearchGraph( - prompt="List me all the projects with their description", - source="https://perinim.github.io", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/together/document_scraper_together.py b/examples/together/document_scraper_together.py deleted file mode 100644 index c3324330..00000000 --- a/examples/together/document_scraper_together.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -document_scraper example -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import DocumentScraperGraph - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -source = """ - The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian - circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. - Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante - from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. - Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood - through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided - by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, - the Beatrice of his earlier poetry, through the celestial spheres of Paradise. -""" - -pdf_scraper_graph = DocumentScraperGraph( - prompt="Summarize the text and find the main topics", - source=source, - config=graph_config, -) -result = pdf_scraper_graph.run() - -print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/together/inputs/books.xml b/examples/together/inputs/books.xml deleted file mode 100644 index e3d1fe87..00000000 --- a/examples/together/inputs/books.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - Gambardella, Matthew - XML Developer's Guide - Computer - 44.95 - 2000-10-01 - An in-depth look at creating applications - with XML. - - - Ralls, Kim - Midnight Rain - Fantasy - 5.95 - 2000-12-16 - A former architect battles corporate zombies, - an evil sorceress, and her own childhood to become queen - of the world. - - - Corets, Eva - Maeve Ascendant - Fantasy - 5.95 - 2000-11-17 - After the collapse of a nanotechnology - society in England, the young survivors lay the - foundation for a new society. - - - Corets, Eva - Oberon's Legacy - Fantasy - 5.95 - 2001-03-10 - In post-apocalypse England, the mysterious - agent known only as Oberon helps to create a new life - for the inhabitants of London. Sequel to Maeve - Ascendant. - - - Corets, Eva - The Sundered Grail - Fantasy - 5.95 - 2001-09-10 - The two daughters of Maeve, half-sisters, - battle one another for control of England. Sequel to - Oberon's Legacy. - - - Randall, Cynthia - Lover Birds - Romance - 4.95 - 2000-09-02 - When Carla meets Paul at an ornithology - conference, tempers fly as feathers get ruffled. - - - Thurman, Paula - Splish Splash - Romance - 4.95 - 2000-11-02 - A deep sea diver finds true love twenty - thousand leagues beneath the sea. - - - Knorr, Stefan - Creepy Crawlies - Horror - 4.95 - 2000-12-06 - An anthology of horror stories about roaches, - centipedes, scorpions and other insects. - - - Kress, Peter - Paradox Lost - Science Fiction - 6.95 - 2000-11-02 - After an inadvertant trip through a Heisenberg - Uncertainty Device, James Salway discovers the problems - of being quantum. - - - O'Brien, Tim - Microsoft .NET: The Programming Bible - Computer - 36.95 - 2000-12-09 - Microsoft's .NET initiative is explored in - detail in this deep programmer's reference. - - - O'Brien, Tim - MSXML3: A Comprehensive Guide - Computer - 36.95 - 2000-12-01 - The Microsoft MSXML3 parser is covered in - detail, with attention to XML DOM interfaces, XSLT processing, - SAX and more. - - - Galos, Mike - Visual Studio 7: A Comprehensive Guide - Computer - 49.95 - 2001-04-16 - Microsoft Visual Studio 7 is explored in depth, - looking at how Visual Basic, Visual C++, C#, and ASP+ are - integrated into a comprehensive development - environment. - - \ No newline at end of file diff --git a/examples/together/inputs/example.json b/examples/together/inputs/example.json deleted file mode 100644 index 2263184c..00000000 --- a/examples/together/inputs/example.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "kind":"youtube#searchListResponse", - "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", - "nextPageToken":"CAUQAA", - "regionCode":"NL", - "pageInfo":{ - "totalResults":1000000, - "resultsPerPage":5 - }, - "items":[ - { - "kind":"youtube#searchResult", - "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", - "id":{ - "kind":"youtube#video", - "videoId":"TvWDY4Mm5GM" - }, - "snippet":{ - "publishedAt":"2023-07-24T14:15:01Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T14:15:01Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", - "id":{ - "kind":"youtube#video", - "videoId":"aZM_42CcNZ4" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:09:27Z", - "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", - "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", - "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"John Nellis", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:09:27Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", - "id":{ - "kind":"youtube#video", - "videoId":"wkP3XS3aNAY" - }, - "snippet":{ - "publishedAt":"2023-07-24T16:00:50Z", - "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", - "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", - "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Shoot for Love", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T16:00:50Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", - "id":{ - "kind":"youtube#video", - "videoId":"rJkDZ0WvfT8" - }, - "snippet":{ - "publishedAt":"2023-07-24T10:00:39Z", - "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", - "title":"TOP 10 DEFENDERS 2023", - "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"Home of Football", - "liveBroadcastContent":"none", - "publishTime":"2023-07-24T10:00:39Z" - } - }, - { - "kind":"youtube#searchResult", - "etag":"wtuknXTmI1txoULeH3aWaOuXOow", - "id":{ - "kind":"youtube#video", - "videoId":"XH0rtu4U6SE" - }, - "snippet":{ - "publishedAt":"2023-07-21T16:30:05Z", - "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", - "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", - "description":"", - "thumbnails":{ - "default":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", - "width":120, - "height":90 - }, - "medium":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", - "width":320, - "height":180 - }, - "high":{ - "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", - "width":480, - "height":360 - } - }, - "channelTitle":"FC Motivate", - "liveBroadcastContent":"none", - "publishTime":"2023-07-21T16:30:05Z" - } - } - ] -} \ No newline at end of file diff --git a/examples/together/inputs/username.csv b/examples/together/inputs/username.csv deleted file mode 100644 index 006ac8e6..00000000 --- a/examples/together/inputs/username.csv +++ /dev/null @@ -1,7 +0,0 @@ -Username; Identifier;First name;Last name -booker12;9012;Rachel;Booker -grey07;2070;Laura;Grey -johnson81;4081;Craig;Johnson -jenkins46;9346;Mary;Jenkins -smith79;5079;Jamie;Smith - diff --git a/examples/together/json_scraper_multi_together.py b/examples/together/json_scraper_multi_together.py deleted file mode 100644 index 0d9ac293..00000000 --- a/examples/together/json_scraper_multi_together.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Module for showing how JSONScraperMultiGraph multi works -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperMultiGraph - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -sources = [text, text] - -multiple_search_graph = JSONScraperMultiGraph( - prompt= "List me all the authors, title and genres of the books", - source= sources, - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/together/json_scraper_together.py b/examples/together/json_scraper_together.py deleted file mode 100644 index a39c6ce4..00000000 --- a/examples/together/json_scraper_together.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Basic example of scraping pipeline using JSONScraperGraph from JSON documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import JSONScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the JSON file -# ************************************************ -together_key = os.getenv("TOGETHER_APIKEY") - -FILE_NAME = "inputs/example.json" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the JSONScraperGraph instance and run it -# ************************************************ - -json_scraper_graph = JSONScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = json_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = json_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/rate_limit_together.py b/examples/together/rate_limit_together.py deleted file mode 100644 index 89e3f89f..00000000 --- a/examples/together/rate_limit_together.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper with a custom rate limit -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - "rate_limit": { - "requests_per_second": 1 - } - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/scrape_plain_text_together.py b/examples/together/scrape_plain_text_together.py deleted file mode 100644 index feff1e3a..00000000 --- a/examples/together/scrape_plain_text_together.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper from text -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the text file -# ************************************************ - -FILE_NAME = "inputs/plain_html_example.txt" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -# It could be also a http request using the request model -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the news with their description.", - source=text, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/script_generator_together.py b/examples/together/script_generator_together.py deleted file mode 100644 index cfe46c83..00000000 --- a/examples/together/script_generator_together.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects", - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/script_multi_generator_together.py b/examples/together/script_multi_generator_together.py deleted file mode 100644 index 0596f1e2..00000000 --- a/examples/together/script_multi_generator_together.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Basic example of scraping pipeline using ScriptCreatorGraph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import ScriptCreatorMultiGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "library": "beautifulsoup" -} - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -urls=[ - "https://schultzbergagency.com/emil-raste-karlsen/", - "https://schultzbergagency.com/johanna-hedberg/", -] - -# ************************************************ -# Create the ScriptCreatorGraph instance and run it -# ************************************************ - -script_creator_graph = ScriptCreatorMultiGraph( - prompt="Find information about actors", - # also accepts a string with the already downloaded HTML code - source=urls, - config=graph_config -) - -result = script_creator_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = script_creator_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/search_graph_schema_together.py b/examples/together/search_graph_schema_together.py deleted file mode 100644 index c5954294..00000000 --- a/examples/together/search_graph_schema_together.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Example of Search Graph -""" - -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Dish(BaseModel): - name: str = Field(description="The name of the dish") - description: str = Field(description="The description of the dish") - -class Dishes(BaseModel): - dishes: List[Dish] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me Chioggia's famous dishes", - config=graph_config, - schema=Dishes -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/search_graph_together.py b/examples/together/search_graph_together.py deleted file mode 100644 index e4c442c4..00000000 --- a/examples/together/search_graph_together.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "max_results": 2, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) diff --git a/examples/together/search_link_graph_together.py b/examples/together/search_link_graph_together.py deleted file mode 100644 index 46c86d5c..00000000 --- a/examples/together/search_link_graph_together.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Example of Search Graph -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SearchGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SearchGraph instance and run it -# ************************************************ - -search_graph = SearchGraph( - prompt="List me the best escursions near Trento", - config=graph_config -) - -result = search_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = search_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json and csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/smart_scraper_lite_together.py b/examples/together/smart_scraper_lite_together.py deleted file mode 100644 index 0519ecba..00000000 --- a/examples/together/smart_scraper_lite_together.py +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/together/smart_scraper_multi_lite_together.py b/examples/together/smart_scraper_multi_lite_together.py deleted file mode 100644 index 8cf66dea..00000000 --- a/examples/together/smart_scraper_multi_lite_together.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiLiteGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config -) - -result = smart_scraper_multi_lite_graph.run() -print(json.dumps(result, indent=4)) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/smart_scraper_multi_together.py b/examples/together/smart_scraper_multi_together.py deleted file mode 100644 index a2da7b8f..00000000 --- a/examples/together/smart_scraper_multi_together.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -import json -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperMultiGraph - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ******************************************************* -# Create the SmartScraperMultiGraph instance and run it -# ******************************************************* - -multiple_search_graph = SmartScraperMultiGraph( - prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - schema=None, - config=graph_config -) - -result = multiple_search_graph.run() -print(json.dumps(result, indent=4)) diff --git a/examples/together/smart_scraper_schema_together.py b/examples/together/smart_scraper_schema_together.py deleted file mode 100644 index 45883ff0..00000000 --- a/examples/together/smart_scraper_schema_together.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from typing import List -from pydantic import BaseModel, Field -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the output schema for the graph -# ************************************************ - -class Project(BaseModel): - title: str = Field(description="The title of the project") - description: str = Field(description="The description of the project") - -class Projects(BaseModel): - projects: List[Project] - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - schema=Projects, - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/smart_scraper_together.py b/examples/together/smart_scraper_together.py deleted file mode 100644 index c60656f2..00000000 --- a/examples/together/smart_scraper_together.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Basic example of scraping pipeline using SmartScraper -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import SmartScraperGraph -from scrapegraphai.utils import prettify_exec_info - -load_dotenv() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the SmartScraperGraph instance and run it -# ************************************************ - -smart_scraper_graph = SmartScraperGraph( - prompt="List me all the projects with their description.", - # also accepts a string with the already downloaded HTML code - source="https://perinim.github.io/projects/", - config=graph_config -) - -result = smart_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = smart_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) diff --git a/examples/together/xml_scraper_graph_multi_together.py b/examples/together/xml_scraper_graph_multi_together.py deleted file mode 100644 index d6d98a0d..00000000 --- a/examples/together/xml_scraper_graph_multi_together.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the XMLScraperMultiGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperMultiGraph( - prompt="List me all the authors, title and genres of the books", - source=[text, text], # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/together/xml_scraper_together.py b/examples/together/xml_scraper_together.py deleted file mode 100644 index b1d39e2e..00000000 --- a/examples/together/xml_scraper_together.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -Basic example of scraping pipeline using XMLScraperGraph from XML documents -""" -import os -from dotenv import load_dotenv -from scrapegraphai.graphs import XMLScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info - -load_dotenv() - -# ************************************************ -# Read the XML file -# ************************************************ - -FILE_NAME = "inputs/books.xml" -curr_dir = os.path.dirname(os.path.realpath(__file__)) -file_path = os.path.join(curr_dir, FILE_NAME) - -with open(file_path, 'r', encoding="utf-8") as file: - text = file.read() - -# ************************************************ -# Define the configuration for the graph -# ************************************************ - - -together_key = os.getenv("TOGETHER_APIKEY") - -graph_config = { - "llm": { - "model": "togetherai/meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", - "api_key": together_key, - }, - "verbose": True, -} - -# ************************************************ -# Create the XMLScraperGraph instance and run it -# ************************************************ - -xml_scraper_graph = XMLScraperGraph( - prompt="List me all the authors, title and genres of the books", - source=text, # Pass the content of the file, not the file object - config=graph_config -) - -result = xml_scraper_graph.run() -print(result) - -# ************************************************ -# Get graph execution info -# ************************************************ - -graph_exec_info = xml_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") From 0b582bea661e2848a7f887993d39708aed85d00c Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Tue, 7 Jan 2025 14:48:40 +0100 Subject: [PATCH 2/9] refactoring examples --- examples/code_generator_graph/.env.example | 14 ++ examples/code_generator_graph/README.md | 30 +++ .../ollama/code_generator_graph_ollama.py | 61 ++++++ .../openai/code_generator_graph_openai.py | 59 ++++++ examples/csv_scraper_graph/.env.example | 11 ++ examples/csv_scraper_graph/README.md | 30 +++ .../ollama/csv_scraper_graph_multi_ollama.py | 62 ++++++ .../ollama/csv_scraper_ollama.py | 62 ++++++ .../ollama/inputs/username.csv | 7 + .../openai/csv_scraper_graph_multi_openai.py} | 17 +- .../openai/csv_scraper_openai.py} | 23 +-- .../openai/inputs/username.csv | 7 + examples/custom_graph/.env.example | 13 ++ examples/custom_graph/README.md | 31 +++ .../ollama/custom_graph_ollama.py | 101 ++++++++++ .../openai/custom_graph_openai.py | 109 +++++++++++ examples/depth_search_graph/.env.example | 14 ++ examples/depth_search_graph/README.md | 30 +++ .../ollama/depth_search_graph_ollama.py | 32 +++ .../openai/depth_search_graph_openai.py | 0 examples/document_scraper_graph/.env.example | 13 ++ examples/document_scraper_graph/README.md | 30 +++ .../ollama/document_scraper_ollama.py | 42 ++++ .../ollama/inputs/plain_html_example.txt | 105 ++++++++++ .../openai/document_scraper_openai.py | 39 ++++ .../openai/inputs/markdown_example.md | 35 ++++ .../openai/inputs/plain_html_example.txt | 105 ++++++++++ examples/json_scraper_graph/.env.example | 11 ++ examples/json_scraper_graph/README.md | 30 +++ .../ollama/inputs/example.json | 182 ++++++++++++++++++ .../ollama/json_scraper_multi_ollama.py | 36 ++++ .../ollama/json_scraper_ollama.py | 59 ++++++ .../openai/inputs/example.json | 182 ++++++++++++++++++ .../openai/json_scraper_multi_openai.py | 37 ++++ .../openai/json_scraper_openai.py | 57 ++++++ .../openai/md_scraper_openai.py | 57 ++++++ .../openai/omni_scraper_openai.py | 47 +++++ examples/omni_scraper_graph/.env.example | 13 ++ examples/omni_scraper_graph/README.md | 30 +++ .../omni_scraper_graph/omni_search_openai.py | 45 +++++ examples/readme.md | 32 +++ examples/script_generator_graph/.env.example | 13 ++ examples/script_generator_graph/README.md | 30 +++ .../ollama/script_generator_ollama.py | 40 ++++ .../ollama/script_multi_generator_ollama.py | 55 ++++++ .../openai/script_generator_multi_openai.py | 54 ++++++ .../openai/script_generator_openai.py | 46 +++++ .../openai/script_generator_schema_openai.py | 60 ++++++ examples/search_graph/.env.example | 11 ++ examples/search_graph/README.md | 31 +++ .../ollama/search_graph_ollama.py | 44 +++++ .../ollama/search_graph_schema_ollama.py | 58 ++++++ .../openai/search_graph_openai.py | 0 .../openai/search_graph_schema_openai.py | 61 ++++++ .../openai/search_link_graph_openai.py | 42 ++++ examples/smart_scraper/.env.example | 7 + examples/smart_scraper/README.md | 30 +++ .../ollama/smart_scraper_lite_ollama.py | 30 +++ .../smart_scraper_multi_concat_ollama.py | 42 ++++ .../ollama/smart_scraper_multi_lite_ollama.py | 45 +++++ .../ollama/smart_scraper_multi_ollama.py | 39 ++++ .../ollama}/smart_scraper_ollama.py | 0 .../ollama/smart_scraper_schema_ollama.py | 43 +++++ .../openai/smart_scraper_lite_openai.py | 32 +++ .../smart_scraper_multi_concat_openai.py | 40 ++++ .../openai/smart_scraper_multi_lite_openai.py | 47 +++++ .../openai/smart_scraper_multi_openai.py | 41 ++++ .../openai/smart_scraper_openai.py | 0 .../openai/smart_scraper_schema_openai.py | 50 +++++ examples/speech_graph/.env.example | 14 ++ examples/speech_graph/README.md | 31 +++ .../speech_graph_openai.py | 0 examples/xml_scraper_graph/.env.example | 11 ++ examples/xml_scraper_graph/README.md | 30 +++ .../xml_scraper_graph/ollama/inputs/books.xml | 120 ++++++++++++ .../ollama/xml_scraper_graph_multi_ollama.py | 58 ++++++ .../ollama/xml_scraper_ollama.py | 58 ++++++ .../xml_scraper_graph/openai/inputs/books.xml | 120 ++++++++++++ .../openai/xml_scraper_graph_multi_openai.py | 58 ++++++ .../openai/xml_scraper_openai.py | 0 80 files changed, 3374 insertions(+), 17 deletions(-) create mode 100644 examples/code_generator_graph/.env.example create mode 100644 examples/code_generator_graph/README.md create mode 100644 examples/code_generator_graph/ollama/code_generator_graph_ollama.py create mode 100644 examples/code_generator_graph/openai/code_generator_graph_openai.py create mode 100644 examples/csv_scraper_graph/.env.example create mode 100644 examples/csv_scraper_graph/README.md create mode 100644 examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py create mode 100644 examples/csv_scraper_graph/ollama/csv_scraper_ollama.py create mode 100644 examples/csv_scraper_graph/ollama/inputs/username.csv rename examples/{anthropic/csv_scraper_graph_multi_anthropic.py => csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py} (77%) rename examples/{anthropic/csv_scraper_anthropic.py => csv_scraper_graph/openai/csv_scraper_openai.py} (71%) create mode 100644 examples/csv_scraper_graph/openai/inputs/username.csv create mode 100644 examples/custom_graph/.env.example create mode 100644 examples/custom_graph/README.md create mode 100644 examples/custom_graph/ollama/custom_graph_ollama.py create mode 100644 examples/custom_graph/openai/custom_graph_openai.py create mode 100644 examples/depth_search_graph/.env.example create mode 100644 examples/depth_search_graph/README.md create mode 100644 examples/depth_search_graph/ollama/depth_search_graph_ollama.py rename examples/{ => depth_search_graph}/openai/depth_search_graph_openai.py (100%) create mode 100644 examples/document_scraper_graph/.env.example create mode 100644 examples/document_scraper_graph/README.md create mode 100644 examples/document_scraper_graph/ollama/document_scraper_ollama.py create mode 100644 examples/document_scraper_graph/ollama/inputs/plain_html_example.txt create mode 100644 examples/document_scraper_graph/openai/document_scraper_openai.py create mode 100644 examples/document_scraper_graph/openai/inputs/markdown_example.md create mode 100644 examples/document_scraper_graph/openai/inputs/plain_html_example.txt create mode 100644 examples/json_scraper_graph/.env.example create mode 100644 examples/json_scraper_graph/README.md create mode 100644 examples/json_scraper_graph/ollama/inputs/example.json create mode 100644 examples/json_scraper_graph/ollama/json_scraper_multi_ollama.py create mode 100644 examples/json_scraper_graph/ollama/json_scraper_ollama.py create mode 100644 examples/json_scraper_graph/openai/inputs/example.json create mode 100644 examples/json_scraper_graph/openai/json_scraper_multi_openai.py create mode 100644 examples/json_scraper_graph/openai/json_scraper_openai.py create mode 100644 examples/json_scraper_graph/openai/md_scraper_openai.py create mode 100644 examples/json_scraper_graph/openai/omni_scraper_openai.py create mode 100644 examples/omni_scraper_graph/.env.example create mode 100644 examples/omni_scraper_graph/README.md create mode 100644 examples/omni_scraper_graph/omni_search_openai.py create mode 100644 examples/readme.md create mode 100644 examples/script_generator_graph/.env.example create mode 100644 examples/script_generator_graph/README.md create mode 100644 examples/script_generator_graph/ollama/script_generator_ollama.py create mode 100644 examples/script_generator_graph/ollama/script_multi_generator_ollama.py create mode 100644 examples/script_generator_graph/openai/script_generator_multi_openai.py create mode 100644 examples/script_generator_graph/openai/script_generator_openai.py create mode 100644 examples/script_generator_graph/openai/script_generator_schema_openai.py create mode 100644 examples/search_graph/.env.example create mode 100644 examples/search_graph/README.md create mode 100644 examples/search_graph/ollama/search_graph_ollama.py create mode 100644 examples/search_graph/ollama/search_graph_schema_ollama.py rename examples/{ => search_graph}/openai/search_graph_openai.py (100%) create mode 100644 examples/search_graph/openai/search_graph_schema_openai.py create mode 100644 examples/search_graph/openai/search_link_graph_openai.py create mode 100644 examples/smart_scraper/.env.example create mode 100644 examples/smart_scraper/README.md create mode 100644 examples/smart_scraper/ollama/smart_scraper_lite_ollama.py create mode 100644 examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py create mode 100644 examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py create mode 100644 examples/smart_scraper/ollama/smart_scraper_multi_ollama.py rename examples/{local_models => smart_scraper/ollama}/smart_scraper_ollama.py (100%) create mode 100644 examples/smart_scraper/ollama/smart_scraper_schema_ollama.py create mode 100644 examples/smart_scraper/openai/smart_scraper_lite_openai.py create mode 100644 examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py create mode 100644 examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py create mode 100644 examples/smart_scraper/openai/smart_scraper_multi_openai.py rename examples/{ => smart_scraper}/openai/smart_scraper_openai.py (100%) create mode 100644 examples/smart_scraper/openai/smart_scraper_schema_openai.py create mode 100644 examples/speech_graph/.env.example create mode 100644 examples/speech_graph/README.md rename examples/{openai => speech_graph}/speech_graph_openai.py (100%) create mode 100644 examples/xml_scraper_graph/.env.example create mode 100644 examples/xml_scraper_graph/README.md create mode 100644 examples/xml_scraper_graph/ollama/inputs/books.xml create mode 100644 examples/xml_scraper_graph/ollama/xml_scraper_graph_multi_ollama.py create mode 100644 examples/xml_scraper_graph/ollama/xml_scraper_ollama.py create mode 100644 examples/xml_scraper_graph/openai/inputs/books.xml create mode 100644 examples/xml_scraper_graph/openai/xml_scraper_graph_multi_openai.py rename examples/{ => xml_scraper_graph}/openai/xml_scraper_openai.py (100%) diff --git a/examples/code_generator_graph/.env.example b/examples/code_generator_graph/.env.example new file mode 100644 index 00000000..a93912e4 --- /dev/null +++ b/examples/code_generator_graph/.env.example @@ -0,0 +1,14 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Code Generator Settings +DEFAULT_LANGUAGE=python +GENERATE_TESTS=true +ADD_DOCUMENTATION=true +CODE_STYLE=pep8 +TYPE_CHECKING=true \ No newline at end of file diff --git a/examples/code_generator_graph/README.md b/examples/code_generator_graph/README.md new file mode 100644 index 00000000..bc4b5dec --- /dev/null +++ b/examples/code_generator_graph/README.md @@ -0,0 +1,30 @@ +# Code Generator Graph Example + +This example demonstrates how to use Scrapegraph-ai to generate code based on specifications and requirements. + +## Features + +- Code generation from specifications +- Multiple programming languages support +- Code documentation +- Best practices implementation + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import CodeGeneratorGraph + +graph = CodeGeneratorGraph() +code = graph.generate("code specification") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/code_generator_graph/ollama/code_generator_graph_ollama.py b/examples/code_generator_graph/ollama/code_generator_graph_ollama.py new file mode 100644 index 00000000..46ab8ab3 --- /dev/null +++ b/examples/code_generator_graph/ollama/code_generator_graph_ollama.py @@ -0,0 +1,61 @@ +""" +Basic example of scraping pipeline using Code Generator with schema +""" + +import json +from typing import List +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from scrapegraphai.graphs import CodeGeneratorGraph + +load_dotenv() + +# ************************************************ +# Define the output schema for the graph +# ************************************************ + +class Project(BaseModel): + title: str = Field(description="The title of the project") + description: str = Field(description="The description of the project") + +class Projects(BaseModel): + projects: List[Project] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", + "base_url": "http://localhost:11434", + }, + "verbose": True, + "headless": False, + "reduction": 2, + "max_iterations": { + "overall": 10, + "syntax": 3, + "execution": 3, + "validation": 3, + "semantic": 3 + }, + "output_file_name": "extracted_data.py" +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +code_generator_graph = CodeGeneratorGraph( + prompt="List me all the projects with their description", + source="https://perinim.github.io/projects/", + schema=Projects, + config=graph_config +) + +result = code_generator_graph.run() +print(result) \ No newline at end of file diff --git a/examples/code_generator_graph/openai/code_generator_graph_openai.py b/examples/code_generator_graph/openai/code_generator_graph_openai.py new file mode 100644 index 00000000..a9a2ea56 --- /dev/null +++ b/examples/code_generator_graph/openai/code_generator_graph_openai.py @@ -0,0 +1,59 @@ +""" +Basic example of scraping pipeline using Code Generator with schema +""" +import os +from typing import List +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from scrapegraphai.graphs import CodeGeneratorGraph + +load_dotenv() + +# ************************************************ +# Define the output schema for the graph +# ************************************************ + +class Project(BaseModel): + title: str = Field(description="The title of the project") + description: str = Field(description="The description of the project") + +class Projects(BaseModel): + projects: List[Project] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key":openai_key, + "model": "openai/gpt-4o-mini", + }, + "verbose": True, + "headless": False, + "reduction": 2, + "max_iterations": { + "overall": 10, + "syntax": 3, + "execution": 3, + "validation": 3, + "semantic": 3 + }, + "output_file_name": "extracted_data.py" +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +code_generator_graph = CodeGeneratorGraph( + prompt="List me all the projects with their description", + source="https://perinim.github.io/projects/", + schema=Projects, + config=graph_config +) + +result = code_generator_graph.run() +print(result) diff --git a/examples/csv_scraper_graph/.env.example b/examples/csv_scraper_graph/.env.example new file mode 100644 index 00000000..1917f9aa --- /dev/null +++ b/examples/csv_scraper_graph/.env.example @@ -0,0 +1,11 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# CSV Scraper Settings +CSV_DELIMITER=, +MAX_ROWS=1000 \ No newline at end of file diff --git a/examples/csv_scraper_graph/README.md b/examples/csv_scraper_graph/README.md new file mode 100644 index 00000000..d39858b0 --- /dev/null +++ b/examples/csv_scraper_graph/README.md @@ -0,0 +1,30 @@ +# CSV Scraper Graph Example + +This example demonstrates how to use Scrapegraph-ai to extract data from web sources and save it in CSV format. + +## Features + +- Table data extraction +- CSV formatting +- Data cleaning +- Structured output + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import CsvScraperGraph + +graph = CsvScraperGraph() +csv_data = graph.scrape("https://example.com/table") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py b/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py new file mode 100644 index 00000000..fb6bce51 --- /dev/null +++ b/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py @@ -0,0 +1,62 @@ +""" +Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents +""" + +import os +import pandas as pd +from scrapegraphai.graphs import CSVScraperMultiGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +# ************************************************ +# Read the CSV file +# ************************************************ + +FILE_NAME = "inputs/username.csv" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +text = pd.read_csv(file_path) + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + "embeddings": { + "model": "ollama/nomic-embed-text", + "temperature": 0, + "base_url": "http://localhost:11434", + }, + "verbose": True, +} + +# ************************************************ +# Create the CSVScraperMultiGraph instance and run it +# ************************************************ + +csv_scraper_graph = CSVScraperMultiGraph( + prompt="List me all the last names", + source=[str(text), str(text)], + config=graph_config +) + +result = csv_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = csv_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py b/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py new file mode 100644 index 00000000..8d1edbd7 --- /dev/null +++ b/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py @@ -0,0 +1,62 @@ +""" +Basic example of scraping pipeline using CSVScraperGraph from CSV documents +""" + +import os +import pandas as pd +from scrapegraphai.graphs import CSVScraperGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +# ************************************************ +# Read the CSV file +# ************************************************ + +FILE_NAME = "inputs/username.csv" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +text = pd.read_csv(file_path) + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + "embeddings": { + "model": "ollama/nomic-embed-text", + "temperature": 0, + "base_url": "http://localhost:11434", + }, + "verbose": True, +} + +# ************************************************ +# Create the CSVScraperGraph instance and run it +# ************************************************ + +csv_scraper_graph = CSVScraperGraph( + prompt="List me all the last names", + source=str(text), # Pass the content of the file, not the file object + config=graph_config +) + +result = csv_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = csv_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/ollama/inputs/username.csv b/examples/csv_scraper_graph/ollama/inputs/username.csv new file mode 100644 index 00000000..006ac8e6 --- /dev/null +++ b/examples/csv_scraper_graph/ollama/inputs/username.csv @@ -0,0 +1,7 @@ +Username; Identifier;First name;Last name +booker12;9012;Rachel;Booker +grey07;2070;Laura;Grey +johnson81;4081;Craig;Johnson +jenkins46;9346;Mary;Jenkins +smith79;5079;Jamie;Smith + diff --git a/examples/anthropic/csv_scraper_graph_multi_anthropic.py b/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py similarity index 77% rename from examples/anthropic/csv_scraper_graph_multi_anthropic.py rename to examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py index ed0bcbc5..6ed33c90 100644 --- a/examples/anthropic/csv_scraper_graph_multi_anthropic.py +++ b/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py @@ -3,8 +3,9 @@ """ import os from dotenv import load_dotenv +import pandas as pd from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import prettify_exec_info +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info load_dotenv() # ************************************************ @@ -15,17 +16,17 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -with open(file_path, 'r') as file: - text = file.read() +text = pd.read_csv(file_path) # ************************************************ # Define the configuration for the graph # ************************************************ +openai_key = os.getenv("OPENAI_APIKEY") graph_config = { - "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", }, } @@ -48,3 +49,7 @@ graph_exec_info = csv_scraper_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/anthropic/csv_scraper_anthropic.py b/examples/csv_scraper_graph/openai/csv_scraper_openai.py similarity index 71% rename from examples/anthropic/csv_scraper_anthropic.py rename to examples/csv_scraper_graph/openai/csv_scraper_openai.py index 4fd5aaaf..d9527b86 100644 --- a/examples/anthropic/csv_scraper_anthropic.py +++ b/examples/csv_scraper_graph/openai/csv_scraper_openai.py @@ -3,8 +3,9 @@ """ import os from dotenv import load_dotenv +import pandas as pd from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import prettify_exec_info +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info load_dotenv() @@ -16,22 +17,18 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -with open(file_path, 'r') as file: - text = file.read() +text = pd.read_csv(file_path) # ************************************************ # Define the configuration for the graph # ************************************************ -# required environment variables in .env -# HUGGINGFACEHUB_API_TOKEN -# ANTHROPIC_API_KEY -load_dotenv() +openai_key = os.getenv("OPENAI_APIKEY") graph_config = { "llm": { - "api_key": os.getenv("ANTHROPIC_API_KEY"), - "model": "anthropic/claude-3-haiku-20240307", + "api_key": openai_key, + "model": "openai/gpt-4o", }, } @@ -41,7 +38,7 @@ csv_scraper_graph = CSVScraperGraph( prompt="List me all the last names", - source=text, # Pass the content of the file + source=str(text), # Pass the content of the file, not the file object config=graph_config ) @@ -53,4 +50,8 @@ # ************************************************ graph_exec_info = csv_scraper_graph.get_execution_info() -print(prettify_exec_info(graph_exec_info)) \ No newline at end of file +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/openai/inputs/username.csv b/examples/csv_scraper_graph/openai/inputs/username.csv new file mode 100644 index 00000000..006ac8e6 --- /dev/null +++ b/examples/csv_scraper_graph/openai/inputs/username.csv @@ -0,0 +1,7 @@ +Username; Identifier;First name;Last name +booker12;9012;Rachel;Booker +grey07;2070;Laura;Grey +johnson81;4081;Craig;Johnson +jenkins46;9346;Mary;Jenkins +smith79;5079;Jamie;Smith + diff --git a/examples/custom_graph/.env.example b/examples/custom_graph/.env.example new file mode 100644 index 00000000..9eac4cb8 --- /dev/null +++ b/examples/custom_graph/.env.example @@ -0,0 +1,13 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Custom Graph Settings +CUSTOM_NODE_TIMEOUT=30 +MAX_NODES=10 +DEBUG_MODE=false +LOG_LEVEL=info \ No newline at end of file diff --git a/examples/custom_graph/README.md b/examples/custom_graph/README.md new file mode 100644 index 00000000..e6d3b88a --- /dev/null +++ b/examples/custom_graph/README.md @@ -0,0 +1,31 @@ +# Custom Graph Example + +This example demonstrates how to create and implement custom graphs using Scrapegraph-ai. + +## Features + +- Custom node creation +- Graph customization +- Pipeline configuration +- Custom data processing + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import CustomGraph + +graph = CustomGraph() +graph.add_node("custom_node", CustomNode()) +results = graph.process() +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/custom_graph/ollama/custom_graph_ollama.py b/examples/custom_graph/ollama/custom_graph_ollama.py new file mode 100644 index 00000000..c505d068 --- /dev/null +++ b/examples/custom_graph/ollama/custom_graph_ollama.py @@ -0,0 +1,101 @@ +""" +Example of custom graph using existing nodes +""" + +import os +from langchain_openai import OpenAIEmbeddings +from langchain_openai import ChatOpenAI +from scrapegraphai.graphs import BaseGraph +from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/mistral", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + + "verbose": True, +} + +# ************************************************ +# Define the graph nodes +# ************************************************ + +llm_model = ChatOpenAI(graph_config["llm"]) +embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) + +# define the nodes for the graph +robot_node = RobotsNode( + input="url", + output=["is_scrapable"], + node_config={ + "llm_model": llm_model, + "force_scraping": True, + "verbose": True, + } +) + +fetch_node = FetchNode( + input="url | local_dir", + output=["doc"], + node_config={ + "verbose": True, + "headless": True, + } +) +parse_node = ParseNode( + input="doc", + output=["parsed_doc"], + node_config={ + "chunk_size": 4096, + "verbose": True, + } +) + +generate_answer_node = GenerateAnswerNode( + input="user_prompt & (relevant_chunks | parsed_doc | doc)", + output=["answer"], + node_config={ + "llm_model": llm_model, + "verbose": True, + } +) + +# ************************************************ +# Create the graph by defining the connections +# ************************************************ + +graph = BaseGraph( + nodes=[ + robot_node, + fetch_node, + parse_node, + generate_answer_node, + ], + edges=[ + (robot_node, fetch_node), + (fetch_node, parse_node), + (parse_node, generate_answer_node) + ], + entry_point=robot_node +) + +# ************************************************ +# Execute the graph +# ************************************************ + +result, execution_info = graph.execute({ + "user_prompt": "Describe the content", + "url": "https://example.com/" +}) + +# get the answer from the result +result = result.get("answer", "No answer found.") +print(result) diff --git a/examples/custom_graph/openai/custom_graph_openai.py b/examples/custom_graph/openai/custom_graph_openai.py new file mode 100644 index 00000000..00fecfdd --- /dev/null +++ b/examples/custom_graph/openai/custom_graph_openai.py @@ -0,0 +1,109 @@ +""" +Example of custom graph using existing nodes +""" +import os +from dotenv import load_dotenv +from langchain_openai import OpenAIEmbeddings +from langchain_openai import ChatOpenAI +from scrapegraphai.graphs import BaseGraph +from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode, RobotsNode + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") +graph_config = { + "llm": { + "api_key": openai_key, + "model": "gpt-4o", + }, +} + +# ************************************************ +# Define the graph nodes +# ************************************************ + +llm_model = ChatOpenAI(graph_config["llm"]) +embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key) + +# define the nodes for the graph +robot_node = RobotsNode( + input="url", + output=["is_scrapable"], + node_config={ + "llm_model": llm_model, + "force_scraping": True, + "verbose": True, + } +) + +fetch_node = FetchNode( + input="url | local_dir", + output=["doc"], + node_config={ + "verbose": True, + "headless": True, + } +) +parse_node = ParseNode( + input="doc", + output=["parsed_doc"], + node_config={ + "chunk_size": 4096, + "verbose": True, + } +) +rag_node = RAGNode( + input="user_prompt & (parsed_doc | doc)", + output=["relevant_chunks"], + node_config={ + "llm_model": llm_model, + "embedder_model": embedder, + "verbose": True, + } +) +generate_answer_node = GenerateAnswerNode( + input="user_prompt & (relevant_chunks | parsed_doc | doc)", + output=["answer"], + node_config={ + "llm_model": llm_model, + "verbose": True, + } +) + +# ************************************************ +# Create the graph by defining the connections +# ************************************************ + +graph = BaseGraph( + nodes=[ + robot_node, + fetch_node, + parse_node, + rag_node, + generate_answer_node, + ], + edges=[ + (robot_node, fetch_node), + (fetch_node, parse_node), + (parse_node, rag_node), + (rag_node, generate_answer_node) + ], + entry_point=robot_node +) + +# ************************************************ +# Execute the graph +# ************************************************ + +result, execution_info = graph.execute({ + "user_prompt": "Describe the content", + "url": "https://example.com/" +}) + +# get the answer from the result +result = result.get("answer", "No answer found.") +print(result) diff --git a/examples/depth_search_graph/.env.example b/examples/depth_search_graph/.env.example new file mode 100644 index 00000000..8c10cfbb --- /dev/null +++ b/examples/depth_search_graph/.env.example @@ -0,0 +1,14 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Depth Search Settings +MAX_DEPTH=5 +CRAWL_DELAY=1 +RESPECT_ROBOTS_TXT=true +MAX_PAGES_PER_DOMAIN=100 +USER_AGENT=Mozilla/5.0 \ No newline at end of file diff --git a/examples/depth_search_graph/README.md b/examples/depth_search_graph/README.md new file mode 100644 index 00000000..c4ce05df --- /dev/null +++ b/examples/depth_search_graph/README.md @@ -0,0 +1,30 @@ +# Depth Search Graph Example + +This example demonstrates how to use Scrapegraph-ai for deep web crawling and content exploration. + +## Features + +- Deep web crawling +- Content discovery +- Link analysis +- Recursive search + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import DepthSearchGraph + +graph = DepthSearchGraph() +results = graph.search("https://example.com", depth=3) +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/depth_search_graph/ollama/depth_search_graph_ollama.py b/examples/depth_search_graph/ollama/depth_search_graph_ollama.py new file mode 100644 index 00000000..d0f960b5 --- /dev/null +++ b/examples/depth_search_graph/ollama/depth_search_graph_ollama.py @@ -0,0 +1,32 @@ +""" +depth_search_graph_opeani example +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import DepthSearchGraph + +load_dotenv() + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "verbose": True, + "headless": False, + "depth": 2, + "only_inside_links": False, +} + +search_graph = DepthSearchGraph( + prompt="List me all the projects with their description", + source="https://perinim.github.io", + config=graph_config +) + +result = search_graph.run() +print(result) diff --git a/examples/openai/depth_search_graph_openai.py b/examples/depth_search_graph/openai/depth_search_graph_openai.py similarity index 100% rename from examples/openai/depth_search_graph_openai.py rename to examples/depth_search_graph/openai/depth_search_graph_openai.py diff --git a/examples/document_scraper_graph/.env.example b/examples/document_scraper_graph/.env.example new file mode 100644 index 00000000..2e7bab46 --- /dev/null +++ b/examples/document_scraper_graph/.env.example @@ -0,0 +1,13 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Document Scraper Settings +OCR_ENABLED=true +EXTRACT_METADATA=true +MAX_FILE_SIZE=10485760 # 10MB +SUPPORTED_FORMATS=pdf,doc,docx,txt \ No newline at end of file diff --git a/examples/document_scraper_graph/README.md b/examples/document_scraper_graph/README.md new file mode 100644 index 00000000..f8561ee7 --- /dev/null +++ b/examples/document_scraper_graph/README.md @@ -0,0 +1,30 @@ +# Document Scraper Graph Example + +This example demonstrates how to use Scrapegraph-ai to extract data from various document formats (PDF, DOC, DOCX, etc.). + +## Features + +- Multi-format document support +- Text extraction +- Document parsing +- Metadata extraction + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import DocumentScraperGraph + +graph = DocumentScraperGraph() +content = graph.scrape("document.pdf") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/document_scraper_graph/ollama/document_scraper_ollama.py b/examples/document_scraper_graph/ollama/document_scraper_ollama.py new file mode 100644 index 00000000..6853a549 --- /dev/null +++ b/examples/document_scraper_graph/ollama/document_scraper_ollama.py @@ -0,0 +1,42 @@ +""" +document_scraper example +""" +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import DocumentScraperGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + "model_tokens": 4000, + }, + "verbose": True, + "headless": False, +} + +source = """ + The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian + circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. + Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante + from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. + Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood + through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided + by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, + the Beatrice of his earlier poetry, through the celestial spheres of Paradise. +""" + +pdf_scraper_graph = DocumentScraperGraph( + prompt="Summarize the text and find the main topics", + source=source, + config=graph_config, +) +result = pdf_scraper_graph.run() + +print(json.dumps(result, indent=4)) diff --git a/examples/document_scraper_graph/ollama/inputs/plain_html_example.txt b/examples/document_scraper_graph/ollama/inputs/plain_html_example.txt new file mode 100644 index 00000000..78f814ae --- /dev/null +++ b/examples/document_scraper_graph/ollama/inputs/plain_html_example.txt @@ -0,0 +1,105 @@ + +
+ + +
+
+
+ + +
+ \ No newline at end of file diff --git a/examples/document_scraper_graph/openai/document_scraper_openai.py b/examples/document_scraper_graph/openai/document_scraper_openai.py new file mode 100644 index 00000000..f9475446 --- /dev/null +++ b/examples/document_scraper_graph/openai/document_scraper_openai.py @@ -0,0 +1,39 @@ +""" +document_scraper example +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import DocumentScraperGraph + +load_dotenv() + + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + } +} + +source = """ + The Divine Comedy, Italian La Divina Commedia, original name La commedia, long narrative poem written in Italian + circa 1308/21 by Dante. It is usually held to be one of the world s great works of literature. + Divided into three major sections—Inferno, Purgatorio, and Paradiso—the narrative traces the journey of Dante + from darkness and error to the revelation of the divine light, culminating in the Beatific Vision of God. + Dante is guided by the Roman poet Virgil, who represents the epitome of human knowledge, from the dark wood + through the descending circles of the pit of Hell (Inferno). He then climbs the mountain of Purgatory, guided + by the Roman poet Statius, who represents the fulfilment of human knowledge, and is finally led by his lifelong love, + the Beatrice of his earlier poetry, through the celestial spheres of Paradise. +""" + +pdf_scraper_graph = DocumentScraperGraph( + prompt="Summarize the text and find the main topics", + source=source, + config=graph_config, +) +result = pdf_scraper_graph.run() + +print(json.dumps(result, indent=4)) \ No newline at end of file diff --git a/examples/document_scraper_graph/openai/inputs/markdown_example.md b/examples/document_scraper_graph/openai/inputs/markdown_example.md new file mode 100644 index 00000000..85088f29 --- /dev/null +++ b/examples/document_scraper_graph/openai/inputs/markdown_example.md @@ -0,0 +1,35 @@ +Marco Perini Toggle navigation + + * About + * Projects(current) + +Projects + +Competitions + + * CV + * ____ + +# Projects + + ![project thumbnail Rotary Pendulum RL +Open Source project aimed at controlling a real life rotary pendulum using RL +algorithms ](/projects/rotary-pendulum-rl/) + + ![project thumbnail DQN +Implementation from scratch Developed a Deep Q-Network algorithm to train a +simple and double pendulum ](https://github.com/PeriniM/DQN-SwingUp) + + ![project thumbnail Multi Agents HAED +University project which focuses on simulating a multi-agent system to perform +environment mapping. Agents, equipped with sensors, explore and record their +surroundings, considering uncertainties in their readings. +](https://github.com/PeriniM/Multi-Agents-HAED) + + ![project thumbnail Wireless ESC for Modular +Drones Modular drone architecture proposal and proof of concept. The project +received maximum grade. ](/projects/wireless-esc-drone/) + +© Copyright 2023 Marco Perini. Powered by Jekyll with +al-folio theme. Hosted by [GitHub +Pages](https://pages.github.com/). \ No newline at end of file diff --git a/examples/document_scraper_graph/openai/inputs/plain_html_example.txt b/examples/document_scraper_graph/openai/inputs/plain_html_example.txt new file mode 100644 index 00000000..78f814ae --- /dev/null +++ b/examples/document_scraper_graph/openai/inputs/plain_html_example.txt @@ -0,0 +1,105 @@ + +
+ + +
+
+
+ + +
+ \ No newline at end of file diff --git a/examples/json_scraper_graph/.env.example b/examples/json_scraper_graph/.env.example new file mode 100644 index 00000000..f1862149 --- /dev/null +++ b/examples/json_scraper_graph/.env.example @@ -0,0 +1,11 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# JSON Scraper Settings +MAX_DEPTH=3 +TIMEOUT=30 \ No newline at end of file diff --git a/examples/json_scraper_graph/README.md b/examples/json_scraper_graph/README.md new file mode 100644 index 00000000..217875ff --- /dev/null +++ b/examples/json_scraper_graph/README.md @@ -0,0 +1,30 @@ +# JSON Scraper Graph Example + +This example demonstrates how to use Scrapegraph-ai to extract and process JSON data from web sources. + +## Features + +- JSON data extraction +- Schema validation +- Data transformation +- Structured output + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import JsonScraperGraph + +graph = JsonScraperGraph() +json_data = graph.scrape("https://api.example.com/data") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/json_scraper_graph/ollama/inputs/example.json b/examples/json_scraper_graph/ollama/inputs/example.json new file mode 100644 index 00000000..2263184c --- /dev/null +++ b/examples/json_scraper_graph/ollama/inputs/example.json @@ -0,0 +1,182 @@ +{ + "kind":"youtube#searchListResponse", + "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", + "nextPageToken":"CAUQAA", + "regionCode":"NL", + "pageInfo":{ + "totalResults":1000000, + "resultsPerPage":5 + }, + "items":[ + { + "kind":"youtube#searchResult", + "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", + "id":{ + "kind":"youtube#video", + "videoId":"TvWDY4Mm5GM" + }, + "snippet":{ + "publishedAt":"2023-07-24T14:15:01Z", + "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", + "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", + "description":"", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"FC Motivate", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T14:15:01Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", + "id":{ + "kind":"youtube#video", + "videoId":"aZM_42CcNZ4" + }, + "snippet":{ + "publishedAt":"2023-07-24T16:09:27Z", + "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", + "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", + "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"John Nellis", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T16:09:27Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", + "id":{ + "kind":"youtube#video", + "videoId":"wkP3XS3aNAY" + }, + "snippet":{ + "publishedAt":"2023-07-24T16:00:50Z", + "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", + "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", + "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"Shoot for Love", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T16:00:50Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", + "id":{ + "kind":"youtube#video", + "videoId":"rJkDZ0WvfT8" + }, + "snippet":{ + "publishedAt":"2023-07-24T10:00:39Z", + "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", + "title":"TOP 10 DEFENDERS 2023", + "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"Home of Football", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T10:00:39Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"wtuknXTmI1txoULeH3aWaOuXOow", + "id":{ + "kind":"youtube#video", + "videoId":"XH0rtu4U6SE" + }, + "snippet":{ + "publishedAt":"2023-07-21T16:30:05Z", + "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", + "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", + "description":"", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"FC Motivate", + "liveBroadcastContent":"none", + "publishTime":"2023-07-21T16:30:05Z" + } + } + ] +} \ No newline at end of file diff --git a/examples/json_scraper_graph/ollama/json_scraper_multi_ollama.py b/examples/json_scraper_graph/ollama/json_scraper_multi_ollama.py new file mode 100644 index 00000000..e80bf5ec --- /dev/null +++ b/examples/json_scraper_graph/ollama/json_scraper_multi_ollama.py @@ -0,0 +1,36 @@ +""" +Module for showing how PDFScraper multi works +""" +import os +import json +from scrapegraphai.graphs import JSONScraperMultiGraph + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + "model_tokens": 4000, + }, + "verbose": True, + "headless": False, +} + +FILE_NAME = "inputs/example.json" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +sources = [text, text] + +multiple_search_graph = JSONScraperMultiGraph( + prompt= "List me all the authors, title and genres of the books", + source= sources, + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/json_scraper_graph/ollama/json_scraper_ollama.py b/examples/json_scraper_graph/ollama/json_scraper_ollama.py new file mode 100644 index 00000000..ca4eb32e --- /dev/null +++ b/examples/json_scraper_graph/ollama/json_scraper_ollama.py @@ -0,0 +1,59 @@ +""" +Basic example of scraping pipeline using JSONScraperGraph from JSON documents +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import JSONScraperGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +load_dotenv() + +# ************************************************ +# Read the JSON file +# ************************************************ + +FILE_NAME = "inputs/example.json" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/mistral", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + "verbose": True, +} + +# ************************************************ +# Create the JSONScraperGraph instance and run it +# ************************************************ + +json_scraper_graph = JSONScraperGraph( + prompt="List me all the authors, title and genres of the books", + source=text, # Pass the content of the file, not the file object + config=graph_config +) + +result = json_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = json_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/json_scraper_graph/openai/inputs/example.json b/examples/json_scraper_graph/openai/inputs/example.json new file mode 100644 index 00000000..2263184c --- /dev/null +++ b/examples/json_scraper_graph/openai/inputs/example.json @@ -0,0 +1,182 @@ +{ + "kind":"youtube#searchListResponse", + "etag":"q4ibjmYp1KA3RqMF4jFLl6PBwOg", + "nextPageToken":"CAUQAA", + "regionCode":"NL", + "pageInfo":{ + "totalResults":1000000, + "resultsPerPage":5 + }, + "items":[ + { + "kind":"youtube#searchResult", + "etag":"QCsHBifbaernVCbLv8Cu6rAeaDQ", + "id":{ + "kind":"youtube#video", + "videoId":"TvWDY4Mm5GM" + }, + "snippet":{ + "publishedAt":"2023-07-24T14:15:01Z", + "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", + "title":"3 Football Clubs Kylian Mbappe Should Avoid Signing ✍️❌⚽️ #football #mbappe #shorts", + "description":"", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/TvWDY4Mm5GM/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"FC Motivate", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T14:15:01Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"0NG5QHdtIQM_V-DBJDEf-jK_Y9k", + "id":{ + "kind":"youtube#video", + "videoId":"aZM_42CcNZ4" + }, + "snippet":{ + "publishedAt":"2023-07-24T16:09:27Z", + "channelId":"UCM5gMM_HqfKHYIEJ3lstMUA", + "title":"Which Football Club Could Cristiano Ronaldo Afford To Buy? 💰", + "description":"Sign up to Sorare and get a FREE card: https://sorare.pxf.io/NellisShorts Give Soraredata a go for FREE: ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/aZM_42CcNZ4/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"John Nellis", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T16:09:27Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"WbBz4oh9I5VaYj91LjeJvffrBVY", + "id":{ + "kind":"youtube#video", + "videoId":"wkP3XS3aNAY" + }, + "snippet":{ + "publishedAt":"2023-07-24T16:00:50Z", + "channelId":"UC4EP1dxFDPup_aFLt0ElsDw", + "title":"PAULO DYBALA vs THE WORLD'S LONGEST FREEKICK WALL", + "description":"Can Paulo Dybala curl a football around the World's longest free kick wall? We met up with the World Cup winner and put him to ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/wkP3XS3aNAY/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"Shoot for Love", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T16:00:50Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"juxv_FhT_l4qrR05S1QTrb4CGh8", + "id":{ + "kind":"youtube#video", + "videoId":"rJkDZ0WvfT8" + }, + "snippet":{ + "publishedAt":"2023-07-24T10:00:39Z", + "channelId":"UCO8qj5u80Ga7N_tP3BZWWhQ", + "title":"TOP 10 DEFENDERS 2023", + "description":"SoccerKingz https://soccerkingz.nl Use code: 'ILOVEHOF' to get 10% off. TOP 10 DEFENDERS 2023 Follow us! • Instagram ...", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/rJkDZ0WvfT8/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"Home of Football", + "liveBroadcastContent":"none", + "publishTime":"2023-07-24T10:00:39Z" + } + }, + { + "kind":"youtube#searchResult", + "etag":"wtuknXTmI1txoULeH3aWaOuXOow", + "id":{ + "kind":"youtube#video", + "videoId":"XH0rtu4U6SE" + }, + "snippet":{ + "publishedAt":"2023-07-21T16:30:05Z", + "channelId":"UCwozCpFp9g9x0wAzuFh0hwQ", + "title":"3 Things You Didn't Know About Erling Haaland ⚽️🇳🇴 #football #haaland #shorts", + "description":"", + "thumbnails":{ + "default":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/default.jpg", + "width":120, + "height":90 + }, + "medium":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/mqdefault.jpg", + "width":320, + "height":180 + }, + "high":{ + "url":"https://i.ytimg.com/vi/XH0rtu4U6SE/hqdefault.jpg", + "width":480, + "height":360 + } + }, + "channelTitle":"FC Motivate", + "liveBroadcastContent":"none", + "publishTime":"2023-07-21T16:30:05Z" + } + } + ] +} \ No newline at end of file diff --git a/examples/json_scraper_graph/openai/json_scraper_multi_openai.py b/examples/json_scraper_graph/openai/json_scraper_multi_openai.py new file mode 100644 index 00000000..f7cb528a --- /dev/null +++ b/examples/json_scraper_graph/openai/json_scraper_multi_openai.py @@ -0,0 +1,37 @@ +""" +Module for showing how PDFScraper multi works +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import JSONScraperMultiGraph + +load_dotenv() + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + } +} + +FILE_NAME = "inputs/example.json" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +sources = [text, text] + +multiple_search_graph = JSONScraperMultiGraph( + prompt= "List me all the authors, title and genres of the books", + source= sources, + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/json_scraper_graph/openai/json_scraper_openai.py b/examples/json_scraper_graph/openai/json_scraper_openai.py new file mode 100644 index 00000000..891ec32a --- /dev/null +++ b/examples/json_scraper_graph/openai/json_scraper_openai.py @@ -0,0 +1,57 @@ +""" +Basic example of scraping pipeline using JSONScraperGraph from JSON documents +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import JSONScraperGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +load_dotenv() + +# ************************************************ +# Read the JSON file +# ************************************************ + +FILE_NAME = "inputs/example.json" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, +} + +# ************************************************ +# Create the JSONScraperGraph instance and run it +# ************************************************ + +json_scraper_graph = JSONScraperGraph( + prompt="List me all the authors, title and genres of the books", + source=text, # Pass the content of the file, not the file object + config=graph_config +) + +result = json_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = json_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/json_scraper_graph/openai/md_scraper_openai.py b/examples/json_scraper_graph/openai/md_scraper_openai.py new file mode 100644 index 00000000..118e7d59 --- /dev/null +++ b/examples/json_scraper_graph/openai/md_scraper_openai.py @@ -0,0 +1,57 @@ +""" +Basic example of scraping pipeline using DocumentScraperGraph from MD documents +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import DocumentScraperGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +load_dotenv() + +# ************************************************ +# Read the MD file +# ************************************************ + +FILE_NAME = "inputs/markdown_example.md" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, +} + +# ************************************************ +# Create the DocumentScraperGraph instance and run it +# ************************************************ + +md_scraper_graph = DocumentScraperGraph( + prompt="List me all the projects", + source=text, # Pass the content of the file, not the file object + config=graph_config +) + +result = md_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = md_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/json_scraper_graph/openai/omni_scraper_openai.py b/examples/json_scraper_graph/openai/omni_scraper_openai.py new file mode 100644 index 00000000..61da3b6a --- /dev/null +++ b/examples/json_scraper_graph/openai/omni_scraper_openai.py @@ -0,0 +1,47 @@ +""" +Basic example of scraping pipeline using OmniScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import OmniScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": True, + "max_images": 5 +} + +# ************************************************ +# Create the OmniScraperGraph instance and run it +# ************************************************ + +omni_scraper_graph = OmniScraperGraph( + prompt="List me all the projects with their titles and image links and descriptions.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = omni_scraper_graph.run() +print(json.dumps(result, indent=2)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = omni_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/omni_scraper_graph/.env.example b/examples/omni_scraper_graph/.env.example new file mode 100644 index 00000000..d5bb1b4d --- /dev/null +++ b/examples/omni_scraper_graph/.env.example @@ -0,0 +1,13 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Omni Scraper Settings +DEFAULT_FORMAT=auto +TIMEOUT=60 +MAX_RETRIES=3 +USER_AGENT=Mozilla/5.0 \ No newline at end of file diff --git a/examples/omni_scraper_graph/README.md b/examples/omni_scraper_graph/README.md new file mode 100644 index 00000000..da5ab652 --- /dev/null +++ b/examples/omni_scraper_graph/README.md @@ -0,0 +1,30 @@ +# Omni Scraper Graph Example + +This example demonstrates how to use Scrapegraph-ai for universal web scraping across multiple data formats. + +## Features + +- Multi-format data extraction (JSON, XML, HTML, CSV) +- Automatic format detection +- Unified data output +- Content transformation + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import OmniScraperGraph + +graph = OmniScraperGraph() +data = graph.scrape("https://example.com/data") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/omni_scraper_graph/omni_search_openai.py b/examples/omni_scraper_graph/omni_search_openai.py new file mode 100644 index 00000000..a6fdb266 --- /dev/null +++ b/examples/omni_scraper_graph/omni_search_openai.py @@ -0,0 +1,45 @@ +""" +Example of OmniSearchGraph +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import OmniSearchGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "max_results": 2, + "max_images": 1, + "verbose": True, +} + +# ************************************************ +# Create the OmniSearchGraph instance and run it +# ************************************************ + +omni_search_graph = OmniSearchGraph( + prompt="List me all Chioggia's famous dishes and describe their pictures.", + config=graph_config +) + +result = omni_search_graph.run() +print(json.dumps(result, indent=2)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = omni_search_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/readme.md b/examples/readme.md new file mode 100644 index 00000000..1d7b375f --- /dev/null +++ b/examples/readme.md @@ -0,0 +1,32 @@ +# Scrapegraph-ai Examples + +This directory contains various example implementations of Scrapegraph-ai for different use cases. + +If you want more specific examples, visit [this](https://github.com/ScrapeGraphAI/ScrapegraphLib-Examples). + +## Available Examples + +- `smart_scraper/` - Advanced web scraping with intelligent content extraction +- `depth_search_graph/` - Deep web crawling and content exploration +- `csv_scraper_graph/` - Scraping and processing data into CSV format +- `xml_scraper_graph/` - XML data extraction and processing +- `speech_graph/` - Speech processing and analysis +- `omni_scraper_graph/` - Universal web scraping for multiple data types +- `omni_search_graph/` - Comprehensive search across multiple sources +- `document_scraper_graph/` - Document parsing and data extraction +- `script_generator_graph/` - Automated script generation +- `custom_graph/` - Custom graph implementation examples +- `code_generator_graph/` - Code generation utilities +- `json_scraper_graph/` - JSON data extraction and processing +- `search_graph/` - Web search and data retrieval + +## Getting Started + +1. Choose the example that best fits your use case +2. Navigate to the corresponding directory +3. Follow the README instructions in each directory +4. Configure any required environment variables using the provided `.env.example` files + +## Requirements + +Each example may have its own specific requirements. Please refer to the individual README files in each directory for detailed setup instructions. diff --git a/examples/script_generator_graph/.env.example b/examples/script_generator_graph/.env.example new file mode 100644 index 00000000..216ab8a7 --- /dev/null +++ b/examples/script_generator_graph/.env.example @@ -0,0 +1,13 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Script Generator Settings +DEFAULT_LANGUAGE=python +INCLUDE_COMMENTS=true +ADD_TYPE_HINTS=true +CODE_STYLE=pep8 \ No newline at end of file diff --git a/examples/script_generator_graph/README.md b/examples/script_generator_graph/README.md new file mode 100644 index 00000000..7d1495c6 --- /dev/null +++ b/examples/script_generator_graph/README.md @@ -0,0 +1,30 @@ +# Script Generator Graph Example + +This example demonstrates how to use Scrapegraph-ai to generate automation scripts based on data analysis. + +## Features + +- Automated script generation +- Task automation +- Code optimization +- Multiple language support + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import ScriptGeneratorGraph + +graph = ScriptGeneratorGraph() +script = graph.generate("task description") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/script_generator_graph/ollama/script_generator_ollama.py b/examples/script_generator_graph/ollama/script_generator_ollama.py new file mode 100644 index 00000000..caa0455c --- /dev/null +++ b/examples/script_generator_graph/ollama/script_generator_ollama.py @@ -0,0 +1,40 @@ +""" +Basic example of scraping pipeline using ScriptCreatorGraph +""" +from scrapegraphai.graphs import ScriptCreatorGraph +from scrapegraphai.utils import prettify_exec_info +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0.5, + # "model_tokens": 2000, # set context length arbitrarily, + "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "library": "beautifoulsoup", + "verbose": True, +} + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +smart_scraper_graph = ScriptCreatorGraph( + prompt="List me all the news with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/script_generator_graph/ollama/script_multi_generator_ollama.py b/examples/script_generator_graph/ollama/script_multi_generator_ollama.py new file mode 100644 index 00000000..d94faba6 --- /dev/null +++ b/examples/script_generator_graph/ollama/script_multi_generator_ollama.py @@ -0,0 +1,55 @@ +""" +Basic example of scraping pipeline using ScriptCreatorGraph +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import ScriptCreatorMultiGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/mistral", + "temperature": 0, + # "model_tokens": 2000, # set context length arbitrarily, + "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "library": "beautifoulsoup", + "verbose": True, +} + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +urls=[ + "https://schultzbergagency.com/emil-raste-karlsen/", + "https://schultzbergagency.com/johanna-hedberg/", +] + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +script_creator_graph = ScriptCreatorMultiGraph( + prompt="Find information about actors", + # also accepts a string with the already downloaded HTML code + source=urls, + config=graph_config +) + +result = script_creator_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = script_creator_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/script_generator_graph/openai/script_generator_multi_openai.py b/examples/script_generator_graph/openai/script_generator_multi_openai.py new file mode 100644 index 00000000..19eacf66 --- /dev/null +++ b/examples/script_generator_graph/openai/script_generator_multi_openai.py @@ -0,0 +1,54 @@ +""" +Basic example of scraping pipeline using ScriptCreatorGraph +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import ScriptCreatorMultiGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "library": "beautifulsoup", + "verbose": True, +} + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +urls=[ + "https://schultzbergagency.com/emil-raste-karlsen/", + "https://schultzbergagency.com/johanna-hedberg/", +] + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +script_creator_graph = ScriptCreatorMultiGraph( + prompt="Find information about actors", + # also accepts a string with the already downloaded HTML code + source=urls, + config=graph_config +) + +result = script_creator_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = script_creator_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/script_generator_graph/openai/script_generator_openai.py b/examples/script_generator_graph/openai/script_generator_openai.py new file mode 100644 index 00000000..611acc57 --- /dev/null +++ b/examples/script_generator_graph/openai/script_generator_openai.py @@ -0,0 +1,46 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import ScriptCreatorGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "library": "beautifulsoup", + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = ScriptCreatorGraph( + prompt="List me all the news with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/script_generator_graph/openai/script_generator_schema_openai.py b/examples/script_generator_graph/openai/script_generator_schema_openai.py new file mode 100644 index 00000000..adb646d1 --- /dev/null +++ b/examples/script_generator_graph/openai/script_generator_schema_openai.py @@ -0,0 +1,60 @@ +""" +Basic example of scraping pipeline using ScriptCreatorGraph +""" +import os +from typing import List +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from scrapegraphai.graphs import ScriptCreatorGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the schema for the graph +# ************************************************ + +class Project(BaseModel): + title: str = Field(description="The title of the project") + description: str = Field(description="The description of the project") + +class Projects(BaseModel): + projects: List[Project] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o" + }, + "library": "beautifulsoup", + "verbose": True, +} + +# ************************************************ +# Create the ScriptCreatorGraph instance and run it +# ************************************************ + +script_creator_graph = ScriptCreatorGraph( + prompt="List me all the projects with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects", + config=graph_config, + schema=Projects +) + +result = script_creator_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = script_creator_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + diff --git a/examples/search_graph/.env.example b/examples/search_graph/.env.example new file mode 100644 index 00000000..a4b25c88 --- /dev/null +++ b/examples/search_graph/.env.example @@ -0,0 +1,11 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Search API Configuration +SERP_API_KEY=your-serp-api-key-here + +# Optional Configurations +MAX_SEARCH_RESULTS=10 +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 \ No newline at end of file diff --git a/examples/search_graph/README.md b/examples/search_graph/README.md new file mode 100644 index 00000000..084c6ea2 --- /dev/null +++ b/examples/search_graph/README.md @@ -0,0 +1,31 @@ +# Search Graph Example + +This example shows how to implement a search graph for web content retrieval and analysis using Scrapegraph-ai. + +## Features + +- Web search integration +- Content relevance scoring +- Result filtering +- Data aggregation + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import SearchGraph + +graph = SearchGraph() +results = graph.search("your search query") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key +- `SERP_API_KEY`: Your SERP API key (optional) \ No newline at end of file diff --git a/examples/search_graph/ollama/search_graph_ollama.py b/examples/search_graph/ollama/search_graph_ollama.py new file mode 100644 index 00000000..039ca00e --- /dev/null +++ b/examples/search_graph/ollama/search_graph_ollama.py @@ -0,0 +1,44 @@ +""" +Example of Search Graph +""" +from scrapegraphai.graphs import SearchGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + # "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "max_results": 5, + "verbose": True, +} + +# ************************************************ +# Create the SearchGraph instance and run it +# ************************************************ + +search_graph = SearchGraph( + prompt="List me the best escursions near Trento", + config=graph_config +) + +result = search_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = search_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json and csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/search_graph/ollama/search_graph_schema_ollama.py b/examples/search_graph/ollama/search_graph_schema_ollama.py new file mode 100644 index 00000000..fb87954f --- /dev/null +++ b/examples/search_graph/ollama/search_graph_schema_ollama.py @@ -0,0 +1,58 @@ +""" +Example of Search Graph +""" +from scrapegraphai.graphs import SearchGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +from pydantic import BaseModel, Field +from typing import List + +# ************************************************ +# Define the output schema for the graph +# ************************************************ + +class Dish(BaseModel): + name: str = Field(description="The name of the dish") + description: str = Field(description="The description of the dish") + +class Dishes(BaseModel): + dishes: List[Dish] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/mistral", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "verbose": True, + "headless": False +} + +# ************************************************ +# Create the SearchGraph instance and run it +# ************************************************ + +search_graph = SearchGraph( + prompt="List me Chioggia's famous dishes", + config=graph_config, + schema=Dishes +) + +result = search_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = search_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json and csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/openai/search_graph_openai.py b/examples/search_graph/openai/search_graph_openai.py similarity index 100% rename from examples/openai/search_graph_openai.py rename to examples/search_graph/openai/search_graph_openai.py diff --git a/examples/search_graph/openai/search_graph_schema_openai.py b/examples/search_graph/openai/search_graph_schema_openai.py new file mode 100644 index 00000000..3109cc79 --- /dev/null +++ b/examples/search_graph/openai/search_graph_schema_openai.py @@ -0,0 +1,61 @@ +""" +Example of Search Graph +""" +import os +from typing import List +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from scrapegraphai.graphs import SearchGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the output schema for the graph +# ************************************************ + +class Dish(BaseModel): + name: str = Field(description="The name of the dish") + description: str = Field(description="The description of the dish") + +class Dishes(BaseModel): + dishes: List[Dish] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o" + }, + "max_results": 2, + "verbose": True, +} + +# ************************************************ +# Create the SearchGraph instance and run it +# ************************************************ + +search_graph = SearchGraph( + prompt="List me Chioggia's famous dishes", + config=graph_config, + schema=Dishes +) + +result = search_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = search_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json and csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/search_graph/openai/search_link_graph_openai.py b/examples/search_graph/openai/search_link_graph_openai.py new file mode 100644 index 00000000..f7436159 --- /dev/null +++ b/examples/search_graph/openai/search_link_graph_openai.py @@ -0,0 +1,42 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import SearchLinkGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SearchLinkGraph instance and run it +# ************************************************ + +smart_scraper_graph = SearchLinkGraph( + source="https://sport.sky.it/nba?gr=www", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/smart_scraper/.env.example b/examples/smart_scraper/.env.example new file mode 100644 index 00000000..7d2c49c0 --- /dev/null +++ b/examples/smart_scraper/.env.example @@ -0,0 +1,7 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 \ No newline at end of file diff --git a/examples/smart_scraper/README.md b/examples/smart_scraper/README.md new file mode 100644 index 00000000..ba4f638c --- /dev/null +++ b/examples/smart_scraper/README.md @@ -0,0 +1,30 @@ +# Smart Scraper Example + +This example demonstrates how to use Scrapegraph-ai for intelligent web scraping with automatic content detection and extraction. + +## Features + +- Intelligent content detection +- Automatic data extraction +- Content classification +- Clean data output + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your OpenAI API key in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import SmartScraperGraph + +graph = SmartScraperGraph() +results = graph.scrape("https://example.com") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/smart_scraper/ollama/smart_scraper_lite_ollama.py b/examples/smart_scraper/ollama/smart_scraper_lite_ollama.py new file mode 100644 index 00000000..2cf6c402 --- /dev/null +++ b/examples/smart_scraper/ollama/smart_scraper_lite_ollama.py @@ -0,0 +1,30 @@ +""" +Basic example of scraping pipeline using SmartScraper + +""" +import json +from scrapegraphai.graphs import SmartScraperLiteGraph +from scrapegraphai.utils import prettify_exec_info + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", + "base_url": "http://localhost:11434", + }, + "verbose": True, + "headless": False +} + +smart_scraper_lite_graph = SmartScraperLiteGraph( + prompt="Who is Marco Perini?", + source="https://perinim.github.io/", + config=graph_config +) + +result = smart_scraper_lite_graph.run() +print(json.dumps(result, indent=4)) + +graph_exec_info = smart_scraper_lite_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py b/examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py new file mode 100644 index 00000000..665b5db4 --- /dev/null +++ b/examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py @@ -0,0 +1,42 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperMultiConcatGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "verbose": True, + "headless": False +} + +# ******************************************************* +# Create the SmartScraperMultiGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperMultiConcatGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py b/examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py new file mode 100644 index 00000000..f09c4cb4 --- /dev/null +++ b/examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py @@ -0,0 +1,45 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import json +from scrapegraphai.graphs import SmartScraperMultiLiteGraph +from scrapegraphai.utils import prettify_exec_info + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "verbose": True, + "headless": False +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + config=graph_config +) + +result = smart_scraper_multi_lite_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_ollama.py b/examples/smart_scraper/ollama/smart_scraper_multi_ollama.py new file mode 100644 index 00000000..c9d49793 --- /dev/null +++ b/examples/smart_scraper/ollama/smart_scraper_multi_ollama.py @@ -0,0 +1,39 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import json +from scrapegraphai.graphs import SmartScraperMultiGraph + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + + "verbose": True, + "headless": False +} + + +# ******************************************************* +# Create the SmartScraperMultiGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperMultiGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/local_models/smart_scraper_ollama.py b/examples/smart_scraper/ollama/smart_scraper_ollama.py similarity index 100% rename from examples/local_models/smart_scraper_ollama.py rename to examples/smart_scraper/ollama/smart_scraper_ollama.py diff --git a/examples/smart_scraper/ollama/smart_scraper_schema_ollama.py b/examples/smart_scraper/ollama/smart_scraper_schema_ollama.py new file mode 100644 index 00000000..5a5b3cea --- /dev/null +++ b/examples/smart_scraper/ollama/smart_scraper_schema_ollama.py @@ -0,0 +1,43 @@ +""" +Basic example of scraping pipeline using SmartScraper with schema +""" +import json +from typing import List +from pydantic import BaseModel, Field +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +class Project(BaseModel): + title: str = Field(description="The title of the project") + description: str = Field(description="The description of the project") + +class Projects(BaseModel): + projects: List[Project] + +graph_config = { + "llm": { + "model": "ollama/llama3.1", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "verbose": True, + "headless": False +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description", + source="https://perinim.github.io/projects/", + schema=Projects, + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/smart_scraper/openai/smart_scraper_lite_openai.py b/examples/smart_scraper/openai/smart_scraper_lite_openai.py new file mode 100644 index 00000000..5de725bb --- /dev/null +++ b/examples/smart_scraper/openai/smart_scraper_lite_openai.py @@ -0,0 +1,32 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperLiteGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} + +smart_scraper_lite_graph = SmartScraperLiteGraph( + prompt="Who is Marco Perini?", + source="https://perinim.github.io/", + config=graph_config +) + +result = smart_scraper_lite_graph.run() +print(json.dumps(result, indent=4)) + +graph_exec_info = smart_scraper_lite_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + diff --git a/examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py b/examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py new file mode 100644 index 00000000..650971f1 --- /dev/null +++ b/examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py @@ -0,0 +1,40 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperMultiConcatGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} + +# ******************************************************* +# Create the SmartScraperMultiGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperMultiConcatGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py b/examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py new file mode 100644 index 00000000..69eeafc7 --- /dev/null +++ b/examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py @@ -0,0 +1,47 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperMultiLiteGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + config=graph_config +) + +result = smart_scraper_multi_lite_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/smart_scraper/openai/smart_scraper_multi_openai.py b/examples/smart_scraper/openai/smart_scraper_multi_openai.py new file mode 100644 index 00000000..ba889c96 --- /dev/null +++ b/examples/smart_scraper/openai/smart_scraper_multi_openai.py @@ -0,0 +1,41 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperMultiGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} + +# ******************************************************* +# Create the SmartScraperMultiGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperMultiGraph( + prompt="Who is Marco Perini?", + source= [ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/openai/smart_scraper_openai.py b/examples/smart_scraper/openai/smart_scraper_openai.py similarity index 100% rename from examples/openai/smart_scraper_openai.py rename to examples/smart_scraper/openai/smart_scraper_openai.py diff --git a/examples/smart_scraper/openai/smart_scraper_schema_openai.py b/examples/smart_scraper/openai/smart_scraper_schema_openai.py new file mode 100644 index 00000000..32e8891a --- /dev/null +++ b/examples/smart_scraper/openai/smart_scraper_schema_openai.py @@ -0,0 +1,50 @@ +""" +Basic example of scraping pipeline using SmartScraper with schema +""" +import os +from typing import List +from dotenv import load_dotenv +from pydantic import BaseModel, Field +from scrapegraphai.graphs import SmartScraperGraph + +load_dotenv() + +# ************************************************ +# Define the output schema for the graph +# ************************************************ + +class Project(BaseModel): + title: str = Field(description="The title of the project") + description: str = Field(description="The description of the project") + +class Projects(BaseModel): + projects: List[Project] + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o-mini", + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description", + source="https://perinim.github.io/projects/", + schema=Projects, + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) diff --git a/examples/speech_graph/.env.example b/examples/speech_graph/.env.example new file mode 100644 index 00000000..93aa505d --- /dev/null +++ b/examples/speech_graph/.env.example @@ -0,0 +1,14 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Whisper API Configuration (Optional) +WHISPER_API_KEY=your-whisper-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# Speech Settings +AUDIO_FORMAT=mp3 +SAMPLE_RATE=16000 \ No newline at end of file diff --git a/examples/speech_graph/README.md b/examples/speech_graph/README.md new file mode 100644 index 00000000..35be155f --- /dev/null +++ b/examples/speech_graph/README.md @@ -0,0 +1,31 @@ +# Speech Graph Example + +This example demonstrates how to use Scrapegraph-ai for speech processing and analysis. + +## Features + +- Speech-to-text conversion +- Audio processing +- Text analysis +- Sentiment analysis + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import SpeechGraph + +graph = SpeechGraph() +text = graph.process("audio_file.mp3") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key +- `WHISPER_API_KEY`: Your Whisper API key (optional) \ No newline at end of file diff --git a/examples/openai/speech_graph_openai.py b/examples/speech_graph/speech_graph_openai.py similarity index 100% rename from examples/openai/speech_graph_openai.py rename to examples/speech_graph/speech_graph_openai.py diff --git a/examples/xml_scraper_graph/.env.example b/examples/xml_scraper_graph/.env.example new file mode 100644 index 00000000..9f0d484b --- /dev/null +++ b/examples/xml_scraper_graph/.env.example @@ -0,0 +1,11 @@ +# OpenAI API Configuration +OPENAI_API_KEY=your-openai-api-key-here + +# Optional Configurations +MAX_TOKENS=4000 +MODEL_NAME=gpt-4-1106-preview +TEMPERATURE=0.7 + +# XML Scraper Settings +XPATH_TIMEOUT=30 +VALIDATE_XML=true \ No newline at end of file diff --git a/examples/xml_scraper_graph/README.md b/examples/xml_scraper_graph/README.md new file mode 100644 index 00000000..ed7eaf30 --- /dev/null +++ b/examples/xml_scraper_graph/README.md @@ -0,0 +1,30 @@ +# XML Scraper Graph Example + +This example demonstrates how to use Scrapegraph-ai to extract and process XML data from web sources. + +## Features + +- XML data extraction +- XPath querying +- Data transformation +- Schema validation + +## Setup + +1. Install required dependencies +2. Copy `.env.example` to `.env` +3. Configure your API keys in the `.env` file + +## Usage + +```python +from scrapegraphai.graphs import XmlScraperGraph + +graph = XmlScraperGraph() +xml_data = graph.scrape("https://example.com/feed.xml") +``` + +## Environment Variables + +Required environment variables: +- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file diff --git a/examples/xml_scraper_graph/ollama/inputs/books.xml b/examples/xml_scraper_graph/ollama/inputs/books.xml new file mode 100644 index 00000000..e3d1fe87 --- /dev/null +++ b/examples/xml_scraper_graph/ollama/inputs/books.xml @@ -0,0 +1,120 @@ + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + \ No newline at end of file diff --git a/examples/xml_scraper_graph/ollama/xml_scraper_graph_multi_ollama.py b/examples/xml_scraper_graph/ollama/xml_scraper_graph_multi_ollama.py new file mode 100644 index 00000000..0494ff2c --- /dev/null +++ b/examples/xml_scraper_graph/ollama/xml_scraper_graph_multi_ollama.py @@ -0,0 +1,58 @@ +""" +Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents +""" + +import os +from scrapegraphai.graphs import XMLScraperMultiGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +# ************************************************ +# Read the XML file +# ************************************************ + +FILE_NAME = "inputs/books.xml" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + + "verbose": True, +} + +# ************************************************ +# Create the XMLScraperMultiGraph instance and run it +# ************************************************ + +xml_scraper_graph = XMLScraperMultiGraph( + prompt="List me all the authors, title and genres of the books", + source=[text, text], # Pass the content of the file, not the file object + config=graph_config +) + +result = xml_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = xml_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/xml_scraper_graph/ollama/xml_scraper_ollama.py b/examples/xml_scraper_graph/ollama/xml_scraper_ollama.py new file mode 100644 index 00000000..50c4f8e7 --- /dev/null +++ b/examples/xml_scraper_graph/ollama/xml_scraper_ollama.py @@ -0,0 +1,58 @@ +""" +Basic example of scraping pipeline using XMLScraperGraph from XML documents +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import XMLScraperGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +load_dotenv() + +# ************************************************ +# Read the XML file +# ************************************************ + +FILE_NAME = "inputs/books.xml" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + # "model_tokens": 2000, # set context length arbitrarily + "base_url": "http://localhost:11434", + }, + "verbose": True, +} + +# ************************************************ +# Create the XMLScraperGraph instance and run it +# ************************************************ + +xml_scraper_graph = XMLScraperGraph( + prompt="List me all the authors, title and genres of the books", + source=text, # Pass the content of the file, not the file object + config=graph_config +) + +result = xml_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = xml_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/xml_scraper_graph/openai/inputs/books.xml b/examples/xml_scraper_graph/openai/inputs/books.xml new file mode 100644 index 00000000..e3d1fe87 --- /dev/null +++ b/examples/xml_scraper_graph/openai/inputs/books.xml @@ -0,0 +1,120 @@ + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + \ No newline at end of file diff --git a/examples/xml_scraper_graph/openai/xml_scraper_graph_multi_openai.py b/examples/xml_scraper_graph/openai/xml_scraper_graph_multi_openai.py new file mode 100644 index 00000000..3604489b --- /dev/null +++ b/examples/xml_scraper_graph/openai/xml_scraper_graph_multi_openai.py @@ -0,0 +1,58 @@ +""" +Basic example of scraping pipeline using XMLScraperMultiGraph from XML documents +""" +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import XMLScraperMultiGraph +from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info + +load_dotenv() + +# ************************************************ +# Read the XML file +# ************************************************ + +FILE_NAME = "inputs/books.xml" +curr_dir = os.path.dirname(os.path.realpath(__file__)) +file_path = os.path.join(curr_dir, FILE_NAME) + +with open(file_path, 'r', encoding="utf-8") as file: + text = file.read() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key":openai_key, + "model": "openai/gpt-4o", + }, + "verbose": True, + "headless": False, +} +# ************************************************ +# Create the XMLScraperMultiGraph instance and run it +# ************************************************ + +xml_scraper_graph = XMLScraperMultiGraph( + prompt="List me all the authors, title and genres of the books", + source=[text, text], # Pass the content of the file, not the file object + config=graph_config +) + +result = xml_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = xml_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) + +# Save to json or csv +convert_to_csv(result, "result") +convert_to_json(result, "result") diff --git a/examples/openai/xml_scraper_openai.py b/examples/xml_scraper_graph/openai/xml_scraper_openai.py similarity index 100% rename from examples/openai/xml_scraper_openai.py rename to examples/xml_scraper_graph/openai/xml_scraper_openai.py From 14b4b19f60e33c855bee4eea0a1a6fcc01a98c1a Mon Sep 17 00:00:00 2001 From: PeriniM Date: Wed, 8 Jan 2025 04:16:38 +0100 Subject: [PATCH 3/9] docs: improved readme + fix csv scraper imports --- .../ollama/csv_scraper_graph_multi_ollama.py | 13 ++-- .../ollama/csv_scraper_ollama.py | 13 ++-- .../openai/csv_scraper_graph_multi_openai.py | 17 +++-- .../openai/csv_scraper_openai.py | 15 ++-- examples/readme.md | 68 +++++++++++++------ .../.env.example | 2 +- .../README.md | 2 +- .../ollama/smart_scraper_lite_ollama.py | 8 ++- .../smart_scraper_multi_concat_ollama.py | 16 ++--- .../ollama/smart_scraper_multi_lite_ollama.py | 14 ++-- .../ollama/smart_scraper_multi_ollama.py | 13 ++-- .../ollama/smart_scraper_ollama.py | 0 .../ollama/smart_scraper_schema_ollama.py | 19 +++++- .../openai/smart_scraper_lite_openai.py | 10 +-- .../smart_scraper_multi_concat_openai.py | 14 ++-- .../openai/smart_scraper_multi_lite_openai.py | 14 ++-- .../openai/smart_scraper_multi_openai.py | 14 ++-- .../openai/smart_scraper_openai.py | 0 .../openai/smart_scraper_schema_openai.py | 10 ++- 19 files changed, 150 insertions(+), 112 deletions(-) rename examples/{smart_scraper => smart_scraper_graph}/.env.example (89%) rename examples/{smart_scraper => smart_scraper_graph}/README.md (93%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_lite_ollama.py (92%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_multi_concat_ollama.py (78%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_multi_lite_ollama.py (88%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_multi_ollama.py (85%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_ollama.py (100%) rename examples/{smart_scraper => smart_scraper_graph}/ollama/smart_scraper_schema_ollama.py (81%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_lite_openai.py (95%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_multi_concat_openai.py (86%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_multi_lite_openai.py (89%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_multi_openai.py (86%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_openai.py (100%) rename examples/{smart_scraper => smart_scraper_graph}/openai/smart_scraper_schema_openai.py (97%) diff --git a/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py b/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py index fb6bce51..558a876f 100644 --- a/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py +++ b/examples/csv_scraper_graph/ollama/csv_scraper_graph_multi_ollama.py @@ -3,9 +3,9 @@ """ import os -import pandas as pd + from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +from scrapegraphai.utils import prettify_exec_info # ************************************************ # Read the CSV file @@ -15,7 +15,8 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -text = pd.read_csv(file_path) +with open(file_path, "r") as file: + text = file.read() # ************************************************ # Define the configuration for the graph @@ -44,7 +45,7 @@ csv_scraper_graph = CSVScraperMultiGraph( prompt="List me all the last names", source=[str(text), str(text)], - config=graph_config + config=graph_config, ) result = csv_scraper_graph.run() @@ -56,7 +57,3 @@ graph_exec_info = csv_scraper_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py b/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py index 8d1edbd7..d6e6eab2 100644 --- a/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py +++ b/examples/csv_scraper_graph/ollama/csv_scraper_ollama.py @@ -3,9 +3,9 @@ """ import os -import pandas as pd + from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +from scrapegraphai.utils import prettify_exec_info # ************************************************ # Read the CSV file @@ -15,7 +15,8 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -text = pd.read_csv(file_path) +with open(file_path, "r") as file: + text = file.read() # ************************************************ # Define the configuration for the graph @@ -44,7 +45,7 @@ csv_scraper_graph = CSVScraperGraph( prompt="List me all the last names", source=str(text), # Pass the content of the file, not the file object - config=graph_config + config=graph_config, ) result = csv_scraper_graph.run() @@ -56,7 +57,3 @@ graph_exec_info = csv_scraper_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py b/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py index 6ed33c90..b7bc83ae 100644 --- a/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py +++ b/examples/csv_scraper_graph/openai/csv_scraper_graph_multi_openai.py @@ -1,11 +1,13 @@ """ Basic example of scraping pipeline using CSVScraperMultiGraph from CSV documents """ + import os + from dotenv import load_dotenv -import pandas as pd + from scrapegraphai.graphs import CSVScraperMultiGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +from scrapegraphai.utils import prettify_exec_info load_dotenv() # ************************************************ @@ -16,7 +18,8 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -text = pd.read_csv(file_path) +with open(file_path, "r") as file: + text = file.read() # ************************************************ # Define the configuration for the graph @@ -24,7 +27,7 @@ openai_key = os.getenv("OPENAI_APIKEY") graph_config = { - "llm": { + "llm": { "api_key": openai_key, "model": "openai/gpt-4o", }, @@ -37,7 +40,7 @@ csv_scraper_graph = CSVScraperMultiGraph( prompt="List me all the last names", source=[str(text), str(text)], - config=graph_config + config=graph_config, ) result = csv_scraper_graph.run() @@ -49,7 +52,3 @@ graph_exec_info = csv_scraper_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/csv_scraper_graph/openai/csv_scraper_openai.py b/examples/csv_scraper_graph/openai/csv_scraper_openai.py index d9527b86..a0abd714 100644 --- a/examples/csv_scraper_graph/openai/csv_scraper_openai.py +++ b/examples/csv_scraper_graph/openai/csv_scraper_openai.py @@ -1,11 +1,13 @@ """ Basic example of scraping pipeline using CSVScraperGraph from CSV documents """ + import os + from dotenv import load_dotenv -import pandas as pd + from scrapegraphai.graphs import CSVScraperGraph -from scrapegraphai.utils import convert_to_csv, convert_to_json, prettify_exec_info +from scrapegraphai.utils import prettify_exec_info load_dotenv() @@ -17,7 +19,8 @@ curr_dir = os.path.dirname(os.path.realpath(__file__)) file_path = os.path.join(curr_dir, FILE_NAME) -text = pd.read_csv(file_path) +with open(file_path, "r") as file: + text = file.read() # ************************************************ # Define the configuration for the graph @@ -39,7 +42,7 @@ csv_scraper_graph = CSVScraperGraph( prompt="List me all the last names", source=str(text), # Pass the content of the file, not the file object - config=graph_config + config=graph_config, ) result = csv_scraper_graph.run() @@ -51,7 +54,3 @@ graph_exec_info = csv_scraper_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - -# Save to json or csv -convert_to_csv(result, "result") -convert_to_json(result, "result") diff --git a/examples/readme.md b/examples/readme.md index 1d7b375f..1a5aae8b 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -1,32 +1,62 @@ -# Scrapegraph-ai Examples +# 🕷️ Scrapegraph-ai Examples -This directory contains various example implementations of Scrapegraph-ai for different use cases. +This directory contains various example implementations of Scrapegraph-ai for different use cases. Each example demonstrates how to leverage the power of Scrapegraph-ai for specific scenarios. -If you want more specific examples, visit [this](https://github.com/ScrapeGraphAI/ScrapegraphLib-Examples). +> **Note:** While these examples showcase implementations using OpenAI and Ollama, Scrapegraph-ai supports many other LLM providers! Check out our [documentation](https://docs-oss.scrapegraphai.com/examples) for the full list of supported providers. -## Available Examples +## 📚 Available Examples -- `smart_scraper/` - Advanced web scraping with intelligent content extraction -- `depth_search_graph/` - Deep web crawling and content exploration -- `csv_scraper_graph/` - Scraping and processing data into CSV format -- `xml_scraper_graph/` - XML data extraction and processing -- `speech_graph/` - Speech processing and analysis -- `omni_scraper_graph/` - Universal web scraping for multiple data types -- `omni_search_graph/` - Comprehensive search across multiple sources -- `document_scraper_graph/` - Document parsing and data extraction -- `script_generator_graph/` - Automated script generation -- `custom_graph/` - Custom graph implementation examples -- `code_generator_graph/` - Code generation utilities -- `json_scraper_graph/` - JSON data extraction and processing -- `search_graph/` - Web search and data retrieval +- 🧠 `smart_scraper/` - Advanced web scraping with intelligent content extraction +- 🔎 `search_graph/` - Web search and data retrieval +- ⚙️ `script_generator_graph/` - Automated script generation +- 🌐 `depth_search_graph/` - Deep web crawling and content exploration +- 📊 `csv_scraper_graph/` - Scraping and processing data into CSV format +- 📑 `xml_scraper_graph/` - XML data extraction and processing +- 🎤 `speech_graph/` - Speech processing and analysis +- 🔄 `omni_scraper_graph/` - Universal web scraping for multiple data types +- 🔍 `omni_search_graph/` - Comprehensive search across multiple sources +- 📄 `document_scraper_graph/` - Document parsing and data extraction +- 🛠️ `custom_graph/` - Custom graph implementation examples +- 💻 `code_generator_graph/` - Code generation utilities +- 📋 `json_scraper_graph/` - JSON data extraction and processing -## Getting Started +## 🚀 Getting Started 1. Choose the example that best fits your use case 2. Navigate to the corresponding directory 3. Follow the README instructions in each directory 4. Configure any required environment variables using the provided `.env.example` files -## Requirements +## ⚡ Quick Setup + +```bash +pip install scrapegraphai + +playwright install + +# choose an example +cd examples/smart_scraper_graph/openai + +# run the example +python smart_scraper_openai.py +``` + +## 📋 Requirements Each example may have its own specific requirements. Please refer to the individual README files in each directory for detailed setup instructions. + +## 📚 Additional Resources + +- 📖 [Full Documentation](https://docs-oss.scrapegraphai.com/examples) +- 💡 [Examples Repository](https://github.com/ScrapeGraphAI/ScrapegraphLib-Examples) +- 🤝 [Community Support](https://github.com/ScrapeGraphAI/scrapegraph-ai/discussions) + +## 🤔 Need Help? + +- Check out our [documentation](https://docs-oss.scrapegraphai.com) +- Join our [Discord community](https://discord.gg/scrapegraphai) +- Open an [issue](https://github.com/ScrapeGraphAI/scrapegraph-ai/issues) + +--- + +⭐ Don't forget to star our repository if you find these examples helpful! diff --git a/examples/smart_scraper/.env.example b/examples/smart_scraper_graph/.env.example similarity index 89% rename from examples/smart_scraper/.env.example rename to examples/smart_scraper_graph/.env.example index 7d2c49c0..0c8d0b86 100644 --- a/examples/smart_scraper/.env.example +++ b/examples/smart_scraper_graph/.env.example @@ -4,4 +4,4 @@ OPENAI_API_KEY=your-openai-api-key-here # Optional Configurations MAX_TOKENS=4000 MODEL_NAME=gpt-4-1106-preview -TEMPERATURE=0.7 \ No newline at end of file +TEMPERATURE=0.7 diff --git a/examples/smart_scraper/README.md b/examples/smart_scraper_graph/README.md similarity index 93% rename from examples/smart_scraper/README.md rename to examples/smart_scraper_graph/README.md index ba4f638c..d5f0d564 100644 --- a/examples/smart_scraper/README.md +++ b/examples/smart_scraper_graph/README.md @@ -27,4 +27,4 @@ results = graph.scrape("https://example.com") ## Environment Variables Required environment variables: -- `OPENAI_API_KEY`: Your OpenAI API key \ No newline at end of file +- `OPENAI_API_KEY`: Your OpenAI API key diff --git a/examples/smart_scraper/ollama/smart_scraper_lite_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py similarity index 92% rename from examples/smart_scraper/ollama/smart_scraper_lite_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py index 2cf6c402..fd23f39c 100644 --- a/examples/smart_scraper/ollama/smart_scraper_lite_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py @@ -1,8 +1,10 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ + import json + from scrapegraphai.graphs import SmartScraperLiteGraph from scrapegraphai.utils import prettify_exec_info @@ -14,13 +16,13 @@ "base_url": "http://localhost:11434", }, "verbose": True, - "headless": False + "headless": False, } smart_scraper_lite_graph = SmartScraperLiteGraph( prompt="Who is Marco Perini?", source="https://perinim.github.io/", - config=graph_config + config=graph_config, ) result = smart_scraper_lite_graph.run() diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py similarity index 78% rename from examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py index 665b5db4..566be922 100644 --- a/examples/smart_scraper/ollama/smart_scraper_multi_concat_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py @@ -1,10 +1,11 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ -import os import json + from dotenv import load_dotenv + from scrapegraphai.graphs import SmartScraperMultiConcatGraph load_dotenv() @@ -18,10 +19,10 @@ "model": "ollama/llama3.1", "temperature": 0, "format": "json", # Ollama needs the format to be specified explicitly - "base_url": "http://localhost:11434", # set ollama URL arbitrarily + "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, - "headless": False + "headless": False, } # ******************************************************* @@ -30,12 +31,9 @@ multiple_search_graph = SmartScraperMultiConcatGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], schema=None, - config=graph_config + config=graph_config, ) result = multiple_search_graph.run() diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py similarity index 88% rename from examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py index f09c4cb4..90c58f9d 100644 --- a/examples/smart_scraper/ollama/smart_scraper_multi_lite_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py @@ -1,7 +1,9 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ + import json + from scrapegraphai.graphs import SmartScraperMultiLiteGraph from scrapegraphai.utils import prettify_exec_info @@ -17,7 +19,7 @@ "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, - "headless": False + "headless": False, } # ************************************************ @@ -26,11 +28,8 @@ smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], + config=graph_config, ) result = smart_scraper_multi_lite_graph.run() @@ -42,4 +41,3 @@ graph_exec_info = smart_scraper_multi_lite_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/smart_scraper/ollama/smart_scraper_multi_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py similarity index 85% rename from examples/smart_scraper/ollama/smart_scraper_multi_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py index c9d49793..c42bb627 100644 --- a/examples/smart_scraper/ollama/smart_scraper_multi_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py @@ -1,8 +1,9 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ import json + from scrapegraphai.graphs import SmartScraperMultiGraph # ************************************************ @@ -15,9 +16,8 @@ "format": "json", # Ollama needs the format to be specified explicitly # "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, - "verbose": True, - "headless": False + "headless": False, } @@ -27,12 +27,9 @@ multiple_search_graph = SmartScraperMultiGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], schema=None, - config=graph_config + config=graph_config, ) result = multiple_search_graph.run() diff --git a/examples/smart_scraper/ollama/smart_scraper_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_ollama.py similarity index 100% rename from examples/smart_scraper/ollama/smart_scraper_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_ollama.py diff --git a/examples/smart_scraper/ollama/smart_scraper_schema_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py similarity index 81% rename from examples/smart_scraper/ollama/smart_scraper_schema_ollama.py rename to examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py index 5a5b3cea..38eeaeb5 100644 --- a/examples/smart_scraper/ollama/smart_scraper_schema_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py @@ -1,12 +1,16 @@ -""" +""" Basic example of scraping pipeline using SmartScraper with schema """ + import json from typing import List + from pydantic import BaseModel, Field + from scrapegraphai.graphs import SmartScraperGraph from scrapegraphai.utils import prettify_exec_info + # ************************************************ # Define the configuration for the graph # ************************************************ @@ -14,9 +18,11 @@ class Project(BaseModel): title: str = Field(description="The title of the project") description: str = Field(description="The description of the project") + class Projects(BaseModel): projects: List[Project] + graph_config = { "llm": { "model": "ollama/llama3.1", @@ -25,7 +31,7 @@ class Projects(BaseModel): # "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, - "headless": False + "headless": False, } # ************************************************ @@ -36,8 +42,15 @@ class Projects(BaseModel): prompt="List me all the projects with their description", source="https://perinim.github.io/projects/", schema=Projects, - config=graph_config + config=graph_config, ) result = smart_scraper_graph.run() print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/smart_scraper/openai/smart_scraper_lite_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_lite_openai.py similarity index 95% rename from examples/smart_scraper/openai/smart_scraper_lite_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_lite_openai.py index 5de725bb..3d768548 100644 --- a/examples/smart_scraper/openai/smart_scraper_lite_openai.py +++ b/examples/smart_scraper_graph/openai/smart_scraper_lite_openai.py @@ -1,9 +1,12 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ -import os + import json +import os + from dotenv import load_dotenv + from scrapegraphai.graphs import SmartScraperLiteGraph from scrapegraphai.utils import prettify_exec_info @@ -21,7 +24,7 @@ smart_scraper_lite_graph = SmartScraperLiteGraph( prompt="Who is Marco Perini?", source="https://perinim.github.io/", - config=graph_config + config=graph_config, ) result = smart_scraper_lite_graph.run() @@ -29,4 +32,3 @@ graph_exec_info = smart_scraper_lite_graph.get_execution_info() print(prettify_exec_info(graph_exec_info)) - diff --git a/examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_multi_concat_openai.py similarity index 86% rename from examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_multi_concat_openai.py index 650971f1..4774e620 100644 --- a/examples/smart_scraper/openai/smart_scraper_multi_concat_openai.py +++ b/examples/smart_scraper_graph/openai/smart_scraper_multi_concat_openai.py @@ -1,9 +1,12 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ -import os + import json +import os + from dotenv import load_dotenv + from scrapegraphai.graphs import SmartScraperMultiConcatGraph load_dotenv() @@ -28,12 +31,9 @@ multiple_search_graph = SmartScraperMultiConcatGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], schema=None, - config=graph_config + config=graph_config, ) result = multiple_search_graph.run() diff --git a/examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_multi_lite_openai.py similarity index 89% rename from examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_multi_lite_openai.py index 69eeafc7..acc970be 100644 --- a/examples/smart_scraper/openai/smart_scraper_multi_lite_openai.py +++ b/examples/smart_scraper_graph/openai/smart_scraper_multi_lite_openai.py @@ -1,9 +1,12 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ -import os + import json +import os + from dotenv import load_dotenv + from scrapegraphai.graphs import SmartScraperMultiLiteGraph from scrapegraphai.utils import prettify_exec_info @@ -29,11 +32,8 @@ smart_scraper_multi_lite_graph = SmartScraperMultiLiteGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], - config=graph_config + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], + config=graph_config, ) result = smart_scraper_multi_lite_graph.run() diff --git a/examples/smart_scraper/openai/smart_scraper_multi_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_multi_openai.py similarity index 86% rename from examples/smart_scraper/openai/smart_scraper_multi_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_multi_openai.py index ba889c96..ec510fc2 100644 --- a/examples/smart_scraper/openai/smart_scraper_multi_openai.py +++ b/examples/smart_scraper_graph/openai/smart_scraper_multi_openai.py @@ -1,9 +1,12 @@ -""" +""" Basic example of scraping pipeline using SmartScraper """ -import os + import json +import os + from dotenv import load_dotenv + from scrapegraphai.graphs import SmartScraperMultiGraph load_dotenv() @@ -29,12 +32,9 @@ multiple_search_graph = SmartScraperMultiGraph( prompt="Who is Marco Perini?", - source= [ - "https://perinim.github.io/", - "https://perinim.github.io/cv/" - ], + source=["https://perinim.github.io/", "https://perinim.github.io/cv/"], schema=None, - config=graph_config + config=graph_config, ) result = multiple_search_graph.run() diff --git a/examples/smart_scraper/openai/smart_scraper_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_openai.py similarity index 100% rename from examples/smart_scraper/openai/smart_scraper_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_openai.py diff --git a/examples/smart_scraper/openai/smart_scraper_schema_openai.py b/examples/smart_scraper_graph/openai/smart_scraper_schema_openai.py similarity index 97% rename from examples/smart_scraper/openai/smart_scraper_schema_openai.py rename to examples/smart_scraper_graph/openai/smart_scraper_schema_openai.py index 32e8891a..3a75bd5a 100644 --- a/examples/smart_scraper/openai/smart_scraper_schema_openai.py +++ b/examples/smart_scraper_graph/openai/smart_scraper_schema_openai.py @@ -1,10 +1,13 @@ -""" +""" Basic example of scraping pipeline using SmartScraper with schema """ + import os from typing import List + from dotenv import load_dotenv from pydantic import BaseModel, Field + from scrapegraphai.graphs import SmartScraperGraph load_dotenv() @@ -13,13 +16,16 @@ # Define the output schema for the graph # ************************************************ + class Project(BaseModel): title: str = Field(description="The title of the project") description: str = Field(description="The description of the project") + class Projects(BaseModel): projects: List[Project] + # ************************************************ # Define the configuration for the graph # ************************************************ @@ -43,7 +49,7 @@ class Projects(BaseModel): prompt="List me all the projects with their description", source="https://perinim.github.io/projects/", schema=Projects, - config=graph_config + config=graph_config, ) result = smart_scraper_graph.run() From ec0bd232104b74ebf9fc2db7dab17011c570e0f4 Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Wed, 8 Jan 2025 12:02:19 +0100 Subject: [PATCH 4/9] add extras --- examples/extras/.env.example | 4 + .../extras/Savedscreenshots/test_image.jpeg | Bin 0 -> 178104 bytes examples/extras/authenticated_playwright.py | 93 ++++++++++++++ examples/extras/browser_base_integration.py | 49 ++++++++ examples/extras/chromium_selenium.py | 119 ++++++++++++++++++ examples/extras/cond_smartscraper_usage.py | 38 ++++++ examples/extras/conditional_usage.py | 41 ++++++ examples/extras/custom_prompt.py | 50 ++++++++ examples/extras/example.yml | 15 +++ examples/extras/force_mode.py | 54 ++++++++ examples/extras/html_mode.py | 49 ++++++++ examples/extras/load_yml.py | 32 +++++ examples/extras/no_cut.py | 43 +++++++ examples/extras/proxy_rotation.py | 48 +++++++ examples/extras/rag_caching.py | 46 +++++++ examples/extras/reasoning.py | 46 +++++++ examples/extras/scrape_do.py | 40 ++++++ examples/extras/screenshot_scaping.py | 32 +++++ examples/extras/serch_graph_scehma.py | 43 +++++++ examples/extras/slow_mo.py | 48 +++++++ examples/extras/undected_playwright.py | 47 +++++++ 21 files changed, 937 insertions(+) create mode 100644 examples/extras/.env.example create mode 100644 examples/extras/Savedscreenshots/test_image.jpeg create mode 100644 examples/extras/authenticated_playwright.py create mode 100644 examples/extras/browser_base_integration.py create mode 100644 examples/extras/chromium_selenium.py create mode 100644 examples/extras/cond_smartscraper_usage.py create mode 100644 examples/extras/conditional_usage.py create mode 100644 examples/extras/custom_prompt.py create mode 100644 examples/extras/example.yml create mode 100644 examples/extras/force_mode.py create mode 100644 examples/extras/html_mode.py create mode 100644 examples/extras/load_yml.py create mode 100644 examples/extras/no_cut.py create mode 100644 examples/extras/proxy_rotation.py create mode 100644 examples/extras/rag_caching.py create mode 100644 examples/extras/reasoning.py create mode 100644 examples/extras/scrape_do.py create mode 100644 examples/extras/screenshot_scaping.py create mode 100644 examples/extras/serch_graph_scehma.py create mode 100644 examples/extras/slow_mo.py create mode 100644 examples/extras/undected_playwright.py diff --git a/examples/extras/.env.example b/examples/extras/.env.example new file mode 100644 index 00000000..dc01444e --- /dev/null +++ b/examples/extras/.env.example @@ -0,0 +1,4 @@ +OPENAI_API_KEY="YOUR_OPENAI_API_KEY" +BROWSER_BASE_PROJECT_ID="YOUR_BROWSER_BASE_PROJECT_ID" +BROWSER_BASE_API_KEY="YOUR_BROWSERBASE_API_KEY" +SCRAPE_DO_API_KEY="YOUR_SCRAPE_DO_API_KEY" \ No newline at end of file diff --git a/examples/extras/Savedscreenshots/test_image.jpeg b/examples/extras/Savedscreenshots/test_image.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..159625bcec1cc5553bd03d7fb74b93f16b276bc7 GIT binary patch literal 178104 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

%#7M@LBBE*~5>&Uo4=g|6{dXaD(YP-=*jQ>ZX< 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 MU(A154gA6QZ$zW>YybcN literal 0 HcmV?d00001 diff --git a/examples/extras/authenticated_playwright.py b/examples/extras/authenticated_playwright.py new file mode 100644 index 00000000..a4926bc7 --- /dev/null +++ b/examples/extras/authenticated_playwright.py @@ -0,0 +1,93 @@ +""" +Example leveraging a state file containing session cookies which +might be leveraged to authenticate to a website and scrape protected +content. +""" + +import os +import random +from dotenv import load_dotenv + +# import playwright so we can use it to create the state file +from playwright.async_api import async_playwright + +from scrapegraphai.graphs import OmniScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Leveraging Playwright external to the invocation of the graph to +# login and create the state file +# ************************************************ + + +# note this is just an example and probably won't actually work on +# LinkedIn, the implementation of the login is highly dependent on the website +async def do_login(): + async with async_playwright() as playwright: + browser = await playwright.chromium.launch( + timeout=30000, + headless=False, + slow_mo=random.uniform(500, 1500), + ) + page = await browser.new_page() + + # very basic implementation of a login, in reality it may be trickier + await page.goto("https://www.linkedin.com/login") + await page.get_by_label("Email or phone").fill("some_bloke@some_domain.com") + await page.get_by_label("Password").fill("test1234") + await page.get_by_role("button", name="Sign in").click() + await page.wait_for_timeout(3000) + + # assuming a successful login, we save the cookies to a file + await page.context.storage_state(path="./state.json") + + +async def main(): + await do_login() + + # ************************************************ + # Define the configuration for the graph + # ************************************************ + + openai_api_key = os.getenv("OPENAI_APIKEY") + + graph_config = { + "llm": { + "api_key": openai_api_key, + "model": "openai/gpt-4o", + }, + "max_images": 10, + "headless": False, + # provide the path to the state file + "storage_state": "./state.json", + } + + # ************************************************ + # Create the OmniScraperGraph instance and run it + # ************************************************ + + omni_scraper_graph = OmniScraperGraph( + prompt="List me all the projects with their description.", + source="https://www.linkedin.com/feed/", + config=graph_config, + ) + + # the storage_state is used to load the cookies from the state file + # so we are authenticated and able to scrape protected content + result = omni_scraper_graph.run() + print(result) + + # ************************************************ + # Get graph execution info + # ************************************************ + + graph_exec_info = omni_scraper_graph.get_execution_info() + print(prettify_exec_info(graph_exec_info)) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) diff --git a/examples/extras/browser_base_integration.py b/examples/extras/browser_base_integration.py new file mode 100644 index 00000000..7030e101 --- /dev/null +++ b/examples/extras/browser_base_integration.py @@ -0,0 +1,49 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "browser_base": { + "api_key": os.getenv("BROWSER_BASE_API_KEY"), + "project_id": os.getenv("BROWSER_BASE_PROJECT_ID"), + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me what does the company do, the name and a contact email.", + source="https://scrapegraphai.com/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/chromium_selenium.py b/examples/extras/chromium_selenium.py new file mode 100644 index 00000000..fba530d4 --- /dev/null +++ b/examples/extras/chromium_selenium.py @@ -0,0 +1,119 @@ +import asyncio +import os +import json +from dotenv import load_dotenv +from scrapegraphai.docloaders.chromium import ChromiumLoader # Import your ChromiumLoader class +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info +from aiohttp import ClientError + +# Load environment variables for API keys +load_dotenv() + +# ************************************************ +# Define function to analyze content with ScrapegraphAI +# ************************************************ +async def analyze_content_with_scrapegraph(content: str): + """ + Analyze scraped content using ScrapegraphAI. + + Args: + content (str): The scraped HTML or text content. + + Returns: + dict: The result from ScrapegraphAI analysis. + """ + try: + # Initialize ScrapegraphAI SmartScraperGraph + smart_scraper = SmartScraperGraph( + prompt="Summarize the main content of this webpage and extract any contact information.", + source=content, # Pass the content directly + config={ + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "verbose": True + } + ) + result = smart_scraper.run() + return result + except Exception as e: + print(f"❌ ScrapegraphAI analysis failed: {e}") + return {"error": str(e)} + +# ************************************************ +# Test scraper and ScrapegraphAI pipeline +# ************************************************ +async def test_scraper_with_analysis(scraper: ChromiumLoader, urls: list): + """ + Test scraper for the given backend and URLs, then analyze content with ScrapegraphAI. + + Args: + scraper (ChromiumLoader): The ChromiumLoader instance. + urls (list): A list of URLs to scrape. + """ + for url in urls: + try: + print(f"\n🔎 Scraping: {url} using {scraper.backend}...") + result = await scraper.scrape(url) + + if "Error" in result or not result.strip(): + print(f"❌ Failed to scrape {url}: {result}") + else: + print(f"✅ Successfully scraped {url}. Content (first 200 chars): {result[:200]}") + + # Pass scraped content to ScrapegraphAI for analysis + print("🤖 Analyzing content with ScrapegraphAI...") + analysis_result = await analyze_content_with_scrapegraph(result) + print("📝 Analysis Result:") + print(json.dumps(analysis_result, indent=4)) + + except ClientError as ce: + print(f"❌ Network error while scraping {url}: {ce}") + except Exception as e: + print(f"❌ Unexpected error while scraping {url}: {e}") + +# ************************************************ +# Main Execution +# ************************************************ +async def main(): + urls_to_scrape = [ + "https://example.com", + "https://www.python.org", + "https://invalid-url.test" + ] + + # Test with Playwright backend + print("\n--- Testing Playwright Backend ---") + try: + scraper_playwright_chromium = ChromiumLoader(urls=urls_to_scrape, backend="playwright", headless=True, browser_name = "chromium") + await test_scraper_with_analysis(scraper_playwright_chromium, urls_to_scrape) + + scraper_playwright_firefox = ChromiumLoader(urls=urls_to_scrape, backend="playwright", headless=True, browser_name = "firefox") + await test_scraper_with_analysis(scraper_playwright_firefox, urls_to_scrape) + except ImportError as ie: + print(f"❌ Playwright ImportError: {ie}") + except Exception as e: + print(f"❌ Error initializing Playwright ChromiumLoader: {e}") + + # Test with Selenium backend + print("\n--- Testing Selenium Backend ---") + try: + scraper_selenium_chromium = ChromiumLoader(urls=urls_to_scrape, backend="selenium", headless=True, browser_name = "chromium") + await test_scraper_with_analysis(scraper_selenium_chromium, urls_to_scrape) + + scraper_selenium_firefox = ChromiumLoader(urls=urls_to_scrape, backend="selenium", headless=True, browser_name = "firefox") + await test_scraper_with_analysis(scraper_selenium_firefox, urls_to_scrape) + except ImportError as ie: + print(f"❌ Selenium ImportError: {ie}") + except Exception as e: + print(f"❌ Error initializing Selenium ChromiumLoader: {e}") + +if __name__ == "__main__": + try: + asyncio.run(main()) + except KeyboardInterrupt: + print("❌ Program interrupted by user.") + except Exception as e: + print(f"❌ Program crashed: {e}") diff --git a/examples/extras/cond_smartscraper_usage.py b/examples/extras/cond_smartscraper_usage.py new file mode 100644 index 00000000..54c40712 --- /dev/null +++ b/examples/extras/cond_smartscraper_usage.py @@ -0,0 +1,38 @@ +""" +Basic example of scraping pipeline using SmartScraperMultiConcatGraph with Groq +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "api_key": os.getenv("GROQ_APIKEY"), + "model": "groq/gemma-7b-it", + }, + "verbose": True, + "headless": True, + "reattempt": True #Setting this to True will allow the graph to reattempt the scraping process +} + +# ******************************************************* +# Create the SmartScraperMultiCondGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperGraph( + prompt="Who is Marco Perini?", + source="https://perinim.github.io/", + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/extras/conditional_usage.py b/examples/extras/conditional_usage.py new file mode 100644 index 00000000..d3152bed --- /dev/null +++ b/examples/extras/conditional_usage.py @@ -0,0 +1,41 @@ +""" +Basic example of scraping pipeline using SmartScraperMultiConcatGraph with Groq +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperMultiGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + + "verbose": True, + "headless": False, +} + +# ******************************************************* +# Create the SmartScraperMultiCondGraph instance and run it +# ******************************************************* + +multiple_search_graph = SmartScraperMultiGraph( + prompt="Who is Marco Perini?", + source=[ + "https://perinim.github.io/", + "https://perinim.github.io/cv/" + ], + schema=None, + config=graph_config +) + +result = multiple_search_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/extras/custom_prompt.py b/examples/extras/custom_prompt.py new file mode 100644 index 00000000..7def35a3 --- /dev/null +++ b/examples/extras/custom_prompt.py @@ -0,0 +1,50 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +prompt = "Some more info" + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-3.5-turbo", + }, + "additional_info": prompt, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config, +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/example.yml b/examples/extras/example.yml new file mode 100644 index 00000000..fd5713c7 --- /dev/null +++ b/examples/extras/example.yml @@ -0,0 +1,15 @@ +{ + "llm": { + "model": "ollama/llama3", + "temperature": 0, + "format": "json", + # "base_url": "http://localhost:11434", + }, + "embeddings": { + "model": "ollama/nomic-embed-text", + "temperature": 0, + # "base_url": "http://localhost:11434", + }, + "verbose": true, + "headless": false +} \ No newline at end of file diff --git a/examples/extras/force_mode.py b/examples/extras/force_mode.py new file mode 100644 index 00000000..85593032 --- /dev/null +++ b/examples/extras/force_mode.py @@ -0,0 +1,54 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "model": "ollama/llama3", + "temperature": 0, + # "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "embeddings": { + "model": "ollama/nomic-embed-text", + "temperature": 0, + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "force": True, + "caching": True +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/html_mode.py b/examples/extras/html_mode.py new file mode 100644 index 00000000..6e2670a0 --- /dev/null +++ b/examples/extras/html_mode.py @@ -0,0 +1,49 @@ +""" +Basic example of scraping pipeline using SmartScraper +By default smart scraper converts in md format the +code. If you want to just use the original code, you have +to specify in the confi +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "html_mode": True, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me what does the company do, the name and a contact email.", + source="https://scrapegraphai.com/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/load_yml.py b/examples/extras/load_yml.py new file mode 100644 index 00000000..974ba4d5 --- /dev/null +++ b/examples/extras/load_yml.py @@ -0,0 +1,32 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +import yaml +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +with open("example.yml", 'r') as file: + graph_config = yaml.safe_load(file) + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the titles", + source="https://sport.sky.it/nba?gr=www", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/no_cut.py b/examples/extras/no_cut.py new file mode 100644 index 00000000..71bfad86 --- /dev/null +++ b/examples/extras/no_cut.py @@ -0,0 +1,43 @@ +""" +This example shows how to do not process the html code in the fetch phase +""" + +import os, json +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": "s", + "model": "openai/gpt-3.5-turbo", + }, + "cut": False, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="Extract me the python code inside the page", + source="https://www.exploit-db.com/exploits/51447", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/proxy_rotation.py b/examples/extras/proxy_rotation.py new file mode 100644 index 00000000..adfb87ed --- /dev/null +++ b/examples/extras/proxy_rotation.py @@ -0,0 +1,48 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "api_key": "API_KEY", + "model": "openai/gpt-3.5-turbo", + }, + "loader_kwargs": { + "proxy" : { + "server": "http:/**********", + "username": "********", + "password": "***", + }, + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/rag_caching.py b/examples/extras/rag_caching.py new file mode 100644 index 00000000..df73d2b4 --- /dev/null +++ b/examples/extras/rag_caching.py @@ -0,0 +1,46 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-3.5-turbo", + }, + "caching": True +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) \ No newline at end of file diff --git a/examples/extras/reasoning.py b/examples/extras/reasoning.py new file mode 100644 index 00000000..80e57faa --- /dev/null +++ b/examples/extras/reasoning.py @@ -0,0 +1,46 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "reasoning": True, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me what does the company do, the name and a contact email.", + source="https://scrapegraphai.com/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) diff --git a/examples/extras/scrape_do.py b/examples/extras/scrape_do.py new file mode 100644 index 00000000..45026f21 --- /dev/null +++ b/examples/extras/scrape_do.py @@ -0,0 +1,40 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +import json +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + + +graph_config = { + "llm": { + "api_key": os.getenv("OPENAI_API_KEY"), + "model": "openai/gpt-4o", + }, + "scrape_do": { + "api_key": os.getenv("SCRAPE_DO_API_KEY"), + }, + "verbose": True, + "headless": False, +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects", + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(json.dumps(result, indent=4)) diff --git a/examples/extras/screenshot_scaping.py b/examples/extras/screenshot_scaping.py new file mode 100644 index 00000000..439c2a0c --- /dev/null +++ b/examples/extras/screenshot_scaping.py @@ -0,0 +1,32 @@ +""" +example of scraping with screenshots +""" +import asyncio +from scrapegraphai.utils.screenshot_scraping import (take_screenshot, + select_area_with_opencv, + crop_image, detect_text) + +# STEP 1: Take a screenshot +image = asyncio.run(take_screenshot( + url="https://colab.google/", + save_path="Savedscreenshots/test_image.jpeg", + quality = 50 +)) + +# STEP 2 (Optional): Select an area of the image which you want to use for text detection. +LEFT, TOP, RIGHT, BOTTOM = select_area_with_opencv(image) +print("LEFT: ", LEFT, " TOP: ", TOP, " RIGHT: ", RIGHT, " BOTTOM: ", BOTTOM) + +# STEP 3 (Optional): Crop the image. +# Note: If any of the coordinates (LEFT, TOP, RIGHT, BOTTOM) is None, +# it will be set to the corresponding edge of the image. +cropped_image = crop_image(image, LEFT=LEFT, RIGHT=RIGHT,TOP=TOP,BOTTOM=BOTTOM) + +# STEP 4: Detect text +TEXT = detect_text( + cropped_image, # The image to detect text from + languages = ["en"] # The languages to detect text in +) + +print("DETECTED TEXT: ") +print(TEXT) diff --git a/examples/extras/serch_graph_scehma.py b/examples/extras/serch_graph_scehma.py new file mode 100644 index 00000000..66c47a33 --- /dev/null +++ b/examples/extras/serch_graph_scehma.py @@ -0,0 +1,43 @@ +""" +Example of Search Graph +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import SearchGraph +from pydantic import BaseModel, Field +from typing import List +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ +class CeoName(BaseModel): + ceo_name: str = Field(description="The name and surname of the ceo") + +class Ceos(BaseModel): + names: List[CeoName] + +openai_key = os.getenv("OPENAI_APIKEY") + +graph_config = { + "llm": { + "api_key": openai_key, + "model": "openai/gpt-4o", + }, + "max_results": 2, + "verbose": True, +} + +# ************************************************ +# Create the SearchGraph instance and run it +# ************************************************ + +search_graph = SearchGraph( + prompt=f"Who is the ceo of Appke?", + schema = Ceos, + config=graph_config, +) + +result = search_graph.run() +print(result) diff --git a/examples/extras/slow_mo.py b/examples/extras/slow_mo.py new file mode 100644 index 00000000..55b40cd7 --- /dev/null +++ b/examples/extras/slow_mo.py @@ -0,0 +1,48 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +graph_config = { + "llm": { + "model": "ollama/mistral", + "temperature": 0, + "format": "json", # Ollama needs the format to be specified explicitly + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "embeddings": { + "model": "ollama/nomic-embed-text", + "temperature": 0, + # "base_url": "http://localhost:11434", # set ollama URL arbitrarily + }, + "loader_kwargs": { + "slow_mo": 10000 + }, + "verbose": True, + "headless": False +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the titles", + # also accepts a string with the already downloaded HTML code + source="https://www.wired.com/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) \ No newline at end of file diff --git a/examples/extras/undected_playwright.py b/examples/extras/undected_playwright.py new file mode 100644 index 00000000..999fe42e --- /dev/null +++ b/examples/extras/undected_playwright.py @@ -0,0 +1,47 @@ +""" +Basic example of scraping pipeline using SmartScraper +""" + +import os +from dotenv import load_dotenv +from scrapegraphai.graphs import SmartScraperGraph +from scrapegraphai.utils import prettify_exec_info + +load_dotenv() + +# ************************************************ +# Define the configuration for the graph +# ************************************************ + +groq_key = os.getenv("GROQ_APIKEY") + +graph_config = { + "llm": { + "model": "groq/gemma-7b-it", + "api_key": groq_key, + "temperature": 0 + }, + "headless": False, + "backend": "undetected_chromedriver" +} + +# ************************************************ +# Create the SmartScraperGraph instance and run it +# ************************************************ + +smart_scraper_graph = SmartScraperGraph( + prompt="List me all the projects with their description.", + # also accepts a string with the already downloaded HTML code + source="https://perinim.github.io/projects/", + config=graph_config +) + +result = smart_scraper_graph.run() +print(result) + +# ************************************************ +# Get graph execution info +# ************************************************ + +graph_exec_info = smart_scraper_graph.get_execution_info() +print(prettify_exec_info(graph_exec_info)) From 1fad1181a6b2d654c4eb996348907940b1d8a7af Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Wed, 8 Jan 2025 12:26:28 +0100 Subject: [PATCH 5/9] feat: add example of collab --- examples/ScrapegraphAI_cookbook.ipynb | 915 ++++++++++++++++++++++++++ examples/readme.md | 4 + 2 files changed, 919 insertions(+) create mode 100644 examples/ScrapegraphAI_cookbook.ipynb diff --git a/examples/ScrapegraphAI_cookbook.ipynb b/examples/ScrapegraphAI_cookbook.ipynb new file mode 100644 index 00000000..b58bf0ea --- /dev/null +++ b/examples/ScrapegraphAI_cookbook.ipynb @@ -0,0 +1,915 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9_CQrFgOj78b" + }, + "outputs": [], + "source": [ + "%%capture\n", + "!pip install scrapegraphai\n", + "!apt install chromium-chromedriver\n", + "!pip install nest_asyncio\n", + "!pip install playwright\n", + "!playwright install" + ] + }, + { + "cell_type": "code", + "source": [ + "import nest_asyncio\n", + "nest_asyncio.apply()" + ], + "metadata": { + "id": "tb33AcRHywFb" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "00a84YVhhxJr" + }, + "outputs": [], + "source": [ + "# correct APIKEY\n", + "OPENAI_API_KEY = \"YOUR API KEY\"" + ] + }, + { + "cell_type": "markdown", + "source": [ + "For more examples visit [the examples folder](https://github.com/ScrapeGraphAI/Scrapegraph-ai/tree/main/examples)" + ], + "metadata": { + "id": "vGDjka17pqqg" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Mrujgp-nlp12" + }, + "source": [ + "# SmartScraperGraph\n", + "**SmartScraperGraph** is a class representing one of the default scraping pipelines. It uses a direct graph implementation where each node has its own function, from retrieving html from a website to extracting relevant information based on your query and generate a coherent answer." + ] + }, + { + "cell_type": "markdown", + "source": [ + "![Screenshot 2024-09-19 alle 17.04.56.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA4sAAACSCAYAAADsIl+tAAABfGlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGAqSSwoyGFhYGDIzSspCnJ3UoiIjFJgv8PAzcDDIMRgxSCemFxc4BgQ4MOAE3y7xsAIoi/rgsxK8/x506a1fP4WNq+ZclYlOrj1gQF3SmpxMgMDIweQnZxSnJwLZOcA2TrJBUUlQPYMIFu3vKQAxD4BZIsUAR0IZN8BsdMh7A8gdhKYzcQCVhMS5AxkSwDZAkkQtgaInQ5hW4DYyRmJKUC2B8guiBvAgNPDRcHcwFLXkYC7SQa5OaUwO0ChxZOaFxoMcgcQyzB4MLgwKDCYMxgwWDLoMjiWpFaUgBQ65xdUFmWmZ5QoOAJDNlXBOT+3oLQktUhHwTMvWU9HwcjA0ACkDhRnEKM/B4FNZxQ7jxDLX8jAYKnMwMDcgxBLmsbAsH0PA4PEKYSYyjwGBn5rBoZt5woSixLhDmf8xkKIX5xmbARh8zgxMLDe+///sxoDA/skBoa/E////73o//+/i4H2A+PsQA4AJHdp4IxrEg8AAABWZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAOShgAHAAAAEgAAAESgAgAEAAAAAQAAA4ugAwAEAAAAAQAAAJIAAAAAQVNDSUkAAABTY3JlZW5zaG90qcY5WgAAAdZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTQ2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjkwNzwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgqQ4mNtAABAAElEQVR4Ae2dB3xUVfbHDyUhBZKQEAjSEqo0AVERFbB3XVesa3d17a79b++9916xobsKiF3RxYKigkjvJBAgEFJJISTA//ze8GbelIRkMpl5b+Z3Pp8wM6/cd+/3zVzeuae1qq6u2SEUEiABEiABEiABEiABEiABEiABErAQaG15z7ckQAIkQAIkQAIkQAIkQAIkQAIkYBCgssgvAgmQAAmQAAmQAAmQAAmQAAmQgB8BKot+SLiBBEiABEiABEiABEiABEiABEiAyiK/AyRAAiRAAiRAAiRAAiRAAiRAAn4EqCz6IeEGEiABEiABEiABEiABEiABEiABKov8DpAACZAACZAACZAACZAACZAACfgRoLLoh4QbSIAESIAESIAESIAESIAESIAEqCzyO0ACJEACJEACJEACJEACJEACJOBHgMqiHxJuIAESIAESIAESIAESIAESIAESoLLI7wAJkAAJkAAJkAAJkAAJkAAJkIAfASqLfki4gQRIgARIgARIgARIgARIgARIgMoivwMkQAIkQAIkQAIkQAIkQAIkQAJ+BKgs+iHhBhIgARIgARIgARIgARIgARIgASqL/A6QAAmQAAmQAAmQAAmQAAmQAAn4EaCy6IeEG0iABEiABEiABEiABEiABEiABKgs8jtAAiRAAiRAAiRAAiRAAiRAAiTgR4DKoh8SbiABEiABEiABEiABEiABEiABEqCyyO8ACZAACZAACZAACZAACZAACZCAHwEqi35IuIEESIAESIAESIAESIAESIAESIDKIr8DJEACJEACJEACJEACJEACJEACfgSoLPoh4QYSIAESIAESIAESIAESIAESIAEqi/wOkAAJkAAJkAAJkAAJkAAJkAAJ+BFo67eFG0iABEiABGxHID+vSmZOL5a5f5RK0cYaKS7cKpWVdSI7bNdVdogE/Ai0atVK2qe2lfRO8dK5a4LsuW+a7DMmQzp1aed3LDdEN4HS4lr5/acimTWjRArWbtG5rEbKy+pkx3ZOZtF956NndInJbYy5LCOznQzeM1VGjc2QnH7J0TNAn5G0qq6u4a/TBwo/kgAJkECkCezYLrJkQbkqiEUy84diWavKIoUEookAFMg+uycbD1p42OrVN3oftqLpvgUzlnWrq3Uew1xWJEvmbZbtVAyDwchzbEyg824J7rls0PAUadOmlY1727SuUVlsGi8eTQIkQAItSqC6cptMejdfvppcIKVFW1v0WmycBOxEIKtbghx3Wjc58sSu0rZt9Dxo2YlxOPsChfD7zzfKpHfyZc0qLnaFkz2vFVkCHVLj5KCjO8vJ5/WQFH3vdKGy6PQ7yP6TAAlEBYG6uh3y1aT18sFrq6WspDYqxsRBkEAwBLK6J8pZF/eS/Q/NFDU+UhxI4I8ZxTLhuVzJW17pwN6zyyQQGgJJ7dvK+LO7y3GndpN2Cc5NExP1ymLNlu2G+1apPnyVqZ98afFW40EMPvNlJVsF+ykkYAcCbXQlPSUtTtI6xklqerykpeurvk/T91hxx3tK9BHYoYEAP08rlHdeyJP1+dXRN0COiASCJNB3UAc597JsGbpXWpAt8LRwE1i2cLO8+WyuzJ9VGu5L83okYFsCGZ3byekX9pRDjukirR3onhqVyqIZPI04n79+K5GtNVQIbfsLYscaRQCxPX0Htnf5w4/LkJ69kxp1Hg+yNwHE8Tx+xxLBAxaFBEggMIG9DkiXK2/tzwWzwHhssbW6apu88OBy+eHrQtmBFTAKCZCAH4Ee+ux29R0DNFa7vd8+O2+IGmVx4/oaY3WewdN2/rqxb6Ei0FXdtEap0jj6wAzZfY+UUDXLdsJIYM7MEnnk1sVSUa4ZTSkkQAINEkDyiFseGSTZTILTIKdI7ERG0/uuXyirV9DlNBL8eU1nEWiX0EauvK2fHKBu9k4RxyuLiO354PXVGutTIHW1tCA65YvHfoaOwLC90+Scy3Mct1IVOgLOa2nqB+vkjadWyrZtXIF33t1jjyNFIDGpjVx15wDZVxfKKPYgMH92mTx00yIpL2WctT3uCHvhBALwFjvl/B7qmtrLEXHZjlUWt1Rvk0/eXysfa5YtZA+kkEAsE2jVupWMObSTnHFxthHfGMss7Dz2utod8uIjy+WbKQV27ib7RgK2JYC57ox/9ZKTz+0hwuQ3Eb1PX368Xl55bKXU1XGhPqI3ghd3LIHRB3WSq+7oLwmJbWw9Bscpi1iJ//aTAnn/1dVSsolp5W397WLnwk6gbVxrOWp8VzkF6Zo1WQ7FPgQQ03P3NQtk4Z9l9ukUe0ICDiUw7sjOxkNWa1UeKeEn8OoTK2XqxLXhvzCvSAJRRiCnf7Lc+dRQI6mhXYfmKGVxc1mtujsslnnMsmXX7xP7ZRMCHTvFy00PDZIBQzrYpEex3Y0duvB+//8tlN+0IDWFBEggNAROOKO7nHdlTmgaYyuNJoC6iW8+s6rRx/NAEiCBhgkMHJYi9zy3h8TF2XPxyzFFP1avrJLrzptDRbHh7xv3koBBAFb3Wy6ZK99/sZFEbEDgnRdzqSja4D6wC9FFYPJ7+fLdZxuia1A2H41ZP9Hm3WT3SMBRBBb9VS4vPLTMtn12hLL4+0/FcsMFcwQZtygkQAKNI1C7dbs8edcSeevZVbJ9OxOpNI5a6I+a/tVG+e+ENaFvmC2SQKwT0GnteS3XsHheeayTCMv416yqksduW8L/T8JCmxeJNQLTpm6QKZqLxY5iezfUjybka7HqXE5Odvz2sE+OIYA6ZdfevbskJds7iNoxQBvZUdRPvPniuaz12khePIwEgiGQlhEvj70xXDp1aRfM6TynEQQ2l9XJ9efPkfX51Y04moeQAAkEQ6B1m1Zy22ODZc/RHYM5vcXOsbVl8W1VEic8R6tIi919NhwzBP5Q6/ztV8yj0hLGO46yPvffsJDMw8icl4pNAqVFW406f8g2TAk9gR2K9ZFbF1FRDD1atkgCXgS2axLPR29bLAX59vKktK2yaLhuvUXXLa9vET+QQDMILFuwWZ65z74+8c0Ymi1Pff/VPCkuZMZmW94cdirqCKxcUiEo5UAJPYGfpxXKX7+Vhr5htkgCJOBHoHJznbyp4UN2Elsqi3iofRYPtVwktNN3hX2JAgI/aPzcf97kIkxL38p1q6vl68mspdjSnNk+CVgJfPDGaqli3WUrkma/r6vboaFAec1uhw2QAAk0nsAv/9skS2wUi207ZbFIV+KRYn5rDYu8Nv5rxSNJoPEE3n0pT2ayhEPjgQVxJFzot+lDFoUESCB8BMrV9XvS2/nhu2AMXOmrSevpfhoD95lDtBkBfXx489lc23TKVsoiFMQHNMaHrlu2+X6wI1FIYIdmRn3ijiWSt6IyCkcX+SEtVc+IX75nPcXI3wn2IBYJTNFC8cVaOojSfALVaqX94LXVzW8oSlvokNJGUju2df9F6TA5rAgRWDinTH770R7PErZSFrEaj+yBFBIggZYlUF21TR6+ebFs02BqSmgJoFj1DmSEoJAACYSdQE31Nnn/FbpNhgL8pHfzBYm6KP4E0tLbyitTBskrkwe6//oNSvI/kFtIoBkEJjyn1SBs8JxmG2Vxw7ot8vl/GZzejO8UTyWBJhHIz62Sb6Ywrq5J0HZx8F+/l8qCP8t2cRR3kwAJtCQB1CvbuL6mJS8R9W1XVtTJlPfsWfPNDvD3PyRNWvs8QY89Is0OXWMfoogAapv++O2miI/I56seuf6882Ke1NUyTjFyd4BXjkUCE9XFaIuuxFNCQ2DGd5Gf1EMzErZCAs4lAI+JX6fzt9icOzhrRgn/b2gA4Lgj/evg7XdwmrSNa9XAWdxFAk0ngGzEkRZbKIsrFlfIj99EHkakbwavTwLhJlCisT1cPQ4NdXie/sbEQaGByVZIoJkEZk63R6xPM4cRsdOZBK1+9D17J0h23wT3AWbUAWIYR+zbwb2db0ggFATmzCyVmi2RNabZQll8S+uJIOkGhQRIIPwEGJcSGuaIt2ZijdCwZCsk0FwCi/4ql81ljLcLhmNd7Q6ZPaM4mFNj4pyxh3vcTfNWbJH5syvc4x53hL/F0b2Tb0ggCAI1W7bJnN9KgjgzdKe0DV1TwbX0568lgjgfCgmQQGQImBnv/nVdn8h0IEquSktGlNxIDiMqCMAV9fefiuXgY7pExXjCOYi5s0pZr7Ie4K3UxDLmMI+yOOO7UiktqpOhI9sbZ+yplsX2amGsKA8c3jH+7M6SmRVvHPvph4WSn1sjg0cky4hRHfS1vSQlt5bVK7fIL/8rkxnf1R//3j27nRx3aqZ079VOOnWJk816vQ1rt8q0z4pl9i/eiSIPODRNhuzp6l/Rxq1aa3mj1+iQmOeQY9Pd25bMr5TvP/dWTvY+IEVG7pdiHLO5vE7efdE/38GAIUlysLbTSy2vHTvFCYrLr1uzVaZ/VSKzft4s2wMYhcafozy6uHh88dEmzdK+RTI6x8nI0R0MpgvnVMoXH9NLAF5Lo8ZmuO9RuN9EXFn87D/rwj1mXo8ESMCHwLeaEOKcy3OkXYItnA18eueMj3TbcsZ9Yi9jh8DMH6gsBnO3ufBVP7WhqnRBETLl52llhmJ4wbU7JE7jFRGzuN9BqfL1lMCW2b32T5E+uycapy/6q1IGDkuWC6/pZjZnvHbt0U5GjUtVhalUnr1/jWbX9tqtSmInOfPirgLF1RT0Ce6xe49J0XIL5fLY7XnqsefaCyXt4GNcFk9YjSe/t0lqt3rcGmEpNffjjEHDk/2UxUOPS3e72P70rb+B55Tzu8hJqvhZpWNGW+menSD7aJ+g/D599xq/DOz7qBKa09/FY/miKlUoRe58qrd0SG1jNJWryiNFjIUv3MfWrSMTE2v5qoX/diCxBq2K4efOK5KALwE7uDn49slJnwvytwiyllFIgATsQ2DOzBLZankotk/P7N0Tu9R2syMlq5vpsgVVmnV3q2GF/fNXjzVvbCNdUQ8/IV0uuNqlKPoqhBj7GFXikDTHKrsPTfZSFKH8rVhcrVY8jyUTytn4szyK21+/VxhKGNqBMttvkEs5M9sdto93nGVWt3jpspvL2odjoJQOGOopCzJrhmes2P+3f2T6KYpVWqPTKqMPTJUrb+8hbdrUr+zssVd7ue3xHLeiaD0/1t+jhM3iud7cw8kkosrin5jIazyrG+EcOK9FAiTgTYCWMW8eTfm0elVlUw7nsSRAAmEggAVplOWiNJ4AwhKKC7c2/oQYOjIhsbXsM9bliolh/zTNY2GzWtv6D06Srt3b7ZIM3D+h5D2lFrdzj1ko5x27UF57cp1sq/OYEk8616P0oUFc37QobtpQK+cft1Buumi58frtVI8186CjPbGTuAZcS02BNdMUKIVQDiHWusvDLQpkdp9EdY91Wfpg+fvrd4/SghIiZ1yUZTanySpL5dZLV8h5Op6rz14qk94pdFs4oTDCAlmf7Kv7Ub8SijOU8DkzN8v6NSyBY/LKW+G5h+a2cL1G1A115nTPFztcA+Z1SIAEAhNAfE8k3RwC98oZW0s2MZGGM+4UexlrBJDxuUe2xyoSa+Nv6ngRj0YJTGDU2FR3qAZcPH/53hNTCGtbddV2SUxy2WDg2vnB6xsCN2TZ+tTdq1X58iTI+WpSkfTMSZDD/uaKIdxNXVLj27V2G1Y6pHoe21HnEdfbUr3dULDeena9WBVGuCyacYKIYxy4h0tJNF/RjeEaK2nK15OL5ajxGcbH4aPay1eTXbGCcEs1ZakqndZ4zGNP6WTuMmImX3goX8vguZTdtXk18v4rBRIf30qO2Xncocena8zkBvcx7pN3voFyeP8NubrIwwULXzaRTKAXMcsiVjD++JnKou+XgZ9JIFIEytXNYdHc8khd3tHXLSnif2yOvoHsfNQS4G+zabe2opwLX/URG3uExyV0wZwKKS32KNaIAUSsoClwIW1Vv8elcdja1TVeiqJ57myLSyvayMzyxEjO/cNj1UvPjJOn3xsg197dU+AeC8vnyiXV7j9TUUS71qQ3SERjuoMO38eV+AbHfP7fTYbCh/dItmPWjLRaImdZkuekdmzrjr/EOX/8XG4opEj2Y/0rLfFwQnmRhqyud121iooiYAaQSCqLniWKAB1ryU0L5zCtdUvyZdskEAwBWPsHD08N5tSYPocPpDF9+zl4GxOAZZHSeAK0LAZmlaGK2RBVoEwpKqwTuE1apaLMoxR17hoviC9cNLd+18F1qiwGkpIib4UdShmsdJCf1M2ztyaEOeZkl0UPSemQDAd/cN9ENtHPPtxkZCC1tr1m1RaB2yoyp+KcnP4Jkrt8iztLKix6sOb9qa6fR56YYSieUCqRjdRqibQqnZ00a6lVYD00LYjW7b7voeSiP74C19Nieun4YnF/Li4M/H1xH9CCbyKmLEa6ZkgLMmXTJOBYAq7fZY5j+x+pjlNZjBR5XpcEGibAh8+G+fju3WxReHz3xfLnA7RchhkrCA7j1MqIv4YErqgNKYtwHw0k1thB7LcaKKEQwt10+pcl6qqaISjVgVITxnF6YHbfBLns5u4CK+i912oNc5dHqLEfSXhM91YogAmJbdxutX/OdLnC4hgoixC4qJaXbnMnnCksqPVS8uLivZ0TEY5R59GXjTYC/bO1ngLzq5ZWBzqc23YSiEnL4qaCyGnI/OaRAAkEJsDfZWAuu9pKZXFXhLifBCJDgL/NpnGnG2pgXlD8mir7agmN159e71Wmoqlt1Hc8rIKvPLbW2I1SG1AaUf6ih8Y7QuAG2ntAopEp1dig/8z+tdyjLGqSmxS1WJoCiyJkgVoSa7dqGRCNMxy+dwcpVGufKTjfKqjZaJXnH8wP6FZrPaah9zU1Fs22oQNjdF8kvSQ835Qww4+khhzmofJyJOAYApWVdUbguRmr4JiOR7ijpT5uQxHuDi9PAiSwk0Ap44mb9F2o0ELqFG8CqANoKmHYM+W9QsPd0/so1ye4q55xsSs7aHL7NrLXfh2MGoOBjm3qNsQk/u30TPdpiG1ctrDKyBj6mbqR/v5TuTwxob+h6OEgKJAoq2HK/NkeRRAusmZ5DFQlgLspBO8X/FlhWBV7qZUS2U5NsbqgYtumwlq3ays+o2SINVkPtkGgxKalu6yfRXoOrKKUphMoL43cb5PKYtPvF88ggegloAt7lRV1ktrROxYhegccmpHV1gZ2JwpN62yFBEggWAL8bTaNXJ2lbEPTzozeo61WRbiO/vetjVJTjyslEtIc8fcMIzYQRKBAoSB9KATXHqYJafoOdGX3Rdu3XLLcnWgnMbm1OykNrrdujbflD32er4rgCHUvba+JZvAHWfAnlEjP/2GwMppZUs3kNi4l0jv+Ehlhv/mkSE6/0KUcj1FXXcRFgg/aQ6bWozW28lRLuYxn71tjXJP/NJ3ADqtPcdNPb9YZVBabhY8nk0D0EYgGZfHX6UUydaLLRefYU3eT0Qd60ntH3x3jiEiABKKZwDdTCuSbqRsElqqTzu3BJGRhvNnIGnrAoR7r2u+a8bQ+RRHdwvP8z9+Vui2AKEGRktZWY/9CYxX68uMiufwWl7KILKkvfTRQli2qMohAiTQzsCLu0VoP0UQG6yCURauYLqjmtjk74xfNz3idN6vSXb7Dun2yWllR3mPcka66jn8/M1NQTqOwYKt00fqNZtZVnINMrT9+W2o9ne8dQiBiymKVWi8oJEAC9iNQ6XA3pIK1W+SBGxa6wc6fXSYn6wPWmZdku7fxDQmQAAk4gcC8WaXy7P3L3F2d/UuJnH9Vb1VGurm38U3LEdhj7/bqaeN5VP6pEcrOjGllbmURytL+h6TKFx+5ahY2t6c/fF2qbqat5bwruxr1F5F0p/9g7zqiqIP45F2rveohmtdFAhtf8d22Pl8zo651KXvmsb7xiuZ2WBef19qK2/X1oKNdCiPiHXfr2c48xHhFWZHnH8gXHE9xHgHPL8B5fXdcj41ireayTyN6v6V6myN/WOPP6SzpGS43xsVawPVHndyaIigkC1eLPhqcjQlm9Ur/FMtNaY/HNo1AZcW2pp1gs6OXL/L/z/A/b66R5Ysr5NKb+knnLO//xGzW/ajqTr1zni6/m4WknTxgPAjCcpDdL1FmTi+T/FwmbnPy/bRj35cucGWptPbt9SdXaiyazmc39jUyWlr38X1oCSCuz4zVq9Vi83P/8L8fvldctaxaS1eUCmoKQsx4PbxfrKU0zPqMuXpcIKmu3C6zZnj+H9usyp9Vpn1aLEsXVMnBqpwhrrBX30TRxybJ1bIZuZpR9MtJRfXWKkR5iu+/KJFUtXZCkP0WJTN85Qu1YO6xl6dUyGxLf3yPhQL44sP5Mue3zXLQUehTolpT2xgKJ2ImwWz6V4HjFBfNrdJyGS7jEbOh+pK1z+dW1dWRST/0t1E/2odCmHoy8fuh0to703CDV/73GUsFKzxOk8fe7OcOBv/usxJjEmnKGI7StM3n/Xs34xRMQlf8Y4lggqOEh8BNDw+SfcdlhOdiLXCV/NwquezUWQFbTkmLMx6wRh8UWrfUc4+ZKZHMVBZwsDbY+PZXg92p2X27U121XfBwsEJdk5bOr5KZP4Qmrsf3Oi35+fjTMtVi7YrXgdvXZacsYZ2wlgQeRNsDh6XIgy8PC+JMe5zy568lcue/5wfsTLdeSXLZTX21gLp3vb+ABzdy48TXVsv7L+c18mgeRgKBCcAuEsEQu8CdioKtU2aOicgomqC6RKR/vGgICWCVCymW8WeueIWw+ZA1NWRPz2oWXCwGD08OWdtsKPoJdM9OkqvvHCDxWnjYV8pLa+XBGxfJOy/k+u7i5zATgNVxkP62jzu1k1x7T085XxeImuB4EebeBr7ckD09cxOsjGYyiMBHcysJNJ3AiH07yj+v7h3wxLV5VXLzxXNlyvuu+OyAB3EjCUSAABXFCEBvwUvSDbUF4TbU9Nq8ml1ay7bUk22roXYb2nfqP7Pk8BPSjUM+fnujTHx1Q0OHR2zftM+KZYSmfEb5BrhrzPzBu7ZPxDrGCzuGwIFHdZY+u7eX5x9crinB/S1WdEsN/61EDMxGTXoAgVKIOKCsbu3cad5RCBqp4VGryyky7dMSo55Zm7atpGhjrfzxM+cqp9w7J/Xz+NO6ueazB5arq7MrmYm1/3RLtdLgexIggVAToLIYaqKNbA8+559+uKmRR4fmsIzOziiHgPiAf524SHr1SVD//iqBexeFBJpKoEdOkjzw0h7y6hMr3ZlRrW3Avevac/5sEbdU63X43kXgu89LZNI7G71wQGG86o6e6kbnstAdqPEuWMQq3lTrdZxdP8B19l8nVkhPLYSN2Jvt2zlX2fVeOb1fg4enyuNvjdAkIcvkf196/44wtum6bfmiipC7pTqdG/tPAiTQfAJUFpvP0DEtdHKIsgigyOaF2j8UZxGY8d0mrbtUIHYr7JzVPUGD+Gs0YZT3w7zplnr6hb3ktAt6Ogt2FPS2rKROJr+7UZXFHPdo4JramIyD7hMi/GZzmc5VOwtaR7grvHyICWAu++GrQtmyxTvBSIgv0+TmMru2k8L1/vkMTLfUC67po+7drrj/JjfOE0iABEjAhwCVRR8gdv8Y36611oxLlVHjUiQzK14SNC6rqLBWV7Ur5Tu1VhZqQVSrwJp4wj8yjU1Z3ePdu4bv08Go2WRumPjaBqnc7P8fYt+BiZoOOd2w8qWlt5WSojopUHeynzV9NDJfNVZ2H5ose47uYMT0wNUMGU5/+b4soNtWv0FJYi2C+/YLBe76Pjn9E40MYLhuvrryfqVZvzqktpF9xqQa1oneuh8MUM9nitb/qar0H5PZZ/Db+4AUwfVy+iUYdZDW69i2+rj/Yryf/Se8VmCzj056RXa+j9/Ol2ULG/+9sMv43n8lz0hHPv7s7nbpUsz0A/W7MPckd3BlDhwwJCmgsrjPmBQZMCRZM48maEbbeP2dbzXmou/VYrlsob9rXtfu7eTok1yJmuDO/tEElzUGc9FQzfKHeMN7r831KkbdZ/dEOeKEDMG5HTu55rt1a2rkS017jwyHvjJgaJIccIinBtubz6x3e0Jg7hynRbMhq1dtkW+mFBuut5hzBo9oL737J2goQq1m6a2ST94vFCT8qU+QkXGv/VOMFPnZmv2wVJXsgnydq2q8z1m7WvuqWQwpzScwa0aJfmfyZf0a//ve/NZbtoVXH19hZLsce0Tnlr0QWycBEogJAlQWHXSbkZTmzqd7uzONml1H4VMzUcSDN+bJ/Nme1M4oBnvE3/0zW/bWshT4MwWFVX2VxVP/2UXGn+39n03nrvH6wJakD0FpsmRelTx6W57AOtCQHHJsuvzr2m6CZDWmwMV0zGFpxgPUK497B+ejwKu1z3BL27pzEbWrKrzmvjxNEw2F8y5l0q2XpxwC6vsM09pIKKT78C25krfcv/QGxn7LIzmGomn2CeftvocnYYW5fdFflVQWTRgNvBYW1DhSUTSHNH92qX7fqSyaPML1igWtJC02bsomnwUvFCK/5MbuuiCUYh5ivGLeG7KnyKHHpcvP01CLLl+21Xksx+mZnrkPqeihLJ56vs5pWtrHFGtCnXMu7yrHnOydJdec75AOHud/oItqVumRneCej7B9wvMFbmXROo8hffxvGnt9z7O9JUsVUVOQbAxlgoy56uY8WaNKpa9A6bz54RxpvzMNP/bjvIEB5qp5syqoLPoCDPLzOlUSnagomsNd+Fe5UFk0afCVBEigOQQsj+/NaYbnNpUAMufFaQKXQH+oM+greGC69bEcP0Wxdqvn4QhWxxsf7KUPUJ5sor7tNPaz8VDloyj6notV9ZsfyRajlprvzp2fh+uD0EXXeyuK1kMP+1u6Yd2zbmvsezzIgYlVUbSem5kVZyip1m14j1X6O57o7aUoojQHispaJT93i0ybWiw/6YMoZdcEevZJ0u+C56F/12fY6wgkxKGEnwDiFK1K20JdnDEFc+F9L/TxUxRrfKz/+6t177QLupin+b0mJreWMy/O8lIUrQdh4cqqKKKeGhaj8GoKFs72Va+OYCRLFdvbHs/xUhSt7WBOuvAaf7dBLGDdrnOVVVFETTTfwtbw1MBcNeM7/2RO1uvwfeMJ9Oqd1PiDbXhkTj/OZza8LewSCTiSAC2LEbptZ+iDC/4CCSxpyFZqlRvu7yVwwYSgmDVWuH/T5ArlGi8D96RjT+mk2dISxVQY/33mUiM7H1woH/i/XOO8f9/eQ5KSXQ/zeKiwFkktL/W4ax6uCpx19R2WubeeW2+4jvYblChHntjJsNyh0RwtRo1aYx+87r3iblxQ/0nPjDNcQd96dr27sC1W0VGbDAoz5CRd6f/9p6ZnEYSSCpesX/9XJv95c6ORXRYWy39d10169k4w2oaLKVxurS6zcAPDwyMErmWP377aKEoLK+w/r9pNRh/keiBEge2XHvW2ehon8Z+ABHbrkSjnXpEjn3+0Xl16vd2hA54Qxo21tdulqmKbbK8nWdJhf8tSZSI7jD2KvUv17N3OrWzhl5+qbu3wUtjvYI8bJ6yKcCE3BQXvoTCZMkXdNeFmCbfSoboodtalWe4FtONPzZTP/1uk9S4Df/eOP93ljl+nCiBcS+FSb8awmr95XGeZFru+86pVhntqXHxrufXRbHdJDBTBxnzTVIGLLf5+nlamFsoNUlhQa7jTXqRzVXe1TkLg1YCFPqtnCKypcNuHLF9UJU/etcaY55AY6EL11jCtrVAWOVcZmEL2zx57pxnzGeIWGwpnCNkFm9AQ3I8xn+2opz7B+LN7qMU78PNFEy7DQ0mABEjAIEBl0QFfBLghWet3IaOgNYYOLlhzf98sT707wFiBhsII188PVYGr1pi9P391xZDhIcmUgrU17u3mNrxihf84Vf5MwcPbrZetEHMlf9aMzVqKoFIeeb2fwLIHGXdkR/nwzQ1+q91mG0/cuUb+ssQ3ou/d1W30EHUfg/RUBQ8WhGAyCSIJzuN3rDYvJUv1Qe8J/fz4hP5uawVcTq3K4h4ar2TKZ5qRFiv1kPLSOlU6N7iVxUBuXuZ5fA1M4MgTu+piQtfAOyO09aMJa2TCc7n1Xv3iG/rKUePt1ed6O+vgHbD+4a8+we/w7qtXud04cRwUwvWq2EGwePPeSwXuQs/4TUNpuuxml+sw3NyzdS6pT1lEG5h73nlRXUUt7qrYjnZMab1zEQufa7dul8d0MalrD9dc53ueeU5jXv/6rUKeutszV8GN/6m71xhzqXk+Yq6tyqJ1rkL2bHhAQOD6j7nKVBY5V5kEQ/v69zO7C/7sJG88vUqTQuUH7FJyB/093NRPf2fe7tQBD+ZGEiABEmgkAc//kI08gYeFhgBiU9ZrgoJAgiQFVhm5nydWB0kQli+qFiRp8BWslvcf7HKdwYp9MIJVbrhEmYKVfFNRNLehD9edt0zaBSh6bh5jvmLF26oomttnaXkMU1mEhRFxS4U7a7CZxzTm9dMPC/0OA7+C/Bojrgc7TaXWPLCVxecNirVVrJ9hwaU4l0BFeZ089+AymTFtU8BB5PRvb5TN6D+4Q8D93BgeAjCOIC746XvW+JXMgEcD/kzBolLHjLZGDVZsW7m02nAfb73zZwyX9D9nBk6w9ItaBOHhEEjmz640El1hHzw0np04wEi+NWtGuZGVGYpdcyXQXAVXV8x7SLYFacpc1c4yd3Guau7dsf/561ZXG3Vj580KHBYxTC2hl6qimNXNZam2/4jYQxIgAacQoLIYoTuFDH6NrbPYqYtHeYPrJWJfdiXBlsno1MW7FiOUvUCCh5PGPKD4Kr5mW76r/8i0GoyyuG51YIW7WF3MkAQCYrUa4POKJVVGUgm8P0bddzFGZFNEQorTNKmPKXM1WQTFmQTmzCwxHqw2rAv8/T30+Cy57Ma+YrUiOXOkzuk1LGtIwGLKlupthjvpKlX4fLM4m8fgFcrhsadkGhZ/uLWbiqH1GPN9XLzLtd38bH2FQlqfwO0fLu0j9nUtHOCahx2fbvwhbnGxZptGght4VQQr63wWAc12ijfVuZVFuOZaZYVmSjVrUB53aidZqxmg4Y4K19xTNFmPKXP/8HA1t/E1egj8+E2hPKf1FeEpFEhOPKu7nHP5rp8LAp3LbSRAAiSwKwLe/zPt6mjujwiB+HaeByC4kvpmLQ3UKWsMYqD99W0z4wjN/VbXVXNbU16RhTCQbKsndizQsQ1tq64K/J+nNTbNYkg0mkJcE7IbduwUJ930oeve5/sYaeutiXpgTf3fFyUNXZr7bEpg04YauevqBfXGJ9LtNDI3DolrPpno7wnQUG9QwuL+l/p4lflp6PiG9lljIX2Pw+/9wRtzNRa7g+HxMHRksju+G0nIho5sb/zBjbU+66Rvm76fq+vxVGhorsKCIspvQInskZNgJPuBZ4d1rsKinTX+3Pe6/OxsAos0q+mjty4OOAi6nQbEwo02I3DkiRkyamyqu0wQatNSnEWAyqID7lfxRk/CBsT1XH320hbr9SatXWYVuHUFqmFmPcZp7xGb+M0nxV4r89aHr0pNHPCgJgWKtnE39j41xr24sW1F4rjF88oDKop0O43E3WjeNRGPiEzQEFj43nxmncb0VcrGnXHGKBnUGE8LnO/rTo9tVoE7LOIg8Qd3V8SKw9J48DHphnUTx+Kh579vbWzUgp217WDfI5HPtM+K5cSzPOU+rHNVRfk2uf+GVV5JgYK9Fs+zJwGUwAgkdDsNRIXb7EYA8dTn/3s3o1vwktiueuL7rxTYrZvszy4IUFncBSA77F6iSVuO2dkRuB8hKypct6wCN06kfzdltsYE+rqAVqmVL2XnIZkW11bzHLyu0SQSSJ5gum4infwPX5V6JZ+B9fH2J3PcGUexSnT1WUu9ElNY27Tb+z1Hd3DXj0TMUK5mRE1LjzN4LV1Qabia4SEtViW5vbOnhR7Z/vG6dDt13rcZixZ9B3ru5QxN5IXC9lY5MkANWev+xryH6/2Ywzq6D0XCMCSSQbIs/CGJ1u1PuFz8MPehhmu4SlQgc/Pf/uFKOIbMzatX1kiaJuPJz9ti9A1usbuqc+seGN84kkDPACU86HbqyFsZdZ0eNS5VUP8b8sfP5UZYge8g8WxqFbj4U5xHIGJ3LSGxjca80RTdmK8Mykogxg9uk3CpvOaunkYyCNPylakPO9fd6ymtAUXna5+HKlwHSV9Q7wsycv8OghIZKzRNPVZ6cpdXG1kGke3vW7W6maUzUIri2nt6yqtPrDP6gOQ3KJVhzb6H+MtQuZUanWvBf2CJuPbuXtKmbSsjIyJKkECxDiYTawt2M6JNO11Z7NU3WS75v74yCRkD1Vp0whndme00ot+o4C8OF01Y+SAog2PNmgyrH8oGNVfKdL5E6aEOqa6HHiiD99+QKyhPADFLV5jXMbMnm59b6hWur1fd2dMoMYRwAJRUQtwn56qWIm7Pdvc+IF3OuKiXfDmpQMuvtNV6oj1l/4OZ7dSedyu2enX+lV2N51KMGtmqAy2y/6bPrzN/KJeRukiPxfmpHwROOBdb5Jw32ogpi+mZ8YLsXpRdE4ACd9/1ucbqNmoBQmFDoWrU6oKSZiqAZksomRHI5eqv3ytk+ChXAgfUW7zgmm7mKXLm4QvcD0eoWZjVPd6d5h6r2/iDy5O1ODROxoPTlPeaFofkvmgE3gwYkixmEgwojKhfiQcxJNfZpO6+SHaTu2yL/PZjmRHHGIEuRvySSTvd/iLekWZ0wI4lPJoxnJg8FXMYLHtY4IHAq+LVKQNl8bxKdQuNE5TEgetohXo2mIpeMKDg3jrt02JdVHBZ8HC916cONCyKaLfPAI91E4plQ7GPwVy/vnNQdxHxkpC2+nrTQ9mGK+4mc67SB6+Vam38TR/EAs339bXL7c4jcMr5PTVsoqfzOs4eRy0BeFnAI2tXgufXx27LM+YyzLUUZxLwrhsQxjGkd/Jk+AzjZR17KSgxd2mhaKvLUWZWnJeiiJXwFx/Ol2+nertqmYP+4qMir2yE5nbfV6xcP3NvvlFA2rovkKJ433XefbIeb8f3qFH5ymNrvbqGBzFkTsVKPtxuESf17MTd3cqy18Ex8AGr1xQSsAMBxChaV6sxB8GaiPIWkJd0vptTT6mMpvQfHgYoE2TWOEcJHVgu4QaL+o2Q4sJaIwmOeYxra8v9+583NsjrT63zugCUR/dcpdbQK27pYZT52PfAVK/j+IEESMBFwCi3s9MrKxgmcIeH91ZcfPMel5M7tGlUuTHfPqL/GZoF2vf5y/e4xnzeVT4C7DdDkHbVXnqntu65cVfHYn9TFEX0A+EBWNBvjmAeDwW35vQhWs6N2FNhxxhUFpE23kz7DitWUwW1GW++aLkcrnE6o8ak6I8pHl52kqcupHAnRTxPfaUucC0ogfdcs8qwEg7RYteo6WVmWvV1bXIpjGuMB7GDju4ocEfFZLdZrYsFWs/xh29KjdX4QNlSYQ0wH/DycwOXLkBGP2sa/SpLSvCSolqvfVYXV6zsW8+rbwJC/TVT4GJrCiahcUd64pN++7Fclml/MTFldWsnfQclGgk1YFG47Kbu6lqxxXCdMM+P9tfEpDYS38z/FKOdEcfXeAJIRmPOMcGUxsldvkVuuWSFYfVDwfqeOg9t1gRV8zWO8Fetm4g4GZ3WJG1nHMzG9Z55tWLzNq+5AnNOfYI55t0XC2SelqDY/5A0Y77r0TvB8LZAH3J1PpmsHhTWxTq0VazhAdb5aIdFkyzR8j3WfVhhDySYu+t27sNcbgrcX5EJ1RTUiYRV05yr+ulcBQ8RPNxBacRcBVcwCgnEOgEs8Jzwj85GfDEWlvD/PhbTUaLHmn0YnD6ZuEmmf+md+Ry/KSwcjz08TVCuxxTkgfhOvRA+14X3QL/nx97sZx4qd1y50gjxOenczoLnrV46n0A2aDz0Fx9tki8/LnIvTrlPsrzBbx+hQn10wcp8bsRz0i/flRkLWwVrvZMR4tTTL8zSxTSX9xiMAzAcoCTQocdl6GJ4soYbbZEn7lxtuYoYWZZPPCtTcvolCrJPgx0yLGM+mfLeJnUhLfM6/pBj0+XokzL8nhMuv6W728MBHmcP35xnnIc56p7nervbeO/lApk1w78WLhKZIRzgQM1Uj7rbkB06ZSNW+6vJRYJwp0By5W09jPka+15/cp0s1DJHx5+aKchN0VdDF7DAhjCuX6eXy7svFbg96AK1xW31E2hVXV0T+H+w+s8JyZ43n1klk97RmCJK0AQQv4hVJ6syFXRjjTgRFrhAymEjTrXNIUdpNsPzdmbmQvFuZD21PN9Jok5sT7zVz/0fBFb34ZYbK9Jdk8M898HIWBluyMZ57jEz9T8k//+8Q3YBNmQQsMYstjSScF4r0FhQV/GsS7sau6AUmw9f5rF4uHry7f5GWQ1sQ4bBSe84JyTAHEdLvw4cliIPvjyspS8TNe1PfG21vP+y60HfiYPCc8oVt/aQ0Y20tr/9/HqvODqE+tz5VI50z3Ypd4EYIAbvybtW+ymMH04f6j789stXyhkXZ8mAIR43dvdOfYMkWWgjkJyp5x1/usstPtB+LJrfdfVKv8Why27uoQtMriyGUBRhQEAyQjOj9C/fl3kpi1g4v+Dq3Rq0eGLueeSWPPdz0t/P7KxKaZdA3XJvg6J5zTnLjM+w7L0+dZB73zP3rZEfvy51f8YbGCJu1/rhSN5Yn0C59vW0wLH3aemzfoNdjF/T3BpYUESN3ECCft100Qq3UhvoGLtvmzJzTES6qGsIkZGhI+k201zyUHLCpSiir05XFDGGgcNc8U94jyLdVkUR21D02LrqlaIrjLEk/F3G0t123lh9PSBacgThvFagcVjnKmQ99RWU+Jn9q2eFHg+5FBKIdQKnnNfFrSji//cVi6sNyyEULKvA7fzxO1YbFidzO5SWWx/zVhThTYV8D2bCKxw7amyKXHWHJp9qwE3ymrt7GooivJ9gHdukVk2r7HdwqhH6Yt2G96ec38VLUdyu1jX8/pGjwhTUXb3jid6q0LYzN/m9IgkhxmIqir4HwNoJ7ylYXSGw4oHV8kVVXofC7f9YXbhqKQmkKOJZE7ysz2coW3Tela4SHPX1BYkZoSiC2dq8Gs2LUmO8N4/HAgAsxpSmE4jY/y577JWmhYXbaBIRZkRt+m3jGcESKN7k+Q8Dq2pYabNmN+ymSTRG7udy48A15s/yf0gL9tpOOG/U2AwndJN9JIGoJ1Bc6JmrEAowc3qZ4UZnDrxHToI7YRm2zZ9dYe7iKwnELAHEGpuCHA6m+yLcK2GFMsvxFGkoEFzZrXLJ/3U33DaxDW6mj9yaZ2QgxqI86pseqM8M56rCAq8uKIxwE4W7ZyBByQhksn/+gXzBwg4ELu5wm8T5ECguVld1KGYnqcJjyteTi+WD1wqM8B+cgwR9UPC6aFZ7KIywoP7fBcvNw71eUSMbgrrSi+dVCcKYrOE5hxzrcXFH+bMb/rlMijQuG4IYzXtf6OuuL3us9nOquutCPplYKJ//d5Nk90uQe57tY2zDP/deu0qWzHcpmlYlz31APW8uvr6b26KI81DHdrLmloCSjQoAl9zQzT3PHTU+wxiDr9uw2TSYY5yP3rZa1mu4FKSPJkK7+ZEcdxK0Y9TV9eO3Y8dbzGTT3NeIKYsIFt5zdEdNosI0us29iTy/8QRmzSjXMgoZxmQNxfCZ9wcYK1hI6dwjp50Rx2m2hrjLuRpnGiuSpPUVh47cWYgzVgbNcZKATQlgrjr8BJc7FRTD5z7c3bAuIC69p8Y/IcGZKYjJQXwohQRimQCsVMivAEGG4J++9SiDsJxN+7TErSz201jAL8Wj6EHRsJbi+XJSkVFWy+SJmOcv1BVywNBkgVUQcvAx9SuLiFl+5t41Rvyf2QZquB5waJp7QRoZnq1y6HEe90kk1Hr7hfVul0koUsgE/ZrG5d38SLZxGuIM8QfLZSDBdoTaoC9WgeJcXrrNnQwRGZVNRRHHIbYTCpmZIRpKG+opwsoKJRp/W30i2PC5qVmZ0e7eYzxehj+oeypCf0zBvPbY7asNd3szjhEKen3KIiyKT929xq0ooh3EhH/2n01acsblOotxmGMxr8PXXROImLKIrsGKQWVx1zeJR4SOAFbxkA0VZUPMoHEkjMCfVbA6hUkWbqmxIiN18QbxHpSmEzBXipt+Js8ggcAEEFONGJ3zrlBLxs6AESiIViURZ2KhC3NVUx/UAl81+ra24o+zSTfVybiqK7cbvwO4VuIPbpqrLMnuUKvVlHVad9oqsNqZzwTYDuVs/NkeK595bFLyzh+jbkD79cU2I9YPiWJ8BQkATe+lTprIBb9tKLIQq+v5+vytRsIX1x7Pv8jwaRUsHNWnLL78yFo/RRHn4npvPO3KtAxXWpRfG7ZPB0nTsBuTge/3oLOWbNtcHlgptfanKe/7DUx0Xw/nfTvVo7yb7WBem/5ViZx4lute9N09yag9GygEa40upAVK8gjmVkFyx1CPxdp+NL6PqLI4cv90d3H0aITLMdmTAAK//9RYnwPVtWvIiPaCFNAdUttKwdoanXRRZ7HaKBtizdBqz5GEtlejxtEFNViiHVLjtLQCE9wEy4/nBSaApA546Dzo6HSj3mS6Zn3FXLVeH3RRDxYPibBWNJTpNXDLsbMVvCiNJ5CU5FxeiDOGYoAyWJCLrusmsBAiscmeo1PUquexYiHzsVXSM73HjcycuxLUGkTmdN8syThvo2YEDSRwCzUFi7PtVPmDUonkenB1NWXwiGTB364EFtFAAjfOPFWe6hMoqUeP7yRIpGXN+Frf8VCKQy2mtdBst0AV5EBizfyKfnfUZzbfGFCch0yzgcT3/ji1lnRCYptAwwvLtsDfsrBcWqS91nMbMiJVg4dLw3RFXoYEXATgcvGR+sbjj4Ki361l5GiPCwyZNI1Ax4x4LWFDN8CmUePRjSGAhyKra1ZjzuExHgKs6exh0Zh37R2uXL+qGTEfeqWvoPRMb41Xu/TG7n7D/lFLfy3zSeSy3eJEBMsbStU0RgJZD3GeWQ7Htw1reR3rPt+SHlB6AylE1nPwfrV6QQUSxOw1lJTwzIu6ynGneSvEKA1SofGLkJS0NkZN10Bth2qbrysr7llZiX/r2G4V3/PMfQ2N1zzGya+RLDkYUWURN+3wE7KoLDr528u+RwWBAw7tJE5dbbPDDYCySCEBErAfAf42m3ZPOqRE/LGwaR32ORpZT5G8xkzwYt0N10UkjXnzmXVemTZxzKaNHqsUrFfvvrjeK6GUtZ2WeA93S8QEIp4O8tdvm5tVtiuQm6bZbySwsSqKc9XKivhKqwXuElWyu/bwjqk0zw/06uu2GugY322+tXcRb2pNOGgeb8ah4jM4Wa2z5jGx8BrJha+Izwr7H5Ipk99dK8sWelKAx8JN5xhJwC4EkGzqjIt62aU7juxHJFf8HAmMnSaBMBHgb7NpoJ2sLCJO8aaHsw1FEcrSOy8UGNa1+HatjEQnKA1RX2wvylPASmhasVDnEMlkrJKqMX3Id9B2Z8mMGd+VCqyUoZLZv2x210lE8pzPNdNq5WaLyVMvhNIaSGoDgdKEjK9NyT6K83pr3J9VkDHWqiiiDM8Bmrm1IUECQKugRuKiuU3zrkH5sgpVkFGLEXKylj1BOSCrhRBxochCawoyzMaqpGdGblE64soiViPOuTxbbr10Xqzef46bBCJK4OiTumoW2PoLEEe0cw65eMcM7wRJDuk2u0kCUU+AlsWm3eL2Gn/tVLn6TldtQ/QfLpxQ/lYsrjIshL5Kl+8YEff79eQid43DI/6eYeTUQJkIWCuRBfXkczu7yzygbShqoRRca7+DUiUuvpUgnu/Op3rLOy8WGLUPkYRm3BEdBfUGTYEy21RFEedu2uCxouLzoVqbcMn8SoMZrosSIuhDQ4JMpVC8zTqNfz8zU5Bhfp26vyKTa2PceBFXOfWDQjn9wizjUrAgPvBiX5n8XqHRR5Q5Ofm8zu56lqh1+emHsVtBIaYti/iGIF3/yP3StRh6cUPfTe4jARIIMYFkjRs++dyeIW419prjA2ns3XOO2BkEIvmA5QxC3r10smXRWv6hi2bvvEhr+JmChHVICrVsYZVRJ9C3nASOe/elArVytdWSGC5LFkpZWMtZmG3h9YPXNnhZ46z7gn2PzK0P35wrN9yfbShrUJ5u2Vkmw7dNWEmRrC8YQb1FWBJhKYUMHp4sz2tpHijUKD8CQcwklDUzO6qx0eef/31RIlCqIWjrMC1rAYHFsDHKIo6d9E6hkb/EdIvt1TdB/n17D+zyEiiKD92UJyu1FEasSnqnxrsFh5qRd9RoqFtvQntnX5ZtpCBuwik8lARIoJkExp/dw8iu2MxmYv70zC6Rm8RjHj4BkEB9BNQ40om/zfroBNyOBUSEJjhRUBbru88CZEjRwSRpttFBqhT97R+ZRn3lkful+A0RVrqXHsmXbz6pXwmrrNgmj9yaZ9Tu82sgBBv++r1CHryx4VI430wpltsvX2HUOwzmkkjgc881qwwLoPV8U1FEOZ4HbsiVjfVkFzXPgdUzFG6hqCc5dWL9FkNYMKEoovRZLEtmVuSeM1pVV/tU1ozgnXjq7qX6Q/cU5IxgV3hpEoh6AniIeuE/e4lv3aaoH3gLDBCZ784+8lddmfWO42iBS7FJEiCBRhLoPaC9PDFhRCOP5mEmgbuuXiCzHejpNVpdOK+6o6cgvAmWw+fuX2NkJc3sEi+7qYvk/oekasiFK+4LVrRLT1lcb9kZZFI94NA06dq9nSZ/a23U71up1jwoc8XqghlIzFqA2Df3j83qPupvBctWyxnKeJgy5f3CgEofSnKMPbyj9B+cpOW9tDSTXhPWxMXzKg2rn3m+9XWv/VMEdRchpcW19SrO5jkdtRQP+tJb4w2REAhK4oI/KwylDG65Yw5Pk85ZLl7faVwjXE8DSY+cBMnulyAZmXFGDUQkrvnha1csJ54vrGVIoFyijnUgQd/HaXwi3FmhuGLMy9TCOf3LEiP5T6BzDjyqo8EH+1Ai5bcf/WMawfKw4z3uuz99W7pLRTjQtSK5DfUwJ3yxr2H5jkQ/bKUsVpTXyfXnz1GfZ/8fWCTg8JokEK0EUCrj7meGaB0nT92paB1ruMb12G2L9T/IwnBdjtchARLYBYHT/9VLTvsn3ex3gclv95eT1ssLDy732273DQ++3Ncol4F+PvB/uUY9ZWufkQX0mYm7u10r77hiZZOTsljb43sSCBeBPfZKk3ueGxquy/ldx1a+BvAVv+XRQZLcPuJ5d/xAcQMJRBOBi67rQ0UxxDd01DjPymWIm2ZzJEACQRAYNZa/ySCwyT5jMqRVCxRhD6YvjT0H5S6sJRZK1bLoK4Wa9GazZhA1ZXsw2WHMk/lKAmEksE+E5zJbKYvg3j07Sa69V1d+2jSciSmM94iXIoGoInDsKbsZ9U2jalA2GMyeo9MlTi22FBIggcgT6LxbgpYYSI58RxzYAyQF6jeovaN6jjg8a4F6JLcZvk8Hw50RiiRKO1yoZS9S013GCLihLltALzZH3eRY7ayqQ5Fe+LKlCW/k6I5aTiNH3nhqZax+NThuEmgRAsP2SZPzr+rdIm3HeqNIoDB0r1SZ/UvgBAuxzofjJ4FwEoj0w1U4x9oS1wK/pfM3t0TTLdbmt5qY5sJrXRlQEXN4s2YShfEQmTTNEg/mxREruH277qSQgM0J5PRrr7G2kUtuAzy2XQY/4R/d5JBju9j8FrJ7JOAcArv1TJQb7htoBKA7p9fO6ikfUJ11v9jb6CUwaqwrjX/0jrBlR+bEuQxZTN94ap0gY6kpSHZjVRS3aTKyFx7Ml8nvMr7cZMRXexOwQ4iLrRLc+N6ubdt2yKuPr9SaOOt8d/EzCZBAEwj0G9RBtNlX6QAACoRJREFUbnp4kGYrc2U2a8KpPLQJBFDL6+Lxv2sNq8BZ45rQFA8lARIIkkBOf1cWVCgKlOAJ3HHlfJkz03meEij9sc8YV2bQdM3QGRfXysj0mbusWswag8FT4ZkkED4C7RLayIv/3UvSI/zsZmtl0bwdX368Xl5+LPiaMmY7fCWBWCQw9vBMueLW/iyREaab/+mH6+QVna8oJEACkSFw59NDZMQoV2H1yPQgOq66cmmFXHPOHNlBd83ouKEcheMInHxuDznzkuyI99u2bqhWMkee2FXuenqodEiLs27mexIggQYIIJsdJplr796dimIDnEK968i/d5Ws7q5aV6Fum+2RAAk0TABx2VQUG2bU2L291UKLxUYKCZBA+AmkqM5z4lndw3/hAFd0hLKIfg8dmSqPvj5cC44yu1mA+8hNJOBFIDGpjdz00EDBqpTQFcuLTUt/aKsuT2denN3Sl2H7JEACPgSwQIbkeJTQETjz4l4Ct04KCZBAeAmccl5PSbJJKUFHzQBZ3RLk4deGyckKsF1im/DeNV6NBJxAQBXD0Qd2kscnjIh4qmUn4GqpPh5waKb0HdihpZpnuyRAAgEIjDksU/oMcFbJhwDDsNWmzl0T5OjxXW3VJ3aGBKKdQBfVd44an2WbYToiZjEQreJNW+X9V/Jk2tQNgkQ4FBKIdQKDhqfqqnq27D40JdZR2GL882aVyW2XzdPU7ZyfbHFD2ImoJhDfrrU8O3GkdNH6ipTQEthcVisXn/SHVJR7CtqH9gpsjQRIwErgOq03j8Uvu4hjlUUTYH5ulUx4Pldm/lAkwmcyEwtfY4hAj5wkOevSbFoSbXjP33s5Tz54bbUNe8YukUAUEVCPimvuGiDjjugcRYOy11D+1Kyod1+9QLZzcd5eN4a9iToCR2jeg0tv7GurcTleWTRponjs9K82GkpjYUGNuZmvJBCVBBK1APye+6bL6IMyZP+DO0nrNgxMtOONhlHxoZsWyS/fb7Jj99gnEogKAied08NYMIuKwdh4EFMnrpNXn2CmZxvfInbN4QSG7Jkqdz0zVNq2tdczXdQoi9bvx8olFYbSCGvjqmWVtDha4fC9Ywl07BSvtaMyDAviHnulMumAQ+7kluptcuO/5soqTUNPIQESCC2BfcZmyM1aQ5Y1FUPLtb7Wnr1/mXwzpaC+3dxOAiQQJAHEKSKRJ7Kg2k2iUlm0Qt64fossW1ghiHEs0T/ra/GmGqnZst16ON+TQMQItNGVpI7p8QKlMH3nn/m+W69EI2EKH4gidnuadWF4O1x33hwpLd7arHZ4MgmQgIdArz7J8tCrwwTZnynhIVBXu0Nuu3yeLJxTFp4L8iokEAMEMIdhLsOcZkeJemXRjtDZJxIggdgjsOivcrn9inmytYYLVLF39zniUBNITY+TR14bzoQ2oQbbiPbKSmrl+n/OkQ1rtzTiaB5CAiTQEIE2GkZ0o5Y6g+eYXcVRpTPsCpH9IgESIIFdERg4LEXue2EPw2q8q2O5nwRIoH4CPXX1/eFXqSjWT6hl96R2jJOHXhnGzNsti5mtxwCB9ilt5fYnBttaUcRtoGUxBr6MHCIJkIB9CBQVbpX7r18oyxdttk+n2BMScAgBrL5fc/cAup7a4H7Vbt0uzz+4XL77bIMNesMukICzCHTrlSS3PjpIduuZaPuOU1m0/S1iB0mABKKNAFxRn753qfz4dWG0DY3jIYGWIaDJAcefrVlPL86WVvSJahnGQbY66d18mfBcLstqBMmPp8UegRH7dpTrtZZicoe2jhg8lUVH3CZ2kgRIIOoIaFmND99cI6jFuGM7i8RG3f3lgEJGIL5da7n85n4y7kjWUQwZ1BA3NGtGsTx62xKpqqgLcctsjgSiiIAueh1/Wjc574ocR5U8o7IYRd9BDoUESMB5BJYvrpC3nl0lc38vdV7n2WMSaEECrTT98wGHdZIz1ZqYpWnlKfYmUKwu9u+/mifTpm6Qbdu4AGbvu8XehZtA/yEd5JzLc2TIiNRwX7rZ16Oy2GyEbIAESIAEmk9g9q8lMkGVRqM2bPObYwsk4GgCe+yVZjxY9R3Y3tHjiMXOr8mtkrfVLXXmj0Wscx2LXwCO2YsAYhLPvCRb9juok2PrwVJZ9Lql/EACJEACkSOwQ6tq/O/LjfLuy7lSuL4mch3hlUkgQgSy+yXLOZflyJ6jO0aoB7xsqAgs1HJB8JpYPLc8VE2yHRJwDIE0rZt96j97yhEnZAnqaDtZqCw6+e6x7yRAAlFJAFkGZ/1SIjN/KJI/fiqW8tLaqBwnB0UCIJCZ1c5IHT9qXIbsMTKNCWyi7GsBpXHm9CJjPlu/pjrKRsfhkICHQFL7tjJyv44yamyG7H1AuiQktvHsdPA7KosOvnnsOgmQQPQT2K6xP4t0ZR6KIx64ClgIO/pverSPUBfZs/smGw9UeKjqM0BdTZ298B7tdyxk41u9sso1l+l8tnxhhezYwdjGkMFlQxEhkNG53c65LF2G6GJXW4dbEQNBpLIYiAq3kQAJkIBNCSCJRGnxVilTayMsjmUlntfqym3CRy+b3rgY65bmppH2mhY+JS1OUMTdeNX3Kfo+vVO88TnGkHC4PgQqyusEdWfLS/FX5zWXVZTXCpNE+wDjx4gRSExqI6k75y/jdee8hrkNyiLmu2gWKovRfHc5NhIgARIgARIgARIgARIgARIIkgBL2wYJjqeRAAmQAAmQAAmQAAmQAAmQQDQToLIYzXeXYyMBEiABEiABEiABEiABEiCBIAlQWQwSHE8jARIgARIgARIgARIgARIggWgmQGUxmu8ux0YCJEACJEACJEACJEACJEACQRKgshgkOJ5GAiRAAiRAAiRAAiRAAiRAAtFMgMpiNN9djo0ESIAESIAESIAESIAESIAEgiRAZTFIcDyNBEiABEiABEiABEiABEiABKKZAJXFaL67HBsJkAAJkAAJkAAJkAAJkAAJBEmAymKQ4HgaCZAACZAACZAACZAACZAACUQzASqL0Xx3OTYSIAESIAESIAESIAESIAESCJIAlcUgwfE0EiABEiABEiABEiABEiABEohmAlQWo/nucmwkQAIkQAIkQAIkQAIkQAIkECQBKotBguNpJEACJEACJEACJEACJEACJBDNBKgsRvPd5dhIgARIgARIgARIgARIgARIIEgCVBaDBMfTSIAESIAESIAESIAESIAESCCaCVBZjOa7y7GRAAmQAAmQAAmQAAmQAAmQQJAEqCwGCY6nkQAJkAAJkAAJkAAJkAAJkEA0E6CyGM13l2MjARIgARIgARIgARIgARIggSAJUFkMEhxPIwESIAESIAESIAESIAESIIFoJkBlMZrvLsdGAiRAAiRAAiRAAiRAAiRAAkESoLIYJDieRgIkQAIkQAIkQAIkQAIkQALRTIDKYjTfXY6NBEiABEiABEiABEiABEiABIIkQGUxSHA8jQRIgARIgARIgARIgARIgASimQCVxWi+uxwbCZAACZAACZAACZAACZAACQRJgMpikOB4GgmQAAmQAAmQAAmQAAmQAAlEMwEqi9F8dzk2EiABEiABEiABEiABEiABEgiSwP8DOdatjZ7OLj8AAAAASUVORK5CYII=)" + ], + "metadata": { + "id": "M-dmSB0_zHCQ" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uqYBNOM2YZD9" + }, + "source": [ + "## Using OpenAI models" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ogiF4g5Z-bzG" + }, + "outputs": [], + "source": [ + "from scrapegraphai.graphs import SmartScraperGraph" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7ZzONlJ6-oe_" + }, + "source": [ + "Define the configuration for the graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MPZgrZ12-eRc" + }, + "outputs": [], + "source": [ + "graph_config = {\n", + " \"llm\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"openai/gpt-4o-mini\",\n", + " \"temperature\":0,\n", + " },\n", + " \"verbose\":True,\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DjDt_10r-q8P" + }, + "source": [ + "Create the SmartScraperGraph instance and run it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aV4VTnx9-h_d" + }, + "outputs": [], + "source": [ + "smart_scraper_graph = SmartScraperGraph(\n", + " prompt=\"List me all the projects with their descriptions.\",\n", + " # also accepts a string with the already downloaded HTML code\n", + " source=\"https://perinim.github.io/projects/\",\n", + " config=graph_config\n", + ")" + ] + }, + { + "cell_type": "code", + "source": [ + "graph_config = {\n", + " \"llm\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"openai/gpt-4o-mini\",\n", + " },\n", + " \"verbose\": True,\n", + " \"headless\": True,\n", + "}\n", + "\n", + "# ************************************************\n", + "# Create the SmartScraperGraph instance and run it\n", + "# ************************************************\n", + "\n", + "smart_scraper_graph = SmartScraperGraph(\n", + " prompt=\"List me all the projects with their description\",\n", + " source=\"https://perinim.github.io/projects/\",\n", + " config=graph_config\n", + ")" + ], + "metadata": { + "id": "E3pyGQZLTiZ8" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Zty23idsAtwU", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "419dd75f-18c6-44d2-da82-ca8967d17e0f" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "--- Executing Fetch Node ---\n", + "--- (Fetching HTML from: https://perinim.github.io/projects/) ---\n", + "--- Executing ParseNode Node ---\n", + "--- Executing GenerateAnswer Node ---\n" + ] + } + ], + "source": [ + "result = smart_scraper_graph.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rnGhLGCuAqRU", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "062aeab2-3e96-4fec-d04a-b9acae142f40" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{\n", + " \"projects\": [\n", + " {\n", + " \"name\": \"Rotary Pendulum RL\",\n", + " \"description\": \"Open Source project aimed at controlling a real life rotary pendulum using RL algorithms\"\n", + " },\n", + " {\n", + " \"name\": \"DQN Implementation from scratch\",\n", + " \"description\": \"Developed a Deep Q-Network algorithm to train a simple and double pendulum\"\n", + " },\n", + " {\n", + " \"name\": \"Multi Agents HAED\",\n", + " \"description\": \"University project which focuses on simulating a multi-agent system to perform environment mapping. Agents, equipped with sensors, explore and record their surroundings, considering uncertainties in their readings.\"\n", + " },\n", + " {\n", + " \"name\": \"Wireless ESC for Modular Drones\",\n", + " \"description\": \"Modular drone architecture proposal and proof of concept. The project received maximum grade.\"\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "import json\n", + "\n", + "output = json.dumps(result, indent=2)\n", + "\n", + "line_list = output.split(\"\\n\") # Sort of line replacing \"\\n\" with a new line\n", + "\n", + "for line in line_list:\n", + " print(line)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5poLHYLVa-6E" + }, + "source": [ + "# Search graph\n", + "This graph **transforms** the user prompt in a **internet search query**, fetch the relevant URLs, and start the scraping process. Similar to the **SmartScraperGraph** but with the addition of the **SearchInternetNode** node." + ] + }, + { + "cell_type": "markdown", + "source": [ + "![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA9IAAAEXCAIAAADOS+unAAAgAElEQVR4Aey9h5sUVfr+/ftX3ut63+v3/a6rwHTOYTpOT8eZIa2rq2sEMaxr2KBrWMOuKypIFFBBUJKIZAYmzxDNidUVw5pWCRM6VFc6L6fu7kMzoAvszjAwT19NU91dVeecT9VU3+ep+zzn/zB6EAEiQASIABEgAkSACBABIjDCBP7PCO+fdk8EiAARIAJEgAgQASJABIgAI9lNJwERIAJEgAgQASJABIgAERhxAiS7RxwxFUAEiAARIAJEgAgQASJABEh20zlABIgAESACRIAIEAEiQARGnADJ7hFHTAUQASJABIgAESACRIAIEAGS3XQOEAEiQASIABEgAkSACBCBESdAsnvEEVMBRIAIEAEiQASIABEgAkSAZDedA0SACBABIkAEiAARIAJEYMQJkOweccRUABEgAkSACBABIkAEiAARINlN5wARIAJEgAgQASJABIgAERhxAiS7RxwxFUAEiAARIAJEgAgQASJABEh20zlABIgAESACRIAIEAEiQARGnADJ7hFHTAUQASJABIgAESACRIAIEAGS3XQOEAEiQASIABEgAkSACBCBESdAsnvEEVMBRIAIEAEiQASIABEgAkSAZDedA0SACBABIkAEiAARIAJEYMQJkOweccRUABEgAkSACBABIkAEiAARINlN5wARIAJEgAgQASJABIgAERhxAiS7RxwxFUAEiAARIAJEgAgQASJABEh20zlABIgAESACRIAIEAEiQARGnADJ7hFHTAUQASJABIgAESACRIAIEAGS3XQOEAEiQASIABEgAkSACBCBESdAsnvEEVMBRIAIEAEiQASIABEgAkSAZDedA0SACBABIkAEiAARIAJEYMQJkOweccRUABEgAkSACBABIkAEiAARINlN5wARIAJEgAgQASJABIgAERhxAiS7RxwxFUAEiAARIAJEgAgQASJABEh20zlABIgAESACRIAIEAEiQARGnADJ7hFHTAUQASJABIgAESACRIAIEAGS3XQOEAEiQASIABEgAkSACBCBESdAsnvEEVMBRIAIEAEiQASIABEgAkSAZDedA0SACPyXCaiqKssydqoaDyzrui4WNE37L5d6MexOURTGWKlUEigURRHL59QCXdcBGfvUjIfAyxgrFAp4q6qq+FzT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)" + ], + "metadata": { + "id": "NRIoaXSzzP8M" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RIvbQjyhbHhW" + }, + "outputs": [], + "source": [ + "from scrapegraphai.graphs import SearchGraph\n", + "\n", + "# Define the configuration for the graph\n", + "graph_config = {\n", + " \"llm\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"openai/gpt-4o-mini\",\n", + " \"temperature\": 0,\n", + " },\n", + "}\n", + "\n", + "# Create the SearchGraph instance\n", + "search_graph = SearchGraph(\n", + " prompt=\"List me all the European countries. Look in wikipedia.\",\n", + " config=graph_config\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XnVtc7SzCkUY" + }, + "outputs": [], + "source": [ + "result = search_graph.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3LPAh-yQCqkY" + }, + "source": [ + "Prettify the result and display the JSON" + ] + }, + { + "cell_type": "code", + "source": [ + "import json\n", + "\n", + "output = json.dumps(result, indent=2)\n", + "\n", + "line_list = output.split(\"\\n\") # Sort of line replacing \"\\n\" with a new line\n", + "\n", + "for line in line_list:\n", + " print(line)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xgnWDLTjzHwv", + "outputId": "f0c8ebf4-5ba5-4330-dbd8-1c9fdd93eaeb" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{\n", + " \"European_countries\": [\n", + " \"Albania\",\n", + " \"Andorra\",\n", + " \"Armenia\",\n", + " \"Austria\",\n", + " \"Azerbaijan\",\n", + " \"Belarus\",\n", + " \"Belgium\",\n", + " \"Bosnia and Herzegovina\",\n", + " \"Bulgaria\",\n", + " \"Croatia\",\n", + " \"Cyprus\",\n", + " \"Czech Republic\",\n", + " \"Denmark\",\n", + " \"Estonia\",\n", + " \"Finland\",\n", + " \"France\",\n", + " \"Georgia\",\n", + " \"Germany\",\n", + " \"Greece\",\n", + " \"Hungary\",\n", + " \"Iceland\",\n", + " \"Ireland\",\n", + " \"Italy\",\n", + " \"Jersey\",\n", + " \"Isle of Man\",\n", + " \"Kazakhstan\",\n", + " \"Latvia\",\n", + " \"Liechtenstein\",\n", + " \"Lithuania\",\n", + " \"Luxembourg\",\n", + " \"Malta\",\n", + " \"Moldova\",\n", + " \"Monaco\",\n", + " \"Montenegro\",\n", + " \"Netherlands\",\n", + " \"North Macedonia\",\n", + " \"Norway\",\n", + " \"Poland\",\n", + " \"Portugal\",\n", + " \"Romania\",\n", + " \"Russia\",\n", + " \"San Marino\",\n", + " \"Serbia\",\n", + " \"Slovakia\",\n", + " \"Slovenia\",\n", + " \"Spain\",\n", + " \"Sweden\",\n", + " \"Switzerland\",\n", + " \"Turkey\",\n", + " \"Ukraine\",\n", + " \"United Kingdom\",\n", + " \"Vatican City\",\n", + " \"Kosovo\",\n", + " \"Gibraltar\",\n", + " \"Faroe Islands\",\n", + " \"Guernsey\",\n", + " \"Jersey\"\n", + " ],\n", + " \"sources\": [\n", + " \"https://simple.wikipedia.org/wiki/List_of_European_countries\",\n", + " \"https://en.wikipedia.org/wiki/List_of_European_countries_by_population\",\n", + " \"https://en.wikipedia.org/wiki/Member_state_of_the_European_Union\"\n", + " ]\n", + "}\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "N5IMdKHvlXFY" + }, + "source": [ + "# SpeechGraph\n", + "**SpeechGraph** is a class representing one of the default scraping pipelines that generate the answer together with an audio file. Similar to the **SmartScraperGraph** but with the addition of the **TextToSpeechNode** node.\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "![image.png](data:image/png;base64,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)" + ], + "metadata": { + "id": "pqJsEVgizs-M" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "W9KhWlT3lXFd" + }, + "outputs": [], + "source": [ + "from scrapegraphai.graphs import SpeechGraph\n", + "\n", + "# Define the configuration for the graph\n", + "graph_config = {\n", + " \"llm\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"gpt-3.5-turbo\",\n", + " },\n", + " \"tts_model\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"tts-1\",\n", + " \"voice\": \"alloy\"\n", + " },\n", + " \"output_path\": \"website_summary.mp3\",\n", + "}\n", + "\n", + "# Create the SpeechGraph instance\n", + "speech_graph = SpeechGraph(\n", + " prompt=\"Create a summary of the website\",\n", + " source=\"https://perinim.github.io/projects/\",\n", + " config=graph_config,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nVolb3paEczD", + "outputId": "d7d316a0-7580-4a6c-8f20-7e1cb1fc3f07" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--- Executing Fetch Node ---\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Fetching pages: 100%|##########| 1/1 [00:00<00:00, 17.07it/s]\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--- Executing Parse Node ---\n", + "--- Executing RAG Node ---\n", + "--- (updated chunks metadata) ---\n", + "--- (tokens compressed and vector stored) ---\n", + "--- Executing GenerateAnswer Node ---\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Processing chunks: 100%|██████████| 1/1 [00:00<00:00, 339.78it/s]\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--- Executing TextToSpeech Node ---\n", + "Audio saved to website_summary.mp3\n" + ] + } + ], + "source": [ + "result = speech_graph.run()\n", + "answer = result.get(\"answer\", \"No answer found\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "znt2EOKZE3z2" + }, + "source": [ + "Prettify the result and display the JSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QqY0TbwbEp-O", + "outputId": "c2b1127d-0c49-4121-922e-39da65c329ee" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{\n", + " \"summary\": {\n", + " \"title\": \"Projects | Marco Perini\",\n", + " \"projects\": [\n", + " {\n", + " \"title\": \"Rotary Pendulum RL\",\n", + " \"description\": \"Open Source project aimed at controlling a real life rotary pendulum using RL algorithms\"\n", + " },\n", + " {\n", + " \"title\": \"DQN Implementation from scratch\",\n", + " \"description\": \"Developed a Deep Q-Network algorithm to train a simple and double pendulum\"\n", + " },\n", + " {\n", + " \"title\": \"Multi Agents HAED\",\n", + " \"description\": \"University project which focuses on simulating a multi-agent system to perform environment mapping. Agents, equipped with sensors, explore and record their surroundings, considering uncertainties in their readings.\"\n", + " },\n", + " {\n", + " \"title\": \"Wireless ESC for Modular Drones\",\n", + " \"description\": \"Modular drone architecture proposal and proof of concept. The project received maximum grade.\"\n", + " }\n", + " ]\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "import json\n", + "\n", + "output = json.dumps(answer, indent=2)\n", + "\n", + "line_list = output.split(\"\\n\") # Sort of line replacing \"\\n\" with a new line\n", + "\n", + "for line in line_list:\n", + " print(line)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 75 + }, + "id": "lfJ_jVwklXFd", + "outputId": "dc4ad491-4422-4edb-91ae-35775b23168a" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "\n", + " \n", + " " + ] + }, + "metadata": {} + } + ], + "source": [ + "from IPython.display import Audio\n", + "wn = Audio(\"website_summary.mp3\", autoplay=True)\n", + "display(wn)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p9kC0x4NuLTx" + }, + "source": [ + "# Build a Custom Graph\n", + "It is possible to **build your own scraping pipeline** by using the default nodes and place them as you wish, without using pre-defined graphs." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Pr6DIqt2uLUI" + }, + "source": [ + "You can create **custom graphs** based on your necessities, using standard nodes provided by the library.\n", + "\n", + "The list of the existing nodes can be found through the *nodes_metadata* json construct.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-o29vDSIvG4t", + "outputId": "be469b65-ba01-437a-e217-ed1c4f3ad264" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "dict_keys(['SearchInternetNode', 'FetchNode', 'GetProbableTagsNode', 'ParseNode', 'RAGNode', 'GenerateAnswerNode', 'ConditionalNode', 'ImageToTextNode', 'TextToSpeechNode'])" + ] + }, + "metadata": {}, + "execution_count": 17 + } + ], + "source": [ + "# check available nodes\n", + "from scrapegraphai.helpers import nodes_metadata\n", + "\n", + "nodes_metadata.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "829wW5E6vrjJ", + "outputId": "58203025-64ce-4107-f6d3-3b3cfa5537d5" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "{'description': 'Converts image content to text by \\n extracting visual information and interpreting it.',\n", + " 'type': 'node',\n", + " 'args': {'image_data': 'Data of the image to be processed.'},\n", + " 'returns': \"Updated state with the textual description of the image under 'image_text' key.\"}" + ] + }, + "metadata": {}, + "execution_count": 18 + } + ], + "source": [ + "# to get more information about a node\n", + "nodes_metadata['ImageToTextNode']" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3pnNFDckwWy7" + }, + "source": [ + "To create a custom graph we must:\n", + "\n", + "1. **Istantiate the nodes** you want to use\n", + "2. Create the graph using **BaseGraph** class, which must have a **list of nodes**, tuples representing the **edges** of the graph, an **entry_point**\n", + "3. Run it using the **execute** method\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "eQLZJyg4uLUJ" + }, + "outputs": [], + "source": [ + "from langchain_openai import OpenAIEmbeddings\n", + "from scrapegraphai.models import OpenAI\n", + "from scrapegraphai.graphs import BaseGraph\n", + "from scrapegraphai.nodes import FetchNode, ParseNode, RAGNode, GenerateAnswerNode\n", + "\n", + "# Define the configuration for the graph\n", + "graph_config = {\n", + " \"llm\": {\n", + " \"api_key\": OPENAI_API_KEY,\n", + " \"model\": \"openai/gpt-4o\",\n", + " \"temperature\": 0,\n", + " \"streaming\": True\n", + " },\n", + "}\n", + "\n", + "llm_model = OpenAI(graph_config[\"llm\"])\n", + "embedder = OpenAIEmbeddings(api_key=llm_model.openai_api_key)\n", + "\n", + "# define the nodes for the graph\n", + "fetch_node = FetchNode(\n", + " input=\"url | local_dir\",\n", + " output=[\"doc\", \"link_urls\", \"img_urls\"],\n", + " node_config={\n", + " \"verbose\": True,\n", + " \"headless\": True,\n", + " }\n", + ")\n", + "parse_node = ParseNode(\n", + " input=\"doc\",\n", + " output=[\"parsed_doc\"],\n", + " node_config={\n", + " \"chunk_size\": 4096,\n", + " \"verbose\": True,\n", + " }\n", + ")\n", + "rag_node = RAGNode(\n", + " input=\"user_prompt & (parsed_doc | doc)\",\n", + " output=[\"relevant_chunks\"],\n", + " node_config={\n", + " \"llm_model\": llm_model,\n", + " \"embedder_model\": embedder,\n", + " \"verbose\": True,\n", + " }\n", + ")\n", + "generate_answer_node = GenerateAnswerNode(\n", + " input=\"user_prompt & (relevant_chunks | parsed_doc | doc)\",\n", + " output=[\"answer\"],\n", + " node_config={\n", + " \"llm_model\": llm_model,\n", + " \"verbose\": True,\n", + " }\n", + ")\n", + "\n", + "# create the graph by defining the nodes and their connections\n", + "graph = BaseGraph(\n", + " nodes=[\n", + " fetch_node,\n", + " parse_node,\n", + " rag_node,\n", + " generate_answer_node,\n", + " ],\n", + " edges=[\n", + " (fetch_node, parse_node),\n", + " (parse_node, rag_node),\n", + " (rag_node, generate_answer_node)\n", + " ],\n", + " entry_point=fetch_node\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5FYKF9H1Fvb8", + "outputId": "666d51fe-5e2f-4398-a3b0-bb820960a0d1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Executing Fetch Node ---\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Fetching pages: 100%|##########| 1/1 [00:00<00:00, 28.65it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Executing Parse Node ---\n", + "--- Executing RAG Node ---\n", + "--- (updated chunks metadata) ---\n", + "--- (tokens compressed and vector stored) ---\n", + "--- Executing GenerateAnswer Node ---\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Processing chunks: 100%|██████████| 1/1 [00:00<00:00, 911.01it/s]\n" + ] + } + ], + "source": [ + "# execute the graph\n", + "result, execution_info = graph.execute({\n", + " \"user_prompt\": \"List me the projects with their description\",\n", + " \"url\": \"https://perinim.github.io/projects/\"\n", + "})\n", + "\n", + "# get the answer from the result\n", + "result = result.get(\"answer\", \"No answer found.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JEP8_zZ9GHW2" + }, + "source": [ + "Prettify the result and display the JSON" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nx9qGaxvFmfT", + "outputId": "fb327a6a-0dfa-417b-8dbb-505bebc96fe8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"projects\": [\n", + " {\n", + " \"title\": \"Rotary Pendulum RL\",\n", + " \"description\": \"Open Source project aimed at controlling a real life rotary pendulum using RL algorithms\"\n", + " },\n", + " {\n", + " \"title\": \"DQN Implementation from scratch\",\n", + " \"description\": \"Developed a Deep Q-Network algorithm to train a simple and double pendulum\"\n", + " },\n", + " {\n", + " \"title\": \"Multi Agents HAED\",\n", + " \"description\": \"University project which focuses on simulating a multi-agent system to perform environment mapping. Agents, equipped with sensors, explore and record their surroundings, considering uncertainties in their readings.\"\n", + " },\n", + " {\n", + " \"title\": \"Wireless ESC for Modular Drones\",\n", + " \"description\": \"Modular drone architecture proposal and proof of concept. The project received maximum grade.\"\n", + " }\n", + " ]\n", + "}\n" + ] + } + ], + "source": [ + "import json\n", + "\n", + "output = json.dumps(result, indent=2)\n", + "\n", + "line_list = output.split(\"\\n\") # Sort of line replacing \"\\n\" with a new line\n", + "\n", + "for line in line_list:\n", + " print(line)" + ] + } + ], + "metadata": { + "colab": { + "collapsed_sections": [ + "N5IMdKHvlXFY" + ], + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/examples/readme.md b/examples/readme.md index 1a5aae8b..b750ccf8 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -19,6 +19,10 @@ This directory contains various example implementations of Scrapegraph-ai for di - 🛠️ `custom_graph/` - Custom graph implementation examples - 💻 `code_generator_graph/` - Code generation utilities - 📋 `json_scraper_graph/` - JSON data extraction and processing +- 📋 `colab example`: + + Open In Colab + ## 🚀 Getting Started From f9680659aaa884022d6143787c314da74a48e814 Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Thu, 9 Jan 2025 15:13:11 +0100 Subject: [PATCH 6/9] Delete README.md --- cookbook/README.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 cookbook/README.md diff --git a/cookbook/README.md b/cookbook/README.md deleted file mode 100644 index fe1cb2c6..00000000 --- a/cookbook/README.md +++ /dev/null @@ -1,9 +0,0 @@ -## 📚 Official Cookbook - -Looking for examples and guides? Then head over to the official ScrapeGraph SDK [Cookbook](https://github.com/ScrapeGraphAI/scrapegraph-sdk/tree/main/cookbook)! - -The cookbook provides step-by-step instructions, practical examples, and tips to help you get started and make the most out of ScrapeGraph SDK. - -You will find some colab notebooks with our partners as well, such as Langchain 🦜 and LlamaIndex 🦙 - -Happy scraping! 🚀 From 5ca325c7257b71fc4cd12ee26bde3e992ade5756 Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Fri, 10 Jan 2025 09:27:57 +0100 Subject: [PATCH 7/9] docs: refactoring of the doc --- docs/source/introduction/overview.rst | 79 ++++++++++++++++--- .../scrapegraphai.helpers.models_tokens.rst | 2 +- docs/source/scrapers/benchmarks.rst | 23 ------ 3 files changed, 71 insertions(+), 33 deletions(-) delete mode 100644 docs/source/scrapers/benchmarks.rst diff --git a/docs/source/introduction/overview.rst b/docs/source/introduction/overview.rst index 4e2bd604..4dcaadbe 100644 --- a/docs/source/introduction/overview.rst +++ b/docs/source/introduction/overview.rst @@ -30,37 +30,93 @@ ScrapGraphAI supports a wide range of AI models from various providers. Each mod OpenAI Models ------------- - GPT-3.5 Turbo (16,385 tokens) -- GPT-4 (8,192 tokens) +- GPT-3.5 (4,096 tokens) +- GPT-3.5 Turbo Instruct (4,096 tokens) - GPT-4 Turbo Preview (128,000 tokens) -- GPT-4o (128000 tokens) -- GTP-4o-mini (128000 tokens) +- GPT-4 Vision Preview (128,000 tokens) +- GPT-4 (8,192 tokens) +- GPT-4 32k (32,768 tokens) +- GPT-4o (128,000 tokens) +- O1 Preview (128,000 tokens) +- O1 Mini (128,000 tokens) Azure OpenAI Models ------------------- - GPT-3.5 Turbo (16,385 tokens) -- GPT-4 (8,192 tokens) +- GPT-3.5 (4,096 tokens) - GPT-4 Turbo Preview (128,000 tokens) -- GPT-4o (128000 tokens) -- GTP-4o-mini (128000 tokens) +- GPT-4 (8,192 tokens) +- GPT-4 32k (32,768 tokens) +- GPT-4o (128,000 tokens) +- O1 Preview (128,000 tokens) +- O1 Mini (128,000 tokens) Google AI Models ---------------- - Gemini Pro (128,000 tokens) +- Gemini 1.5 Flash (128,000 tokens) - Gemini 1.5 Pro (128,000 tokens) +- Gemini 1.0 Pro (128,000 tokens) Anthropic Models ---------------- - Claude Instant (100,000 tokens) -- Claude 2 (200,000 tokens) +- Claude 2 (9,000 tokens) +- Claude 2.1 (200,000 tokens) - Claude 3 (200,000 tokens) +- Claude 3.5 (200,000 tokens) +- Claude 3 Opus (200,000 tokens) +- Claude 3 Sonnet (200,000 tokens) +- Claude 3 Haiku (200,000 tokens) Mistral AI Models ----------------- -- Mistral Large (128,000 tokens) +- Mistral Large Latest (128,000 tokens) +- Open Mistral Nemo (128,000 tokens) +- Codestral Latest (32,000 tokens) - Open Mistral 7B (32,000 tokens) - Open Mixtral 8x7B (32,000 tokens) +- Open Mixtral 8x22B (64,000 tokens) +- Open Codestral Mamba (256,000 tokens) -For a complete list of supported models and their token limits, please refer to the API documentation. +Ollama Models +------------- +- Command-R (12,800 tokens) +- CodeLlama (16,000 tokens) +- DBRX (32,768 tokens) +- DeepSeek Coder 33B (16,000 tokens) +- Llama2 Series (4,096 tokens) +- Llama3 Series (8,192-128,000 tokens) +- Mistral Models (32,000-128,000 tokens) +- Mixtral 8x22B Instruct (65,536 tokens) +- Phi3 Series (12,800-128,000 tokens) +- Qwen Series (32,000 tokens) + +Hugging Face Models +------------------ +- Grok-1 (8,192 tokens) +- Meta Llama 3 Series (8,192 tokens) +- Google Gemma Series (8,192 tokens) +- Microsoft Phi Series (2,048-131,072 tokens) +- GPT-2 Series (1,024 tokens) +- DeepSeek V2 Series (131,072 tokens) + +Bedrock Models +------------- +- Claude 3 Series (200,000 tokens) +- Llama2 & Llama3 Series (4,096-8,192 tokens) +- Mistral Series (32,768 tokens) +- Titan Embed Text (8,000 tokens) +- Cohere Embed (512 tokens) + +Fireworks Models +--------------- +- Llama V2 7B (4,096 tokens) +- Mixtral 8x7B Instruct (4,096 tokens) +- Llama 3.1 Series (131,072 tokens) +- Mixtral MoE Series (65,536 tokens) + +For a complete and up-to-date list of supported models and their token limits, please refer to the API documentation. Understanding token limits is crucial for optimizing your scraping tasks. Larger token limits allow for processing more text in a single API call, which can be beneficial for scraping lengthy web pages or documents. @@ -139,3 +195,8 @@ Sponsors :width: 15% :alt: Stat Proxies :target: https://dashboard.statproxies.com/?refferal=scrapegraph + +.. image:: ../../assets/scrapedo.png + :width: 11% + :alt: Scrapedo + :target: https://scrape.do diff --git a/docs/source/modules/scrapegraphai.helpers.models_tokens.rst b/docs/source/modules/scrapegraphai.helpers.models_tokens.rst index 173e1bc3..82615b3b 100644 --- a/docs/source/modules/scrapegraphai.helpers.models_tokens.rst +++ b/docs/source/modules/scrapegraphai.helpers.models_tokens.rst @@ -19,7 +19,7 @@ Example usage: print(f"GPT-4 token limit: {gpt4_limit}") # Check the token limit for a specific model - model_name = "gpt-3.5-turbo" + model_name = "gpt-4o-mini" if model_name in models_tokens['openai']: print(f"{model_name} token limit: {models_tokens['openai'][model_name]}") else: diff --git a/docs/source/scrapers/benchmarks.rst b/docs/source/scrapers/benchmarks.rst deleted file mode 100644 index b5521ef1..00000000 --- a/docs/source/scrapers/benchmarks.rst +++ /dev/null @@ -1,23 +0,0 @@ -Benchmarks -========== - -SearchGraph -^^^^^^^^^^^ - -`SearchGraph` instantiates multiple `SmartScraperGraph` object for each URL and extract the data from the HTML. -A concurrent approach is used to speed up the process and the following table shows the time required for a scraping task with different **batch sizes**. -Only two results are taken into account. - -.. list-table:: SearchGraph - :header-rows: 1 - - * - Batch Size - - Total Time (s) - * - 1 - - 31.1 - * - 2 - - 33.52 - * - 4 - - 28.47 - * - 16 - - 21.80 From 7fee21724d853ae1da4957274d5dd4dd9f615be9 Mon Sep 17 00:00:00 2001 From: Marco Vinciguerra Date: Sat, 11 Jan 2025 10:50:05 +0100 Subject: [PATCH 8/9] Update installation.rst --- docs/source/getting_started/installation.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 666322af..30acfb5a 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -25,18 +25,18 @@ The library is available on PyPI, so it can be installed using the following com It is higly recommended to install the library in a virtual environment (conda, venv, etc.) -If your clone the repository, it is recommended to use a package manager like `rye `_. -To install the library using rye, you can run the following command: +If your clone the repository, it is recommended to use a package manager like `uv `_. +To install the library using uv, you can run the following command: .. code-block:: bash - rye pin 3.10 - rye sync - rye build + uv pin 3.10 + uv sync + uv build .. caution:: - **Rye** must be installed first by following the instructions on the `official website `_. + **Rye** must be installed first by following the instructions on the `official website `_. Additionally on Windows when using WSL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 3b9591156d96ac7266055703e7ffb354e90b01f0 Mon Sep 17 00:00:00 2001 From: PeriniM Date: Sun, 12 Jan 2025 12:58:36 +0100 Subject: [PATCH 9/9] fix: updated ollama structured output --- .../ollama/smart_scraper_lite_ollama.py | 1 - .../ollama/smart_scraper_multi_concat_ollama.py | 1 - .../ollama/smart_scraper_multi_lite_ollama.py | 1 - .../ollama/smart_scraper_multi_ollama.py | 1 - .../smart_scraper_graph/ollama/smart_scraper_ollama.py | 3 +-- .../ollama/smart_scraper_schema_ollama.py | 1 - scrapegraphai/nodes/merge_answers_node.py | 8 ++++++++ 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py index fd23f39c..9c4b9a69 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_lite_ollama.py @@ -12,7 +12,6 @@ "llm": { "model": "ollama/llama3.1", "temperature": 0, - "format": "json", "base_url": "http://localhost:11434", }, "verbose": True, diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py index 566be922..a29ac3fc 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_concat_ollama.py @@ -18,7 +18,6 @@ "llm": { "model": "ollama/llama3.1", "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py index 90c58f9d..15055f96 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_lite_ollama.py @@ -15,7 +15,6 @@ "llm": { "model": "ollama/llama3.1", "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py index c42bb627..04eb0e67 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_multi_ollama.py @@ -13,7 +13,6 @@ "llm": { "model": "ollama/llama3.1", "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly # "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_ollama.py index 61294eaf..1a766905 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_ollama.py @@ -13,9 +13,8 @@ "llm": { "model": "ollama/llama3.2:3b", "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly # "base_url": "http://localhost:11434", # set ollama URL arbitrarily - "model_tokens": 1024, + "model_tokens": 4096, }, "verbose": True, "headless": False, diff --git a/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py b/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py index 38eeaeb5..9cbf65f2 100644 --- a/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py +++ b/examples/smart_scraper_graph/ollama/smart_scraper_schema_ollama.py @@ -27,7 +27,6 @@ class Projects(BaseModel): "llm": { "model": "ollama/llama3.1", "temperature": 0, - "format": "json", # Ollama needs the format to be specified explicitly # "base_url": "http://localhost:11434", # set ollama URL arbitrarily }, "verbose": True, diff --git a/scrapegraphai/nodes/merge_answers_node.py b/scrapegraphai/nodes/merge_answers_node.py index 77eb1587..b867b3e0 100644 --- a/scrapegraphai/nodes/merge_answers_node.py +++ b/scrapegraphai/nodes/merge_answers_node.py @@ -5,6 +5,7 @@ from typing import List, Optional from langchain.prompts import PromptTemplate +from langchain_community.chat_models import ChatOllama from langchain_core.output_parsers import JsonOutputParser from langchain_mistralai import ChatMistralAI from langchain_openai import ChatOpenAI @@ -42,6 +43,13 @@ def __init__( super().__init__(node_name, "node", input, output, 2, node_config) self.llm_model = node_config["llm_model"] + + if isinstance(self.llm_model, ChatOllama): + if self.node_config.get("schema", None) is None: + self.llm_model.format = "json" + else: + self.llm_model.format = self.node_config["schema"].model_json_schema() + self.verbose = ( False if node_config is None else node_config.get("verbose", False) )