forked from 0xWheatyz/SPARC
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4696838fb8 |
@@ -34,6 +34,17 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ruff check SPARC/ tests/
|
ruff check SPARC/ tests/
|
||||||
|
|
||||||
|
- name: Install Node.js and frontend dependencies
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
apk add --no-cache nodejs npm
|
||||||
|
cd frontend && npm ci
|
||||||
|
|
||||||
|
- name: Run TypeScript type check
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
cd frontend && npx tsc --noEmit
|
||||||
|
|
||||||
- name: Run pytest
|
- name: Run pytest
|
||||||
shell: sh
|
shell: sh
|
||||||
env:
|
env:
|
||||||
|
|||||||
+11
-21
@@ -108,10 +108,12 @@ class CompanyAnalyzer:
|
|||||||
def analyze_single_patent(self, patent_id: str, company_name: str) -> str:
|
def analyze_single_patent(self, patent_id: str, company_name: str) -> str:
|
||||||
"""Analyze a single patent by ID.
|
"""Analyze a single patent by ID.
|
||||||
|
|
||||||
If the patent PDF is not already on disk, this method attempts to
|
Prerequisite:
|
||||||
download it automatically by looking up the PDF link in the database
|
The patent PDF must already exist at ``patents/{patent_id}.pdf``
|
||||||
cache. If the link is not cached either, a ``FileNotFoundError`` is
|
before calling this method. PDFs are downloaded automatically when
|
||||||
raised with instructions on how to obtain the PDF.
|
using the batch analysis pipeline (``analyze_company`` or the
|
||||||
|
``/analyze/batch`` API endpoint). For standalone usage, download
|
||||||
|
the PDF manually or call ``SERP.save_patents()`` first.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
patent_id: Publication ID of the patent (e.g. "US-11234567-B2")
|
patent_id: Publication ID of the patent (e.g. "US-11234567-B2")
|
||||||
@@ -121,7 +123,7 @@ class CompanyAnalyzer:
|
|||||||
Analysis of the specific patent's innovation quality
|
Analysis of the specific patent's innovation quality
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FileNotFoundError: If the patent PDF cannot be found or downloaded.
|
FileNotFoundError: If the patent PDF is not found at the expected path.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
logger.info("Analyzing patent %s for %s...", patent_id, company_name)
|
logger.info("Analyzing patent %s for %s...", patent_id, company_name)
|
||||||
@@ -129,22 +131,10 @@ class CompanyAnalyzer:
|
|||||||
patent_path = f"patents/{patent_id}.pdf"
|
patent_path = f"patents/{patent_id}.pdf"
|
||||||
|
|
||||||
if not os.path.exists(patent_path):
|
if not os.path.exists(patent_path):
|
||||||
# Attempt to download the PDF automatically from cached metadata
|
raise FileNotFoundError(
|
||||||
cached = self.db.get_cached_patent(patent_id)
|
f"Patent PDF not found at '{patent_path}'. "
|
||||||
pdf_link = cached.get("pdf_link") if cached else None
|
f"Download the PDF first using SERP.save_patents() or the batch analysis pipeline."
|
||||||
|
)
|
||||||
if pdf_link:
|
|
||||||
logger.info("PDF not on disk; downloading %s from cached link", patent_id)
|
|
||||||
patent = SERP.save_patents(
|
|
||||||
Patent(patent_id=patent_id, pdf_link=pdf_link)
|
|
||||||
)
|
|
||||||
patent_path = patent.pdf_path
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError(
|
|
||||||
f"Patent PDF not found at '{patent_path}' and no download link is "
|
|
||||||
f"cached for '{patent_id}'. Run a company analysis first to populate "
|
|
||||||
f"the cache, or call SERP.save_patents() with the patent's PDF link."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sections = SERP.parse_patent_pdf(patent_path)
|
sections = SERP.parse_patent_pdf(patent_path)
|
||||||
|
|||||||
@@ -429,38 +429,6 @@ async def analyze_company(
|
|||||||
return _convert_result(result)
|
return _convert_result(result)
|
||||||
|
|
||||||
|
|
||||||
@app.get(
|
|
||||||
"/analyze/patent/{patent_id}",
|
|
||||||
tags=["Analysis"],
|
|
||||||
)
|
|
||||||
async def analyze_single_patent(
|
|
||||||
patent_id: str,
|
|
||||||
company_name: str = Query(description="Company name for analysis context"),
|
|
||||||
_: UserResponse = Depends(get_current_user),
|
|
||||||
):
|
|
||||||
"""Analyze a single patent by its publication ID.
|
|
||||||
|
|
||||||
If the patent PDF is not already cached locally, the system will attempt
|
|
||||||
to download it automatically from a previously cached link. If no link
|
|
||||||
is available, a 404 error is returned.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
patent_id: Patent publication ID (e.g. "US-11234567-B2")
|
|
||||||
company_name: Company name for analysis context
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Analysis text for the patent
|
|
||||||
"""
|
|
||||||
if not _analyzer:
|
|
||||||
raise HTTPException(status_code=503, detail="Analyzer not initialized")
|
|
||||||
|
|
||||||
try:
|
|
||||||
analysis = _analyzer.analyze_single_patent(patent_id, company_name)
|
|
||||||
return {"patent_id": patent_id, "company_name": company_name, "analysis": analysis}
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
raise HTTPException(status_code=404, detail=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@app.post(
|
@app.post(
|
||||||
"/analyze/batch",
|
"/analyze/batch",
|
||||||
response_model=BatchAnalysisResponse,
|
response_model=BatchAnalysisResponse,
|
||||||
|
|||||||
Generated
+4
-4
@@ -10,7 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-query": "^5.51.0",
|
"@tanstack/react-query": "^5.51.0",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"lucide-react": "^0.400.0",
|
"lucide-react": "^1.7.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
@@ -3452,9 +3452,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lucide-react": {
|
"node_modules/lucide-react": {
|
||||||
"version": "0.400.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.400.0.tgz",
|
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.7.0.tgz",
|
||||||
"integrity": "sha512-rpp7pFHh3Xd93KHixNgB0SqThMHpYNzsGUu69UaQbSZ75Q/J3m5t6EhKyMT3m4w2WOxmJ2mY0tD3vebnXqQryQ==",
|
"integrity": "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-query": "^5.51.0",
|
"@tanstack/react-query": "^5.51.0",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"lucide-react": "^0.400.0",
|
"lucide-react": "^1.7.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-router-dom": "^6.24.0",
|
"react-router-dom": "^6.24.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user