linktimecloud commited on
Commit
e824e2c
·
verified ·
1 Parent(s): e1a52d9

Upload folder using huggingface_hub

Browse files
.env.tpl ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # right now we use Google search API
2
+ SEARCH_API_KEY=your-google-search-api-key
3
+ SEARCH_PROJECT_KEY=your-google-cx-key
4
+
5
+ # right now we use OpenAI API
6
+ LLM_API_KEY=your-openai-api-key
7
+
8
+ # Run and share Gradio UI
9
+ RUN_GRADIO_UI=False
10
+ SHARE_GRADIO_UI=False
.gitignore ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110
+ .pdm.toml
111
+ .pdm-python
112
+ .pdm-build/
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .venv
127
+ env/
128
+ venv/
129
+ ENV/
130
+ env.bak/
131
+ venv.bak/
132
+
133
+ # Spyder project settings
134
+ .spyderproject
135
+ .spyproject
136
+
137
+ # Rope project settings
138
+ .ropeproject
139
+
140
+ # mkdocs documentation
141
+ /site
142
+
143
+ # mypy
144
+ .mypy_cache/
145
+ .dmypy.json
146
+ dmypy.json
147
+
148
+ # Pyre type checker
149
+ .pyre/
150
+
151
+ # pytype static type analyzer
152
+ .pytype/
153
+
154
+ # Cython debug symbols
155
+ cython_debug/
156
+
157
+ # PyCharm
158
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
161
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
162
+ #.idea/
163
+
164
+ .gradio
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 pengfeng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,12 +1,164 @@
1
  ---
2
- title: Ask2.py
3
- emoji: 👀
4
- colorFrom: yellow
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 5.4.0
8
- app_file: app.py
9
- pinned: false
10
  ---
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: ask2.py
3
+ app_file: ask.py
 
 
4
  sdk: gradio
5
+ sdk_version: 5.3.0
 
 
6
  ---
7
+ # ask.py
8
 
9
+ [![License](https://img.shields.io/github/license/pengfeng/ask.py)](LICENSE)
10
+
11
+ A single Python program to implement the search-extract-summarize flow, similar to AI search
12
+ engines such as Perplexity.
13
+
14
+ > [!NOTE]
15
+ > Our main goal is to illustrate the basic concepts of AI search engines with the raw constructs.
16
+ > Performance or scalability is not in the scope of this program.
17
+
18
+ > [UPDATE]
19
+ >
20
+ > - 2024-10-28: add extract function as a new output mode
21
+ > - 2024-10-25: add hybrid search demo using DuckDB full-text search
22
+ > - 2024-10-22: add GradIO integation
23
+ > - 2024-10-21: use DuckDB for the vector search and use API for embedding
24
+ > - 2024-10-20: allow to specify a list of input urls
25
+ > - 2024-10-18: output-language and output-length parameters for LLM
26
+ > - 2024-10-18: date-restrict and target-site parameters for seach
27
+
28
+ ## The search-extract-summarize flow
29
+
30
+ Given a query, the program will
31
+
32
+ - search Google for the top 10 web pages
33
+ - crawl and scape the pages for their text content
34
+ - chunk the text content into chunks and save them into a vectordb
35
+ - perform a vector search with the query and find the top 10 matched chunks
36
+ - [Optional] search using full-text search and combine the results with the vector search
37
+ - [Optional] use a reranker to re-rank the top chunks
38
+ - use the top chunks as the context to ask an LLM to generate the answer
39
+ - output the answer with the references
40
+
41
+ Of course this flow is a very simplified version of the real AI search engines, but it is a good
42
+ starting point to understand the basic concepts.
43
+
44
+ One benefit is that we can manipulate the search function and output format.
45
+
46
+ For example, we can:
47
+
48
+ - search with date-restrict to only retrieve the latest information.
49
+ - search within a target-site to only create the answer from the contents from it.
50
+ - ask LLM to use a specific language to answer the question.
51
+ - ask LLM to answer with a specific length.
52
+ - crawl a specific list of urls and answer based on those contents only.
53
+
54
+ ## Quick start
55
+
56
+ ```bash
57
+ # recommend to use Python 3.10 or later and use venv or conda to create a virtual environment
58
+ pip install -r requirements.txt
59
+
60
+ # modify .env file to set the API keys or export them as environment variables as below
61
+
62
+ # right now we use Google search API
63
+ export SEARCH_API_KEY="your-google-search-api-key"
64
+ export SEARCH_PROJECT_KEY="your-google-cx-key"
65
+
66
+ # right now we use OpenAI API
67
+ export LLM_API_KEY="your-openai-api-key"
68
+
69
+ # run the program
70
+ python ask.py -q "What is an LLM agent?"
71
+
72
+ # we can specify more parameters to control the behavior such as date_restrict and target_site
73
+ python ask.py --help
74
+ Usage: ask.py [OPTIONS]
75
+
76
+ Search web for the query and summarize the results.
77
+
78
+ Options:
79
+ -q, --query TEXT Query to search
80
+ -o, --output-mode [answer|extract]
81
+ Output mode for the answer, default is a
82
+ simple answer
83
+ -d, --date-restrict INTEGER Restrict search results to a specific date
84
+ range, default is no restriction
85
+ -s, --target-site TEXT Restrict search results to a specific site,
86
+ default is no restriction
87
+ --output-language TEXT Output language for the answer
88
+ --output-length INTEGER Output length for the answer
89
+ --url-list-file TEXT Instead of doing web search, scrape the
90
+ target URL list and answer the query based
91
+ on the content
92
+ --extract-schema-file TEXT Pydantic schema for the extract mode
93
+ -m, --inference-model-name TEXT
94
+ Model name to use for inference
95
+ --hybrid-search Use hybrid search mode with both vector
96
+ search and full-text search
97
+ --web-ui Launch the web interface
98
+ -l, --log-level [DEBUG|INFO|WARNING|ERROR]
99
+ Set the logging level [default: INFO]
100
+ --help Show this message and exit.
101
+ ```
102
+
103
+ ## Libraries and APIs used
104
+
105
+ - [Google Search API](https://developers.google.com/custom-search/v1/overview)
106
+ - [OpenAI API](https://beta.openai.com/docs/api-reference/completions/create)
107
+ - [Jinja2](https://jinja.palletsprojects.com/en/3.0.x/)
108
+ - [bs4](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
109
+ - [DuckDB](https://github.com/duckdb/duckdb)
110
+ - [GradIO](https://github.com/gradio-app/gradio)
111
+
112
+ ## GradIO Deployment
113
+
114
+ > [!NOTE]
115
+ > Original GradIO app-sharing document [here](https://www.gradio.app/guides/sharing-your-app).
116
+ > We have a running example [here](https://huggingface.co/spaces/leettools/AskPy).
117
+
118
+ ### Quick test and sharing
119
+
120
+ You can run the program with `--web-ui` option to launch the web interface and check it locally.
121
+
122
+ ```bash
123
+ python ask.py --web-ui
124
+ * Running on local URL: http://127.0.0.1:7860
125
+
126
+ # you can also specify SHARE_GRADIO_UI to run a sharable UI through GradIO
127
+ export SHARE_GRADIO_UI=True
128
+ python ask.py --web-ui
129
+ * Running on local URL: http://127.0.0.1:7860
130
+ * Running on public URL: https://77c277af0330326587.gradio.live
131
+ ```
132
+
133
+ ### To share a more permanent link using HuggingFace Space
134
+
135
+ - First, you need to [create a free HuggingFace account](https://huggingface.co/welcome).
136
+ - Then in your [settings/token page](https://huggingface.co/settings/tokens), create a new token with Write permissions.
137
+ - In your terminal, run the following commands in you app directory to deploy your program to
138
+ HuggingFace Space:
139
+
140
+ ```bash
141
+ pip install gradio
142
+ gradio deploy
143
+ # You will be prompted to enter your HuggingFace token
144
+ ```
145
+
146
+ After the deployment, the app should be on https://huggingface.co/spaces/your_username/AskPy
147
+
148
+ Now you need to go to the settings page to add some variables and secrets https://huggingface.co/spaces/your_username/AskPy/settings
149
+
150
+ - variable: RUN_GRADIO_UI=True
151
+ - variable: SHARE_GRADIO_UI=True
152
+ - secret: SEARCH_API_KEY=<YOUR_SEARCH_API_KEY>
153
+ - secret: SEARCH_PROJECT_KEY=<YOUR_SEARCH_PROJECT_KEY>
154
+ - sercet: LLM_API_KEY=<YOUR_LLM_API_KEY>
155
+
156
+ Now you can use the HuggingFace space app to run your queries.
157
+
158
+ ![image](https://github.com/user-attachments/assets/0483e6a2-75d7-4fbd-813f-bfa13839c836)
159
+
160
+ ## Use Cases
161
+
162
+ - [Search like Perplexity](demos/search_and_answer.md)
163
+ - [Only use the latest information from a specific site](demos/search_on_site_and_date.md)
164
+ - [Extract information from web search results](demos/search_and_extract.md)
ask.py ADDED
@@ -0,0 +1,1020 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import csv
2
+ import io
3
+ import json
4
+ import logging
5
+ import os
6
+ import queue
7
+ import urllib.parse
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ from datetime import datetime
10
+ from enum import Enum
11
+ from functools import partial
12
+ from queue import Queue
13
+ from typing import Any, Dict, Generator, List, Optional, Tuple, TypeVar
14
+
15
+ import click
16
+ import duckdb
17
+ import gradio as gr
18
+ import requests
19
+ from bs4 import BeautifulSoup
20
+ from dotenv import load_dotenv
21
+ from jinja2 import BaseLoader, Environment
22
+ from openai import OpenAI
23
+ from pydantic import BaseModel, create_model
24
+
25
+ TypeVar_BaseModel = TypeVar("TypeVar_BaseModel", bound=BaseModel)
26
+
27
+
28
+ script_dir = os.path.dirname(os.path.abspath(__file__))
29
+ default_env_file = os.path.abspath(os.path.join(script_dir, ".env"))
30
+
31
+
32
+ class OutputMode(str, Enum):
33
+ answer = "answer"
34
+ extract = "extract"
35
+
36
+
37
+ class AskSettings(BaseModel):
38
+ date_restrict: int
39
+ target_site: str
40
+ output_language: str
41
+ output_length: int
42
+ url_list: List[str]
43
+ inference_model_name: str
44
+ hybrid_search: bool
45
+ output_mode: OutputMode
46
+ extract_schema_str: str
47
+
48
+
49
+ def _get_logger(log_level: str) -> logging.Logger:
50
+ logger = logging.getLogger(__name__)
51
+ logger.setLevel(log_level)
52
+ if len(logger.handlers) > 0:
53
+ return logger
54
+
55
+ handler = logging.StreamHandler()
56
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
57
+ handler.setFormatter(formatter)
58
+ logger.addHandler(handler)
59
+ return logger
60
+
61
+
62
+ def _read_url_list(url_list_file: str) -> List[str]:
63
+ if not url_list_file:
64
+ return []
65
+
66
+ with open(url_list_file, "r") as f:
67
+ links = f.readlines()
68
+ url_list = [
69
+ link.strip()
70
+ for link in links
71
+ if link.strip() != "" and not link.startswith("#")
72
+ ]
73
+ return url_list
74
+
75
+
76
+ def _read_extract_schema_str(extract_schema_file: str) -> str:
77
+ if not extract_schema_file:
78
+ return ""
79
+
80
+ with open(extract_schema_file, "r") as f:
81
+ schema_str = f.read()
82
+ return schema_str
83
+
84
+
85
+ def _output_csv(result_dict: Dict[str, List[BaseModel]], key_name: str) -> str:
86
+ # generate the CSV content from a Dict of URL and list of extracted items
87
+ output = io.StringIO()
88
+ csv_writer = None
89
+ for src_url, items in result_dict.items():
90
+ for item in items:
91
+ value_dict = item.model_dump()
92
+ item_with_url = {**value_dict, key_name: src_url}
93
+
94
+ if csv_writer is None:
95
+ headers = list(value_dict.keys()) + [key_name]
96
+ csv_writer = csv.DictWriter(output, fieldnames=headers)
97
+ csv_writer.writeheader()
98
+
99
+ csv_writer.writerow(item_with_url)
100
+
101
+ csv_content = output.getvalue()
102
+ output.close()
103
+ return csv_content
104
+
105
+
106
+ class Ask:
107
+
108
+ def __init__(self, logger: Optional[logging.Logger] = None):
109
+ self.read_env_variables()
110
+
111
+ if logger is not None:
112
+ self.logger = logger
113
+ else:
114
+ self.logger = _get_logger("INFO")
115
+
116
+ self.db_con = duckdb.connect(":memory:")
117
+
118
+ self.db_con.install_extension("vss")
119
+ self.db_con.load_extension("vss")
120
+ self.db_con.install_extension("fts")
121
+ self.db_con.load_extension("fts")
122
+ self.db_con.sql("CREATE SEQUENCE seq_docid START 1000")
123
+
124
+ self.session = requests.Session()
125
+ user_agent: str = (
126
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
127
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
128
+ "Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
129
+ )
130
+ self.session.headers.update({"User-Agent": user_agent})
131
+
132
+ def read_env_variables(self) -> None:
133
+ err_msg = ""
134
+
135
+ self.search_api_key = os.environ.get("SEARCH_API_KEY")
136
+ if self.search_api_key is None:
137
+ err_msg += "SEARCH_API_KEY env variable not set.\n"
138
+ self.search_project_id = os.environ.get("SEARCH_PROJECT_KEY")
139
+ if self.search_project_id is None:
140
+ err_msg += "SEARCH_PROJECT_KEY env variable not set.\n"
141
+ self.llm_api_key = os.environ.get("LLM_API_KEY")
142
+ if self.llm_api_key is None:
143
+ err_msg += "LLM_API_KEY env variable not set.\n"
144
+
145
+ if err_msg != "":
146
+ raise Exception(f"\n{err_msg}\n")
147
+
148
+ self.llm_base_url = os.environ.get("LLM_BASE_URL")
149
+ if self.llm_base_url is None:
150
+ self.llm_base_url = "https://api.openai.com/v1"
151
+
152
+ self.embedding_model = os.environ.get("EMBEDDING_MODEL")
153
+ self.embedding_dimensions = os.environ.get("EMBEDDING_DIMENSIONS")
154
+
155
+ if self.embedding_model is None or self.embedding_dimensions is None:
156
+ self.embedding_model = "text-embedding-3-small"
157
+ self.embedding_dimensions = 1536
158
+
159
+ def search_web(self, query: str, settings: AskSettings) -> List[str]:
160
+ escaped_query = urllib.parse.quote(query)
161
+ url_base = (
162
+ f"https://www.googleapis.com/customsearch/v1?key={self.search_api_key}"
163
+ f"&cx={self.search_project_id}&q={escaped_query}"
164
+ )
165
+ url_paras = f"&safe=active"
166
+ if settings.date_restrict > 0:
167
+ url_paras += f"&dateRestrict={settings.date_restrict}"
168
+ if settings.target_site:
169
+ url_paras += f"&siteSearch={settings.target_site}&siteSearchFilter=i"
170
+ url = f"{url_base}{url_paras}"
171
+
172
+ self.logger.debug(f"Searching for query: {query}")
173
+
174
+ resp = requests.get(url)
175
+
176
+ if resp is None:
177
+ raise Exception("No response from search API")
178
+
179
+ search_results_dict = json.loads(resp.text)
180
+ if "error" in search_results_dict:
181
+ raise Exception(
182
+ f"Error in search API response: {search_results_dict['error']}"
183
+ )
184
+
185
+ if "searchInformation" not in search_results_dict:
186
+ raise Exception(
187
+ f"No search information in search API response: {resp.text}"
188
+ )
189
+
190
+ total_results = search_results_dict["searchInformation"].get("totalResults", 0)
191
+ if total_results == 0:
192
+ self.logger.warning(f"No results found for query: {query}")
193
+ return []
194
+
195
+ results = search_results_dict.get("items", [])
196
+ if results is None or len(results) == 0:
197
+ self.logger.warning(f"No result items in the response for query: {query}")
198
+ return []
199
+
200
+ found_links = []
201
+ for result in results:
202
+ link = result.get("link", None)
203
+ if link is None or link == "":
204
+ self.logger.warning(f"Search result link missing: {result}")
205
+ continue
206
+ found_links.append(link)
207
+ return found_links
208
+
209
+ def _scape_url(self, url: str) -> Tuple[str, str]:
210
+ self.logger.info(f"Scraping {url} ...")
211
+ try:
212
+ response = self.session.get(url, timeout=10)
213
+ soup = BeautifulSoup(response.content, "lxml", from_encoding="utf-8")
214
+
215
+ body_tag = soup.body
216
+ if body_tag:
217
+ body_text = body_tag.get_text()
218
+ body_text = " ".join(body_text.split()).strip()
219
+ self.logger.debug(f"Scraped {url}: {body_text}...")
220
+ if len(body_text) > 100:
221
+ self.logger.info(
222
+ f"✅ Successfully scraped {url} with length: {len(body_text)}"
223
+ )
224
+ return url, body_text
225
+ else:
226
+ self.logger.warning(
227
+ f"Body text too short for url: {url}, length: {len(body_text)}"
228
+ )
229
+ return url, ""
230
+ else:
231
+ self.logger.warning(f"No body tag found in the response for url: {url}")
232
+ return url, ""
233
+ except Exception as e:
234
+ self.logger.error(f"Scraping error {url}: {e}")
235
+ return url, ""
236
+
237
+ def scrape_urls(self, urls: List[str]) -> Dict[str, str]:
238
+ # the key is the url and the value is the body text
239
+ scrape_results: Dict[str, str] = {}
240
+
241
+ partial_scrape = partial(self._scape_url)
242
+ with ThreadPoolExecutor(max_workers=10) as executor:
243
+ results = executor.map(partial_scrape, urls)
244
+
245
+ for url, body_text in results:
246
+ if body_text != "":
247
+ scrape_results[url] = body_text
248
+
249
+ return scrape_results
250
+
251
+ def chunk_results(
252
+ self, scrape_results: Dict[str, str], size: int, overlap: int
253
+ ) -> Dict[str, List[str]]:
254
+ chunking_results: Dict[str, List[str]] = {}
255
+ for url, text in scrape_results.items():
256
+ chunks = []
257
+ for pos in range(0, len(text), size - overlap):
258
+ chunks.append(text[pos : pos + size])
259
+ chunking_results[url] = chunks
260
+ return chunking_results
261
+
262
+ def get_embedding(self, client: OpenAI, texts: List[str]) -> List[List[float]]:
263
+ if len(texts) == 0:
264
+ return []
265
+
266
+ response = client.embeddings.create(input=texts, model=self.embedding_model)
267
+ embeddings = []
268
+ for i in range(len(response.data)):
269
+ embeddings.append(response.data[i].embedding)
270
+ return embeddings
271
+
272
+ def batch_get_embedding(
273
+ self, client: OpenAI, chunk_batch: Tuple[str, List[str]]
274
+ ) -> Tuple[Tuple[str, List[str]], List[List[float]]]:
275
+ """
276
+ Return the chunk_batch as well as the embeddings for each chunk so that
277
+ we can aggregate them and save them to the database together.
278
+
279
+ Args:
280
+ - client: OpenAI client
281
+ - chunk_batch: Tuple of URL and list of chunks scraped from the URL
282
+
283
+ Returns:
284
+ - Tuple of chunk_bach and list of result embeddings
285
+ """
286
+ texts = chunk_batch[1]
287
+ embeddings = self.get_embedding(client, texts)
288
+ return chunk_batch, embeddings
289
+
290
+ def _create_table(self) -> str:
291
+ # Simple ways to get a unique table name
292
+ timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M_%S_%f")
293
+ table_name = f"document_chunks_{timestamp}"
294
+
295
+ self.db_con.execute(
296
+ f"""
297
+ CREATE TABLE {table_name} (
298
+ doc_id INTEGER PRIMARY KEY DEFAULT nextval('seq_docid'),
299
+ url TEXT,
300
+ chunk TEXT,
301
+ vec FLOAT[{self.embedding_dimensions}]
302
+ );
303
+ """
304
+ )
305
+ return table_name
306
+
307
+ def save_chunks_to_db(self, chunking_results: Dict[str, List[str]]) -> str:
308
+ """
309
+ The key of chunking_results is the URL and the value is the list of chunks.
310
+ """
311
+ client = self._get_api_client()
312
+ embed_batch_size = 50
313
+ query_batch_size = 100
314
+ insert_data = []
315
+
316
+ table_name = self._create_table()
317
+
318
+ batches: List[Tuple[str, List[str]]] = []
319
+ for url, list_chunks in chunking_results.items():
320
+ for i in range(0, len(list_chunks), embed_batch_size):
321
+ list_chunks = list_chunks[i : i + embed_batch_size]
322
+ batches.append((url, list_chunks))
323
+
324
+ self.logger.info(f"Embedding {len(batches)} batches of chunks ...")
325
+ partial_get_embedding = partial(self.batch_get_embedding, client)
326
+ with ThreadPoolExecutor(max_workers=10) as executor:
327
+ all_embeddings = executor.map(partial_get_embedding, batches)
328
+ self.logger.info(f"✅ Finished embedding.")
329
+
330
+ # we batch the insert data to speed up the insertion operation
331
+ # although the DuckDB doc says executeMany is optimized for batch insert
332
+ # but we found that it is faster to batch the insert data and run a single insert
333
+ for chunk_batch, embeddings in all_embeddings:
334
+ url = chunk_batch[0]
335
+ list_chunks = chunk_batch[1]
336
+ insert_data.extend(
337
+ [
338
+ (url.replace("'", " "), chunk.replace("'", " "), embedding)
339
+ for chunk, embedding in zip(list_chunks, embeddings)
340
+ ]
341
+ )
342
+
343
+ for i in range(0, len(insert_data), query_batch_size):
344
+ value_str = ", ".join(
345
+ [
346
+ f"('{url}', '{chunk}', {embedding})"
347
+ for url, chunk, embedding in insert_data[i : i + embed_batch_size]
348
+ ]
349
+ )
350
+ query = f"""
351
+ INSERT INTO {table_name} (url, chunk, vec) VALUES {value_str};
352
+ """
353
+ self.db_con.execute(query)
354
+
355
+ self.db_con.execute(
356
+ f"""
357
+ CREATE INDEX {table_name}_cos_idx ON {table_name} USING HNSW (vec)
358
+ WITH (metric = 'cosine');
359
+ """
360
+ )
361
+ self.logger.info(f"✅ Created the vector index ...")
362
+ self.db_con.execute(
363
+ f"""
364
+ PRAGMA create_fts_index(
365
+ {table_name}, 'doc_id', 'chunk'
366
+ );
367
+ """
368
+ )
369
+ self.logger.info(f"✅ Created the full text search index ...")
370
+ return table_name
371
+
372
+ def vector_search(
373
+ self, table_name: str, query: str, settings: AskSettings
374
+ ) -> List[Dict[str, Any]]:
375
+ """
376
+ The return value is a list of {url: str, chunk: str} records.
377
+ In a real world, we will define a class of Chunk to have more metadata such as offsets.
378
+ """
379
+ client = self._get_api_client()
380
+ embeddings = self.get_embedding(client, [query])[0]
381
+
382
+ query_result: duckdb.DuckDBPyRelation = self.db_con.sql(
383
+ f"""
384
+ SELECT * FROM {table_name}
385
+ ORDER BY array_distance(vec, {embeddings}::FLOAT[{self.embedding_dimensions}])
386
+ LIMIT 10;
387
+ """
388
+ )
389
+
390
+ self.logger.debug(query_result)
391
+
392
+ # use a dict to remove duplicates from vector search and full-text search
393
+ matched_chunks_dict = {}
394
+ for vec_result in query_result.fetchall():
395
+ doc_id = vec_result[0]
396
+ result_record = {
397
+ "url": vec_result[1],
398
+ "chunk": vec_result[2],
399
+ }
400
+ matched_chunks_dict[doc_id] = result_record
401
+
402
+ if settings.hybrid_search:
403
+ self.logger.info("Running full-text search ...")
404
+
405
+ self.db_con.execute(
406
+ f"""
407
+ PREPARE fts_query AS (
408
+ WITH scored_docs AS (
409
+ SELECT *, fts_main_{table_name}.match_bm25(
410
+ doc_id, ?, fields := 'chunk'
411
+ ) AS score FROM {table_name})
412
+ SELECT doc_id, url, chunk, score
413
+ FROM scored_docs
414
+ WHERE score IS NOT NULL
415
+ ORDER BY score DESC
416
+ LIMIT 10)
417
+ """
418
+ )
419
+ self.db_con.execute("PRAGMA threads=4")
420
+
421
+ # You can run more complex query rewrite methods here
422
+ # usually: stemming, stop words, etc.
423
+ escaped_query = query.replace("'", " ")
424
+ fts_result: duckdb.DuckDBPyRelation = self.db_con.execute(
425
+ f"EXECUTE fts_query('{escaped_query}')"
426
+ )
427
+
428
+ index = 0
429
+ for fts_record in fts_result.fetchall():
430
+ index += 1
431
+ self.logger.debug(f"The full text search record #{index}: {fts_record}")
432
+ doc_id = fts_record[0]
433
+ result_record = {
434
+ "url": fts_record[1],
435
+ "chunk": fts_record[2],
436
+ }
437
+
438
+ # You can configure the score threashold and top-k
439
+ if fts_record[3] > 1:
440
+ matched_chunks_dict[doc_id] = result_record
441
+ else:
442
+ break
443
+
444
+ if index >= 10:
445
+ break
446
+
447
+ return matched_chunks_dict.values()
448
+
449
+ def _get_api_client(self) -> OpenAI:
450
+ return OpenAI(api_key=self.llm_api_key, base_url=self.llm_base_url)
451
+
452
+ def _render_template(self, template_str: str, variables: Dict[str, Any]) -> str:
453
+ env = Environment(loader=BaseLoader(), autoescape=False)
454
+ template = env.from_string(template_str)
455
+ return template.render(variables)
456
+
457
+ def _get_target_class(self, extract_schema_str: str) -> TypeVar_BaseModel:
458
+ local_namespace = {"BaseModel": BaseModel}
459
+ exec(extract_schema_str, local_namespace, local_namespace)
460
+ for key, value in local_namespace.items():
461
+ if key == "__builtins__":
462
+ continue
463
+ if key == "BaseModel":
464
+ continue
465
+ if isinstance(value, type):
466
+ if issubclass(value, BaseModel):
467
+ return value
468
+ raise Exception("No Pydantic schema found in the extract schema str.")
469
+
470
+ def run_inference(
471
+ self,
472
+ query: str,
473
+ matched_chunks: List[Dict[str, Any]],
474
+ settings: AskSettings,
475
+ ) -> str:
476
+ system_prompt = (
477
+ "You are an expert summarizing the answers based on the provided contents."
478
+ )
479
+ user_promt_template = """
480
+ Given the context as a sequence of references with a reference id in the
481
+ format of a leading [x], please answer the following question using {{ language }}:
482
+
483
+ {{ query }}
484
+
485
+ In the answer, use format [1], [2], ..., [n] in line where the reference is used.
486
+ For example, "According to the research from Google[3], ...".
487
+
488
+ Please create the answer strictly related to the context. If the context has no
489
+ information about the query, please write "No related information found in the context."
490
+ using {{ language }}.
491
+
492
+ {{ length_instructions }}
493
+
494
+ Here is the context:
495
+ {{ context }}
496
+ """
497
+ context = ""
498
+ for i, chunk in enumerate(matched_chunks):
499
+ context += f"[{i+1}] {chunk['chunk']}\n"
500
+
501
+ if not settings.output_length:
502
+ length_instructions = ""
503
+ else:
504
+ length_instructions = (
505
+ f"Please provide the answer in { settings.output_length } words."
506
+ )
507
+
508
+ user_prompt = self._render_template(
509
+ user_promt_template,
510
+ {
511
+ "query": query,
512
+ "context": context,
513
+ "language": settings.output_language,
514
+ "length_instructions": length_instructions,
515
+ },
516
+ )
517
+
518
+ self.logger.debug(
519
+ f"Running inference with model: {settings.inference_model_name}"
520
+ )
521
+ self.logger.debug(f"Final user prompt: {user_prompt}")
522
+
523
+ api_client = self._get_api_client()
524
+ completion = api_client.chat.completions.create(
525
+ model=settings.inference_model_name,
526
+ messages=[
527
+ {
528
+ "role": "system",
529
+ "content": system_prompt,
530
+ },
531
+ {
532
+ "role": "user",
533
+ "content": user_prompt,
534
+ },
535
+ ],
536
+ )
537
+ if completion is None:
538
+ raise Exception("No completion from the API")
539
+
540
+ response_str = completion.choices[0].message.content
541
+ return response_str
542
+
543
+ def run_extract(
544
+ self,
545
+ query: str,
546
+ extract_schema_str: str,
547
+ target_content: str,
548
+ settings: AskSettings,
549
+ ) -> List[TypeVar_BaseModel]:
550
+ target_class = self._get_target_class(extract_schema_str)
551
+ system_prompt = (
552
+ "You are an expert of extract structual information from the document."
553
+ )
554
+ user_promt_template = """
555
+ Given the provided content, if it contains information about {{ query }}, please extract the
556
+ list of structured data items as defined in the following Pydantic schema:
557
+
558
+ {{ extract_schema_str }}
559
+
560
+ Below is the provided content:
561
+ {{ content }}
562
+ """
563
+ user_prompt = self._render_template(
564
+ user_promt_template,
565
+ {
566
+ "query": query,
567
+ "content": target_content,
568
+ "extract_schema_str": extract_schema_str,
569
+ },
570
+ )
571
+
572
+ self.logger.debug(
573
+ f"Running extraction with model: {settings.inference_model_name}"
574
+ )
575
+ self.logger.debug(f"Final user prompt: {user_prompt}")
576
+
577
+ class_name = target_class.__name__
578
+ list_class_name = f"{class_name}_list"
579
+ response_pydantic_model = create_model(
580
+ list_class_name,
581
+ items=(List[target_class], ...),
582
+ )
583
+
584
+ api_client = self._get_api_client()
585
+ completion = api_client.beta.chat.completions.parse(
586
+ model=settings.inference_model_name,
587
+ messages=[
588
+ {
589
+ "role": "system",
590
+ "content": system_prompt,
591
+ },
592
+ {
593
+ "role": "user",
594
+ "content": user_prompt,
595
+ },
596
+ ],
597
+ response_format=response_pydantic_model,
598
+ )
599
+ if completion is None:
600
+ raise Exception("No completion from the API")
601
+
602
+ message = completion.choices[0].message
603
+ if message.refusal:
604
+ raise Exception(
605
+ f"Refused to extract information from the document: {message.refusal}."
606
+ )
607
+
608
+ extract_result = message.parsed
609
+ return extract_result.items
610
+
611
+ def run_query_gradio(
612
+ self,
613
+ query: str,
614
+ date_restrict: int,
615
+ target_site: str,
616
+ output_language: str,
617
+ output_length: int,
618
+ url_list_str: str,
619
+ inference_model_name: str,
620
+ hybrid_search: bool,
621
+ output_mode_str: str,
622
+ extract_schema_str: str,
623
+ ) -> Generator[Tuple[str, str], None, Tuple[str, str]]:
624
+ logger = self.logger
625
+ log_queue = Queue()
626
+
627
+ if url_list_str:
628
+ url_list = url_list_str.split("\n")
629
+ else:
630
+ url_list = []
631
+
632
+ settings = AskSettings(
633
+ date_restrict=date_restrict,
634
+ target_site=target_site,
635
+ output_language=output_language,
636
+ output_length=output_length,
637
+ url_list=url_list,
638
+ inference_model_name=inference_model_name,
639
+ hybrid_search=hybrid_search,
640
+ output_mode=OutputMode(output_mode_str),
641
+ extract_schema_str=extract_schema_str,
642
+ )
643
+
644
+ queue_handler = logging.Handler()
645
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
646
+ queue_handler.emit = lambda record: log_queue.put(formatter.format(record))
647
+ logger.addHandler(queue_handler)
648
+
649
+ def update_logs():
650
+ logs = []
651
+ while True:
652
+ try:
653
+ log = log_queue.get_nowait()
654
+ logs.append(log)
655
+ except queue.Empty:
656
+ break
657
+ return "\n".join(logs)
658
+
659
+ # wrap the process in a generator to yield the logs to integrate with GradIO
660
+ def process_with_logs():
661
+ if len(settings.url_list) > 0:
662
+ links = settings.url_list
663
+ else:
664
+ logger.info("Searching the web ...")
665
+ yield "", update_logs()
666
+ links = self.search_web(query, settings)
667
+ logger.info(f"✅ Found {len(links)} links for query: {query}")
668
+ for i, link in enumerate(links):
669
+ logger.debug(f"{i+1}. {link}")
670
+ yield "", update_logs()
671
+
672
+ logger.info("Scraping the URLs ...")
673
+ yield "", update_logs()
674
+ scrape_results = self.scrape_urls(links)
675
+ logger.info(f"✅ Scraped {len(scrape_results)} URLs.")
676
+ yield "", update_logs()
677
+
678
+ if settings.output_mode == OutputMode.answer:
679
+ logger.info("Chunking the text ...")
680
+ yield "", update_logs()
681
+ chunking_results = self.chunk_results(scrape_results, 1000, 100)
682
+ total_chunks = 0
683
+ for url, chunks in chunking_results.items():
684
+ logger.debug(f"URL: {url}")
685
+ total_chunks += len(chunks)
686
+ for i, chunk in enumerate(chunks):
687
+ logger.debug(f"Chunk {i+1}: {chunk}")
688
+ logger.info(f"✅ Generated {total_chunks} chunks ...")
689
+ yield "", update_logs()
690
+
691
+ logger.info(f"Saving {total_chunks} chunks to DB ...")
692
+ yield "", update_logs()
693
+ table_name = self.save_chunks_to_db(chunking_results)
694
+ logger.info(f"✅ Successfully embedded and saved chunks to DB.")
695
+ yield "", update_logs()
696
+
697
+ logger.info("Querying the vector DB to get context ...")
698
+ matched_chunks = self.vector_search(table_name, query, settings)
699
+ for i, result in enumerate(matched_chunks):
700
+ logger.debug(f"{i+1}. {result}")
701
+ logger.info(f"✅ Got {len(matched_chunks)} matched chunks.")
702
+ yield "", update_logs()
703
+
704
+ logger.info("Running inference with context ...")
705
+ yield "", update_logs()
706
+ answer = self.run_inference(
707
+ query=query,
708
+ matched_chunks=matched_chunks,
709
+ settings=settings,
710
+ )
711
+ logger.info("✅ Finished inference API call.")
712
+ logger.info("Generating output ...")
713
+ yield "", update_logs()
714
+
715
+ answer = f"# Answer\n\n{answer}\n"
716
+ references = "\n".join(
717
+ [
718
+ f"[{i+1}] {result['url']}"
719
+ for i, result in enumerate(matched_chunks)
720
+ ]
721
+ )
722
+ yield f"{answer}\n\n# References\n\n{references}", update_logs()
723
+ elif settings.output_mode == OutputMode.extract:
724
+ logger.info("Extracting structured data ...")
725
+ yield "", update_logs()
726
+
727
+ aggregated_output = {}
728
+ for url, text in scrape_results.items():
729
+ items = self.run_extract(
730
+ query=query,
731
+ extract_schema_str=extract_schema_str,
732
+ target_content=text,
733
+ settings=settings,
734
+ )
735
+ self.logger.info(
736
+ f"✅ Finished inference API call. Extracted {len(items)} items from {url}."
737
+ )
738
+ yield "", update_logs()
739
+
740
+ self.logger.debug(items)
741
+ aggregated_output[url] = items
742
+
743
+ logger.info("✅ Finished extraction from all urls.")
744
+ logger.info("Generating output ...")
745
+ yield "", update_logs()
746
+ answer = _output_csv(aggregated_output, "SourceURL")
747
+ yield f"{answer}", update_logs()
748
+ else:
749
+ raise Exception(f"Invalid output mode: {settings.output_mode}")
750
+
751
+ logs = ""
752
+ final_result = ""
753
+
754
+ try:
755
+ for result, log_update in process_with_logs():
756
+ logs += log_update + "\n"
757
+ final_result = result
758
+ yield final_result, logs
759
+ finally:
760
+ logger.removeHandler(queue_handler)
761
+
762
+ return final_result, logs
763
+
764
+ def run_query(
765
+ self,
766
+ query: str,
767
+ settings: AskSettings,
768
+ ) -> str:
769
+ url_list_str = "\n".join(settings.url_list)
770
+
771
+ for result, logs in self.run_query_gradio(
772
+ query=query,
773
+ date_restrict=settings.date_restrict,
774
+ target_site=settings.target_site,
775
+ output_language=settings.output_language,
776
+ output_length=settings.output_length,
777
+ url_list_str=url_list_str,
778
+ inference_model_name=settings.inference_model_name,
779
+ hybrid_search=settings.hybrid_search,
780
+ output_mode_str=settings.output_mode,
781
+ extract_schema_str=settings.extract_schema_str,
782
+ ):
783
+ final_result = result
784
+ return final_result
785
+
786
+
787
+ def launch_gradio(
788
+ query: str,
789
+ init_settings: AskSettings,
790
+ share_ui: bool,
791
+ logger: logging.Logger,
792
+ ) -> None:
793
+ ask = Ask(logger=logger)
794
+
795
+ def toggle_schema_textbox(option):
796
+ if option == "extract":
797
+ return gr.update(visible=True)
798
+ else:
799
+ return gr.update(visible=False)
800
+
801
+ with gr.Blocks() as demo:
802
+ gr.Markdown("# Ask.py - Web Search-Extract-Summarize")
803
+ gr.Markdown(
804
+ "Search the web with the query and summarize the results. Source code: https://github.com/pengfeng/ask.py"
805
+ )
806
+
807
+ with gr.Row():
808
+ with gr.Column():
809
+
810
+ query_input = gr.Textbox(label="Query", value=query)
811
+ output_mode_input = gr.Radio(
812
+ label="Output Mode [answer: simple answer, extract: get structured data]",
813
+ choices=["answer", "extract"],
814
+ value=init_settings.output_mode,
815
+ )
816
+ extract_schema_input = gr.Textbox(
817
+ label="Extract Pydantic Schema",
818
+ visible=(init_settings.output_mode == "extract"),
819
+ value=init_settings.extract_schema_str,
820
+ lines=5,
821
+ max_lines=20,
822
+ )
823
+ output_mode_input.change(
824
+ fn=toggle_schema_textbox,
825
+ inputs=output_mode_input,
826
+ outputs=extract_schema_input,
827
+ )
828
+ date_restrict_input = gr.Number(
829
+ label="Date Restrict (Optional) [0 or empty means no date limit.]",
830
+ value=init_settings.date_restrict,
831
+ )
832
+ target_site_input = gr.Textbox(
833
+ label="Target Sites (Optional) [Empty means searching the whole web.]",
834
+ value=init_settings.target_site,
835
+ )
836
+ output_language_input = gr.Textbox(
837
+ label="Output Language (Optional) [Default is English.]",
838
+ value=init_settings.output_language,
839
+ )
840
+ output_length_input = gr.Number(
841
+ label="Output Length in words (Optional) [Default is automatically decided by LLM.]",
842
+ value=init_settings.output_length,
843
+ )
844
+ url_list_input = gr.Textbox(
845
+ label="URL List (Optional) [When specified, scrape the urls instead of searching the web.]",
846
+ lines=5,
847
+ max_lines=20,
848
+ value="\n".join(init_settings.url_list),
849
+ )
850
+
851
+ with gr.Accordion("More Options", open=False):
852
+ hybrid_search_input = gr.Checkbox(
853
+ label="Hybrid Search [Use both vector search and full-text search.]",
854
+ value=init_settings.hybrid_search,
855
+ )
856
+ inference_model_name_input = gr.Textbox(
857
+ label="Inference Model Name",
858
+ value=init_settings.inference_model_name,
859
+ )
860
+
861
+ submit_button = gr.Button("Submit")
862
+
863
+ with gr.Column():
864
+ answer_output = gr.Textbox(label="Answer")
865
+ logs_output = gr.Textbox(label="Logs", lines=10)
866
+
867
+ submit_button.click(
868
+ fn=ask.run_query_gradio,
869
+ inputs=[
870
+ query_input,
871
+ date_restrict_input,
872
+ target_site_input,
873
+ output_language_input,
874
+ output_length_input,
875
+ url_list_input,
876
+ inference_model_name_input,
877
+ hybrid_search_input,
878
+ output_mode_input,
879
+ extract_schema_input,
880
+ ],
881
+ outputs=[answer_output, logs_output],
882
+ )
883
+
884
+ demo.queue().launch(share=share_ui)
885
+
886
+
887
+ @click.command(help="Search web for the query and summarize the results.")
888
+ @click.option("--query", "-q", required=False, help="Query to search")
889
+ @click.option(
890
+ "--output-mode",
891
+ "-o",
892
+ type=click.Choice(["answer", "extract"], case_sensitive=False),
893
+ default="answer",
894
+ required=False,
895
+ help="Output mode for the answer, default is a simple answer",
896
+ )
897
+ @click.option(
898
+ "--date-restrict",
899
+ "-d",
900
+ type=int,
901
+ required=False,
902
+ default=0,
903
+ help="Restrict search results to a specific date range, default is no restriction",
904
+ )
905
+ @click.option(
906
+ "--target-site",
907
+ "-s",
908
+ required=False,
909
+ default="",
910
+ help="Restrict search results to a specific site, default is no restriction",
911
+ )
912
+ @click.option(
913
+ "--output-language",
914
+ required=False,
915
+ default="English",
916
+ help="Output language for the answer",
917
+ )
918
+ @click.option(
919
+ "--output-length",
920
+ type=int,
921
+ required=False,
922
+ default=0,
923
+ help="Output length for the answer",
924
+ )
925
+ @click.option(
926
+ "--url-list-file",
927
+ type=str,
928
+ required=False,
929
+ default="",
930
+ show_default=True,
931
+ help="Instead of doing web search, scrape the target URL list and answer the query based on the content",
932
+ )
933
+ @click.option(
934
+ "--extract-schema-file",
935
+ type=str,
936
+ required=False,
937
+ default="",
938
+ show_default=True,
939
+ help="Pydantic schema for the extract mode",
940
+ )
941
+ @click.option(
942
+ "--inference-model-name",
943
+ "-m",
944
+ required=False,
945
+ default="gpt-4o-mini",
946
+ help="Model name to use for inference",
947
+ )
948
+ @click.option(
949
+ "--hybrid-search",
950
+ is_flag=True,
951
+ help="Use hybrid search mode with both vector search and full-text search",
952
+ )
953
+ @click.option(
954
+ "--web-ui",
955
+ is_flag=True,
956
+ help="Launch the web interface",
957
+ )
958
+ @click.option(
959
+ "-l",
960
+ "--log-level",
961
+ "log_level",
962
+ default="INFO",
963
+ type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR"], case_sensitive=False),
964
+ help="Set the logging level",
965
+ show_default=True,
966
+ )
967
+ def search_extract_summarize(
968
+ query: str,
969
+ output_mode: str,
970
+ date_restrict: int,
971
+ target_site: str,
972
+ output_language: str,
973
+ output_length: int,
974
+ url_list_file: str,
975
+ extract_schema_file: str,
976
+ inference_model_name: str,
977
+ hybrid_search: bool,
978
+ web_ui: bool,
979
+ log_level: str,
980
+ ):
981
+ load_dotenv(dotenv_path=default_env_file, override=False)
982
+ logger = _get_logger(log_level)
983
+
984
+ if output_mode == "extract" and not extract_schema_file:
985
+ raise Exception("Extract mode requires the --extract-schema-file argument.")
986
+
987
+ settings = AskSettings(
988
+ date_restrict=date_restrict,
989
+ target_site=target_site,
990
+ output_language=output_language,
991
+ output_length=output_length,
992
+ url_list=_read_url_list(url_list_file),
993
+ inference_model_name=inference_model_name,
994
+ hybrid_search=hybrid_search,
995
+ output_mode=OutputMode(output_mode),
996
+ extract_schema_str=_read_extract_schema_str(extract_schema_file),
997
+ )
998
+
999
+ if web_ui or os.environ.get("RUN_GRADIO_UI", "false").lower() != "false":
1000
+ if os.environ.get("SHARE_GRADIO_UI", "false").lower() == "true":
1001
+ share_ui = True
1002
+ else:
1003
+ share_ui = False
1004
+ launch_gradio(
1005
+ query=query,
1006
+ init_settings=settings,
1007
+ share_ui=share_ui,
1008
+ logger=logger,
1009
+ )
1010
+ else:
1011
+ if query is None:
1012
+ raise Exception("Query is required for the command line mode")
1013
+ ask = Ask(logger=logger)
1014
+
1015
+ final_result = ask.run_query(query=query, settings=settings)
1016
+ click.echo(final_result)
1017
+
1018
+
1019
+ if __name__ == "__main__":
1020
+ search_extract_summarize()
demos/search_and_answer.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```
2
+ % python ask.py -q "Why do we need agentic RAG even if we have ChatGPT?"
3
+
4
+ ✅ Found 10 links for query: Why do we need agentic RAG even if we have ChatGPT?
5
+ ✅ Scraping the URLs ...
6
+ ✅ Scraped 10 URLs ...
7
+ ✅ Chunking the text ...
8
+ ✅ Saving to vector DB ...
9
+ ✅ Querying the vector DB ...
10
+ ✅ Running inference with context ...
11
+
12
+ # Answer
13
+
14
+ Agentic RAG (Retrieval-Augmented Generation) is needed alongside ChatGPT for several reasons:
15
+
16
+ 1. **Precision and Contextual Relevance**: While ChatGPT offers generative responses, it may not
17
+ reliably provide precise answers, especially when specific, accurate information is critical[5].
18
+ Agentic RAG enhances this by integrating retrieval mechanisms that improve response context and
19
+ accuracy, allowing users to access the most relevant and recent data without the need for costly
20
+ model fine-tuning[2].
21
+
22
+ 2. **Customizability**: RAG allows businesses to create tailored chatbots that can securely
23
+ reference company-specific data[2]. In contrast, ChatGPT’s broader capabilities may not be
24
+ directly suited for specialized, domain-specific questions without comprehensive customization[3].
25
+
26
+ 3. **Complex Query Handling**: RAG can be optimized for complex queries and can be adjusted to
27
+ work better with specific types of inputs, such as comparing and contrasting information, a task
28
+ where ChatGPT may struggle under certain circumstances[9]. This level of customization can lead to
29
+ better performance in niche applications where precise retrieval of information is crucial.
30
+
31
+ 4. **Asynchronous Processing Capabilities**: Future agentic systems aim to integrate asynchronous
32
+ handling of actions, allowing for parallel processing and reducing wait times for retrieval and
33
+ computation, which is a limitation in the current form of ChatGPT[7]. This advancement would enhance
34
+ overall efficiency and responsiveness in conversations.
35
+
36
+ 5. **Incorporating Retrieved Information Effectively**: Using RAG can significantly improve how
37
+ retrieved information is utilized within a conversation. By effectively managing the context and
38
+ relevance of retrieved documents, RAG helps in framing prompts that can guide ChatGPT towards
39
+ delivering more accurate responses[10].
40
+
41
+ In summary, while ChatGPT excels in generating conversational responses, agentic RAG brings
42
+ precision, customization, and efficiency that can significantly enhance the overall conversational
43
+ AI experience.
44
+
45
+ # References
46
+
47
+ [1] https://community.openai.com/t/how-to-use-rag-properly-and-what-types-of-query-it-is-good-at/658204
48
+ [2] https://www.linkedin.com/posts/brianjuliusdc_dax-powerbi-chatgpt-activity-7235953280177041408-wQqq
49
+ [3] https://community.openai.com/t/how-to-use-rag-properly-and-what-types-of-query-it-is-good-at/658204
50
+ [4] https://community.openai.com/t/prompt-engineering-for-rag/621495
51
+ [5] https://www.ben-evans.com/benedictevans/2024/6/8/building-ai-products
52
+ [6] https://community.openai.com/t/prompt-engineering-for-rag/621495
53
+ [7] https://www.linkedin.com/posts/kurtcagle_agentic-rag-personalizing-and-optimizing-activity-7198097129993613312-z7Sm
54
+ [8] https://community.openai.com/t/how-to-use-rag-properly-and-what-types-of-query-it-is-good-at/658204
55
+ [9] https://community.openai.com/t/how-to-use-rag-properly-and-what-types-of-query-it-is-good-at/658204
56
+ [10] https://community.openai.com/t/prompt-engineering-for-rag/621495
57
+ ```
demos/search_and_extract.md ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```
2
+ % python ask.py -q "LLM Gen-AI Startups" -o extract --extract-schema-file instructions/extract_example.txt
3
+ 2024-10-29 08:15:24,320 - INFO - Searching the web ...
4
+ 2024-10-29 08:15:24,684 - INFO - ✅ Found 10 links for query: LLM Gen-AI Startups
5
+ 2024-10-29 08:15:24,684 - INFO - Scraping the URLs ...
6
+ 2024-10-29 08:15:24,685 - INFO - Scraping https://www.ycombinator.com/companies/industry/generative-ai ...
7
+ 2024-10-29 08:15:24,686 - INFO - Scraping https://app.dealroom.co/lists/33530 ...
8
+ 2024-10-29 08:15:24,687 - INFO - Scraping https://explodingtopics.com/blog/generative-ai-startups ...
9
+ 2024-10-29 08:15:24,688 - INFO - Scraping https://www.reddit.com/r/learnprogramming/comments/1e0gzbo/are_most_ai_startups_these_days_just_openai/ ...
10
+ 2024-10-29 08:15:24,689 - INFO - Scraping https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc ...
11
+ 2024-10-29 08:15:24,690 - INFO - Scraping https://www.reddit.com/r/ycombinator/comments/16xhwz7/is_it_really_impossible_for_genai_startups_to/ ...
12
+ 2024-10-29 08:15:24,691 - INFO - Scraping https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9 ...
13
+ 2024-10-29 08:15:24,692 - INFO - Scraping https://a16z.com/ai/ ...
14
+ 2024-10-29 08:15:24,693 - INFO - Scraping https://www.eweek.com/artificial-intelligence/generative-ai-startups/ ...
15
+ 2024-10-29 08:15:24,695 - INFO - Scraping https://cohere.com/ ...
16
+ 2024-10-29 08:15:24,875 - WARNING - Body text too short for url: https://app.dealroom.co/lists/33530, length: 41
17
+ 2024-10-29 08:15:24,975 - INFO - ✅ Successfully scraped https://explodingtopics.com/blog/generative-ai-startups with length: 17631
18
+ 2024-10-29 08:15:25,429 - INFO - ✅ Successfully scraped https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9 with length: 3649
19
+ 2024-10-29 08:15:26,119 - INFO - ✅ Successfully scraped https://a16z.com/ai/ with length: 14828
20
+ 2024-10-29 08:15:26,144 - INFO - ✅ Successfully scraped https://cohere.com/ with length: 2696
21
+ 2024-10-29 08:15:26,220 - INFO - ✅ Successfully scraped https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc with length: 13858
22
+ 2024-10-29 08:15:26,520 - INFO - ✅ Successfully scraped https://www.reddit.com/r/learnprogramming/comments/1e0gzbo/are_most_ai_startups_these_days_just_openai/ with length: 2029
23
+ 2024-10-29 08:15:26,541 - INFO - ✅ Successfully scraped https://www.reddit.com/r/ycombinator/comments/16xhwz7/is_it_really_impossible_for_genai_startups_to/ with length: 3445
24
+ 2024-10-29 08:15:26,947 - WARNING - Body text too short for url: https://www.ycombinator.com/companies/industry/generative-ai, length: 0
25
+ 2024-10-29 08:15:26,989 - INFO - ✅ Successfully scraped https://www.eweek.com/artificial-intelligence/generative-ai-startups/ with length: 69104
26
+ 2024-10-29 08:15:26,990 - INFO - ✅ Scraped 8 URLs.
27
+ 2024-10-29 08:15:26,990 - INFO - Extracting structured data ...
28
+ 2024-10-29 08:15:34,019 - INFO - ✅ Finished inference API call. Extracted 33 items from https://explodingtopics.com/blog/generative-ai-startups.
29
+ 2024-10-29 08:15:34,490 - INFO - ✅ Finished inference API call. Extracted 0 items from https://www.reddit.com/r/learnprogramming/comments/1e0gzbo/are_most_ai_startups_these_days_just_openai/.
30
+ 2024-10-29 08:15:38,135 - INFO - ✅ Finished inference API call. Extracted 20 items from https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc.
31
+ 2024-10-29 08:15:39,165 - INFO - ✅ Finished inference API call. Extracted 2 items from https://www.reddit.com/r/ycombinator/comments/16xhwz7/is_it_really_impossible_for_genai_startups_to/.
32
+ 2024-10-29 08:15:40,463 - INFO - ✅ Finished inference API call. Extracted 7 items from https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9.
33
+ 2024-10-29 08:15:44,150 - INFO - ✅ Finished inference API call. Extracted 23 items from https://a16z.com/ai/.
34
+ 2024-10-29 08:16:02,785 - INFO - ✅ Finished inference API call. Extracted 73 items from https://www.eweek.com/artificial-intelligence/generative-ai-startups/.
35
+ 2024-10-29 08:16:04,423 - INFO - ✅ Finished inference API call. Extracted 3 items from https://cohere.com/.
36
+ 2024-10-29 08:16:04,423 - INFO - ✅ Finished extraction from all urls.
37
+ 2024-10-29 08:16:04,423 - INFO - Generating output ...
38
+ name,description,SourceURL
39
+ Cohere,Cohere is an AI startup that builds multilingual LLMs for enterprise businesses to streamline tasks.,https://explodingtopics.com/blog/generative-ai-startups
40
+ Hugging Face,"Hugging Face is a collaborative AI community that creates tools for developers, offering over 61,000 pre-trained models and 7,000 datasets.",https://explodingtopics.com/blog/generative-ai-startups
41
+ Tabnine,Tabnine is an AI assistant for software developers that uses generative AI to predict or suggest the next lines of code.,https://explodingtopics.com/blog/generative-ai-startups
42
+ Soundraw,Soundraw is a royalty-free AI music generator allowing creators to make original songs.,https://explodingtopics.com/blog/generative-ai-startups
43
+ Tome.app,Tome is an AI-powered storytelling platform that helps users create presentations using generative AI.,https://explodingtopics.com/blog/generative-ai-startups
44
+ AssemblyAI,AssemblyAI is an AI-as-a-service startup providing APIs in 80 different languages for automated speech transcription.,https://explodingtopics.com/blog/generative-ai-startups
45
+ Promptbase,Promptbase is a marketplace for buying and selling prompts to generate content with AI tools.,https://explodingtopics.com/blog/generative-ai-startups
46
+ Photoroom,PhotoRoom is an AI-powered photo editing tool that combines generative AI with traditional editing tools.,https://explodingtopics.com/blog/generative-ai-startups
47
+ Taskade,Taskade is a generative AI productivity tool for task management and team collaboration.,https://explodingtopics.com/blog/generative-ai-startups
48
+ Synthesia,Synthesia AI is a generative AI video maker that creates videos from text in multiple languages.,https://explodingtopics.com/blog/generative-ai-startups
49
+ Humata AI,Humata AI is a tool integrating with your desktop to answer questions about documents using generative AI.,https://explodingtopics.com/blog/generative-ai-startups
50
+ Chatbase,"Chatbase is a chatbot integrated into websites, providing instant answers to users.",https://explodingtopics.com/blog/generative-ai-startups
51
+ Stability AI,"Stability AI is known for creating Stable Diffusion, a deep learning text-to-image AI model.",https://explodingtopics.com/blog/generative-ai-startups
52
+ Anyword,Anyword is a generative AI content generation platform that uses natural language processing for copywriting.,https://explodingtopics.com/blog/generative-ai-startups
53
+ Rephrase AI,Rephrase AI is a text-to-video generation platform that allows customers to create personalized videos.,https://explodingtopics.com/blog/generative-ai-startups
54
+ Inworld AI,Inworld AI specializes in AI-powered character generation for video games.,https://explodingtopics.com/blog/generative-ai-startups
55
+ Runway,Runway is a generative AI video editing platform that produces videos based on text prompts.,https://explodingtopics.com/blog/generative-ai-startups
56
+ Sudowrite,Sudowrite is a generative AI writing assistant designed for novel writing and storytelling.,https://explodingtopics.com/blog/generative-ai-startups
57
+ Steve.ai,Steve.ai is an online video creation platform that turns text prompts into animated videos.,https://explodingtopics.com/blog/generative-ai-startups
58
+ PlayHT,PlayHT is a text-to-speech software that uses generative AI to create audio from text.,https://explodingtopics.com/blog/generative-ai-startups
59
+ Elicit,Elicit is a generative AI research tool for finding and analyzing academic papers.,https://explodingtopics.com/blog/generative-ai-startups
60
+ TalkPal,TalkPal is an AI-powered language learning platform that personalizes sessions based on the user's level.,https://explodingtopics.com/blog/generative-ai-startups
61
+ Dubverse,Dubverse is an AI video dubbing platform capable of translating videos into multiple languages.,https://explodingtopics.com/blog/generative-ai-startups
62
+ Codeium,Codeium is an AI-powered toolkit for developers that auto-generates and explains code.,https://explodingtopics.com/blog/generative-ai-startups
63
+ Fliki,Fliki is an AI video and audio generation platform that incorporates text to speech capabilities.,https://explodingtopics.com/blog/generative-ai-startups
64
+ LOVO AI,LOVO is an AI voice generator startup focused on text-to-speech and voice cloning.,https://explodingtopics.com/blog/generative-ai-startups
65
+ Decktopus,"Decktopus creates presentations from prompts, streamlining slide generation.",https://explodingtopics.com/blog/generative-ai-startups
66
+ Character.ai,Character AI is a generative AI platform that generates customizable animated chatbots.,https://explodingtopics.com/blog/generative-ai-startups
67
+ Descript,Descript is a generative AI video and audio editing application catering to podcasters and videographers.,https://explodingtopics.com/blog/generative-ai-startups
68
+ Papercup,"Papercup uses AI to translate speech and dubbing, creating realistic voiceovers.",https://explodingtopics.com/blog/generative-ai-startups
69
+ Vizcom,Vizcom is a generative AI tool that aids designers in creating 3D concept drawings.,https://explodingtopics.com/blog/generative-ai-startups
70
+ Vidnoz,Vidnoz is a free AI video platform aimed at reducing costs and increasing productivity.,https://explodingtopics.com/blog/generative-ai-startups
71
+ Scalenut,Scalenut is an AI-powered SEO and content marketing platform that automates content creation.,https://explodingtopics.com/blog/generative-ai-startups
72
+ Huma.AI,"A generative AI for life sciences SaaS platform, recognized by Gartner in multiple reports and collaborating with OpenAI for a validated GenAI solution for medical affairs.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
73
+ Viz.ai,"A medical imaging startup specializing in stroke care and expanded into cardiology and oncology, using LLMs for early disease detection.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
74
+ Arionkoder,"A product development studio and AI lab specializing in AI, computer vision, and ML solutions for healthcare.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
75
+ HeHealth,Delivers AI and LLM technologies for efficient recommendations for male healthcare.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
76
+ HOPPR,A multimodal imaging platform improving communication and medical processes through deep image analysis.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
77
+ Medical IP,A medical metaverse solution utilizing generative AI for streamlined medical imaging segmentation.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
78
+ NexusMD,An LLM-powered medical imaging platform automating medical imaging data capture across service sites.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
79
+ Abridge,"A leading generative AI for clinical documentation, converting patient-clinician conversations into structured notes.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
80
+ Autonomize AI,A healthcare-optimized AI platform that cuts clinical administrative time and accelerates care gap closures.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
81
+ DeepScribe,"A med-tech firm leveraging LLMs to automate clinical documentation, reducing clinician burnout.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
82
+ HiLabs,Utilizes AI and LLMs to refine data and identify care gaps for large health plans.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
83
+ Nabla,"Offers Copilot, an ambient AI for physicians that streamlines clinical note generation.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
84
+ AgentifAI,A voice-first AI assistant for healthcare enhancing patient experience.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
85
+ Artisight,An end-to-end sensor fusion platform deployed in hospitals to enhance operational efficiency.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
86
+ dacadoo,"A digital health platform connecting to various devices, with plans to incorporate an LLM-based streaming model.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
87
+ Hippocratic AI,Developing a safety-focused LLM for patient-facing applications.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
88
+ Idoven,An AI-powered cardiology platform with deep-learning models for patient diagnosis.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
89
+ Inference Analytics,A generative AI healthcare platform trained on a vast dataset for various impactful healthcare use cases.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
90
+ Pingoo,"An AI health chatbot providing personalized health education, serving various health systems.",https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
91
+ Talkie.ai,Automates patient phone interactions using AI voice and LLM technology for healthcare organizations.,https://www.linkedin.com/pulse/20-gen-ai-healthcare-startups-shaping-future-recap-from-renee-yao-q7lkc
92
+ Jasper,Jasper (YC GenAI company) who became one of the fastest growing startups of all time is losing customers fast. It is often cited as an example of how GenAI companies struggle to develop a moat.,https://www.reddit.com/r/ycombinator/comments/16xhwz7/is_it_really_impossible_for_genai_startups_to/
93
+ Unnamed GenAI Startup,"We are a GenAI startup that automates tasks in a specific niche area and utilizes a network of LLMs. Our MVP is looking great, and we have a substantial interest from investors.",https://www.reddit.com/r/ycombinator/comments/16xhwz7/is_it_really_impossible_for_genai_startups_to/
94
+ beautiful.ai,A startup providing tools for creating presentations with an innovative approach.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
95
+ Tome,A startup focused on revolutionizing presentation tools.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
96
+ Rows,A startup rethinking spreadsheets with an LLM-first perspective.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
97
+ mem,A note-taking startup utilizing LLM technology.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
98
+ Clio,"A practice management solution for law firms, sitting on a wealth of data to build AI solutions.",https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
99
+ Bench,An accounting startup that has implemented auto-pilot strategies.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
100
+ Pilot,A recent entrant in the accounting space following a similar auto-pilot approach.,https://medium.com/point-nine-news/where-are-the-opportunities-for-new-startups-in-generative-ai-f48068b5f8f9
101
+ a16z,"A venture capital firm that invests in technology companies, with a focus on artificial intelligence and related sectors.",https://a16z.com/ai/
102
+ AI Stack Products,"A collection of open-source AI stacks and tools for developers, including projects for building AI companions and chatbots.",https://a16z.com/ai/
103
+ Llama2 Chatbot,A 13 billion parameter language model fine-tuned for chat completions systems.,https://a16z.com/ai/
104
+ AI Grants,"Grant funding for AI developers focused on LLM training, hosting, and evaluation.",https://a16z.com/ai/
105
+ AI Canon,"A curated collection of impactful papers, posts, courses, and guides on modern artificial intelligence.",https://a16z.com/ai/
106
+ Brain Trust,A community-driven platform aimed at training AI models with human data.,https://a16z.com/ai/
107
+ Character.AI,A platform for creating and interacting with AI characters.,https://a16z.com/ai/
108
+ Civiti,A startup focused on deploying community-driven AI models.,https://a16z.com/ai/
109
+ Creta,A developer's assistant using AI for coding support.,https://a16z.com/ai/
110
+ Databricks,A company that provides a Unified Analytics Platform powered by Apache Spark.,https://a16z.com/ai/
111
+ ElevenLabs,An AI company that specializes in voice generation and text-to-speech technologies.,https://a16z.com/ai/
112
+ Freeno,A healthcare-focused AI startup working on early detection systems.,https://a16z.com/ai/
113
+ OpenAI,An AI research lab dedicated to ensuring that artificial general intelligence benefits all of humanity.,https://a16z.com/ai/
114
+ Zuma,An AI startup aimed at enhancing user experience through intelligent design.,https://a16z.com/ai/
115
+ Nautilus Biotechnology,A company transforming the experience and outcome of biotech with AI applications.,https://a16z.com/ai/
116
+ Saronic,An AI model focused on enhancing predictive analytics in business settings.,https://a16z.com/ai/
117
+ Mistral AI,A company developing scaled AI technologies for multiple applications.,https://a16z.com/ai/
118
+ Turquoise Health,An AI-driven health technology startup offering transparent healthcare pricing.,https://a16z.com/ai/
119
+ Rasa,An open-source framework for building AI assistants.,https://a16z.com/ai/
120
+ Viggle,A startup revolutionizing how audiences engage with multimedia through AI.,https://a16z.com/ai/
121
+ Waymark,A company dedicated to automating video production through generative AI techniques.,https://a16z.com/ai/
122
+ Yolo AI,An emerging company specializing in real-time object detection technology.,https://a16z.com/ai/
123
+ Luma AI,An innovative AI platform designed to enhance the visual experience in various sectors.,https://a16z.com/ai/
124
+ OpenAI,"OpenAI is the highest profile company in the generative AI space. Along with its prebuilt AI solutions, OpenAI also offers API and application development support for developers who want to use its models as baselines. Its close partnership with Microsoft and growing commitment to ethical AI continue to boost its reputation and reach.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
125
+ Anthropic,"Anthropic’s Claude platform is similar to OpenAI’s ChatGPT, with its large language model and content generation focus. Claude has evolved into an enterprise-level AI assistant with high-level conversational capabilities.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
126
+ Cohere,Cohere offers natural language processing (NLP) solutions that are specifically designed to support business operations. Its conversational AI agent allows enterprise users to quickly search for and retrieve company information.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
127
+ Glean,"Glean is a generative AI enterprise search company that connects to a variety of enterprise apps and platforms, enabling easy access to business information sources with a focus on AI privacy and governance.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
128
+ Jasper,"Jasper’s core product is designed for marketing content generation, effective for establishing a consistent brand voice and managing digital marketing campaigns. Jasper also acquired the AI image platform Clickdrop.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
129
+ Hugging Face,"Hugging Face is a community forum focused on AI and ML model development, offering access to BLOOM, an open-source LLM that can generate content in multiple languages.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
130
+ Inflection AI,"Inflection AI, founded by former leaders from LinkedIn and DeepMind, focuses on creating conversational AI tools, recently releasing Pi, a personal AI tool.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
131
+ Stability AI,"Stability AI specializes in generative AI for image and video content generation, with its app Stable Diffusion being a popular solution in the industry.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
132
+ MOSTLY AI,"MOSTLY AI specializes in synthetic data generation, balancing data democratization with anonymity and security requirements particularly useful in banking and telecommunications.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
133
+ Lightricks,"Lightricks is known for its social media-friendly image editing app, Facetune, and uses AI for content generation and avatar creation.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
134
+ AI21 Labs,"AI21 Labs creates enterprise tools focusing on contextual natural language processing, allowing third-party developers to build on their language models.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
135
+ Tabnine,"Tabnine offers generative AI code assistance for software development, helping with code completion and other programming tasks.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
136
+ Mistral AI,"Mistral AI provides developer-facing open AI models and deployment resources, focusing on scalable AI solutions.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
137
+ Codeium,"Codeium is a generative AI company that provides resources for generating logical code, with features for autocomplete and contextual knowledge.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
138
+ Clarifai,"Clarifai's multipurpose platform allows users to build, deploy, and manage AI data projects across various sectors.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
139
+ Gong,"Gong provides revenue intelligence solutions that use generative AI to enhance sales coaching, customer service engagement, and revenue forecasting.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
140
+ Twain,"Twain is an AI writing assistant that helps sales professionals generate captivating content, particularly for outreach emails.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
141
+ Bertha.ai,"Bertha.ai specializes in content generation solutions for WordPress and similar platforms, assisting with written content and imagery.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
142
+ Tome,Tome is a creative generative AI platform known for its versatile interface to create presentations and reports.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
143
+ CopyAI,CopyAI's platform supports marketing and sales professionals in generating effective go-to-market strategies.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
144
+ Synthesia,"Synthesia focuses on AI-driven video creation, allowing users to generate professional-quality videos based on simple text inputs.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
145
+ Midjourney,"Midjourney offers a generative AI solution for image and artwork creation, notable for its advanced editing features.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
146
+ MURF.AI,"MURF.AI provides text-to-speech solutions with bidirectional voice capabilities, designed for creative content production.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
147
+ PlayHT,PlayHT specializes in AI voice generation and personalized podcast content creation.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
148
+ ElevenLabs,ElevenLabs is renowned for its high-quality voice generation technology and enterprise scalability.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
149
+ Colossyan,Colossyan offers tools for creating corporate training videos without the need for actors or original scripting.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
150
+ AssemblyAI,AssemblyAI provides speech-to-text modeling and transcription solutions with strong analysis capacities.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
151
+ Plask,Plask automates animation processes and simplifies creation of hyper-realistic 3D motion videos.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
152
+ LOVO,LOVO delivers video and voice AI generation solutions through its comprehensive platform called Genny.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
153
+ DeepBrain AI,"DeepBrain AI produces AI-generated videos including interactive virtual assistants, enhancing accessibility in public service.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
154
+ Elai.io,"Elai.io provides collaborative tools for AI video generation, tailored for business audiences.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
155
+ Sudowrite,"Sudowrite supports writers by expanding on story outlines, generating ideas, and creating AI art.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
156
+ Tavus,Tavus enables automated video generation personalized for each viewer's characteristics.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
157
+ Hippocratic AI,Hippocratic AI offers a generative AI platform for healthcare focused on patient care and HIPAA compliance.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
158
+ Paige AI,Paige AI integrates generative AI for optimizing cancer diagnostics and pathology.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
159
+ Iambic Therapeutics,Iambic Therapeutics optimizes drug discovery using machine learning in the oncology sector.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
160
+ Insilico Medicine,Insilico Medicine uses AI for efficient drug development across various medical fields.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
161
+ Etcembly,Etcembly enhances T-cell receptor immunotherapies through machine learning advancements.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
162
+ Biomatter,Biomatter employs AI for intelligent architecture in protein design across multiple sectors.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
163
+ Activ Surgical,Activ Surgical utilizes AI for enhanced surgical guidance and visualization.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
164
+ Kaliber Labs,Kaliber Labs designs AI-powered surgical software for improved communication and patient experiences.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
165
+ Osmo,Osmo utilizes machine learning in olfactory science to predict smells based on molecular structure.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
166
+ Aqemia,Aqemia focuses on AI-assisted drug discovery incorporating both quantum and statistical mechanics.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
167
+ Synthetaic,Synthetaic's platform generates AI models for analyzing unstructured and unlabeled datasets.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
168
+ Synthesis AI,Synthesis AI develops synthetic data-driven imagery and human simulations for ethical AI applications.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
169
+ Syntho,Syntho generates synthetic data twins for analytics and product demos while ensuring ease of use.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
170
+ GenRocket,GenRocket emphasizes automation in synthetic data generation and management for various industries.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
171
+ Gridspace,Gridspace creates hybrid voice AI and human agent solutions for improved contact center management.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
172
+ Revery AI,Revery AI utilizes generative AI to create virtual dressing rooms and smart shopping assistants.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
173
+ Veesual,Veesual offers deep learning-based virtual try-on solutions for e-commerce.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
174
+ Frame AI,Frame AI analyzes customer interactions to provide insights for improving customer service.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
175
+ Zowie,Zowie specializes in AI customer service technology tailored for e-commerce environments.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
176
+ Forethought,Forethought provides generative AI solutions for optimizing customer service workflows.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
177
+ Lily AI,Lily AI employs AI to enhance product management and customer service experiences for retailers.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
178
+ Runway,Runway enables filmmakers to use AI for cinema-quality video production.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
179
+ Latitude.io,"Latitude.io offers AI-driven gaming experiences, allowing users to create dynamic narratives.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
180
+ Character.AI,Character.AI allows users to develop and interact with user-created virtual characters.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
181
+ Charisma Entertainment,Charisma Entertainment creates engaging narratives and character-driven storylines for various media.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
182
+ Replika,Replika generates AI companions for personalized conversations and social interactions.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
183
+ Aimi.fm,Aimi.fm provides users with a generative AI music player for composing customized music loops.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
184
+ Inworld AI,Inworld AI utilizes generative AI to enhance the realism of non-player characters in gaming and media.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
185
+ SOUNDRAW,SOUNDRAW enables tailored music composition for various media including videos and games.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
186
+ Notion,Notion offers AI-assisted task management tools for improved workflow efficiency.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
187
+ Harvey,Harvey targets the legal sector with generative AI-driven professional services support.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
188
+ Ironclad,Ironclad provides AI contract management tools for simplifying contract workflows across industries.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
189
+ Taskade,Taskade focuses on AI-powered task management and collaborative tools for creative projects.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
190
+ Humata,"Humata helps users extract useful insights from documents and files, enhancing knowledge management.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
191
+ Simplifai,"Simplifai automates banking and finance processes, offering solutions tailored to regulatory requirements.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
192
+ PatentPal,"PatentPal generates drafts for patent specifications, optimizing the intellectual property protection process.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
193
+ Adept AI,Adept AI utilizes natural language processing to enhance workplace interactions and automate workflows.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
194
+ Perplexity AI,"Perplexity AI offers a personalized AI search engine, resembling chatbots with more detailed outputs.",https://www.eweek.com/artificial-intelligence/generative-ai-startups/
195
+ Andi,Andi is a friendly generative AI search bot that summarizes web information efficiently.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
196
+ You.com,You.com is a private search engine that uses AI to summarize and personalize search results.,https://www.eweek.com/artificial-intelligence/generative-ai-startups/
197
+ Cohere Command,"Command models are used by companies to build production-ready, scalable and efficient AI-powered applications.",https://cohere.com/
198
+ Cohere Embed,"Unlocking the full potential of your enterprise data with the highest performing embedding model, supporting over 100 languages.",https://cohere.com/
199
+ Cohere Rerank,"Surfaces the industry’s most accurate responses, combining Rerank and Embed for reliable and up-to-date responses.",https://cohere.com/
200
+ ```
demos/search_on_site_and_date.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This following query will only use the information from openai.com that are updated in the previous
2
+ day. The behavior is similar to the "site:openai.com" and "date-restrict" search parameters in Google
3
+ search.
4
+
5
+ ```
6
+ % python ask.py -q "OpenAI Swarm Framework" -d 1 -s openai.com
7
+ ✅ Found 10 links for query: OpenAI Swarm Framework
8
+ ✅ Scraping the URLs ...
9
+ ✅ Scraped 10 URLs ...
10
+ ✅ Chunking the text ...
11
+ ✅ Saving to vector DB ...
12
+ ✅ Querying the vector DB to get context ...
13
+ ✅ Running inference with context ...
14
+
15
+ # Answer
16
+
17
+ OpenAI Swarm Framework is an experimental platform designed for building, orchestrating, and
18
+ deploying multi-agent systems, enabling multiple AI agents to collaborate on complex tasks. It contrasts
19
+ with traditional single-agent models by facilitating agent interaction and coordination, thus enhancing
20
+ efficiency[5][9]. The framework provides developers with a way to orchestrate these agent systems in
21
+ a lightweight manner, leveraging Node.js for scalable applications[1][4].
22
+
23
+ One implementation of this framework is Swarm.js, which serves as a Node.js SDK, allowing users to
24
+ create and manage agents that perform tasks and hand off conversations. Swarm.js is positioned as
25
+ an educational tool, making it accessible for both beginners and experts, although it may still contain
26
+ bugs and is currently lightweight[1][3][7]. This new approach emphasizes multi-agent collaboration and is
27
+ well-suited for back-end development, requiring some programming expertise for effective implementation[9].
28
+
29
+ Overall, OpenAI Swarm facilitates a shift in how AI systems can collaborate, differing from existing
30
+ OpenAI tools by focusing on backend orchestration rather than user-interactive front-end applications[9].
31
+
32
+ # References
33
+
34
+ [1] https://community.openai.com/t/introducing-swarm-js-node-js-implementation-of-openai-swarm/977510
35
+ [2] https://community.openai.com/t/introducing-swarm-js-a-node-js-implementation-of-openai-swarm/977510
36
+ [3] https://community.openai.com/t/introducing-swarm-js-node-js-implementation-of-openai-swarm/977510
37
+ [4] https://community.openai.com/t/introducing-swarm-js-a-node-js-implementation-of-openai-swarm/977510
38
+ [5] https://community.openai.com/t/swarm-some-initial-insights/976602
39
+ [6] https://community.openai.com/t/swarm-some-initial-insights/976602
40
+ [7] https://community.openai.com/t/introducing-swarm-js-node-js-implementation-of-openai-swarm/977510
41
+ [8] https://community.openai.com/t/introducing-swarm-js-a-node-js-implementation-of-openai-swarm/977510
42
+ [9] https://community.openai.com/t/swarm-some-initial-insights/976602
43
+ [10] https://community.openai.com/t/swarm-some-initial-insights/976602
44
+ ```
instructions/extract_example.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ class CompanyInfo(BaseModel):
2
+ name: str
3
+ description: str
instructions/links.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # you can specify a --url-list-file argument with links similar to the ones below
2
+ # ask.py will crawl these pages and answer the question based on their contents
3
+ https://en.wikipedia.org/wiki/Large_language_model
4
+ https://en.wikipedia.org/wiki/Retrieval-augmented_generation
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ click==8.1.7
2
+ requests==2.31.0
3
+ openai==1.40.2
4
+ jinja2==3.1.3
5
+ bs4==0.0.2
6
+ lxml==4.8.0
7
+ python-dotenv==1.0.1
8
+ duckdb==1.1.2
9
+ gradio==5.3.0