├── image.png ├── .gitattributes ├── requirements.txt ├── static ├── logo.jpeg ├── tumbnail.png ├── favicon_io │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ └── site.webmanifest ├── light-theme.css └── dark-theme.css ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE ├── app.py ├── README.md ├── CODE_OF_CONDUCT.md └── templates └── index.html /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/image.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/requirements.txt -------------------------------------------------------------------------------- /static/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/logo.jpeg -------------------------------------------------------------------------------- /static/tumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/tumbnail.png -------------------------------------------------------------------------------- /static/favicon_io/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/favicon.ico -------------------------------------------------------------------------------- /static/favicon_io/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon_io/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon_io/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/apple-touch-icon.png -------------------------------------------------------------------------------- /static/favicon_io/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/favicon_io/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oxlac/AI-News-Summariser/HEAD/static/favicon_io/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/favicon_io/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Aadityaa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, render_template, flash, redirect, url_for # Import flash 2 | import nltk 3 | from textblob import TextBlob 4 | from newspaper import Article 5 | from datetime import datetime 6 | from urllib.parse import urlparse 7 | import validators 8 | import requests 9 | 10 | nltk.download('punkt') 11 | 12 | app = Flask(__name__) 13 | 14 | def get_website_name(url): 15 | # Extract the website name from the URL 16 | parsed_url = urlparse(url) 17 | domain = parsed_url.netloc 18 | if domain.startswith("www."): 19 | domain = domain[4:] 20 | return domain 21 | 22 | @app.route('/', methods=['GET', 'POST']) 23 | def index(): 24 | if request.method == 'POST': 25 | url = request.form['url'] 26 | # Check if the input is a valid URL 27 | 28 | if not validators.url(url): 29 | flash('Please enter a valid URL.') 30 | return redirect(url_for('index')) 31 | 32 | try: 33 | response = requests.get(url) 34 | response.raise_for_status() # Raise an HTTPError if the HTTP request returned an unsuccessful status code 35 | except requests.RequestException: 36 | flash('Failed to download the content of the URL.') 37 | return redirect(url_for('index')) 38 | 39 | article = Article(url) 40 | article.download() 41 | article.parse() 42 | article.nlp() # Perform natural language processing 43 | 44 | title = article.title 45 | authors = ', '.join(article.authors) 46 | if not authors: 47 | authors = get_website_name(url) # Set the author field to the website name 48 | publish_date = article.publish_date.strftime('%B %d, %Y') if article.publish_date else "N/A" 49 | 50 | # Manually adjust the summary length by selecting a certain number of sentences 51 | article_text = article.text 52 | sentences = article_text.split('.') 53 | max_summarized_sentences = 5 # Adjust the number of sentences as needed 54 | summary = '.'.join(sentences[:max_summarized_sentences]) 55 | 56 | top_image = article.top_image # Get the top image URL 57 | 58 | analysis = TextBlob(article.text) 59 | polarity = analysis.sentiment.polarity # Get the polarity value 60 | 61 | if summary == "": 62 | flash('Please enter a valid URL.') 63 | return redirect(url_for('index')) 64 | 65 | if polarity > 0: 66 | sentiment = 'happy 😊' 67 | elif polarity < 0: 68 | sentiment = ' sad 😟' 69 | else: 70 | sentiment = 'neutral 😐' 71 | 72 | return render_template('index.html', title=title, authors=authors, publish_date=publish_date, summary=summary, top_image=top_image, sentiment=sentiment) 73 | 74 | return render_template('index.html') 75 | 76 | app.secret_key = 'your_secret_key' 77 | 78 | if __name__ == '__main__': 79 | app.run(debug=True) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | Logo 4 |

AI-News-Summariser

5 |

6 | A tool for automatically summarizing news articles using artificial intelligence. 7 |
8 | Visit the Website » 9 |
10 |
11 | Contact Developer 12 | · 13 | Report Bug 14 | · 15 | Request Feature 16 | . 17 | Discord Support 18 |

19 |
20 | 21 | ## About The Project 22 | 23 | ![AI-News-Summariser Screen Shot](image.png) 24 | 25 | AI-News-Summariser is a tool designed to automatically generate concise summaries of news articles using artificial intelligence. Stay informed without spending too much time reading lengthy articles. 26 | 27 | >[!CAUTION] 28 | >Ensure that you use this tool responsibly. Respect the copyrights and terms of use of the news sources. 29 | 30 |

(back to top)

31 | 32 | ### Features 33 | * Automatic summarization of news articles. 34 | * Support for multiple news sources. 35 | * Easily accessible web interface. 36 | Export summarized content for offline reading. 37 | 38 | ### Built With 39 | * Python 40 | * Newspaper3k 41 | * Flask 42 |

(back to top)

43 | 44 | ## Getting Started 45 | AI-News-Summariser can be installed and used on various platforms. Follow the steps below to get started. 46 | 47 | 48 | ### Installation 49 | 50 | 1. Clone the repo 51 | ```sh 52 | git clone https://github.com/Oxlac/AI-News-Summariser.git 53 | ``` 54 | 2. Install Requirements 55 | ```sh 56 | pip install -r requirements.txt 57 | ``` 58 | 3. Run the app 59 | ```sh 60 | python app.py 61 | ``` 62 | 63 |

(back to top)

64 | 65 | ## Future features and improvements 66 | 67 | - [ ] Customize summarization preferences. 68 | - [ ] Tackling corner cases where some news articles won't be parsed properly. 69 | - [ ] Customizable summarization algorithms. 70 | - [ ] User accounts and preferences. 71 | - [ ] Mobile app version. 72 | - [ ] Improvements in summarization accuracy. 73 | 74 | See the [open issues](https://github.com/oxlac/AI-News-Summariser/issues) for a full list of proposed features and known issues. 75 | 76 |

(back to top)

77 | 78 | ## Contributing 79 | Contributions are what makes the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 80 | 81 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 82 | Don't forget to give the project a star! Thanks again! 83 | 84 | 1. Fork the Project 85 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 86 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 87 | 4. Ensure that your code passes the ruff linter. If it does not pass view the errors and fix them. 88 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 89 | 5. Open a Pull Request 90 | 91 |

(back to top)

92 | 93 | ## License 94 | Distributed under the MIT License. See LICENSE.txt for more information. 95 | 96 |

(back to top)

97 | 98 | ## Contact 99 | Your Name - [@Oxlac_](https://twitter.com/Oxlac_) - contact@oxlac.com 100 | 101 | Discord Server - [https://discord.gg/2YdnSGHdET](https://discord.gg/2YdnSGHdET) 102 | 103 | Project Link: [https://github.com/Oxlac/AI-News-Summariser](https://github.com/oxlac/mr.dm) 104 | 105 | Developer: [Aadityaa Nagarajan](https://aadinagarajan.com) 106 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | support@oxlac.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /static/light-theme.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300&display=swap'); 2 | 3 | body { 4 | background-color: #f8f9fa; /* Light grey background */ 5 | color: #212529; /* Dark grey text */ 6 | font-family: 'Poppins', sans-serif; 7 | scroll-behavior: smooth; 8 | position: relative; 9 | min-height: calc(100vh - 90px); 10 | } 11 | 12 | .heading { 13 | text-align: center; 14 | font-size: 3.5rem; 15 | margin-top: 0; 16 | padding-top: 0; 17 | color: #212529; /* Dark grey text */ 18 | } 19 | 20 | body::-webkit-scrollbar { 21 | width: 7px; 22 | } 23 | 24 | body::-webkit-scrollbar-track { 25 | background: #e9ecef; /* Light grey tracking area */ 26 | } 27 | 28 | body::-webkit-scrollbar-thumb { 29 | background-color: #adb5bd; /* Medium grey scroll thumb */ 30 | border-radius: 20px; 31 | } 32 | 33 | .sub-heading { 34 | text-align: center; 35 | font-size: 2rem; 36 | margin-top: 5rem; 37 | margin-bottom: 0; 38 | padding-bottom: 0; 39 | color: #212529; /* Dark grey text */ 40 | } 41 | 42 | .form { 43 | display: flex; 44 | justify-content: center; 45 | gap: .5rem; 46 | } 47 | 48 | .form input[type=text] { 49 | width: 40%; 50 | height: 3rem; 51 | border: 1px solid #dee2e6; /* Light grey border */ 52 | border-radius: 10px; 53 | outline: none; 54 | padding-left: 1rem; 55 | background-color: #fff; /* White background */ 56 | color: #495057; /* Dark grey text */ 57 | } 58 | 59 | .form button { 60 | position: relative; 61 | border-radius: 10px; 62 | width: 3rem; 63 | outline: none; 64 | border: none; 65 | cursor: pointer; 66 | user-select: none; 67 | transition-duration: 0.4s; 68 | -webkit-transition-duration: 0.4s; 69 | background-color: #f8f9fa; /* Light grey background */ 70 | color: #495057; /* Dark grey text */ 71 | } 72 | 73 | .form button:hover { 74 | transition-duration: 0.1s; 75 | background-color: #28ffad; /* Green background on hover */ 76 | } 77 | 78 | .form button:active { 79 | top: 1px; 80 | } 81 | 82 | .form button:active::after { 83 | box-shadow: 0 0 0 0 white; 84 | position: absolute; 85 | border-radius: 10px; 86 | left: 0; 87 | top:0; 88 | opacity: 1; 89 | transition: 0s; 90 | } 91 | 92 | .form button:after { 93 | content: ""; 94 | display: block; 95 | position: absolute; 96 | border-radius: 10px; 97 | left: 0; 98 | top:0; 99 | width: 100%; 100 | height: 100%; 101 | opacity: 0; 102 | transition: all 0.5s; 103 | box-shadow: 0 0 10px 40px white; 104 | } 105 | 106 | .content { 107 | margin-top: 4rem; 108 | display: flex; 109 | justify-content: center; 110 | } 111 | 112 | .card { 113 | border: 2px solid #dee2e6; /* Light grey border */ 114 | width: 80vw; 115 | padding: 2rem; 116 | border-radius: 10px; 117 | background-color: #fff; /* White background */ 118 | margin-bottom: 5rem; 119 | } 120 | 121 | .card .heading { 122 | margin-top: 2rem; 123 | text-align: center; 124 | font-size: 2.5rem; 125 | color: #212529; /* Dark grey text */ 126 | } 127 | 128 | .main-wrapper { 129 | display: flex; 130 | align-items: center; 131 | } 132 | 133 | .main-wrapper .col-1 { 134 | width: 80%; 135 | } 136 | 137 | .main-wrapper .col-2 { 138 | display: flex; 139 | align-items: center; 140 | justify-content: center; 141 | } 142 | 143 | .main-wrapper .col-2 .top-image { 144 | max-width: 70%; 145 | height: auto; 146 | border-radius: 20px; 147 | } 148 | 149 | .summary-tag, .author-tag, .date-tag, .sentiment-tag { 150 | font-size: 1.5rem; 151 | color: #212529; /* Dark grey text */ 152 | } 153 | 154 | .author-list li.hidden { 155 | display: none; 156 | } 157 | 158 | #readMoreBtn { 159 | display: block; 160 | margin-top: 1rem; 161 | background-color: transparent; 162 | border: none; 163 | color: blue; /* Green text */ 164 | cursor: pointer; 165 | } 166 | 167 | #readMoreBtn:hover { 168 | text-decoration: underline; 169 | } 170 | 171 | @media screen and (max-width: 768px) { 172 | .heading { 173 | font-size: 3rem; 174 | } 175 | 176 | .form input[type=text] { 177 | width: 60%; 178 | } 179 | 180 | .card { 181 | width: 75vw; 182 | padding: 1rem; 183 | } 184 | 185 | .card .heading { 186 | font-size: 1.5rem; 187 | } 188 | 189 | .main-wrapper { 190 | flex-direction: column-reverse; 191 | } 192 | 193 | .main-wrapper .col-2 .top-image { 194 | width: 100%; 195 | } 196 | 197 | .main-wrapper .col-1 { 198 | width: 100%; 199 | } 200 | 201 | .infos { 202 | width: 100%; 203 | text-align: center; 204 | } 205 | } 206 | 207 | .flash-message { 208 | position: fixed; 209 | top: 0; 210 | left: 0; 211 | width: 100%; 212 | background: #e9ecef; /* Light grey background */ 213 | color: #212529; /* Dark grey text */ 214 | text-align: center; 215 | padding: 10px 0; 216 | z-index: 9999; 217 | } 218 | 219 | .alert { 220 | background: #ffcccb; /* Light red background */ 221 | color: #212529; /* Dark grey text */ 222 | padding: 10px; 223 | margin: 10px; 224 | border-radius: 5px; 225 | } 226 | 227 | .infos { 228 | position: absolute; 229 | color: #212529; /* Dark grey text */ 230 | font-size: 14px; 231 | bottom: 10px; 232 | left: 50%; 233 | transform: translateX(-50%); 234 | } 235 | 236 | .developer { 237 | text-decoration: none; 238 | cursor: pointer; 239 | color: #28ffad; /* Green text */ 240 | } 241 | 242 | .theme-switch-wrapper { 243 | display: flex; 244 | align-items: center; 245 | justify-content: center; 246 | margin: 20px; 247 | } 248 | 249 | .theme-switch { 250 | position: relative; 251 | display: inline-block; 252 | width: 60px; 253 | height: 34px; 254 | } 255 | 256 | .theme-switch input { 257 | opacity: 0; 258 | width: 0; 259 | height: 0; 260 | } 261 | 262 | .slider { 263 | position: absolute; 264 | cursor: pointer; 265 | top: 0; 266 | left: 0; 267 | right: 0; 268 | bottom: 0; 269 | background-color: #ccc; 270 | -webkit-transition: .4s; 271 | transition: .4s; 272 | } 273 | 274 | .slider:before { 275 | position: absolute; 276 | content: ""; 277 | height: 26px; 278 | width: 26px; 279 | left: 4px; 280 | bottom: 4px; 281 | background-color: white; 282 | -webkit-transition: .4s; 283 | transition: .4s; 284 | } 285 | 286 | input:checked + .slider { 287 | background-color: #2196F3; 288 | } 289 | 290 | input:focus + .slider { 291 | box-shadow: 0 0 1px #2196F3; 292 | } 293 | 294 | input:checked + .slider:before { 295 | -webkit-transform: translateX(26px); 296 | -ms-transform: translateX(26px); 297 | transform: translateX(26px); 298 | } 299 | 300 | .slider.round { 301 | border-radius: 34px; 302 | } 303 | 304 | .slider.round:before { 305 | border-radius: 50%; 306 | } 307 | 308 | .theme-switch-wrapper span { 309 | margin-right: 10px; 310 | /* Add more styling if needed */ 311 | } -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | News Article Summarizer 18 | 19 | 20 | 21 |

AI Powered

22 |

News Article Summarizer

23 | 24 |
25 | Change Theme 26 | 30 |
31 |
32 | 33 | 38 |
39 | 40 |
41 | {% with messages = get_flashed_messages() %} 42 | {% if messages %} 43 | {% for message in messages %} 44 |
{{ message }}
45 | {% endfor %} 46 | {% endif %} 47 | {% endwith %} 48 |
49 | 50 | 51 | {% if title %} 52 |
53 |
54 |

{{ title }}

55 |
56 |
57 |

Authors:

58 |
    59 | {% for author in authors.split(', ') %} 60 |
  • {{ author }}
  • 61 | {% endfor %} 62 |
63 | 64 |

Publication Date:

65 |
66 |
67 | Top Image 68 |
69 |
70 |

Summary: {{ summary }}

71 |

Sentiment: {{ sentiment }}

72 |
73 |
74 | {% endif %} 75 | 76 |

© , Designed and Developed by Oxlac LLP

77 | 78 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /static/dark-theme.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300&display=swap'); 2 | 3 | body { 4 | background-color: #0E1316; /* Dark background */ 5 | color: #EDEDED; 6 | font-family: 'Poppins', sans-serif; 7 | scroll-behavior: smooth; 8 | position: relative; 9 | min-height: calc(100vh - 90px); 10 | } 11 | 12 | .heading { 13 | text-align: center; 14 | font-size: 3.5rem; 15 | margin-top: 0; 16 | padding-top: 0; 17 | } 18 | 19 | body::-webkit-scrollbar { 20 | width: 7px; /* width of the entire scrollbar */ 21 | } 22 | 23 | body::-webkit-scrollbar-track { 24 | background: #0E1316; /* color of the tracking area */ 25 | } 26 | 27 | body::-webkit-scrollbar-thumb { 28 | background-color: #252930; /* color of the scroll thumb */ 29 | border-radius: 20px; /* roundness of the scroll thumb */ 30 | } 31 | 32 | .sub-heading { 33 | text-align: center; 34 | font-size: 2rem; 35 | margin-top: 5rem; 36 | margin-bottom: 0; 37 | padding-bottom: 0; 38 | } 39 | 40 | .form{ 41 | display: flex; 42 | justify-content: center; 43 | gap: .5rem; 44 | } 45 | 46 | .form input[type=text] { 47 | width: 40%; 48 | height: 3rem; 49 | border: none; 50 | border-radius: 10px; 51 | outline: none; 52 | padding-left: 1rem; 53 | } 54 | 55 | .form input[type=text]:active { 56 | border: none; 57 | outline: none; 58 | } 59 | 60 | .form button { 61 | position: relative; 62 | border-radius: 10px; 63 | width: 3rem; 64 | outline: none; 65 | border: none; 66 | cursor:pointer; 67 | user-select:none; 68 | transition-duration: 0.4s; 69 | -webkit-transition-duration: 0.4s; 70 | } 71 | 72 | .form button:hover { 73 | transition-duration: 0.1s; 74 | background-color: #28ffad; 75 | } 76 | 77 | .form button:active { 78 | top: 1px; 79 | } 80 | 81 | .form button:active::after { 82 | box-shadow: 0 0 0 0 white; 83 | position: absolute; 84 | border-radius: 10px; 85 | left: 0; 86 | top:0; 87 | opacity: 1; 88 | transition: 0s; 89 | } 90 | 91 | .form button:after { 92 | content: ""; 93 | display: block; 94 | position: absolute; 95 | border-radius: 10px; 96 | left: 0; 97 | top:0; 98 | width: 100%; 99 | height: 100%; 100 | opacity: 0; 101 | transition: all 0.5s; 102 | box-shadow: 0 0 10px 40px white; 103 | } 104 | 105 | .content { 106 | margin-top: 4rem; 107 | display: flex; 108 | justify-content: center; 109 | } 110 | 111 | .card { 112 | border: 2px solid #252930; 113 | width: 80vw; 114 | padding: 2rem; 115 | border-radius: 10px; 116 | background-color: #1C1E27; 117 | margin-bottom: 5rem; 118 | /* box-shadow: */ 119 | /* 0 0 21px 1px rgb(255, 35, 101); */ 120 | /* 0 0 .5px 1px rgb(7, 255, 152); */ 121 | } 122 | 123 | .card .heading { 124 | margin-top: 2rem; 125 | text-align: center; 126 | font-size: 2.5rem; 127 | } 128 | 129 | .main-wrapper { 130 | display: flex; 131 | align-items: center; 132 | } 133 | 134 | .main-wrapper .col-1 { 135 | width: 80%; 136 | } 137 | 138 | .main-wrapper .col-2 { 139 | display: flex; 140 | align-items: center; 141 | justify-content: center; 142 | } 143 | 144 | .main-wrapper .col-2 .top-image { 145 | max-width: 70%; 146 | height: auto; 147 | border-radius: 20px; 148 | } 149 | 150 | .summary-tag { 151 | font-size: 1.5rem; 152 | } 153 | 154 | .author-tag { 155 | font-size: 1.5rem; 156 | } 157 | 158 | .date-tag { 159 | font-size: 1.5rem; 160 | } 161 | 162 | .sentiment-tag { 163 | font-size: 1.5rem; 164 | } 165 | 166 | .author-list li.hidden { 167 | display: none; 168 | } 169 | 170 | #readMoreBtn { 171 | display: block; 172 | margin-top: 1rem; 173 | background-color: transparent; 174 | border: none; 175 | color: #28ffad; 176 | cursor: pointer; 177 | } 178 | 179 | #readMoreBtn:hover { 180 | text-decoration: underline; 181 | } 182 | 183 | /* Light Theme */ 184 | .light-theme { 185 | background-color: #FFFFFF; 186 | color: #000000; 187 | } 188 | 189 | /* Dark Theme */ 190 | .dark-theme { 191 | background-color: #0E1316; 192 | color: #EDEDED; 193 | } 194 | 195 | 196 | @media screen and (max-width: 768px) { 197 | .heading { 198 | font-size: 3rem; 199 | } 200 | 201 | .form input[type=text] { 202 | width: 60%; 203 | } 204 | 205 | .card { 206 | width: 75vw; 207 | padding: 1rem; 208 | } 209 | 210 | .card .heading { 211 | font-size: 1.5rem; 212 | } 213 | 214 | .main-wrapper { 215 | flex-direction: column-reverse; 216 | } 217 | 218 | .main-wrapper .col-2 .top-image { 219 | width: 100%; 220 | } 221 | 222 | .main-wrapper .col-1 { 223 | width: 100%; 224 | } 225 | 226 | .infos { 227 | width: 100%; 228 | text-align: center; 229 | } 230 | } 231 | 232 | 233 | .flash-message { 234 | position: fixed; 235 | top: 0; 236 | left: 0; 237 | width: 100%; 238 | background: transparent; /* Background color for the alert container */ 239 | color: #fff; /* Text color for the alert text */ 240 | text-align: center; 241 | padding: 10px 0; 242 | z-index: 9999; /* Ensures the alert is on top of other content */ 243 | } 244 | 245 | .alert { 246 | background: #ff3333; /* Background color for the alert */ 247 | color: #fff; /* Text color for the alert text */ 248 | padding: 10px; 249 | margin: 10px; 250 | border-radius: 5px; 251 | } 252 | 253 | .infos { 254 | position: absolute; 255 | color: #fff; 256 | font-size: 14px; 257 | bottom: 10px; 258 | left: 50%; 259 | transform: translateX(-50%); 260 | } 261 | 262 | .developer { 263 | text-decoration: none; 264 | cursor:pointer; 265 | color: #28ffad; 266 | } 267 | 268 | .theme-switch-wrapper { 269 | display: flex; 270 | align-items: center; 271 | justify-content: center; 272 | margin: 20px; 273 | } 274 | 275 | .theme-switch { 276 | position: relative; 277 | display: inline-block; 278 | width: 60px; 279 | height: 34px; 280 | } 281 | 282 | .theme-switch input { 283 | opacity: 0; 284 | width: 0; 285 | height: 0; 286 | } 287 | 288 | .slider { 289 | position: absolute; 290 | cursor: pointer; 291 | top: 0; 292 | left: 0; 293 | right: 0; 294 | bottom: 0; 295 | background-color: #ccc; 296 | -webkit-transition: .4s; 297 | transition: .4s; 298 | } 299 | 300 | .slider:before { 301 | position: absolute; 302 | content: ""; 303 | height: 26px; 304 | width: 26px; 305 | left: 4px; 306 | bottom: 4px; 307 | background-color: white; 308 | -webkit-transition: .4s; 309 | transition: .4s; 310 | } 311 | 312 | input:checked + .slider { 313 | background-color: #2196F3; 314 | } 315 | 316 | input:focus + .slider { 317 | box-shadow: 0 0 1px #2196F3; 318 | } 319 | 320 | input:checked + .slider:before { 321 | -webkit-transform: translateX(26px); 322 | -ms-transform: translateX(26px); 323 | transform: translateX(26px); 324 | } 325 | 326 | /* Rounded sliders */ 327 | .slider.round { 328 | border-radius: 34px; 329 | } 330 | 331 | .slider.round:before { 332 | border-radius: 50%; 333 | } 334 | 335 | .theme-switch-wrapper span { 336 | margin-right: 10px; 337 | /* Add more styling if needed */ 338 | } --------------------------------------------------------------------------------