diff --git a/backend/app/backend_err_ascii.txt b/backend/app/backend_err_ascii.txt new file mode 100644 index 0000000..bf8d472 --- /dev/null +++ b/backend/app/backend_err_ascii.txt @@ -0,0 +1,159 @@ +..\venv\Scripts\python.exe : +Traceback (most recent call last): +At line:1 char:1 ++ ..\venv\Scripts\python.exe -m +uvicorn app.main:app 2>&1 | +Out-File -E ... ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~ + + CategoryInfo : Not + Specified: (Traceback (most r + ecent call last)::String) [], + RemoteException + + FullyQualifiedErrorId : Nat + iveCommandError + + File "", line +198, in _run_module_as_main + File "", line 88, +in _run_code + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\__main__.py", line +4, in + uvicorn.main() + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\click\core.py", line 1442, +in __call__ + return self.main(*args, +**kwargs) + +^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\click\core.py", line 1363, +in main + rv = self.invoke(ctx) + ^^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\click\core.py", line 1226, +in invoke + return +ctx.invoke(self.callback, +**ctx.params) + ^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\click\core.py", line 794, in +invoke + return callback(*args, +**kwargs) + +^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\main.py", line 413, +in main + run( + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\main.py", line 580, +in run + server.run() + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\server.py", line 66, +in run + return asyncio.run(self.serve( +sockets=sockets)) + ^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ + File "C:\Program Files\WindowsAp +ps\PythonSoftwareFoundation.Python +.3.12_3.12.2800.0_x64__qbz5n2kfra8 +p0\Lib\asyncio\runners.py", line +195, in run + return runner.run(main) + ^^^^^^^^^^^^^^^^ + File "C:\Program Files\WindowsAp +ps\PythonSoftwareFoundation.Python +.3.12_3.12.2800.0_x64__qbz5n2kfra8 +p0\Lib\asyncio\runners.py", line +118, in run + return self._loop.run_until_co +mplete(task) + ^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^ + File "C:\Program Files\WindowsAp +ps\PythonSoftwareFoundation.Python +.3.12_3.12.2800.0_x64__qbz5n2kfra8 +p0\Lib\asyncio\base_events.py", +line 691, in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\server.py", line 70, +in serve + await self._serve(sockets) + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\server.py", line 77, +in _serve + config.load() + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\config.py", line +435, in load + self.loaded_app = +import_from_string(self.app) + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\importer.py", line +22, in import_from_string + raise exc from None + File "C:\Users\nairv\project-4\V +Cell-AI\backend\venv\Lib\site-pack +ages\uvicorn\importer.py", line +19, in import_from_string + module = importlib.import_modu +le(module_str) + ^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^ + File "C:\Program Files\WindowsAp +ps\PythonSoftwareFoundation.Python +.3.12_3.12.2800.0_x64__qbz5n2kfra8 +p0\Lib\importlib\__init__.py", +line 90, in import_module + return _bootstrap._gcd_import( +name[level:], package, level) + ^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line +1387, in _gcd_import + File "", line +1360, in _find_and_load + File "", line +1310, in _find_and_load_unlocked + File "", line 488, +in _call_with_frames_removed + File "", line +1387, in _gcd_import + File "", line +1360, in _find_and_load + File "", line +1324, in _find_and_load_unlocked +ModuleNotFoundError: No module +named 'app' diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 7a9df5b..59fc0a7 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -1,7 +1,8 @@ -from pydantic_settings import BaseSettings +from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): + model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") # Frontend Config FRONTEND_URL: str @@ -24,4 +25,5 @@ class Settings(BaseSettings): LANGFUSE_PUBLIC_KEY: str LANGFUSE_HOST: str + settings = Settings() diff --git a/backend/app/core/singleton.py b/backend/app/core/singleton.py index ce59fc3..f4f1ab2 100644 --- a/backend/app/core/singleton.py +++ b/backend/app/core/singleton.py @@ -22,7 +22,7 @@ def connect_openai(): api_key=settings.AZURE_API_KEY, base_url=settings.AZURE_ENDPOINT, project=None, - organization=None + organization=None, ) return openai_client diff --git a/backend/app/main.py b/backend/app/main.py index f48d10b..c3010db 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -25,8 +25,10 @@ app = FastAPI() -logger.info(f"Starting App : \n {ascii_art}") -logger.info("App Ready") +# Improved startup log formatting: Adding separating lines and clear status messages makes the startup sequence significantly easier to read and distinguish from other log noise in the terminal. +logger.info( + f"Starting App : \n {ascii_art}\n=======\n>>> App Initialization Complete - Ready to accept connections <<<\n=======" +) @app.on_event("startup") diff --git a/backend/app/services/vcelldb_service.py b/backend/app/services/vcelldb_service.py index 8382024..de7848f 100644 --- a/backend/app/services/vcelldb_service.py +++ b/backend/app/services/vcelldb_service.py @@ -15,10 +15,10 @@ def sanitize_vcml_content(vcml_content: str) -> str: """ Sanitizes VCML content by removing only ImageData tags and their content. - + Args: vcml_content (str): Raw VCML content as string. - + Returns: str: Sanitized VCML content with ImageData tags removed. """ @@ -26,15 +26,15 @@ def sanitize_vcml_content(vcml_content: str) -> str: # This pattern matches ... including nested content # The pattern handles multiline content and preserves the rest of the XML structure sanitized_content = re.sub( - r']*>.*?', - '', + r"]*>.*?", + "", vcml_content, - flags=re.DOTALL | re.MULTILINE + flags=re.DOTALL | re.MULTILINE, ) - + # Clean up any extra whitespace that might be left after removing ImageData - sanitized_content = re.sub(r'\n\s*\n', '\n', sanitized_content) - + sanitized_content = re.sub(r"\n\s*\n", "\n", sanitized_content) + logger.info("VCML content sanitized: ImageData tags removed") return sanitized_content @@ -325,15 +325,15 @@ async def fetch_publications() -> List[dict]: List[dict]: A list of publication dictionaries with sanitized data. """ url = f"{VCELL_API_BASE_URL}/publication?submitLow=&submitHigh=&startRow=1&maxRows=1000&hasData=all&waiting=on&queued=on&dispatched=on&running=on" - + logger.info(f"Fetching publications from URL: {url}") - + try: async with httpx.AsyncClient() as client: response = await client.get(url) response.raise_for_status() publications = response.json() - + # Ensure we return a list of dictionaries if isinstance(publications, list): # Sanitize publications by removing unwanted fields @@ -342,33 +342,41 @@ async def fetch_publications() -> List[dict]: if isinstance(pub, dict): # Create a copy and remove unwanted fields sanitized_pub = pub.copy() - sanitized_pub.pop('wittid', None) - sanitized_pub.pop('date', None) - sanitized_pub.pop('url', None) - sanitized_pub.pop('pubKey', None) - sanitized_pub.pop('endnoteid', None) - + sanitized_pub.pop("wittid", None) + sanitized_pub.pop("date", None) + sanitized_pub.pop("url", None) + sanitized_pub.pop("pubKey", None) + sanitized_pub.pop("endnoteid", None) + # Clean up author arrays - remove empty strings and combine - authors = pub.get('authors', []) + authors = pub.get("authors", []) if authors: # Remove empty strings and separators, combine into single string - clean_authors = [a.strip() for a in authors if a.strip() and a.strip() not in ['&', ',']] - sanitized_pub['authors'] = ', '.join(clean_authors) - + clean_authors = [ + a.strip() + for a in authors + if a.strip() and a.strip() not in ["&", ","] + ] + sanitized_pub["authors"] = ", ".join(clean_authors) + sanitized_publications.append(sanitized_pub) else: # If not a dict, keep as is but log warning logger.warning(f"Publication is not a dictionary: {type(pub)}") sanitized_publications.append(pub) - - logger.info(f"Successfully fetched and sanitized {len(sanitized_publications)} publications") + + logger.info( + f"Successfully fetched and sanitized {len(sanitized_publications)} publications" + ) return sanitized_publications else: logger.warning(f"Unexpected response format: {type(publications)}") return [] - + except httpx.HTTPStatusError as e: - logger.error(f"HTTP error fetching publications: {e.response.status_code} - {e.response.text}") + logger.error( + f"HTTP error fetching publications: {e.response.status_code} - {e.response.text}" + ) raise e except httpx.RequestError as e: logger.error(f"Request error fetching publications: {str(e)}") @@ -376,4 +384,3 @@ async def fetch_publications() -> List[dict]: except Exception as e: logger.error(f"Unexpected error fetching publications: {str(e)}") raise e - diff --git a/frontend/.prettierrc b/frontend/.prettierrc similarity index 100% rename from frontend/.prettierrc rename to frontend/.prettierrc diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index ede5909..df17868 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -76,9 +76,10 @@ export default function LandingPage() {
+ {/* The indigo color creates a subtle contrast against the predominantly blue theme, drawing more attention to this primary action button while maintaining aesthetic coherence. */}