|
1 | 1 | import datetime |
2 | 2 |
|
3 | | -from app.core.deps import get_openai_provider, get_specter2_query_embedder |
4 | | -from app.schemas.search_dto import Paper, SearchResponse |
| 3 | +from sqlalchemy import desc |
| 4 | +from sqlalchemy.orm import Session |
| 5 | + |
| 6 | +from app.models.paper import Paper as PaperModel |
| 7 | +from app.schemas.search_dto import Paper as PaperSchema, SearchResponse |
| 8 | + |
| 9 | +# from app.core.deps import get_openai_provider, get_specter2_query_embedder |
5 | 10 |
|
6 | 11 |
|
7 | 12 | class SearchService: |
8 | 13 | """ |
9 | | - Service for managing search requests |
| 14 | + Service for managing search requests. |
| 15 | +
|
| 16 | + NOTE: |
| 17 | + ----- |
| 18 | + For now, we just return the 5 most recently fetched papers from the |
| 19 | + database (ordered by `fetched_at DESC`) to establish the connection |
| 20 | + between the API and the frontend. |
| 21 | +
|
| 22 | + To restore or extend the original behavior that uses OpenAI + SPECTER2 |
| 23 | + embeddings, uncomment and adapt the code in `search_papers` below. |
10 | 24 | """ |
11 | 25 |
|
12 | 26 | @staticmethod |
13 | | - def search_papers(query: str) -> SearchResponse: |
| 27 | + def search_papers(db: Session, query: str) -> SearchResponse: |
14 | 28 | """ |
15 | | - Returns a list of matching papers based on the query |
| 29 | + Return the 5 most recent papers from the database. |
| 30 | +
|
| 31 | + The `query` parameter is currently ignored; it's kept for future |
| 32 | + use when more advanced search logic is implemented. |
16 | 33 | """ |
17 | | - openai_provider = get_openai_provider() |
18 | | - keywords = openai_provider.extract_keywords(query) |
19 | | - |
20 | | - embedder = get_specter2_query_embedder() |
21 | | - embeddings = embedder.embed_batch(keywords) |
22 | | - |
23 | | - # Additionally embedd the original query -> could also be used for searching |
24 | | - embeddings.append(embedder.embed_one(query)) |
25 | | - |
26 | | - # Call search module to find matching papers in vector db |
27 | | - # Needs to be implemented in the future |
28 | | - |
29 | | - # Mock paper as we cannot implement search as of now |
30 | | - example_paper = Paper( |
31 | | - paper_id=1, |
32 | | - doi="some doi", |
33 | | - source="arXiv", |
34 | | - paper_type="conference paper", |
35 | | - title="Deep Reinforcement Learning for Multi-Agent Voting with Approval Preferences", |
36 | | - authors={"main": "Usain Bolt"}, |
37 | | - abstract="Very good paper about DRL and social choice.", |
38 | | - published_at=datetime.date.today(), |
39 | | - pdf_url="some url", |
40 | | - url="some url", |
41 | | - fetched_at=datetime.datetime.now(), |
| 34 | + |
| 35 | + # --- Original implementation (kept for easy reactivation) --- |
| 36 | + # openai_provider = get_openai_provider() |
| 37 | + # keywords = openai_provider.extract_keywords(query) |
| 38 | + # |
| 39 | + # embedder = get_specter2_query_embedder() |
| 40 | + # embeddings = embedder.embed_batch(keywords) |
| 41 | + # |
| 42 | + # # Additionally embed the original query -> could also be used for searching |
| 43 | + # embeddings.append(embedder.embed_one(query)) |
| 44 | + # |
| 45 | + # TODO: Use `embeddings` to perform a vector similarity search against |
| 46 | + # the `paper.embedding` column (pgvector) and return real results. |
| 47 | + |
| 48 | + # Simple placeholder: return the 5 most recently fetched papers |
| 49 | + papers_db = ( |
| 50 | + db.query(PaperModel) |
| 51 | + .order_by(desc(PaperModel.fetched_at)) |
| 52 | + .limit(10) # fetch a few more and filter below |
| 53 | + .all() |
42 | 54 | ) |
43 | 55 |
|
44 | | - return SearchResponse(papers=[example_paper]) |
| 56 | + # Manually map ORM objects to schema to handle slight type/field |
| 57 | + # differences (e.g. authors JSON shape, missing URLs, nullable DOIs). |
| 58 | + paper_schemas: list[PaperSchema] = [] |
| 59 | + for p in papers_db: |
| 60 | + # Only require a title; DOI and URLs may be missing or unreliable. |
| 61 | + if not p.title: |
| 62 | + continue |
| 63 | + |
| 64 | + authors_value = None |
| 65 | + if isinstance(p.authors, dict): |
| 66 | + authors_value = p.authors |
| 67 | + elif isinstance(p.authors, list): |
| 68 | + # Example format: [["Last", "First", "Middle"], ...] |
| 69 | + formatted = [] |
| 70 | + for item in p.authors: |
| 71 | + if isinstance(item, (list, tuple)) and item: |
| 72 | + last = item[0] or "" |
| 73 | + first = item[1] if len(item) > 1 else "" |
| 74 | + middle = item[2] if len(item) > 2 else "" |
| 75 | + name = " ".join(part for part in [first, middle, last] if part) |
| 76 | + if name: |
| 77 | + formatted.append(name) |
| 78 | + if formatted: |
| 79 | + authors_value = {str(idx): name for idx, name in enumerate(formatted)} |
| 80 | + |
| 81 | + paper_schemas.append( |
| 82 | + PaperSchema( |
| 83 | + paper_id=p.paper_id, |
| 84 | + doi=p.doi, |
| 85 | + source=str(getattr(p.source, "value", p.source)), |
| 86 | + paper_type=str(getattr(p.paper_type, "value", p.paper_type)), |
| 87 | + title=p.title, |
| 88 | + authors=authors_value, |
| 89 | + abstract=p.abstract, |
| 90 | + published_at=p.published_at, |
| 91 | + pdf_url=None, |
| 92 | + url=None, |
| 93 | + fetched_at=p.fetched_at, |
| 94 | + ) |
| 95 | + ) |
| 96 | + |
| 97 | + if len(paper_schemas) >= 5: |
| 98 | + break |
| 99 | + |
| 100 | + return SearchResponse(papers=paper_schemas) |
0 commit comments