Skip to content

Commit 72aa1b4

Browse files
committed
add basic (test only) openai integration
1 parent 87fc976 commit 72aa1b4

14 files changed

Lines changed: 115 additions & 4 deletions

File tree

backend/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ DATABASE_URL=postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTG
1111
# Authentication
1212
JWT_SECRET_KEY=3e3cc0b2f8b54b3d6aa597faccb2f9c41b19b1c24befe29661bafbd42e3afe3e
1313

14+
# OpenAI
15+
OPENAI_API_KEY=my_secret_key

backend/app/core/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class Settings(BaseSettings):
2424
ACCESS_TOKEN_EXPIRE_MINUTES: int = 15
2525
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
2626

27+
# --- OpenAI ---
28+
OPENAI_API_KEY: str
29+
2730
model_config = SettingsConfigDict(
2831
env_file=os.getenv("ENV_FILE", "dev.env"),
2932
extra="ignore",

backend/app/core/deps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from app.llm.openai.provider import OpenAIProvider
2+
3+
_openai_provider = None
4+
5+
def get_openai_provider() -> OpenAIProvider:
6+
global _openai_provider
7+
if _openai_provider is None:
8+
_openai_provider = OpenAIProvider()
9+
return _openai_provider

backend/app/llm/__init__.py

Whitespace-only changes.

backend/app/llm/openai/__init__.py

Whitespace-only changes.

backend/app/llm/openai/prompts.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
KEYWORD_PROMPT="""
2+
You are an expert in academic information retrieval. Extract 7–15 single-word academic keywords suitable for searching scientific databases (arXiv, IEEE, ACL).
3+
4+
Rules:
5+
6+
- Single words only.
7+
- Academic, domain-specific terms only (tasks, algorithms, architectures, datasets, phenomena).
8+
- Exclude broad or high-frequency terms (e.g., learning, inference, neural, optimization, classification, system, model, method).
9+
- No generic research words (e.g., study, analysis, results, approach).
10+
- No overlapping or substring-related keywords.
11+
- Each keyword must significantly narrow the search space — prefer specific technical terminology used mainly within a subfield.
12+
13+
Output only a JSON list: ["keyword1", ...].
14+
"""

backend/app/llm/openai/provider.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from openai import OpenAI
2+
3+
from app.core.config import settings
4+
from app.llm.openai.prompts import KEYWORD_PROMPT
5+
6+
7+
class OpenAIProvider:
8+
"""Wrapper around the OpenAI client."""
9+
10+
_model: str
11+
12+
def __init__(self) -> None:
13+
self.client = OpenAI(api_key=settings.OPENAI_API_KEY)
14+
self._model = "gpt-5-nano-2025-08-07"
15+
16+
def extract_keywords(self, user_text: str) -> str:
17+
response = self.client.responses.create(
18+
model=self._model,
19+
reasoning={"effort": "low"},
20+
input=[
21+
{
22+
"role": "developer",
23+
"content": KEYWORD_PROMPT,
24+
},
25+
{
26+
"role": "user",
27+
"content": user_text,
28+
},
29+
],
30+
)
31+
return response.output_text

backend/app/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from app.core.config import settings
99
from app.core.database import init_db
10-
from app.routes import auth_routes, user_routes
10+
from app.routes import auth_routes, user_routes, search_routes
1111

1212
# ---------------------------------------------------------
1313
# Configure Logging
@@ -68,3 +68,4 @@ async def lifespan(_app: FastAPI) -> AsyncGenerator[None, Any]:
6868
# ---------------------------------------------------------
6969
app.include_router(user_routes.router)
7070
app.include_router(auth_routes.router)
71+
app.include_router(search_routes.router)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from fastapi import APIRouter, status, Depends
2+
3+
from app.core.deps import get_openai_provider
4+
from app.llm.openai.provider import OpenAIProvider
5+
from app.schemas.search_dto import SearchRequest
6+
7+
router = APIRouter(prefix="/search", tags=["Search"])
8+
9+
# TODO remove - testing purposes only
10+
@router.post("/", response_model=str, status_code=status.HTTP_200_OK, summary="Authenticate a user and return JWT tokens")
11+
def search(search_request: SearchRequest, provider: OpenAIProvider = Depends(get_openai_provider)) -> str:
12+
return provider.extract_keywords(search_request.search_text)
13+

backend/app/schemas/search_dto.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from pydantic import BaseModel
2+
3+
4+
class SearchRequest(BaseModel):
5+
search_text: str

0 commit comments

Comments
 (0)