PhyllisPeh commited on
Commit
259b34f
·
1 Parent(s): ef730bf

Add application file

Browse files
Files changed (5) hide show
  1. Dockerfile +25 -0
  2. README.md +1 -1
  3. app.py +61 -0
  4. requirements.txt +7 -0
  5. templates/index.html +107 -0
Dockerfile ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ WORKDIR /code
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ build-essential \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Create necessary directories
11
+ RUN mkdir -p /code/templates
12
+
13
+ # Copy requirements first to leverage Docker cache
14
+ COPY ./requirements.txt /code/requirements.txt
15
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
16
+
17
+ # Copy application code
18
+ COPY ./app.py /code/app.py
19
+ COPY ./templates/* /code/templates/
20
+
21
+ # Make port 7860 available to the world outside this container
22
+ EXPOSE 7860
23
+
24
+ # Run gunicorn
25
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app", "--timeout", "300"]
README.md CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
  title: PatentExplorerApp
3
- emoji: 🌖
4
  colorFrom: blue
5
  colorTo: gray
6
  sdk: docker
 
1
  ---
2
  title: PatentExplorerApp
3
+ emoji: 💡
4
  colorFrom: blue
5
  colorTo: gray
6
  sdk: docker
app.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify
2
+ from serpapi import GoogleSearch
3
+ from datetime import datetime
4
+
5
+ app = Flask(__name__)
6
+
7
+ def search_patents(keywords, num_results=15):
8
+ """
9
+ Search patents using SerpAPI Google Patents
10
+ """
11
+ api_key = "1c3072feed5fcd1cdc029bbb7f27a87c7e7aac5710cf05dcd5960dfeebeb8fec"
12
+ search_params = {
13
+ "engine": "google_patents",
14
+ "q": keywords,
15
+ "api_key": api_key,
16
+ "num": num_results
17
+ }
18
+
19
+ try:
20
+ search = GoogleSearch(search_params)
21
+ patents = search.get_dict().get("organic_results", [])
22
+
23
+ formatted_patents = []
24
+ for patent in patents:
25
+ # Format filing date
26
+ date_str = patent.get('filing_date', '')
27
+ filing_year = 'N/A'
28
+ if date_str:
29
+ try:
30
+ filing_year = datetime.strptime(date_str, '%Y-%m-%d').year
31
+ except ValueError:
32
+ pass
33
+
34
+ formatted_patent = {
35
+ 'title': patent.get('title', 'N/A'),
36
+ 'assignee': patent.get('assignee', 'N/A'),
37
+ 'filing_year': filing_year,
38
+ 'abstract': patent.get('snippet', 'N/A'),
39
+ 'link': patent.get('patent_link', '#')
40
+ }
41
+ formatted_patents.append(formatted_patent)
42
+
43
+ return formatted_patents
44
+ except Exception as e:
45
+ return []
46
+
47
+ @app.route('/')
48
+ def home():
49
+ return render_template('index.html')
50
+
51
+ @app.route('/search', methods=['POST'])
52
+ def search():
53
+ keywords = request.form.get('keywords', '')
54
+ if not keywords:
55
+ return jsonify({'error': 'Please enter search keywords'})
56
+
57
+ patents = search_patents(keywords)
58
+ return jsonify({'patents': patents})
59
+
60
+ if __name__ == '__main__':
61
+ app.run(host='0.0.0.0', port=7860)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ flask==2.0.1
2
+ Werkzeug==2.0.3
3
+ google-search-results==2.4.2
4
+ gunicorn==20.1.0
5
+ itsdangerous==2.0.1
6
+ Jinja2==3.0.1
7
+ MarkupSafe==2.0.1
templates/index.html ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Patent Explorer</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
8
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
9
+ </head>
10
+ <body class="bg-gray-100 min-h-screen">
11
+ <div class="container mx-auto px-4 py-8">
12
+ <h1 class="text-4xl font-bold text-center text-blue-600 mb-8">Patent Explorer</h1>
13
+
14
+ <!-- Search Form -->
15
+ <div class="max-w-2xl mx-auto mb-8">
16
+ <form id="searchForm" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
17
+ <div class="mb-4">
18
+ <input type="text" id="keywords" name="keywords"
19
+ class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
20
+ placeholder="Enter keywords to search patents...">
21
+ </div>
22
+ <div class="flex items-center justify-center">
23
+ <button type="submit"
24
+ class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
25
+ Search Patents
26
+ </button>
27
+ </div>
28
+ </form>
29
+ </div>
30
+
31
+ <!-- Loading Spinner -->
32
+ <div id="loading" class="hidden">
33
+ <div class="flex justify-center items-center">
34
+ <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
35
+ </div>
36
+ </div>
37
+
38
+ <!-- Results Container -->
39
+ <div id="results" class="max-w-4xl mx-auto"></div>
40
+ </div>
41
+
42
+ <script>
43
+ $(document).ready(function() {
44
+ $('#searchForm').on('submit', function(e) {
45
+ e.preventDefault();
46
+ const keywords = $('#keywords').val();
47
+
48
+ if (!keywords) {
49
+ alert('Please enter search keywords');
50
+ return;
51
+ }
52
+
53
+ // Show loading spinner
54
+ $('#loading').removeClass('hidden');
55
+ $('#results').empty();
56
+
57
+ $.ajax({
58
+ url: '/search',
59
+ method: 'POST',
60
+ data: { keywords: keywords },
61
+ success: function(response) {
62
+ $('#loading').addClass('hidden');
63
+
64
+ if (response.error) {
65
+ $('#results').html(`<div class="text-red-500 text-center">${response.error}</div>`);
66
+ return;
67
+ }
68
+
69
+ if (!response.patents.length) {
70
+ $('#results').html('<div class="text-center text-gray-600">No patents found.</div>');
71
+ return;
72
+ }
73
+
74
+ const resultsHtml = response.patents.map((patent, index) => `
75
+ <div class="bg-white shadow-md rounded-lg p-6 mb-4">
76
+ <h2 class="text-xl font-bold text-blue-600 mb-2">
77
+ <a href="${patent.link}" target="_blank" class="hover:underline">
78
+ ${patent.title}
79
+ </a>
80
+ </h2>
81
+ <div class="grid grid-cols-2 gap-4 mb-4 text-sm">
82
+ <div>
83
+ <span class="font-semibold">Assignee:</span> ${patent.assignee}
84
+ </div>
85
+ <div>
86
+ <span class="font-semibold">Filing Year:</span> ${patent.filing_year}
87
+ </div>
88
+ </div>
89
+ <div class="text-gray-600">
90
+ <span class="font-semibold">Abstract:</span><br>
91
+ ${patent.abstract}
92
+ </div>
93
+ </div>
94
+ `).join('');
95
+
96
+ $('#results').html(resultsHtml);
97
+ },
98
+ error: function() {
99
+ $('#loading').addClass('hidden');
100
+ $('#results').html('<div class="text-red-500 text-center">An error occurred while searching patents.</div>');
101
+ }
102
+ });
103
+ });
104
+ });
105
+ </script>
106
+ </body>
107
+ </html>