Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Read by thought-leaders and decision-makers around the world. Phone Number: +1-650-246-9381 Email: pub@towardsai.net
228 Park Avenue South New York, NY 10003 United States
Website: Publisher: https://towardsai.net/#publisher Diversity Policy: https://towardsai.net/about Ethics Policy: https://towardsai.net/about Masthead: https://towardsai.net/about
Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Founders: Roberto Iriondo, , Job Title: Co-founder and Advisor Works for: Towards AI, Inc. Follow Roberto: X, LinkedIn, GitHub, Google Scholar, Towards AI Profile, Medium, ML@CMU, FreeCodeCamp, Crunchbase, Bloomberg, Roberto Iriondo, Generative AI Lab, Generative AI Lab Denis Piffaretti, Job Title: Co-founder Works for: Towards AI, Inc. Louie Peters, Job Title: Co-founder Works for: Towards AI, Inc. Louis-François Bouchard, Job Title: Co-founder Works for: Towards AI, Inc. Cover:
Towards AI Cover
Logo:
Towards AI Logo
Areas Served: Worldwide Alternate Name: Towards AI, Inc. Alternate Name: Towards AI Co. Alternate Name: towards ai Alternate Name: towardsai Alternate Name: towards.ai Alternate Name: tai Alternate Name: toward ai Alternate Name: toward.ai Alternate Name: Towards AI, Inc. Alternate Name: towardsai.net Alternate Name: pub.towardsai.net
5 stars – based on 497 reviews

Frequently Used, Contextual References

TODO: Remember to copy unique IDs whenever it needs used. i.e., URL: 304b2e42315e

Resources

Take our 85+ lesson From Beginner to Advanced LLM Developer Certification: From choosing a project to deploying a working product this is the most comprehensive and practical LLM course out there!

Publication

How to make Generative AI reliable
Latest   Machine Learning

How to make Generative AI reliable

Last Updated on September 18, 2024 by Editorial Team

Author(s): Mark O’Neill

Originally published on Towards AI.

They say your greatest strength creates your greatest weakness. Generative AI models that can produce an infinite amount of answers for an infinite amount of prompts, will naturally be terrible at behaving predictably and consistently when asked.

Conversely, if you tell a human you’re going to use LLMs in production, they will predictably and consistently tell you that “LLMs are too unreliable for that!”. If we can’t trust their output then we can’t use them for important functionality. And if we can’t use them properly, then they will never get close to their hype.

Fortunately, there are tools and techniques that let us use GenAI in a safe, scalable, and reliable way.

So before you dismount your AI hype cycle, let’s take one more pedal up the Slope of Enlightenment and learn how to use GenAI reliably.

Generative AI Systems

A GenAI system is a term I’ll use to describe something that goes beyond chat interfaces and content generation. They could also be called an application, API, interface, or whatever makes you happier.

These systems use a combination of generative models, alongside traditional systems to build, classify, decide, interact with, or manage complex objects or tasks.

Examples of use cases in the customer experience domains:

  • Generative UIs: Performing actions and rendering highly personalizing components in a user interface.
  • Automated Customer Service: Systems that don’t just process support tickets but investigate issues, make account changes, and provide assistance.
  • Hyper-Personalization (Marketing or Branding): Systems to curates content, styles, and messaging to perfectly suit each person.

There are a huge variety of GenAI systems — likely many we don’t even notice — in existence today.

I hope this guide helps you consider and build your own.

Why Generative AI outside of just generating?

Even if GenAI has reached its limits, these models already offer valuable skills outside of content generation that are yet to be fully utilized. The abilities of GenAI models to take advantage of are:

  • Understanding Human Language: They can interpret and infer natural language. Empowering us to handle many more varieties of requests and context.
  • Building Complex Artifacts: They can create code, components, designs, music, images, applications, personalities, etc.
  • Processing Complex Data: They can take large unstructured pieces of data and analyze and interpret them — all at a fraction of time compared to a human.
  • In-built World Knowledge: Trained with data beyond what a human can read in one’s lifetime, they have awareness of best practices and techniques from a huge range of areas beyond what we could ever hardcode into an API or UX.

Now it’s time to learn how to use these feisty little models as part of a cooperative and reliable system.

What is a Reliable system?

For a system to be reliable, we need to be able to depend on it to do what we ask, trust it to not do anything wrong, and feel safe that it won’t be compromised.

Breaking this down into three categories, we aim to:

  1. Get Consistent Outputs: We need to define and validate the structure, format, and contents of it’s inputs and outputs.
  2. Design for Scale and Accuracy: We need to build it in a way that breaks down work into simple achievable tasks, so that it can be accurate through growth and changes.
  3. Ensure Safety and Security: We need to do everything possible to reduce risks of data leaks and intrusions from GenAI vulnerabilities.

AI Assistants vs. GenAI Systems

How is this different to the chat services we see today?

In the olden days, companies were tempted to just slap an ‘AI assistant’ into their application and claim it’s powered by AI. They’d give it a human-like name and tell you to ‘chat’ or ‘ask us anything’.

Job done, right?

The AI Assistant Approach

The below example is the standard chat-like AI assistant model. Ignoring the obvious fact that nobody has ever wanted to chat with a pdf, database, or system, this approach of chat conversations is not ideal for complex tasks. It has;

  • No clear structure to support complex tasks.
  • Prioritized chat instead of action.
  • Openned itself to vulnerabilities like prompt injection.
A monolithic chat-style system (source: author)

A GenAI System Approach — Controlled creativity

The second example is an AI engine for a super intelligent GenUI system. It powers the personalized, proactive, and semi-autonomous UI for a world-leading bank. It does a lot, but the functionality we care about today is displaying a personalized dashboard for each user.

A scalable and flexible GenAI System (source: author)

This approach brings a lot of benefits, such as:

  • It can creatively choose components and styles to best meet it’s goal but is limited in making invalid or out of scope outputs.
  • Structured process, inputs, and outputs for fine-grained control.
  • Potential for richer and more complex interfaces and interactions.
  • Easily extendable functionality.
  • Better testing, performance monitoring and measuring.
  • Improved security and data privacy.

Techniques for Getting Consistent Outputs

Getting consistency from LLMs is essential to success. We need a rigid structure for our inputs and outputs, and be able to handle when things don’t work.

History’s best art has always been created within constraints. Limiting a GenAI system doesn’t mean we hurt its creativity, it just means it’s focused on where we need it.

Structure & Validate Inputs and Outputs

Requests and responses between models should be made with confined structures and finite options. These schemas should be made as strict as possible to limit the scope and quality of what is returned.

Structured outputs make handling and validating easier (source: author)

Many LLM providers offer a setting to force JSON structured outputs which do not require additional wrangling or prompting instructions. A system should use a capability like this to ensure responses are valid before they are used or returned by system. Defining schemas for each request/response is tedious but necessary work for a reliable system.

  • A Bad Approach: We ask the system to generate the HTML/CSS/JS for the component from scratch in one big prompt and render it on the front end. No component ever looks the same and it causes issues with inaccessibility, inconsistency, and poor UX.
  • A Good Approach: The system is given a list of components, specifications, and style options to choose from, then decides the best combination to meet the goal. This still supports personalized designs, guarantees the component matches the data, and ensures the UI conforms to any brand and accessibility rules.

Useful Links:

Know How Accept and Handle Defeat

Each function should allow for a scenario where its task cannot be completed. Schemas should be designed in a way to allow for cases of invalid or insufficient detail, and error and default behaviours should be defined.

Eventually, even the best GenAI setup will encounter a situation where a misleading prompt cannot be handled. Prepare for this by giving the system the option to declare when it cannot complete the task, or when data is insufficient. Have rules in place to respond when reponses are invalid or unattainable.

Example: Our system is tasked with building a personalized dashboard for each user. In the case where the customer is new, we may have no useful data to personalize with. Instead of going off track and inventing its own display, or returning a blank view, it is encouraged to state when there is not enough data. The default dashboard can be shown instead.

Techniques for Designing For Scale

GenAI systems are just like any other software system. As such, we should apply best practice techniques and design principles to help them scale and perform like one.

Design to Extend, Not Modify

Functions within the system should be implemented in a way that allows them to be extended on without needing large modifications of the other parts.

New functionality can be added easily (source: author)

A GenAI system that produces complex outputs will require complex inputs. This means fetching data from various sources, interacting with external systems, and iterating over complex outputs. As new capabilities are added, the system should allow them to be added without needing to refactor and modify the other parts.

Example: In our system above, we can easily slot in new functionality, such as usability tweaks and device optimization tactics, that can be incorporated while creating personalised interfaces. This can be done with minimal changes to the rest of the process.

Follow the Single Responsibility Rule

Prompts and functions should each have one singular purpose or responsibility. This includes a defined input and output schema.

Doing this is a very effective way to maintain reliability across a larger task. Rather than asking a model to build an entire view or component, we can ask it to create a single part, in a controlled and defined way.

It’s tempting to create larger system prompts that represent multiple abilities and actions. You may be able to get away with this for a small system, but as more functionality, edge cases, and risks are added, it becomes unmanageable and prone to wild responses.

Useful Links:

Prioritize Doing, Not Chatting

The system should prioritize performing any actions before ‘chatting’. If an action is not able to be completed (e.g. from insufficient or invalid data), it should aim to progress, pre-fill, or assist in completing the action.

These systems are built to do things for us. They should aim to do as much as possible with as little conversation and friction as possible. Ideally they should only resort to ‘chatting’ when needing more information or when asked to explain things. A perfect GenAI system would do everything we needed without us having to ask!

An AI Assistant is like that coworker who loves to tell everyone what to do and how to do it, but is very reluctant to do anything themselves.

(AI Assistant: ‘Ask us anything… except to do something useful for you’)

Techniques for Ensuring Safety and Security

It goes without saying that any software system needs to be safe and secure. GenAI models introduce even more risk for malicious techniques like Prompt Injection.

‘Air-Gap’ Important Functionality

All functionality that involves retrieving or updating important data should be kept separate from components that handle incoming requests (Air Gap). Tasks that involve this data should only be exposed and accessible to explicit and necessary components.

An 'air gap' prevents prompt injection attacks and data leaks (source: author)

Prompt injection, hallucinations, and weird behaviour are always a risk with GenAI. The system must be designed in a way to prevent any harmful requests being carried out by a function with access to sensitive data or restricted APIs. This technique dictates that any function that receives external messages should have no access to restricted systems or information.

Techniques for Prompt Engineering for Reliability

There are so many prompt engineering techniques available that claim to give better accuracy, decision making, formatting, and overall quality.

There’s not much more to say about prompt engineering techniques that hasn’t been written elsewhere. So instead I’ve compiled a list of useful techniques and links that you can use for any prompt-related project, not just GenAI systems. Enjoy!

Conclusion

I hope this article has been helpful in convincing you to consider this approach for making Generative AI more reliable.

There are likely a lot more techniques and technologies that you could use to make great system. I think these are the most powerful and practical for any size implementation.

Please don’t hesitate to reach out as I’d love any feedback, questions, or suggestions for more techniques!

Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

Published via Towards AI

Feedback ↓

Sign Up for the Course
`; } else { console.error('Element with id="subscribe" not found within the page with class "home".'); } } }); // Remove duplicate text from articles /* Backup: 09/11/24 function removeDuplicateText() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, strong'); // Select the desired elements const seenTexts = new Set(); // A set to keep track of seen texts const tagCounters = {}; // Object to track instances of each tag elements.forEach(el => { const tagName = el.tagName.toLowerCase(); // Get the tag name (e.g., 'h1', 'h2', etc.) // Initialize a counter for each tag if not already done if (!tagCounters[tagName]) { tagCounters[tagName] = 0; } // Only process the first 10 elements of each tag type if (tagCounters[tagName] >= 2) { return; // Skip if the number of elements exceeds 10 } const text = el.textContent.trim(); // Get the text content const words = text.split(/\s+/); // Split the text into words if (words.length >= 4) { // Ensure at least 4 words const significantPart = words.slice(0, 5).join(' '); // Get first 5 words for matching // Check if the text (not the tag) has been seen before if (seenTexts.has(significantPart)) { // console.log('Duplicate found, removing:', el); // Log duplicate el.remove(); // Remove duplicate element } else { seenTexts.add(significantPart); // Add the text to the set } } tagCounters[tagName]++; // Increment the counter for this tag }); } removeDuplicateText(); */ // Remove duplicate text from articles function removeDuplicateText() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, strong'); // Select the desired elements const seenTexts = new Set(); // A set to keep track of seen texts const tagCounters = {}; // Object to track instances of each tag // List of classes to be excluded const excludedClasses = ['medium-author', 'post-widget-title']; elements.forEach(el => { // Skip elements with any of the excluded classes if (excludedClasses.some(cls => el.classList.contains(cls))) { return; // Skip this element if it has any of the excluded classes } const tagName = el.tagName.toLowerCase(); // Get the tag name (e.g., 'h1', 'h2', etc.) // Initialize a counter for each tag if not already done if (!tagCounters[tagName]) { tagCounters[tagName] = 0; } // Only process the first 10 elements of each tag type if (tagCounters[tagName] >= 10) { return; // Skip if the number of elements exceeds 10 } const text = el.textContent.trim(); // Get the text content const words = text.split(/\s+/); // Split the text into words if (words.length >= 4) { // Ensure at least 4 words const significantPart = words.slice(0, 5).join(' '); // Get first 5 words for matching // Check if the text (not the tag) has been seen before if (seenTexts.has(significantPart)) { // console.log('Duplicate found, removing:', el); // Log duplicate el.remove(); // Remove duplicate element } else { seenTexts.add(significantPart); // Add the text to the set } } tagCounters[tagName]++; // Increment the counter for this tag }); } removeDuplicateText(); //Remove unnecessary text in blog excerpts document.querySelectorAll('.blog p').forEach(function(paragraph) { // Replace the unwanted text pattern for each paragraph paragraph.innerHTML = paragraph.innerHTML .replace(/Author\(s\): [\w\s]+ Originally published on Towards AI\.?/g, '') // Removes 'Author(s): XYZ Originally published on Towards AI' .replace(/This member-only story is on us\. Upgrade to access all of Medium\./g, ''); // Removes 'This member-only story...' }); //Load ionic icons and cache them if ('localStorage' in window && window['localStorage'] !== null) { const cssLink = 'https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css'; const storedCss = localStorage.getItem('ionicons'); if (storedCss) { loadCSS(storedCss); } else { fetch(cssLink).then(response => response.text()).then(css => { localStorage.setItem('ionicons', css); loadCSS(css); }); } } function loadCSS(css) { const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); } //Remove elements from imported content automatically function removeStrongFromHeadings() { const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6, span'); elements.forEach(el => { const strongTags = el.querySelectorAll('strong'); strongTags.forEach(strongTag => { while (strongTag.firstChild) { strongTag.parentNode.insertBefore(strongTag.firstChild, strongTag); } strongTag.remove(); }); }); } removeStrongFromHeadings(); "use strict"; window.onload = () => { /* //This is an object for each category of subjects and in that there are kewords and link to the keywods let keywordsAndLinks = { //you can add more categories and define their keywords and add a link ds: { keywords: [ //you can add more keywords here they are detected and replaced with achor tag automatically 'data science', 'Data science', 'Data Science', 'data Science', 'DATA SCIENCE', ], //we will replace the linktext with the keyword later on in the code //you can easily change links for each category here //(include class="ml-link" and linktext) link: 'linktext', }, ml: { keywords: [ //Add more keywords 'machine learning', 'Machine learning', 'Machine Learning', 'machine Learning', 'MACHINE LEARNING', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, ai: { keywords: [ 'artificial intelligence', 'Artificial intelligence', 'Artificial Intelligence', 'artificial Intelligence', 'ARTIFICIAL INTELLIGENCE', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, nl: { keywords: [ 'NLP', 'nlp', 'natural language processing', 'Natural Language Processing', 'NATURAL LANGUAGE PROCESSING', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, des: { keywords: [ 'data engineering services', 'Data Engineering Services', 'DATA ENGINEERING SERVICES', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, td: { keywords: [ 'training data', 'Training Data', 'training Data', 'TRAINING DATA', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, ias: { keywords: [ 'image annotation services', 'Image annotation services', 'image Annotation services', 'image annotation Services', 'Image Annotation Services', 'IMAGE ANNOTATION SERVICES', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, l: { keywords: [ 'labeling', 'labelling', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, pbp: { keywords: [ 'previous blog posts', 'previous blog post', 'latest', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, mlc: { keywords: [ 'machine learning course', 'machine learning class', ], //Change your article link (include class="ml-link" and linktext) link: 'linktext', }, }; //Articles to skip let articleIdsToSkip = ['post-2651', 'post-3414', 'post-3540']; //keyword with its related achortag is recieved here along with article id function searchAndReplace(keyword, anchorTag, articleId) { //selects the h3 h4 and p tags that are inside of the article let content = document.querySelector(`#${articleId} .entry-content`); //replaces the "linktext" in achor tag with the keyword that will be searched and replaced let newLink = anchorTag.replace('linktext', keyword); //regular expression to search keyword var re = new RegExp('(' + keyword + ')', 'g'); //this replaces the keywords in h3 h4 and p tags content with achor tag content.innerHTML = content.innerHTML.replace(re, newLink); } function articleFilter(keyword, anchorTag) { //gets all the articles var articles = document.querySelectorAll('article'); //if its zero or less then there are no articles if (articles.length > 0) { for (let x = 0; x < articles.length; x++) { //articles to skip is an array in which there are ids of articles which should not get effected //if the current article's id is also in that array then do not call search and replace with its data if (!articleIdsToSkip.includes(articles[x].id)) { //search and replace is called on articles which should get effected searchAndReplace(keyword, anchorTag, articles[x].id, key); } else { console.log( `Cannot replace the keywords in article with id ${articles[x].id}` ); } } } else { console.log('No articles found.'); } } let key; //not part of script, added for (key in keywordsAndLinks) { //key is the object in keywords and links object i.e ds, ml, ai for (let i = 0; i < keywordsAndLinks[key].keywords.length; i++) { //keywordsAndLinks[key].keywords is the array of keywords for key (ds, ml, ai) //keywordsAndLinks[key].keywords[i] is the keyword and keywordsAndLinks[key].link is the link //keyword and link is sent to searchreplace where it is then replaced using regular expression and replace function articleFilter( keywordsAndLinks[key].keywords[i], keywordsAndLinks[key].link ); } } function cleanLinks() { // (making smal functions is for DRY) this function gets the links and only keeps the first 2 and from the rest removes the anchor tag and replaces it with its text function removeLinks(links) { if (links.length > 1) { for (let i = 2; i < links.length; i++) { links[i].outerHTML = links[i].textContent; } } } //arrays which will contain all the achor tags found with the class (ds-link, ml-link, ailink) in each article inserted using search and replace let dslinks; let mllinks; let ailinks; let nllinks; let deslinks; let tdlinks; let iaslinks; let llinks; let pbplinks; let mlclinks; const content = document.querySelectorAll('article'); //all articles content.forEach((c) => { //to skip the articles with specific ids if (!articleIdsToSkip.includes(c.id)) { //getting all the anchor tags in each article one by one dslinks = document.querySelectorAll(`#${c.id} .entry-content a.ds-link`); mllinks = document.querySelectorAll(`#${c.id} .entry-content a.ml-link`); ailinks = document.querySelectorAll(`#${c.id} .entry-content a.ai-link`); nllinks = document.querySelectorAll(`#${c.id} .entry-content a.ntrl-link`); deslinks = document.querySelectorAll(`#${c.id} .entry-content a.des-link`); tdlinks = document.querySelectorAll(`#${c.id} .entry-content a.td-link`); iaslinks = document.querySelectorAll(`#${c.id} .entry-content a.ias-link`); mlclinks = document.querySelectorAll(`#${c.id} .entry-content a.mlc-link`); llinks = document.querySelectorAll(`#${c.id} .entry-content a.l-link`); pbplinks = document.querySelectorAll(`#${c.id} .entry-content a.pbp-link`); //sending the anchor tags list of each article one by one to remove extra anchor tags removeLinks(dslinks); removeLinks(mllinks); removeLinks(ailinks); removeLinks(nllinks); removeLinks(deslinks); removeLinks(tdlinks); removeLinks(iaslinks); removeLinks(mlclinks); removeLinks(llinks); removeLinks(pbplinks); } }); } //To remove extra achor tags of each category (ds, ml, ai) and only have 2 of each category per article cleanLinks(); */ //Recommended Articles var ctaLinks = [ /* ' ' + '

Subscribe to our AI newsletter!

' + */ '

Take our 85+ lesson From Beginner to Advanced LLM Developer Certification: From choosing a project to deploying a working product this is the most comprehensive and practical LLM course out there!

'+ '

Towards AI has published Building LLMs for Production—our 470+ page guide to mastering LLMs with practical projects and expert insights!

' + '
' + '' + '' + '

Note: Content contains the views of the contributing authors and not Towards AI.
Disclosure: This website may contain sponsored content and affiliate links.

' + 'Discover Your Dream AI Career at Towards AI Jobs' + '

Towards AI has built a jobs board tailored specifically to Machine Learning and Data Science Jobs and Skills. Our software searches for live AI jobs each hour, labels and categorises them and makes them easily searchable. Explore over 10,000 live jobs today with Towards AI Jobs!

' + '
' + '

🔥 Recommended Articles 🔥

' + 'Why Become an LLM Developer? Launching Towards AI’s New One-Stop Conversion Course'+ 'Testing Launchpad.sh: A Container-based GPU Cloud for Inference and Fine-tuning'+ 'The Top 13 AI-Powered CRM Platforms
' + 'Top 11 AI Call Center Software for 2024
' + 'Learn Prompting 101—Prompt Engineering Course
' + 'Explore Leading Cloud Providers for GPU-Powered LLM Training
' + 'Best AI Communities for Artificial Intelligence Enthusiasts
' + 'Best Workstations for Deep Learning
' + 'Best Laptops for Deep Learning
' + 'Best Machine Learning Books
' + 'Machine Learning Algorithms
' + 'Neural Networks Tutorial
' + 'Best Public Datasets for Machine Learning
' + 'Neural Network Types
' + 'NLP Tutorial
' + 'Best Data Science Books
' + 'Monte Carlo Simulation Tutorial
' + 'Recommender System Tutorial
' + 'Linear Algebra for Deep Learning Tutorial
' + 'Google Colab Introduction
' + 'Decision Trees in Machine Learning
' + 'Principal Component Analysis (PCA) Tutorial
' + 'Linear Regression from Zero to Hero
'+ '

', /* + '

Join thousands of data leaders on the AI newsletter. It’s free, we don’t spam, and we never share your email address. Keep up to date with the latest work in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

',*/ ]; var replaceText = { '': '', '': '', '
': '
' + ctaLinks + '
', }; Object.keys(replaceText).forEach((txtorig) => { //txtorig is the key in replacetext object const txtnew = replaceText[txtorig]; //txtnew is the value of the key in replacetext object let entryFooter = document.querySelector('article .entry-footer'); if (document.querySelectorAll('.single-post').length > 0) { //console.log('Article found.'); const text = entryFooter.innerHTML; entryFooter.innerHTML = text.replace(txtorig, txtnew); } else { // console.log('Article not found.'); //removing comment 09/04/24 } }); var css = document.createElement('style'); css.type = 'text/css'; css.innerHTML = '.post-tags { display:none !important } .article-cta a { font-size: 18px; }'; document.body.appendChild(css); //Extra //This function adds some accessibility needs to the site. function addAlly() { // In this function JQuery is replaced with vanilla javascript functions const imgCont = document.querySelector('.uw-imgcont'); imgCont.setAttribute('aria-label', 'AI news, latest developments'); imgCont.title = 'AI news, latest developments'; imgCont.rel = 'noopener'; document.querySelector('.page-mobile-menu-logo a').title = 'Towards AI Home'; document.querySelector('a.social-link').rel = 'noopener'; document.querySelector('a.uw-text').rel = 'noopener'; document.querySelector('a.uw-w-branding').rel = 'noopener'; document.querySelector('.blog h2.heading').innerHTML = 'Publication'; const popupSearch = document.querySelector$('a.btn-open-popup-search'); popupSearch.setAttribute('role', 'button'); popupSearch.title = 'Search'; const searchClose = document.querySelector('a.popup-search-close'); searchClose.setAttribute('role', 'button'); searchClose.title = 'Close search page'; // document // .querySelector('a.btn-open-popup-search') // .setAttribute( // 'href', // 'https://medium.com/towards-artificial-intelligence/search' // ); } // Add external attributes to 302 sticky and editorial links function extLink() { // Sticky 302 links, this fuction opens the link we send to Medium on a new tab and adds a "noopener" rel to them var stickyLinks = document.querySelectorAll('.grid-item.sticky a'); for (var i = 0; i < stickyLinks.length; i++) { /* stickyLinks[i].setAttribute('target', '_blank'); stickyLinks[i].setAttribute('rel', 'noopener'); */ } // Editorial 302 links, same here var editLinks = document.querySelectorAll( '.grid-item.category-editorial a' ); for (var i = 0; i < editLinks.length; i++) { editLinks[i].setAttribute('target', '_blank'); editLinks[i].setAttribute('rel', 'noopener'); } } // Add current year to copyright notices document.getElementById( 'js-current-year' ).textContent = new Date().getFullYear(); // Call functions after page load extLink(); //addAlly(); setTimeout(function() { //addAlly(); //ideally we should only need to run it once ↑ }, 5000); }; function closeCookieDialog (){ document.getElementById("cookie-consent").style.display = "none"; return false; } setTimeout ( function () { closeCookieDialog(); }, 15000); console.log(`%c 🚀🚀🚀 ███ █████ ███████ █████████ ███████████ █████████████ ███████████████ ███████ ███████ ███████ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ Towards AI is looking for contributors! │ │ Join us in creating awesome AI content. │ │ Let's build the future of AI together → │ │ https://towardsai.net/contribute │ │ │ └───────────────────────────────────────────────────────────────────┘ `, `background: ; color: #00adff; font-size: large`); //Remove latest category across site document.querySelectorAll('a[rel="category tag"]').forEach(function(el) { if (el.textContent.trim() === 'Latest') { // Remove the two consecutive spaces (  ) if (el.nextSibling && el.nextSibling.nodeValue.includes('\u00A0\u00A0')) { el.nextSibling.nodeValue = ''; // Remove the spaces } el.style.display = 'none'; // Hide the element } }); // Add cross-domain measurement, anonymize IPs 'use strict'; //var ga = gtag; ga('config', 'G-9D3HKKFV1Q', 'auto', { /*'allowLinker': true,*/ 'anonymize_ip': true/*, 'linker': { 'domains': [ 'medium.com/towards-artificial-intelligence', 'datasets.towardsai.net', 'rss.towardsai.net', 'feed.towardsai.net', 'contribute.towardsai.net', 'members.towardsai.net', 'pub.towardsai.net', 'news.towardsai.net' ] } */ }); ga('send', 'pageview'); -->