Husnain Rasheed commited on
Commit
320e06e
·
verified ·
1 Parent(s): 529d4ca

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +53 -32
main.py CHANGED
@@ -1,63 +1,84 @@
1
  import httpx
2
  import json
3
  from fastapi import FastAPI, HTTPException, Query
4
- from typing import Optional
 
5
 
6
  # Initialize the FastAPI app
7
  app = FastAPI(
8
- title="FastAPI DuckDuckGo API Proxy",
9
- description="A FastAPI proxy for the DuckDuckGo Instant Answer API.",
10
- version="1.0.0",
11
  )
12
 
13
- # Define the base URL for the DuckDuckGo Instant Answer API (for JSON results)
 
 
 
 
 
 
 
 
 
 
14
  DUCKDUCKGO_API_URL = "https://api.duckduckgo.com/"
15
 
16
- @app.get("/search", tags=["Search"])
 
 
 
17
  async def search_duckduckgo(
18
- q: str = Query(..., description="The search query."),
19
  ):
20
  """
21
- Performs a search using the DuckDuckGo Instant Answer API and returns the results in JSON format.
 
 
 
22
  """
23
  params = {
24
  "q": q,
25
- "format": "json", # Request JSON format
26
- "no_html": 1, # Disable HTML in the response
27
  }
28
 
29
  async with httpx.AsyncClient() as client:
30
  try:
31
  response = await client.get(DUCKDUCKGO_API_URL, params=params)
32
-
33
- # Raise an exception for bad status codes (4xx or 5xx)
34
  response.raise_for_status()
35
-
36
- # The API returns an empty string for no results, which is not valid JSON.
37
- # Handle this case explicitly.
38
  if not response.text:
39
- return {"results": [], "message": "No results found."}
40
 
41
- # Attempt to parse the JSON response
42
- return response.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  except json.JSONDecodeError:
45
- # If the response is not valid JSON, raise an internal server error
46
- raise HTTPException(
47
- status_code=500,
48
- detail=f"Failed to decode JSON from DuckDuckGo API. Response text: {response.text}",
49
- )
50
  except httpx.HTTPStatusError as e:
51
- raise HTTPException(
52
- status_code=e.response.status_code,
53
- detail=f"Error from DuckDuckGo API: {e.response.text}",
54
- )
55
  except httpx.RequestError as e:
56
- raise HTTPException(
57
- status_code=500,
58
- detail=f"Failed to connect to DuckDuckGo API: {str(e)}",
59
- )
60
 
61
  @app.get("/", tags=["Root"])
62
  async def read_root():
63
- return {"message": "Welcome to the DuckDuckGo API proxy!"}
 
1
  import httpx
2
  import json
3
  from fastapi import FastAPI, HTTPException, Query
4
+ from pydantic import BaseModel, Field
5
+ from typing import Optional, List, Dict, Any
6
 
7
  # Initialize the FastAPI app
8
  app = FastAPI(
9
+ title="FastAPI DuckDuckGo Instant Answer API Proxy",
10
+ description="A proxy for the DuckDuckGo Instant Answer API. This API provides direct answers and summaries, but not a list of general web search results.",
11
+ version="1.1.0",
12
  )
13
 
14
+ # Define Pydantic models for a cleaner response structure
15
+ class SearchResult(BaseModel):
16
+ heading: Optional[str] = Field(None, description="The title of the answer.")
17
+ answer: Optional[str] = Field(None, description="A direct answer to the query.")
18
+ abstract: Optional[str] = Field(None, description="A summary or abstract of the topic.")
19
+ abstract_url: Optional[str] = Field(None, description="The URL for the abstract source.")
20
+ image_url: Optional[str] = Field(None, description="A relevant image URL.")
21
+ related_topics: List[Dict[str, Any]] = Field([], description="A list of related topics.")
22
+ raw_response: Dict[str, Any] = Field({}, description="The full, raw JSON response from the API.")
23
+
24
+ # Define the base URL for the DuckDuckGo Instant Answer API
25
  DUCKDUCKGO_API_URL = "https://api.duckduckgo.com/"
26
 
27
+ @app.get("/search",
28
+ tags=["Search"],
29
+ response_model=SearchResult,
30
+ summary="Get an Instant Answer from DuckDuckGo")
31
  async def search_duckduckgo(
32
+ q: str = Query(..., description="The search query. Try 'what is the capital of France' or 'Google' to see results."),
33
  ):
34
  """
35
+ Performs a search using the DuckDuckGo Instant Answer API.
36
+
37
+ This endpoint returns structured information for queries that have a direct answer.
38
+ It will return an empty response for general web search queries that do not trigger an Instant Answer.
39
  """
40
  params = {
41
  "q": q,
42
+ "format": "json",
43
+ "no_html": 1,
44
  }
45
 
46
  async with httpx.AsyncClient() as client:
47
  try:
48
  response = await client.get(DUCKDUCKGO_API_URL, params=params)
 
 
49
  response.raise_for_status()
50
+
 
 
51
  if not response.text:
52
+ return SearchResult(raw_response={"message": "No results found."})
53
 
54
+ data = response.json()
55
+
56
+ # Check if a meaningful answer is present.
57
+ # The 'Type' field is 'A' for Article, 'D' for Disambiguation, 'C' for category. Empty for no result.
58
+ if data.get("Type") or data.get("AbstractText"):
59
+ return SearchResult(
60
+ heading=data.get("Heading"),
61
+ answer=data.get("Answer"),
62
+ abstract=data.get("AbstractText"),
63
+ abstract_url=data.get("AbstractURL"),
64
+ image_url=f'https://duckduckgo.com{data.get("Image")}' if data.get("Image") else None,
65
+ related_topics=data.get("RelatedTopics", []),
66
+ raw_response=data
67
+ )
68
+ else:
69
+ # Return an empty but valid SearchResult if no instant answer was found
70
+ return SearchResult(
71
+ raw_response=data,
72
+ related_topics=[{"message": "No direct Instant Answer found for this query."}]
73
+ )
74
 
75
  except json.JSONDecodeError:
76
+ raise HTTPException(status_code=500, detail="Failed to decode JSON from DuckDuckGo API.")
 
 
 
 
77
  except httpx.HTTPStatusError as e:
78
+ raise HTTPException(status_code=e.response.status_code, detail=f"Error from DuckDuckGo API: {e.response.text}")
 
 
 
79
  except httpx.RequestError as e:
80
+ raise HTTPException(status_code=500, detail=f"Failed to connect to DuckDuckGo API: {str(e)}")
 
 
 
81
 
82
  @app.get("/", tags=["Root"])
83
  async def read_root():
84
+ return {"message": "Welcome to the DuckDuckGo Instant Answer API proxy!"}