be52af70
tangwang
first commit
|
1
2
3
4
|
"""
Search API routes.
"""
|
16c42787
tangwang
feat: implement r...
|
5
|
from fastapi import APIRouter, HTTPException, Query, Request
|
be52af70
tangwang
first commit
|
6
|
from typing import Optional
|
16c42787
tangwang
feat: implement r...
|
7
|
import uuid
|
be52af70
tangwang
first commit
|
8
9
10
11
12
13
14
15
|
from ..models import (
SearchRequest,
ImageSearchRequest,
SearchResponse,
DocumentResponse,
ErrorResponse
)
|
16c42787
tangwang
feat: implement r...
|
16
|
from context.request_context import create_request_context, set_current_request_context, clear_current_request_context
|
be52af70
tangwang
first commit
|
17
18
19
20
|
router = APIRouter(prefix="/search", tags=["search"])
|
16c42787
tangwang
feat: implement r...
|
21
22
23
24
25
26
27
28
29
30
31
|
def extract_request_info(request: Request) -> tuple[str, str]:
"""Extract request ID and user ID from HTTP request"""
# Try to get request ID from headers
reqid = request.headers.get('X-Request-ID') or str(uuid.uuid4())[:8]
# Try to get user ID from headers or default to anonymous
uid = request.headers.get('X-User-ID') or request.headers.get('User-ID') or 'anonymous'
return reqid, uid
|
be52af70
tangwang
first commit
|
32
|
@router.post("/", response_model=SearchResponse)
|
16c42787
tangwang
feat: implement r...
|
33
|
async def search(request: SearchRequest, http_request: Request):
|
be52af70
tangwang
first commit
|
34
35
36
37
38
39
40
41
42
43
|
"""
Execute text search query.
Supports:
- Multi-language query processing
- Boolean operators (AND, OR, RANK, ANDNOT)
- Semantic search with embeddings
- Custom ranking functions
- Filters and aggregations
"""
|
16c42787
tangwang
feat: implement r...
|
44
45
46
47
48
49
50
|
reqid, uid = extract_request_info(http_request)
# Create request context
context = create_request_context(reqid=reqid, uid=uid)
# Set context in thread-local storage
set_current_request_context(context)
|
be52af70
tangwang
first commit
|
51
52
|
try:
|
16c42787
tangwang
feat: implement r...
|
53
54
55
56
57
58
59
|
# Log request start
context.logger.info(
f"收到搜索请求 | IP: {http_request.client.host if http_request.client else 'unknown'} | "
f"用户代理: {http_request.headers.get('User-Agent', 'unknown')[:100]}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
60
|
# Get searcher from app state
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
61
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
62
63
|
searcher = get_searcher()
|
16c42787
tangwang
feat: implement r...
|
64
|
# Execute search with context (using backend defaults from config)
|
be52af70
tangwang
first commit
|
65
66
67
68
69
|
result = searcher.search(
query=request.query,
size=request.size,
from_=request.from_,
filters=request.filters,
|
16c42787
tangwang
feat: implement r...
|
70
71
|
min_score=request.min_score,
context=context
|
be52af70
tangwang
first commit
|
72
73
|
)
|
16c42787
tangwang
feat: implement r...
|
74
75
76
|
# Include performance summary in response
performance_summary = context.get_summary() if context else None
|
be52af70
tangwang
first commit
|
77
78
79
80
81
82
83
|
# Convert to response model
return SearchResponse(
hits=result.hits,
total=result.total,
max_score=result.max_score,
took_ms=result.took_ms,
aggregations=result.aggregations,
|
16c42787
tangwang
feat: implement r...
|
84
85
|
query_info=result.query_info,
performance_info=performance_summary
|
be52af70
tangwang
first commit
|
86
87
88
|
)
except Exception as e:
|
16c42787
tangwang
feat: implement r...
|
89
90
91
92
93
94
95
|
# Log error in context
if context:
context.set_error(e)
context.logger.error(
f"搜索请求失败 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
96
|
raise HTTPException(status_code=500, detail=str(e))
|
16c42787
tangwang
feat: implement r...
|
97
98
99
|
finally:
# Clear thread-local context
clear_current_request_context()
|
be52af70
tangwang
first commit
|
100
101
102
|
@router.post("/image", response_model=SearchResponse)
|
16c42787
tangwang
feat: implement r...
|
103
|
async def search_by_image(request: ImageSearchRequest, http_request: Request):
|
be52af70
tangwang
first commit
|
104
105
106
107
108
|
"""
Search by image similarity.
Uses image embeddings to find visually similar products.
"""
|
16c42787
tangwang
feat: implement r...
|
109
110
111
112
113
114
115
116
|
reqid, uid = extract_request_info(http_request)
# Create request context
context = create_request_context(reqid=reqid, uid=uid)
# Set context in thread-local storage
set_current_request_context(context)
|
be52af70
tangwang
first commit
|
117
|
try:
|
16c42787
tangwang
feat: implement r...
|
118
119
120
121
122
123
124
|
# Log request start
context.logger.info(
f"收到图片搜索请求 | 图片URL: {request.image_url} | "
f"IP: {http_request.client.host if http_request.client else 'unknown'}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
125
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
126
127
128
129
130
131
132
133
134
|
searcher = get_searcher()
# Execute image search
result = searcher.search_by_image(
image_url=request.image_url,
size=request.size,
filters=request.filters
)
|
16c42787
tangwang
feat: implement r...
|
135
136
137
|
# Include performance summary in response
performance_summary = context.get_summary() if context else None
|
be52af70
tangwang
first commit
|
138
139
140
141
142
143
|
return SearchResponse(
hits=result.hits,
total=result.total,
max_score=result.max_score,
took_ms=result.took_ms,
aggregations=result.aggregations,
|
16c42787
tangwang
feat: implement r...
|
144
145
|
query_info=result.query_info,
performance_info=performance_summary
|
be52af70
tangwang
first commit
|
146
147
148
|
)
except ValueError as e:
|
16c42787
tangwang
feat: implement r...
|
149
150
151
152
153
154
|
if context:
context.set_error(e)
context.logger.error(
f"图片搜索请求参数错误 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
155
156
|
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
|
16c42787
tangwang
feat: implement r...
|
157
158
159
160
161
162
|
if context:
context.set_error(e)
context.logger.error(
f"图片搜索请求失败 | 错误: {str(e)}",
extra={'reqid': context.reqid, 'uid': context.uid}
)
|
be52af70
tangwang
first commit
|
163
|
raise HTTPException(status_code=500, detail=str(e))
|
16c42787
tangwang
feat: implement r...
|
164
165
166
|
finally:
# Clear thread-local context
clear_current_request_context()
|
be52af70
tangwang
first commit
|
167
168
169
170
171
172
173
174
|
@router.get("/{doc_id}", response_model=DocumentResponse)
async def get_document(doc_id: str):
"""
Get a single document by ID.
"""
try:
|
bb3c5ef8
tangwang
灌入数据流程跑通
|
175
|
from api.app import get_searcher
|
be52af70
tangwang
first commit
|
176
177
178
179
180
181
182
183
184
185
186
187
188
|
searcher = get_searcher()
doc = searcher.get_document(doc_id)
if doc is None:
raise HTTPException(status_code=404, detail=f"Document {doc_id} not found")
return DocumentResponse(id=doc_id, source=doc)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
|