Spaces:
Running
Running
Upload 2 files
Browse files- tools/fetch_page.py +88 -0
- tools/search_ddg.py +41 -0
tools/fetch_page.py
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import html2text
|
3 |
+
from readability import Document
|
4 |
+
from langchain_core.tools import tool
|
5 |
+
from langchain_core.pydantic_v1 import (BaseModel, Field)
|
6 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
7 |
+
|
8 |
+
|
9 |
+
class FetchPageInput(BaseModel):
|
10 |
+
url: str = Field()
|
11 |
+
page_num: int = Field(0, ge=0)
|
12 |
+
|
13 |
+
|
14 |
+
@tool(args_schema=FetchPageInput)
|
15 |
+
def fetch_page(url, page_num=0, timeout_sec=10):
|
16 |
+
"""
|
17 |
+
指定されたURLから(とページ番号から)ウェブページのコンテンツを取得するツール。
|
18 |
+
|
19 |
+
`status` と `page_content`(`title`、`content`、`has_next`インジケーター)を返します。
|
20 |
+
statusが200でない場合は、ページの取得時にエラーが発生しています。(他のページの取得を試みてください)
|
21 |
+
|
22 |
+
デフォルトでは、最大2,000トークンのコンテンツのみが取得されます。
|
23 |
+
ページにさらにコンテンツがある場合、`has_next`の値はTrueになります。
|
24 |
+
続きを読むには、同じURLで`page_num`パラメータをインクリメントして、再度入力してください。
|
25 |
+
(ページングは0から始まるので、次のページは1です)
|
26 |
+
|
27 |
+
1ページが長すぎる場合は、**3回以上取得しないでください**(メモリの負荷がかかるため)。
|
28 |
+
|
29 |
+
Returns
|
30 |
+
-------
|
31 |
+
Dict[str, Any]:
|
32 |
+
- status: str
|
33 |
+
- page_content
|
34 |
+
- title: str
|
35 |
+
- content: str
|
36 |
+
- has_next: bool
|
37 |
+
"""
|
38 |
+
try:
|
39 |
+
response = requests.get(url, timeout=timeout_sec)
|
40 |
+
response.encoding = 'utf-8'
|
41 |
+
except requests.exceptions.Timeout:
|
42 |
+
return {
|
43 |
+
"status": 500,
|
44 |
+
"page_content": {'error_message': 'Could not download page due to Timeout Error. Please try to fetch other pages.'}
|
45 |
+
}
|
46 |
+
|
47 |
+
if response.status_code != 200:
|
48 |
+
return {
|
49 |
+
"status": response.status_code,
|
50 |
+
"page_content": {'error_message': 'Could not download page. Please try to fetch other pages.'}
|
51 |
+
}
|
52 |
+
|
53 |
+
try:
|
54 |
+
doc = Document(response.text)
|
55 |
+
title = doc.title()
|
56 |
+
html_content = doc.summary()
|
57 |
+
content = html2text.html2text(html_content)
|
58 |
+
except:
|
59 |
+
return {
|
60 |
+
"status": 500,
|
61 |
+
"page_content": {'error_message': 'Could not parse page. Please try to fetch other pages.'}
|
62 |
+
}
|
63 |
+
|
64 |
+
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
|
65 |
+
model_name='gpt-4o-mini',
|
66 |
+
chunk_size=1000,
|
67 |
+
chunk_overlap=0,
|
68 |
+
)
|
69 |
+
chunks = text_splitter.split_text(content)
|
70 |
+
if page_num >= len(chunks):
|
71 |
+
return {
|
72 |
+
"status": 500,
|
73 |
+
"page_content": {'error_message': 'page_num parameter looks invalid. Please try to fetch other pages.'}
|
74 |
+
}
|
75 |
+
elif page_num >= 3:
|
76 |
+
return {
|
77 |
+
"status": 503,
|
78 |
+
"page_content": {'error_message': "Reading more of the page_num's content will overload your memory. Please provide your response based on the information you currently have."}
|
79 |
+
}
|
80 |
+
else:
|
81 |
+
return {
|
82 |
+
"status": 200,
|
83 |
+
"page_content": {
|
84 |
+
"title": title,
|
85 |
+
"content": chunks[page_num],
|
86 |
+
"has_next": page_num < len(chunks) - 1
|
87 |
+
}
|
88 |
+
}
|
tools/search_ddg.py
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from itertools import islice
|
2 |
+
from duckduckgo_search import DDGS
|
3 |
+
from langchain_core.tools import tool
|
4 |
+
from langchain_core.pydantic_v1 import (BaseModel, Field)
|
5 |
+
|
6 |
+
|
7 |
+
class SearchDDGInput(BaseModel):
|
8 |
+
query: str = Field(description="検索したいキーワードを入力してください")
|
9 |
+
|
10 |
+
|
11 |
+
@tool(args_schema=SearchDDGInput)
|
12 |
+
def search_ddg(query, max_result_num=5):
|
13 |
+
"""
|
14 |
+
DuckDuckGo検索を実行するためのツールです。
|
15 |
+
検索したいキーワードを入力して使用してください。
|
16 |
+
検索結果の各ページのタイトル、スニペット(説明文)、URLが返されます。
|
17 |
+
このツールから得られる情報は非常に簡素化されており、時には古い情報の場合もあります。
|
18 |
+
|
19 |
+
必要な情報が見つからない場合は、必ず `WEB Page Fetcher` ツールを使用して各ページの内容を確認してください。
|
20 |
+
文脈に応じて最も適切な言語を使用してください(ユーザーの言語と同じである必要はありません)。
|
21 |
+
例えば、プログラミング関連の質問では、英語で検索するのが最適です。
|
22 |
+
|
23 |
+
Returns
|
24 |
+
-------
|
25 |
+
List[Dict[str, str]]:
|
26 |
+
- title
|
27 |
+
- snippet
|
28 |
+
- url
|
29 |
+
"""
|
30 |
+
res = DDGS().text(query + " latest", region='JP', safesearch='off', backend="lite")
|
31 |
+
return [
|
32 |
+
{
|
33 |
+
"title": r.get('title', ""),
|
34 |
+
"snippet": r.get('body', ""),
|
35 |
+
"url": r.get('href', "")
|
36 |
+
}
|
37 |
+
for r in islice(res, max_result_num)
|
38 |
+
]
|
39 |
+
|
40 |
+
|
41 |
+
|