refactor: extract shared config and utilities for API servers#49
refactor: extract shared config and utilities for API servers#49himanshu748 wants to merge 2 commits intokubeflow:mainfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
This PR successfully extracts ~150 lines of duplicated code from the WebSocket server (server/app.py) and HTTPS API server (server-https/app.py) into a new shared module (shared/rag_core.py). The refactoring consolidates configuration constants, the system prompt, tool definitions, Milvus search logic, and tool execution helpers to ensure both server implementations remain synchronized.
Changes:
- Created
shared/rag_core.pymodule containing all shared RAG-related configuration, prompts, tools, and utility functions - Refactored
server/app.pyto import and use shared code instead of duplicating logic - Refactored
server-https/app.pyto import and use shared code instead of duplicating logic
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| shared/rag_core.py | New shared module containing configuration constants, system prompt, tool definitions, Milvus search function, tool execution logic, and utility functions (deduplicate_citations, build_chat_payload) |
| shared/init.py | Empty init file to make shared a Python package |
| server/app.py | Removed ~150 lines of duplicated code; now imports shared configuration and utilities from shared.rag_core; updated logging from print statements to logger; maintained WebSocket-specific logic |
| server-https/app.py | Removed ~150 lines of duplicated code; now imports shared configuration and utilities from shared.rag_core; updated logging from print statements to logger; maintained FastAPI-specific logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Add project root to path so shared module is importable | ||
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | ||
|
|
||
| from shared.rag_core import ( # noqa: E402 | ||
| KSERVE_URL, | ||
| MODEL, | ||
| MILVUS_HOST, | ||
| MILVUS_PORT, | ||
| MILVUS_COLLECTION, | ||
| PORT, | ||
| SYSTEM_PROMPT, | ||
| TOOLS, | ||
| execute_tool, | ||
| deduplicate_citations, | ||
| build_chat_payload, | ||
| ) | ||
|
|
There was a problem hiding this comment.
The sys.path manipulation to enable shared module imports works for development but will fail in Docker containers because the Dockerfiles (server/Dockerfile and server-https/Dockerfile) don't copy the shared/ directory. The Dockerfiles need to be updated to include COPY shared/ /app/shared/ before the application starts, otherwise the import will fail at runtime with a ModuleNotFoundError.
| # Add project root to path so shared module is importable | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from shared.rag_core import ( # noqa: E402 | |
| KSERVE_URL, | |
| MODEL, | |
| MILVUS_HOST, | |
| MILVUS_PORT, | |
| MILVUS_COLLECTION, | |
| PORT, | |
| SYSTEM_PROMPT, | |
| TOOLS, | |
| execute_tool, | |
| deduplicate_citations, | |
| build_chat_payload, | |
| ) | |
| # Import shared module, supporting both installed-package and repo layouts | |
| try: | |
| from shared.rag_core import ( # noqa: E402 | |
| KSERVE_URL, | |
| MODEL, | |
| MILVUS_HOST, | |
| MILVUS_PORT, | |
| MILVUS_COLLECTION, | |
| PORT, | |
| SYSTEM_PROMPT, | |
| TOOLS, | |
| execute_tool, | |
| deduplicate_citations, | |
| build_chat_payload, | |
| ) | |
| except ModuleNotFoundError as original_exc: | |
| # Fallback for development: add project root so ../shared is importable | |
| project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | |
| if project_root not in sys.path: | |
| sys.path.insert(0, project_root) | |
| try: | |
| from shared.rag_core import ( # noqa: E402 | |
| KSERVE_URL, | |
| MODEL, | |
| MILVUS_HOST, | |
| MILVUS_PORT, | |
| MILVUS_COLLECTION, | |
| PORT, | |
| SYSTEM_PROMPT, | |
| TOOLS, | |
| execute_tool, | |
| deduplicate_citations, | |
| build_chat_payload, | |
| ) | |
| except ModuleNotFoundError: | |
| raise ModuleNotFoundError( | |
| "Could not import 'shared.rag_core'. Ensure the 'shared/' directory " | |
| "is available on PYTHONPATH or copied into the runtime environment " | |
| "(for Docker, include 'COPY shared/ /app/shared/')." | |
| ) from original_exc |
| # Add project root to path so shared module is importable | ||
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) |
There was a problem hiding this comment.
The sys.path manipulation to enable shared module imports works for development but will fail in Docker containers because the Dockerfiles (server/Dockerfile and server-https/Dockerfile) don't copy the shared/ directory. The Dockerfiles need to be updated to include COPY shared/ /app/shared/ before the application starts, otherwise the import will fail at runtime with a ModuleNotFoundError.
server/app.py
Outdated
| if citations_collector is None: | ||
| citations_collector = [] | ||
| try: | ||
| import httpx |
There was a problem hiding this comment.
The httpx import is moved inside the function rather than at the module level. While this works, it's inconsistent with the pattern used in server-https/app.py where httpx is imported at the top. For consistency and conventional Python practices, httpx should be imported at the module level alongside other imports.
|
|
||
| def deduplicate_citations(citations: List[str]) -> List[str]: | ||
| """Remove duplicate citations while preserving order.""" | ||
| seen: set[str] = set() |
There was a problem hiding this comment.
The modern Python 3.9+ syntax set[str] is used here, but this is incompatible with Python 3.8 and earlier. Since the Dockerfiles specify Python 3.11, this is fine. However, for better compatibility with the typing imports already used in the file (e.g., List[str] from typing module), consider using Set[str] from the typing module for consistency with the rest of the type hints in this file.
| encoder = SentenceTransformer(EMBEDDING_MODEL) | ||
| query_vec = encoder.encode(query).tolist() |
There was a problem hiding this comment.
The SentenceTransformer model is instantiated on every search call. This is inefficient as it will reload the model from disk or cache each time. Consider moving the model initialization to module-level or using a singleton pattern to reuse the same model instance across multiple searches. This will significantly improve performance and reduce memory overhead.
| SYSTEM_PROMPT, | ||
| TOOLS, |
There was a problem hiding this comment.
The imported SYSTEM_PROMPT and TOOLS constants are not directly used in this file - they are only used indirectly through build_chat_payload() from the shared module. Consider removing these from the import list to keep the imports clean and avoid confusion about what is actually used in this module.
| SYSTEM_PROMPT, | |
| TOOLS, |
|
Feedback addressed: Included the 'shared/' module in Docker builds (server and server-https), optimized imports in rag_core.py and app.py, and added beautifulsoup4 to requirements.txt. |
|
Hello @himanshu748 the duplication was done inorder to ensure appropriate deployment and ease of switching in between sockets and http. However the notion behind this PR is good but the merge might take a while. Also this code would be deprecated in future |
a98cc9b to
b581b57
Compare
himanshu748
left a comment
There was a problem hiding this comment.
DCO failing check fixed by signing off on the commits. The branch has also been rebased against main. I understand the merge might take a while and the code might be deprecated later. Thanks for the context!
19b160f to
56d04dc
Compare
Extracts duplicated configuration, system prompts, Milvus search logic, and tool execution code from `server/app.py` and `server-https/app.py` into a new `shared/rag_core.py` module. Helps reduce code duplication and eases maintainability for future tool-calling expansions in the docs agent. Signed-off-by: himanshu748 <jhahimanshu653@gmail.com>
Signed-off-by: himanshu748 <jhahimanshu653@gmail.com>
56d04dc to
003bca2
Compare
Description
This PR extracts massive code duplication (~150 lines) shared between the WebSocket server (
server/app.py) and the HTTPS API server (server-https/app.py).The duplicated configuration constants, system prompt, tool definitions, Milvus search logic, and tool execution helpers have been moved into a new
shared/rag_core.pymodule.This reduces boilerplate and ensures that both the WebSocket and HTTPS interfaces of the docs-agent remain in sync if we update the RAG system prompt or add new tools.
Testing
python3 -m py_compile)