Spaces:
Sleeping
Sleeping
Upload 6 files
Browse files- few_shot.py +44 -0
- llm_helper.py +15 -0
- main.py +42 -0
- post_generator.py +51 -0
- preprocess.py +86 -0
- raw_posts.json +66 -0
few_shot.py
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import json
|
3 |
+
|
4 |
+
|
5 |
+
class FewShotPosts:
|
6 |
+
def __init__(self, file_path="data/processed_posts.json"):
|
7 |
+
self.df = None
|
8 |
+
self.unique_tags = None
|
9 |
+
self.load_posts(file_path)
|
10 |
+
|
11 |
+
def load_posts(self, file_path):
|
12 |
+
with open(file_path, encoding="utf-8") as f:
|
13 |
+
posts = json.load(f)
|
14 |
+
self.df = pd.json_normalize(posts)
|
15 |
+
self.df['length'] = self.df['line_count'].apply(self.categorize_length)
|
16 |
+
# collect unique tags
|
17 |
+
all_tags = self.df['tags'].apply(lambda x: x).sum()
|
18 |
+
self.unique_tags = list(set(all_tags))
|
19 |
+
|
20 |
+
def get_filtered_posts(self, length, language, tag):
|
21 |
+
df_filtered = self.df[
|
22 |
+
(self.df['tags'].apply(lambda tags: tag in tags)) & # Tags contain 'Influencer'
|
23 |
+
(self.df['language'] == language) & # Language is 'English'
|
24 |
+
(self.df['length'] == length) # Line count is less than 5
|
25 |
+
]
|
26 |
+
return df_filtered.to_dict(orient='records')
|
27 |
+
|
28 |
+
def categorize_length(self, line_count):
|
29 |
+
if line_count < 5:
|
30 |
+
return "Short"
|
31 |
+
elif 5 <= line_count <= 10:
|
32 |
+
return "Medium"
|
33 |
+
else:
|
34 |
+
return "Long"
|
35 |
+
|
36 |
+
def get_tags(self):
|
37 |
+
return self.unique_tags
|
38 |
+
|
39 |
+
|
40 |
+
if __name__ == "__main__":
|
41 |
+
fs = FewShotPosts()
|
42 |
+
# print(fs.get_tags())
|
43 |
+
posts = fs.get_filtered_posts("Short","English","Economy")
|
44 |
+
print(posts)
|
llm_helper.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_groq import ChatGroq
|
2 |
+
import os
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
load_dotenv()
|
6 |
+
llm = ChatGroq(groq_api_key=os.getenv("GROQ_API_KEY"), model_name="llama-3.3-70b-versatile")
|
7 |
+
|
8 |
+
|
9 |
+
if __name__ == "__main__":
|
10 |
+
response = llm.invoke("Two most important ingredient in samosa are ")
|
11 |
+
print(response.content)
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
|
main.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from few_shot import FewShotPosts
|
3 |
+
from post_generator import generate_post
|
4 |
+
|
5 |
+
|
6 |
+
# Options for length and language
|
7 |
+
length_options = ["Short", "Medium", "Long"]
|
8 |
+
language_options = ["English", "Hindi","Kannada"]
|
9 |
+
|
10 |
+
|
11 |
+
# Main app layout
|
12 |
+
def main():
|
13 |
+
st.subheader("LinkedIn Post Generator: Codebasics")
|
14 |
+
|
15 |
+
# Create three columns for the dropdowns
|
16 |
+
col1, col2, col3 = st.columns(3)
|
17 |
+
|
18 |
+
fs = FewShotPosts()
|
19 |
+
tags = fs.get_tags()
|
20 |
+
with col1:
|
21 |
+
# Dropdown for Topic (Tags)
|
22 |
+
selected_tag = st.selectbox("Topic", options=tags)
|
23 |
+
|
24 |
+
with col2:
|
25 |
+
# Dropdown for Length
|
26 |
+
selected_length = st.selectbox("Length", options=length_options)
|
27 |
+
|
28 |
+
with col3:
|
29 |
+
# Dropdown for Language
|
30 |
+
selected_language = st.selectbox("Language", options=language_options)
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
# Generate Button
|
35 |
+
if st.button("Generate"):
|
36 |
+
post = generate_post(selected_length, selected_language, selected_tag)
|
37 |
+
st.write(post)
|
38 |
+
|
39 |
+
|
40 |
+
# Run the app
|
41 |
+
if __name__ == "__main__":
|
42 |
+
main()
|
post_generator.py
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llm_helper import llm
|
2 |
+
from few_shot import FewShotPosts
|
3 |
+
|
4 |
+
few_shot = FewShotPosts()
|
5 |
+
|
6 |
+
|
7 |
+
def get_length_str(length):
|
8 |
+
if length == "Short":
|
9 |
+
return "1 to 5 lines"
|
10 |
+
if length == "Medium":
|
11 |
+
return "6 to 10 lines"
|
12 |
+
if length == "Long":
|
13 |
+
return "11 to 15 lines"
|
14 |
+
|
15 |
+
|
16 |
+
def generate_post(length, language, tag):
|
17 |
+
prompt = get_prompt(length, language, tag)
|
18 |
+
response = llm.invoke(prompt)
|
19 |
+
return response.content
|
20 |
+
|
21 |
+
|
22 |
+
def get_prompt(length, language, tag):
|
23 |
+
length_str = get_length_str(length)
|
24 |
+
|
25 |
+
prompt = f'''
|
26 |
+
Generate a LinkedIn post using the below information. No preamble.
|
27 |
+
|
28 |
+
1) Topic: {tag}
|
29 |
+
2) Length: {length_str}
|
30 |
+
3) Language: {language}
|
31 |
+
The script for the generated post should always be English.
|
32 |
+
'''
|
33 |
+
# prompt = prompt.format(post_topic=tag, post_length=length_str, post_language=language)
|
34 |
+
|
35 |
+
examples = few_shot.get_filtered_posts(length, language, tag)
|
36 |
+
|
37 |
+
if len(examples) > 0:
|
38 |
+
prompt += "4) Use the writing style as per the following examples."
|
39 |
+
|
40 |
+
for i, post in enumerate(examples):
|
41 |
+
post_text = post['text_blocks']
|
42 |
+
prompt += f'\n\n Example {i+1}: \n\n {post_text}'
|
43 |
+
|
44 |
+
if i == 1: # Use max two samples
|
45 |
+
break
|
46 |
+
|
47 |
+
return prompt
|
48 |
+
|
49 |
+
|
50 |
+
if __name__ == "__main__":
|
51 |
+
print(generate_post("Medium", "English", "Economy"))
|
preprocess.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from llm_helper import llm
|
3 |
+
from langchain_core.prompts import PromptTemplate
|
4 |
+
from langchain_core.output_parsers import JsonOutputParser
|
5 |
+
from langchain_core.exceptions import OutputParserException
|
6 |
+
|
7 |
+
|
8 |
+
def process_posts(raw_file_path, processed_file_path=None):
|
9 |
+
with open(raw_file_path, encoding='utf-8') as file:
|
10 |
+
posts = json.load(file)
|
11 |
+
enriched_posts = []
|
12 |
+
for post in posts:
|
13 |
+
metadata = extract_metadata(post['text_blocks'])
|
14 |
+
post_with_metadata = post | metadata
|
15 |
+
enriched_posts.append(post_with_metadata)
|
16 |
+
|
17 |
+
unified_tags = get_unified_tags(enriched_posts)
|
18 |
+
for post in enriched_posts:
|
19 |
+
current_tags = post['tags']
|
20 |
+
new_tags = {unified_tags[tag] for tag in current_tags}
|
21 |
+
post['tags'] = list(new_tags)
|
22 |
+
|
23 |
+
with open(processed_file_path, encoding='utf-8', mode="w") as outfile:
|
24 |
+
json.dump(enriched_posts, outfile, indent=4)
|
25 |
+
|
26 |
+
|
27 |
+
def extract_metadata(post):
|
28 |
+
template = '''
|
29 |
+
You are given a LinkedIn post. You need to extract number of lines, language of the post and tags.
|
30 |
+
1. Return a valid JSON. No preamble.
|
31 |
+
2. JSON object should have exactly three keys: line_count, language and tags.
|
32 |
+
3. tags is an array of text tags. Extract maximum two tags.
|
33 |
+
4. Language should be English, Kannada and Hindi
|
34 |
+
|
35 |
+
Here is the actual post on which you need to perform this task:
|
36 |
+
{post}
|
37 |
+
'''
|
38 |
+
|
39 |
+
pt = PromptTemplate.from_template(template)
|
40 |
+
chain = pt | llm
|
41 |
+
response = chain.invoke(input={"post": post})
|
42 |
+
|
43 |
+
try:
|
44 |
+
json_parser = JsonOutputParser()
|
45 |
+
res = json_parser.parse(response.content)
|
46 |
+
except OutputParserException:
|
47 |
+
raise OutputParserException("Context too big. Unable to parse jobs.")
|
48 |
+
return res
|
49 |
+
|
50 |
+
|
51 |
+
def get_unified_tags(posts_with_metadata):
|
52 |
+
unique_tags = set()
|
53 |
+
# Loop through each post and extract the tags
|
54 |
+
for post in posts_with_metadata:
|
55 |
+
unique_tags.update(post['tags']) # Add the tags to the set
|
56 |
+
|
57 |
+
unique_tags_list = ','.join(unique_tags)
|
58 |
+
|
59 |
+
template = '''I will give you a list of tags. You need to unify tags with the following requirements,
|
60 |
+
1. Tags are unified and merged to create a shorter list.
|
61 |
+
Example 1: "Jobseekers", "Job Hunting" can be all merged into a single tag "Job Search".
|
62 |
+
Example 2: "Motivation", "Inspiration", "Drive" can be mapped to "Motivation"
|
63 |
+
Example 3: "Personal Growth", "Personal Development", "Self Improvement" can be mapped to "Self Improvement"
|
64 |
+
Example 4: "Scam Alert", "Job Scam" etc. can be mapped to "Scams"
|
65 |
+
Example 5: "Finance", "economics", "currency" etc., can be mapped to "Financial literacy"
|
66 |
+
2. Each tag should be follow title case convention. example: "Motivation", "Job Search"
|
67 |
+
3. Output should be a JSON object, No preamble
|
68 |
+
3. Output should have mapping of original tag and the unified tag.
|
69 |
+
For example: {{"Jobseekers": "Job Search", "Job Hunting": "Job Search", "Motivation": "Motivation}}
|
70 |
+
|
71 |
+
Here is the list of tags:
|
72 |
+
{tags}
|
73 |
+
'''
|
74 |
+
pt = PromptTemplate.from_template(template)
|
75 |
+
chain = pt | llm
|
76 |
+
response = chain.invoke(input={"tags": str(unique_tags_list)})
|
77 |
+
try:
|
78 |
+
json_parser = JsonOutputParser()
|
79 |
+
res = json_parser.parse(response.content)
|
80 |
+
except OutputParserException:
|
81 |
+
raise OutputParserException("Context too big. Unable to parse jobs.")
|
82 |
+
return res
|
83 |
+
|
84 |
+
|
85 |
+
if __name__ == "__main__":
|
86 |
+
process_posts("data/raw_posts.json", "data/processed_posts.json")
|
raw_posts.json
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"text_blocks": "The value of 1 Crore (assuming 7% inflation).\n10 years from now = 50 Lakhs\n15 years from now = 36 Lakhs\n20 years from now = 25 Lakhs",
|
4 |
+
"tags": ["Inflation", "Finance"]
|
5 |
+
},
|
6 |
+
{
|
7 |
+
"text_blocks": "Inflation Effect.\nThe buying power of money gets killed with time due to inflation.\nIn simple words, things become expensive over time.",
|
8 |
+
"tags": ["Inflation", "Economic Principles"]
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"text_blocks": "Why does inflation exist?\nWhy should we have inflation in the first place? Why can't we solve inflation permanently?\nModern monetary theorists argue that without inflation, people will save enough money and then stop working.\nIf people don't work, how will the world grow?\nOne way to incentivize people to work is by reducing the buying power of money each year.",
|
12 |
+
"tags": ["Inflation", "Economic Theory"]
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"text_blocks": "How does inflation work?\nPrinting more money each year decreases the buying power of money.\nSince 2018, the average rate of money printing worldwide has been around 8%.",
|
16 |
+
"tags": ["Economics", "Money Supply"]
|
17 |
+
},
|
18 |
+
{
|
19 |
+
"text_blocks": "Building Wealth.\nA SIP of 500 might grow to 123 Crores after 213 years, but its buying power will be significantly lower.\nThe only sustainable way to build wealth is to beat inflation through nuanced investing.",
|
20 |
+
"tags": ["Wealth", "Investing"]
|
21 |
+
},
|
22 |
+
{
|
23 |
+
"text_blocks": "Childhood Inspiration.\nI used to read the work of Ray Dalio.\nHe was a Hedge Fund manager, so I learned what a Hedge Fund does and wanted to run my own fund.",
|
24 |
+
"tags": ["Inspiration", "Ray Dalio"]
|
25 |
+
},
|
26 |
+
{
|
27 |
+
"text_blocks": "Challenges.\nI had no mentors growing up.\nDid not have a rich dad.\nMy parents did their best to provide a good education, and I deeply appreciate that.",
|
28 |
+
"tags": ["Challenges", "Education"]
|
29 |
+
},
|
30 |
+
{
|
31 |
+
"text_blocks": "Journey.\nAced most exams I took.\nHustled and got jobs at top corporate firms.\nWorked 14-15 hours a day to progress.\nQuit corporate and built a YouTube channel.\nBuilt a few firms along the way.\nInvested significant capital in public and private markets.",
|
32 |
+
"tags": ["Career", "Entrepreneurship"]
|
33 |
+
},
|
34 |
+
{
|
35 |
+
"text_blocks": "Current Status.\nNow, I run a small fund and get to live my dream.",
|
36 |
+
"tags": ["Career", "Investing"]
|
37 |
+
},
|
38 |
+
{
|
39 |
+
"text_blocks": "Comparisons.\nKids from rich families run Hedge Funds, PE Funds, and family offices in Singapore or Dubai.\nThey can get a meeting with a Billionaire with just one phone call.\nI can't compete with them, and honestly, I don’t need to.\nLife is not always a competition. Life is about progress.",
|
40 |
+
"tags": ["Comparisons", "Perspective"]
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"text_blocks": "Gratitude.\nLooking back at where I started and the progress I have made, I am happy.\nI am happy being small, useful, and living a life created through hard work, luck, and the blessings of others.\nAnd for that, I am thankful.",
|
44 |
+
"tags": ["Gratitude", "Perspective"]
|
45 |
+
},
|
46 |
+
{
|
47 |
+
"text_blocks": "Dealing with Criticism.\nEven if you give 100% of your wealth to charity, 5% of people will still criticize you.\nNo matter what you do, there will always be naysayers.",
|
48 |
+
"tags": ["Criticism", "Perspective"]
|
49 |
+
},
|
50 |
+
{
|
51 |
+
"text_blocks": "Why Negativity Exists.\nThe internet allows people to say things online that they wouldn't have the guts to say in person.",
|
52 |
+
"tags": ["Negativity", "Internet"]
|
53 |
+
},
|
54 |
+
{
|
55 |
+
"text_blocks": "The Art of Not Giving a F***.\nIt preserves your confidence.\nIt keeps your mental health in check.",
|
56 |
+
"tags": ["Mental Health", "Confidence"]
|
57 |
+
},
|
58 |
+
{
|
59 |
+
"text_blocks": "Tips for Not Caring.\nTake accountability. You are responsible for everything (good or bad) that happens to you, not your friends or family.\nGrow each day. Become a self-learning machine. If your goal is to learn, grow, and share, you will focus on things that matter.\nUnderstand that you are human and will make mistakes. Make a few and move on—that's life.",
|
60 |
+
"tags": ["Self-Improvement", "Mental Health"]
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"text_blocks": "Final Thought.\nLife is about building great stories.\nIf you focus too much on your boss’s feedback, online trolls, or negativity, you will get distracted from building YOUR great story.",
|
64 |
+
"tags": ["Life Lessons", "Stories"]
|
65 |
+
}
|
66 |
+
]
|