├── vault.txt ├── .env ├── requirements.txt ├── README.md ├── raghack.py └── scraped_posts.json /vault.txt: -------------------------------------------------------------------------------- 1 | RAG -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | ANTHROPIC_API_KEY= APIKEY 2 | OPENAI_API_KEY= APIKEY 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | torch 2 | sentence-transformers 3 | openai 4 | anthropic 5 | python-dotenv 6 | PyPDF2 7 | requests 8 | beautifulsoup4 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hacker News AI Search 2 | 3 | ### YouTube Tutorial 4 | [![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/XlTz-TmrLJg/0.jpg)](https://www.youtube.com/watch?v=XlTz-TmrLJg) 5 | 6 | ### Setup 7 | 1. git clone https://github.com/AllAboutAI-YT/hackernews-llm-search.git 8 | 2. cd dir 9 | 3. create venv if needed 10 | 4. pip install -r requirements.txt 11 | 5. SET Your API KEY in .env 12 | 6. Install Ollama if needed (https://ollama.com/download) 13 | 7. Adjust top_k and chunksize if needed 14 | 8. run raghack.py 15 | 16 | ### My YouTube Channel 17 | https://www.youtube.com/c/AllAboutAI 18 | 19 | ### Hacker News 20 | Hacker News is a specialized social news platform that serves the tech community, providing a space for discussion, sharing, and discovery of content relevant to programmers, entrepreneurs, and others in the industry. 21 | https://news.ycombinator.com/ 22 | 23 | ### Sentence Transformer 24 | https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 25 | 26 | ### What is RAG? 27 | RAG is a way to enhance the capabilities of LLMs by combining their powerful language understanding with targeted retrieval of relevant information from external sources often with using embeddings in vector databases, leading to more accurate, trustworthy, and versatile AI-powered applications 28 | 29 | ### What is Ollama? 30 | Ollama is an open-source platform that simplifies the process of running powerful LLMs locally on your own machine, giving users more control and flexibility in their AI projects. https://www.ollama.com 31 | -------------------------------------------------------------------------------- /raghack.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from sentence_transformers import SentenceTransformer, util 3 | import os 4 | from openai import OpenAI 5 | import anthropic 6 | from dotenv import load_dotenv 7 | import json 8 | import PyPDF2 9 | import re 10 | import requests 11 | from bs4 import BeautifulSoup 12 | 13 | load_dotenv() 14 | 15 | def open_file(filepath): 16 | with open(filepath, 'r', encoding='utf-8') as infile: 17 | return infile.read() 18 | 19 | # Anthropic API credentials 20 | anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") 21 | anthropic_client = anthropic.Anthropic(api_key=anthropic_api_key) 22 | 23 | # ANSI escape codes for colors 24 | PINK = '\033[95m' 25 | CYAN = '\033[96m' 26 | YELLOW = '\033[93m' 27 | NEON_GREEN = '\033[92m' 28 | RESET_COLOR = '\033[0m' 29 | 30 | # Configuration for the Ollama API client 31 | client = OpenAI( 32 | base_url='http://localhost:11434/v1', 33 | api_key='mistral' 34 | ) 35 | 36 | def analyse_data(user_input, system_message, vault_embeddings, vault_content, model): 37 | relevant_context = get_relevant_context(user_input, vault_embeddings, vault_content, model) 38 | if relevant_context: 39 | # Convert list to a single string with newlines between items 40 | context_str = "\n".join(relevant_context) 41 | print("Context Pulled from Documents: \n\n" + CYAN + context_str + RESET_COLOR) 42 | else: 43 | print(CYAN + "No relevant context found." + RESET_COLOR) 44 | 45 | # Prepare the user's input by concatenating it with the relevant context 46 | user_input_with_context = user_input 47 | if relevant_context: 48 | user_input_with_context = context_str + "\n\n" + user_input 49 | 50 | response = anthropic_client.messages.create( 51 | model="claude-3-haiku-20240307", 52 | max_tokens=3000, 53 | temperature=0.4, 54 | system=system_message, 55 | messages=[{"role": "user", "content": user_input_with_context}] 56 | ) 57 | dataresponse = response.content[0].text 58 | 59 | return dataresponse 60 | 61 | # Function to get relevant context from the vault based on user input 62 | def get_relevant_context(user_input, vault_embeddings, vault_content, model, top_k=10): 63 | if vault_embeddings.nelement() == 0: # Check if the tensor has any elements 64 | return [] 65 | # Encode the user input 66 | input_embedding = model.encode([user_input]) 67 | # Compute cosine similarity between the input and vault embeddings 68 | cos_scores = util.cos_sim(input_embedding, vault_embeddings)[0] 69 | # Adjust top_k if it's greater than the number of available scores 70 | top_k = min(top_k, len(cos_scores)) 71 | # Sort the scores and get the top-k indices 72 | top_indices = torch.topk(cos_scores, k=top_k)[1].tolist() 73 | # Get the corresponding context from the vault 74 | relevant_context = [vault_content[idx].strip() for idx in top_indices] 75 | return relevant_context 76 | 77 | # Function to interact with the Ollama model 78 | def ollama_chat(user_input, system_message, vault_embeddings, vault_content, model): 79 | # Get relevant context from the vault 80 | relevant_context = get_relevant_context(user_input, vault_embeddings, vault_content, model) 81 | if relevant_context: 82 | # Convert list to a single string with newlines between items 83 | context_str = "\n".join(relevant_context) 84 | print("Context Pulled from Documents: \n\n" + CYAN + context_str + RESET_COLOR) 85 | else: 86 | print(CYAN + "No relevant context found." + RESET_COLOR) 87 | 88 | # Prepare the user's input by concatenating it with the relevant context 89 | user_input_with_context = user_input 90 | if relevant_context: 91 | user_input_with_context = context_str + "\n\n" + user_input 92 | # Create a message history including the system message and the user's input with context 93 | messages = [ 94 | {"role": "system", "content": system_message}, 95 | {"role": "user", "content": user_input_with_context} 96 | ] 97 | # Send the completion request to the Ollama model 98 | response = client.chat.completions.create( 99 | model="mistral", 100 | messages=messages 101 | ) 102 | # Return the content of the response from the model 103 | return response.choices[0].message.content 104 | 105 | # Function to upload a JSON file and append to vault.txt 106 | def upload_jsonfile(file_path): 107 | if file_path: 108 | with open(file_path, 'r', encoding="utf-8") as json_file: 109 | data = json.load(json_file) 110 | 111 | # Flatten the JSON data into a single string 112 | text = json.dumps(data, ensure_ascii=False) 113 | 114 | # Normalize whitespace and clean up text 115 | text = re.sub(r'\s+', ' ', text).strip() 116 | 117 | # Split text into chunks by sentences, respecting a maximum chunk size 118 | sentences = re.split(r'(?<=[.!?]) +', text) # split on spaces following sentence-ending punctuation 119 | chunks = [] 120 | current_chunk = "" 121 | for sentence in sentences: 122 | # Check if the current sentence plus the current chunk exceeds the limit 123 | if len(current_chunk) + len(sentence) + 1 < 1000: # +1 for the space 124 | current_chunk += (sentence + " ").strip() 125 | else: 126 | # When the chunk exceeds 1000 characters, store it and start a new one 127 | chunks.append(current_chunk) 128 | current_chunk = sentence + " " 129 | if current_chunk: # Don't forget the last chunk! 130 | chunks.append(current_chunk) 131 | with open("vault.txt", "a", encoding="utf-8") as vault_file: 132 | for chunk in chunks: 133 | # Write each chunk to its own line 134 | vault_file.write(chunk.strip() + "\n\n") # Two newlines to separate chunks 135 | print(f"JSON file content appended to vault.txt with each chunk on a separate line.") 136 | 137 | def scrape_hacker_news(num_pages): 138 | scraped_posts = [] 139 | 140 | for page in range(1, num_pages + 1): 141 | url = f"https://news.ycombinator.com/news?p={page}" 142 | response = requests.get(url) 143 | soup = BeautifulSoup(response.content, "html.parser") 144 | post_rows = soup.find_all("tr", class_="athing") 145 | 146 | for row in post_rows: 147 | title_element = row.find("span", class_="titleline") 148 | title = title_element.text.strip() 149 | link = title_element.find("a")["href"] 150 | 151 | post_id = row["id"] 152 | comments_url = f"https://news.ycombinator.com/item?id={post_id}" 153 | comments_response = requests.get(comments_url) 154 | comments_soup = BeautifulSoup(comments_response.content, "html.parser") 155 | 156 | comments = comments_soup.find_all("div", class_="comment") 157 | comment_texts = [comment.find("span", class_="commtext").text.strip() 158 | for comment in comments 159 | if comment.find("span", class_="commtext") is not None] 160 | 161 | post_info = { 162 | "Title": title, 163 | "Link": link, 164 | "Comments": comment_texts 165 | } 166 | 167 | scraped_posts.append(post_info) 168 | 169 | return scraped_posts 170 | 171 | def main(): 172 | # Ask how many pages to scrape 173 | num_pages = int(input(NEON_GREEN + "Enter the number of pages to scrape from Hacker News: " + RESET_COLOR)) 174 | 175 | # Scrape the pages using scrape_hacker_news 176 | scraped_data = scrape_hacker_news(num_pages) 177 | 178 | # Save the scraped posts as a JSON file 179 | with open("scraped_posts.json", "w") as file: 180 | json.dump(scraped_data, file, indent=4) 181 | print("Scraped posts saved to scraped_posts.json") 182 | 183 | # Upload the scraped JSON file to vault.txt 184 | upload_jsonfile("scraped_posts.json") 185 | 186 | # Load the model and vault content 187 | model = SentenceTransformer("all-MiniLM-L6-v2") 188 | vault_content = [] 189 | if os.path.exists("vault.txt"): 190 | with open("vault.txt", "r", encoding='utf-8') as vault_file: 191 | vault_content = vault_file.readlines() 192 | vault_embeddings = model.encode(vault_content) if vault_content else [] 193 | 194 | # Convert to tensor and print embeddings 195 | vault_embeddings_tensor = torch.tensor(vault_embeddings) 196 | print("Embeddings for each line in the vault:") 197 | print(vault_embeddings_tensor) 198 | 199 | while True: 200 | # User input 201 | user_input = input(YELLOW + "Ask a question about your documents (or type 'exit' to quit): " + RESET_COLOR) 202 | 203 | if user_input.lower() == 'exit': 204 | break 205 | 206 | system_message = "You are a helpful assistant that is an expert at extracting the most useful information to the USER's Question" 207 | response = analyse_data(user_input, system_message, vault_embeddings_tensor, vault_content, model) 208 | print(NEON_GREEN + "LLM Response: \n\n" + response + RESET_COLOR) 209 | 210 | if __name__ == "__main__": 211 | main() 212 | -------------------------------------------------------------------------------- /scraped_posts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ID": "40062552", 4 | "Title": "Humane AI \u2013 Pico Laser Projection \u2013 $230M AI Twist on an Old Scam (2023) (kguttag.com)", 5 | "Link": "https://kguttag.com/2023/12/06/humane-ai-pico-laser-projection-230m-ai-twist-on-an-old-scam/", 6 | "Comments": [ 7 | "Seems a bit much calling it a scam. That to me implies malicious intent which I don\u2019t think is in place here. Bad/imperfect products happen even to well meaning companies.Must admit I\u2019m surprised by the aggressiveness of it all. It\u2019s almost like an echo chamber where people have decided it\u2019s ok to pile on", 8 | "It\u2019s an unfortunate trend, but it is also an age-old reaction to hubris. Humane made the fatal PR mistake of trying to convince the world they had a revolutionary product that would change everything\u2026 without selling the benefits of the product.That triggers a bunch of memes, from emperor\u2019s new clothes to pride before a fall. Add in a general societal distrust of tech and AI, plus the age-old derision for geeks/nerds, and Humane could not have set themselves up better for fiasco if they had tried.I do think it was all well meaning and earnest, not at all a scam. But their over-the-top marketing for v1 of an experimental tech gadget was really clueless.", 9 | "> Seems a bit much calling it a scam. That to me implies malicious intent which I don\u2019t think is in place here. Bad/imperfect products happen even to well meaning companies.There's no malicious intent in producing glossy promos videos of a device you know a priori does not (and cannot) work, becaue it violates a few laws of physics? I feel like some folks around here have become very innured to false advertising", 10 | "It ain\u2019t pig butchering.", 11 | "Yes, that is bit much but the main point being this projection technology is nowhere novel, I have been playing with pico projectors and modern ones comes with Android OS so it's just a mini projector. However the only thing innovative here is natural voice interaction powered by modern AI but that also seems to be very slow for any practical purpose.", 12 | "Is the hand movement to control what is being projected on your hand as a menu \u201cnowhere novel\u201d?", 13 | "Honest question, is it much different than how VR headsets track hand movements and gesture in VR?", 14 | "From the reviews, it seems different and worse.But it is something novel that requires serious research. Even if the result is disappointing, it is novel enough to not make the it a \u201cscam using old te vc projection\u201d. That was the point of my rhetorical question before.", 15 | "They are not calling this product a scam, but rather noting its similarity to laser projection projects of the past that (obviously) turned out to be scams. A subtle but important distinction.", 16 | "When the content of the writing can't generate revenue, the hate and anger can.", 17 | "I agree with you semantically, but these days I'm less and less concerned with \"intent\" when it comes to scams. It ultimately just revolves down to empty moralism about \"people today,\" and fails to grasp the issue at hand.Like how phone scammers are often themselves trapt in a system beyond their control [1].Or even case in point with this thing. Maybe the owners aren't malicious, but if not, they are clearly somewhat being scammed themselves by AI hype, to the point they are willing to invest so much in the chatbot box, tie their entire business presumably to one current API or another, however bad an idea we know that is.There are just many long chains of debt, confusion, hyperstition that are knotting around us, with no clear source. One person's scam turns into another's \"innovation\" before turning again back into a scam for the end user.If we are really getting ready for the AI future, we need to get used to being wronged and taken advantage of by technically blameless entities, whose intent is logical, capitalist, and at least nominatively \"benevolent.\"The era of morality itself might soon turn to something else! In a world so predetermined and calculated, where there is such advanced science around influencing thought, cybernetics, etc, how does it even make sense anymore? Or at least, how is focusing on something like intent here even satisfying anymore beyond saying \"bad people do bad things\"?1. https://www.propublica.org/article/human-traffickers-force-v...", 18 | "> Must admit I\u2019m surprised by the aggressiveness of it all. It\u2019s almost like an echo chamber where people have decided it\u2019s ok to pile onThis seems to be a really common occurrence recently - I know the internet can be mean, I've been on it since the peak of IRC, but it seems way more intense these days. The moment something is marked as the bad thing, hordes of people absolutely pile onto it out of nowhere.Is this something I've just not noticed, a more people online thing, long term effects of covid (the virus itself and/or the lockdowns), a result of whatever algorithm tweaks Elon has been making, are people just pissed off in general, etc?It feels bizarre how aggro the internet has become!I think psychology might call this Splitting, which honestly seems to describe the business model of social media platforms these days too, so maybe there's a connection there.https://en.wikipedia.org/wiki/Splitting_(psychology)Off topic but using as an example of this: This tweeted photo, showing a pub in the UK that allows dogs, but bans children. Bit edgy, sure, but look at the bloodbath in the replies/quotes! It's absolute chaos!https://twitter.com/hifromkyle/status/1779548610528415809", 19 | "> The moment something is marked as the bad thing, hordes of people absolutely pile onto it out of nowhere.This isn\u2019t \u201cout of nowhere\u201d. Humane and their AI pin have been marketed an d talked an kur all over Internet tech spaces for a very long time. I\u2019ve been seeing talk about the Humane AI pin in these same channels (YouTube, Twitter, tech websites) frequently since they were funded.People have been forming opinions and skepticism for a long time. The key thing that changed is that the product finally transitioned from hypothetical to reality, and suddenly everyone\u2019s thoughts were confirmed all at once.This is nothing like your photo of a pub getting talked about on Twitter for a brief moment. AI and AI hardware have been a hot topic for years and Humane has been pushing marketing materials and demos on social media for a long time.They made themselves the center of the conversation. Now the rubber hits the road and they have to deal with being the center of the conversation without having the substance to back up their big social media push.The real mob mentality is all of the people who are arriving late to this multi-year buildup and trying to scorn the reviewers and critics.", 20 | "It\u2019s plain old mob mentality. It\u2019s been that way since we were hunter-gatherers in the forests.", 21 | "Aye fair point, I guess I've just been noticing it happening more because I noticed it happen and am now tuned to see it - that Baader-Meinhof frequency illusion thing.", 22 | "They have got really positive (relatively) reviews though https://www.youtube.com/watch?v=TitZV6k8zfA \"The Worst Product I've Ever Reviewed... For Now\" at least a different league then the other scams listed.", 23 | "A lot of topic but I find it funny once I set aside the small spelling inconsistencies, that the author's name is Guttag and the founder's name is Bongiorno, which are almost \"good day\" in German or Italian.", 24 | "I take issue with the word \"scam\", but other than, a very well-done rebuttal. It's not just v1 issue, Humane is a product of the most brainless assumptions you can make:a) That a palm-size laser projector could work as a display.b) That awkward hand gestures are a great way to navigate UIc) That voice could work as a primary input.d) That people would be willing to pay $700 and a monthly subscription for a device that barely works.It's at par or even worse than Juicero. The team and its supporters should stop hiding behind \"it's v1\", and \"we were trying to invent a new paradigm.\" The device has to be promising now, not in some imaginary future. And trying to invent shouldn't mean you're going to forgo questioning the basic foundational ideas.", 25 | "Add \"putting an inductive charger against the users skin\" to that. The heat issues aren't going to go away with the form factor they came up with, wireless charging isn't getting any more efficient.", 26 | "People that perform well in corporate jobs, like these founders, often arent at all innovative or good product people. They just excelled at working with others and playing the corporate game", 27 | "Scam is a bit too strong IMHO. But yes it does just appear to be hacking together a bunch of long existing tech into a package that\u2019s not particularly novel in the history of such things.If they\u2019re guilty of anything it\u2019s likely not adequately learning from why all the previous attempts in this space were big flops. That, plus the halo of arrogance that one feels from the marketing materials and presentations, setup a perfect storm for the likely unrecoverable PR dumpster fire they now find themselves in.", 28 | "Ah yes because light rays from lasers are fundamentally better than other light rays.Handheld projectors won't catch on until the next breakthrough in physicshttps://m.youtube.com/watch?v=KbgvSi35n6o love with your heart, use your head for everything else", 29 | "Calling it a \u201cscam\u201d is disingenuous, the product may be a bit crap for a v1 but their intention is to release people from the over-reliance on smartphones which is to be commended", 30 | "If they knew beforehand that the projection won't work as promised then that part qualifies as scam.", 31 | "Hot take: AR via brain-implants will succeed before we get decent small laser projectors.", 32 | "Not a hot take. Even if you had impossibly perfect laser projectors, you do not have anywhere semi decent to project them.", 33 | "I love this take on Humane as a scam reselling the last decade laser projection bullshit with adding AI.And probably poisoning the well for other, simpler and laser-less personal AI devices as a side effect.Btw, you can buy a 60g wearable device whose hardware is prepared for 24/7 microphone listening, has ML accelerator, 24h battery life, and has, for some reason, kept free 16GB of storage that the user can't access and the OS doesn't use.It is called Apple Watch.", 34 | "What do you mean re: storage?I use nearly all of those GBs of storage on mine with synced music and audiobooks for running.", 35 | "For the free space, you can actually sync music on Apple Watch and then connect AirPods to it when exercising so you can avoid taking your phone.", 36 | "Words matter. We should reserve scams for the actual scams.Like we\u2019ve seen with all the shitcoins, rug pulls etc in the crypto space.This is just bad product management in effect.", 37 | "> kept free 16GB of storage that the user can't access and the OS doesn't use.Sounds like it's used for data collection and surveillance.", 38 | "citation needed", 39 | "The real scam is taxation and inflation which we all gladly embrace." 40 | ] 41 | } 42 | ] 43 | } 44 | ] 45 | --------------------------------------------------------------------------------