0xarchit commited on
Commit
c459436
·
1 Parent(s): a6b5235

Add LangSearch web search tool for small model knowledge augmentation

Browse files
Files changed (4) hide show
  1. Dockerfile +2 -1
  2. README.md +23 -0
  3. requirements.txt +2 -1
  4. search_tool.py +61 -0
Dockerfile CHANGED
@@ -63,8 +63,9 @@ RUN python3 -m venv /opt/venv \
63
  && rm -rf /root/.cache/pip
64
 
65
  COPY download_model.py /app/download_model.py
 
66
  COPY start.sh /app/start.sh
67
- RUN chmod +x /app/start.sh \
68
  && mkdir -p /data/models /data/hf-cache \
69
  && chown -R 65532:65532 /app || true
70
 
 
63
  && rm -rf /root/.cache/pip
64
 
65
  COPY download_model.py /app/download_model.py
66
+ COPY search_tool.py /app/search_tool.py
67
  COPY start.sh /app/start.sh
68
+ RUN chmod +x /app/start.sh /app/search_tool.py \
69
  && mkdir -p /data/models /data/hf-cache \
70
  && chown -R 65532:65532 /app || true
71
 
README.md CHANGED
@@ -31,6 +31,7 @@ Optional tuning variables:
31
  - `CACHE_TYPE_K`: KV cache type for keys, default `q8_0`
32
  - `CACHE_TYPE_V`: KV cache type for values, default `q8_0`
33
  - `REASONING`: reasoning mode, accepts `True`, `False`, or `auto` and maps to llama.cpp `--reasoning`
 
34
  - `PARALLEL`: optional override for concurrent prompt decode slots
35
  - `PORT`: listen port, default `7860`
36
 
@@ -50,6 +51,28 @@ The Docker image uses a multi-stage build on Ubuntu 24.04. The builder stage ins
50
 
51
  Model downloads and HF cache live on the `/data` bucket so restarts do not redownload the model.
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  ## curl examples
54
 
55
  ```bash
 
31
  - `CACHE_TYPE_K`: KV cache type for keys, default `q8_0`
32
  - `CACHE_TYPE_V`: KV cache type for values, default `q8_0`
33
  - `REASONING`: reasoning mode, accepts `True`, `False`, or `auto` and maps to llama.cpp `--reasoning`
34
+ - `LANGSEARCH_API_KEY`: optional API key for LangSearch web search tool (free tier: 1 req/sec, 60/min, 1000/day)
35
  - `PARALLEL`: optional override for concurrent prompt decode slots
36
  - `PORT`: listen port, default `7860`
37
 
 
51
 
52
  Model downloads and HF cache live on the `/data` bucket so restarts do not redownload the model.
53
 
54
+ ## Web Search Tool
55
+
56
+ If `LANGSEARCH_API_KEY` is set, use the search tool to augment small model knowledge:
57
+
58
+ ```bash
59
+ python3 /app/search_tool.py "query" [count] [summary] [freshness]
60
+ ```
61
+
62
+ Examples:
63
+ ```bash
64
+ python3 /app/search_tool.py "latest AI news" 5 true noLimit
65
+ python3 /app/search_tool.py "Python 3.13 release" 3 false oneWeek
66
+ ```
67
+
68
+ Parameters:
69
+ - `query`: search string (required)
70
+ - `count`: max results 1-10 (default: 5)
71
+ - `summary`: include summaries (default: true)
72
+ - `freshness`: `oneDay`, `oneWeek`, `oneMonth`, `oneYear`, `noLimit` (default: `noLimit`)
73
+
74
+ Output is JSON with search results, URLs, snippets, and optional summaries.
75
+
76
  ## curl examples
77
 
78
  ```bash
requirements.txt CHANGED
@@ -1 +1,2 @@
1
- huggingface_hub>=0.24,<1
 
 
1
+ huggingface_hub>=0.24,<1
2
+ requests>=2.31,<3
search_tool.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import sys
5
+ import json
6
+ import requests
7
+
8
+
9
+ def search(query: str, count: int = 5, summary: bool = True, freshness: str = "noLimit") -> dict:
10
+ api_key = os.environ.get("LANGSEARCH_API_KEY", "").strip()
11
+ if not api_key:
12
+ raise SystemExit("LANGSEARCH_API_KEY environment variable not set")
13
+
14
+ url = "https://api.langsearch.com/v1/web-search"
15
+ headers = {
16
+ "Authorization": f"Bearer {api_key}",
17
+ "Content-Type": "application/json"
18
+ }
19
+ payload = {
20
+ "query": query,
21
+ "freshness": freshness,
22
+ "summary": summary,
23
+ "count": min(count, 10)
24
+ }
25
+
26
+ try:
27
+ response = requests.post(url, headers=headers, json=payload, timeout=30)
28
+ response.raise_for_status()
29
+ data = response.json()
30
+
31
+ if data.get("code") == 200:
32
+ results = []
33
+ web_pages = data.get("data", {}).get("webPages", {}).get("value", [])
34
+ for page in web_pages:
35
+ results.append({
36
+ "name": page.get("name", ""),
37
+ "url": page.get("url", ""),
38
+ "snippet": page.get("snippet", ""),
39
+ "summary": page.get("summary", "") if summary else ""
40
+ })
41
+ return {"success": True, "query": query, "results": results}
42
+ else:
43
+ return {"success": False, "error": data.get("msg", "Unknown error")}
44
+
45
+ except requests.RequestException as e:
46
+ return {"success": False, "error": str(e)}
47
+
48
+
49
+ if __name__ == "__main__":
50
+ if len(sys.argv) < 2:
51
+ print("Usage: search_tool.py '<query>' [count] [summary] [freshness]")
52
+ print("Example: search_tool.py 'Apple M4 chip' 5 true noLimit")
53
+ sys.exit(1)
54
+
55
+ query = sys.argv[1]
56
+ count = int(sys.argv[2]) if len(sys.argv) > 2 else 5
57
+ summary = sys.argv[3].lower() == "true" if len(sys.argv) > 3 else True
58
+ freshness = sys.argv[4] if len(sys.argv) > 4 else "noLimit"
59
+
60
+ result = search(query, count, summary, freshness)
61
+ print(json.dumps(result, indent=2))