Prudvireddy commited on
Commit
595c6a8
·
verified ·
1 Parent(s): dabdb84

Upload 5 files

Browse files
Files changed (5) hide show
  1. agents.py +82 -0
  2. requirements.txt +7 -0
  3. st_app.py +64 -0
  4. tools.py +125 -0
  5. utils.py +102 -0
agents.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_openai import ChatOpenAI
2
+ from langchain.schema import HumanMessage, SystemMessage
3
+
4
+ def web_summarizer_company(scraped_data):
5
+
6
+ AI71_BASE_URL = "https://api.ai71.ai/v1/"
7
+ AI71_API_KEY = 'ai71-api-f65e97e6-af86-4de9-a667-dc61c1ef8c75'
8
+
9
+ llm = ChatOpenAI(
10
+ model="tiiuae/falcon-180b-chat",
11
+ api_key=AI71_API_KEY,
12
+ base_url=AI71_BASE_URL,
13
+ # streaming=True,
14
+ )
15
+
16
+ summary = llm.invoke(
17
+ [
18
+ SystemMessage(content="You are a Web Data Summarizer. you are skilled at summarizing company webpages into short summaries. "),
19
+ HumanMessage(content=f"provide a neet summary of the company. Do not add up things. \n\n**Scraped Data:** \n\n{scraped_data}"),
20
+ ]
21
+ )
22
+ return summary
23
+
24
+ def web_summarizer_person(scraped_data):
25
+
26
+ AI71_BASE_URL = "https://api.ai71.ai/v1/"
27
+ AI71_API_KEY = 'ai71-api-f65e97e6-af86-4de9-a667-dc61c1ef8c75'
28
+
29
+ llm = ChatOpenAI(
30
+ model="tiiuae/falcon-180b-chat",
31
+ api_key=AI71_API_KEY,
32
+ base_url=AI71_BASE_URL,
33
+ # streaming=True,
34
+ )
35
+
36
+ summary = llm.invoke(
37
+ [
38
+ SystemMessage(content="You are a Web Data Summarizer. you are skilled at summarizing complex webpages into short summaries. "),
39
+ HumanMessage(content=f"provide a neet summary of the youself. Do not add up things. \n\n**Scraped Data from your portfolio:** \n\n{scraped_data}"),
40
+ ]
41
+ )
42
+ return summary
43
+
44
+ def person_linkedin_agent(topic, summary, mood):
45
+
46
+ AI71_BASE_URL = "https://api.ai71.ai/v1/"
47
+ AI71_API_KEY = 'ai71-api-f65e97e6-af86-4de9-a667-dc61c1ef8c75'
48
+
49
+ llm = ChatOpenAI(
50
+ model="tiiuae/falcon-180b-chat",
51
+ api_key=AI71_API_KEY,
52
+ base_url=AI71_BASE_URL,
53
+ # streaming=True,
54
+ )
55
+
56
+ blog = llm.invoke(
57
+ [
58
+ SystemMessage(content=f"Your details are given below: \n\n{summary}"),
59
+ HumanMessage(content=f"Write a LinkedIn post on the topic: {topic}. Mention your details in the post. Add symbols and emojis to make the post attractive. "),
60
+ ]
61
+ )
62
+ return blog
63
+
64
+ def company_linkedin_agent(topic, summary, mood):
65
+
66
+ AI71_BASE_URL = "https://api.ai71.ai/v1/"
67
+ AI71_API_KEY = 'ai71-api-f65e97e6-af86-4de9-a667-dc61c1ef8c75'
68
+
69
+ llm = ChatOpenAI(
70
+ model="tiiuae/falcon-180b-chat",
71
+ api_key=AI71_API_KEY,
72
+ base_url=AI71_BASE_URL,
73
+ # streaming=True,
74
+ )
75
+
76
+ blog = llm.invoke(
77
+ [
78
+ SystemMessage(content=f"You are a content Writer. You write content in {mood} way. You also add symbols, emojis to make the content attractive."),
79
+ HumanMessage(content=f"Write a LinkedIn post on the topic: {topic}.\n\nThe post is for the company mentioned below.\n\n{summary}"),
80
+ ]
81
+ )
82
+ return blog
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ crewai-tools
2
+ langchain
3
+ requests
4
+ json
5
+ Flask==2.2.2
6
+ markupsafe==2.1.2
7
+ langchain-openai
st_app.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from agents import web_summarizer_company, web_summarizer_person, company_linkedin_agent, person_linkedin_agent
3
+ from tools import scrape_website, post_on_linkedin, replace_i_with_you
4
+
5
+ def main():
6
+ st.title('LinkedIn Post Generator')
7
+
8
+ with st.form(key='linkedin_form'):
9
+ topic = st.text_input('Topic')
10
+ url = st.text_input('Website URL')
11
+ mood = st.text_input('Mood')
12
+ post_company = st.checkbox('For Company')
13
+
14
+ generate_button = st.form_submit_button(label='Generate Post')
15
+
16
+ if generate_button:
17
+ if url:
18
+
19
+ scraped_data = scrape_website(url)
20
+
21
+ if post_company:
22
+ summary = web_summarizer_company(scraped_data)
23
+ else:
24
+ summary = web_summarizer_person(scraped_data)
25
+ summary = replace_i_with_you(summary.content)
26
+ print(summary)
27
+
28
+ if post_company:
29
+ post_content = company_linkedin_agent(topic, summary, mood)
30
+ else:
31
+ post_content = person_linkedin_agent(topic, summary, mood)
32
+
33
+ print(post_content.content)
34
+ post_content = post_content.content
35
+
36
+ if post_content.endswith(':'):
37
+ post_content = post_content[:-5]
38
+
39
+ st.session_state.post_content = post_content
40
+ st.session_state.post_generated = True
41
+
42
+ st.markdown(f"**Generated Post Content:**\n\n{st.session_state.post_content}")
43
+
44
+ # Text area for reviewing generated content
45
+ # st.text_area('Post Content (for review)', st.session_state.post_content, height=200)
46
+
47
+ else:
48
+ st.error('Please provide a URL.')
49
+
50
+ # Button to post on LinkedIn outside the form
51
+ if st.session_state.get('post_generated'):
52
+ post_linkedin = st.checkbox('Post on LinkedIn')
53
+
54
+ if post_linkedin:
55
+ token = st.text_input('LinkedIn Token', type='password')
56
+ post_button = st.button('Post')
57
+ if post_button:
58
+ image_path = None
59
+ post_on_linkedin(token, 'linkedin post', st.session_state.post_content, image_path)
60
+ st.success('Post has been successfully published on LinkedIn!')
61
+ st.session_state.post_generated = False # Reset state after posting
62
+
63
+ if __name__ == "__main__":
64
+ main()
tools.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from crewai_tools import ScrapeWebsiteTool
2
+ from langchain.tools import tool
3
+ import requests
4
+ import json
5
+
6
+ def generate_image():
7
+ pass
8
+
9
+ def replace_i_with_you(text):
10
+ # Replace different forms of 'I' with 'you'
11
+ text = text.replace(' I ', ' you ')
12
+ text = text.replace(' I.', ' you.')
13
+ text = text.replace(' I,', ' you,')
14
+ text = text.replace(' I\'m ', ' you\'re ')
15
+ text = text.replace(' I\'m', ' you\'re')
16
+ text = text.replace(' I am ', ' you are ')
17
+ text = text.replace(' I am', ' you are')
18
+
19
+ return text
20
+
21
+ def scrape_website(website_url):
22
+ """Scrapes all the information from the given website.
23
+ Args:
24
+ website_url: A url of a company website.
25
+ Returns:
26
+ Scraped information from the given website.
27
+ """
28
+ scrapper = ScrapeWebsiteTool()
29
+ data = scrapper.run(website_url=website_url)
30
+ print(data)
31
+ if not data =='':
32
+ return data
33
+ return 'unable to scrape data'
34
+
35
+
36
+ def escape_text(text):
37
+ chars = ["\\", "|", "{", "}", "@", "[", "]", "(", ")", "<", ">", "#", "*", "_", "~"]
38
+ for char in chars:
39
+ text = text.replace(char, "\\"+char)
40
+ return text
41
+
42
+ def get_urn(token):
43
+ url = 'https://api.linkedin.com/v2/userinfo'
44
+ headers = {
45
+ 'Authorization': f'Bearer {token}'
46
+ }
47
+ response = requests.get(url, headers=headers)
48
+ if response.status_code == 200:
49
+ user_info = response.json()
50
+ return user_info['sub']
51
+ else:
52
+ raise Exception(f'Failed to fetch user info: {response.status_code}, {response.text}')
53
+
54
+ def post_on_linkedin(token, title, text_content, image_path=None):
55
+ """
56
+ Posts an article on LinkedIn with an optional image.
57
+
58
+ Args:
59
+ token: LinkedIn OAuth token.
60
+ title: LinkedIn post title.
61
+ text_content: LinkedIn post content.
62
+ image_path: file path of the image (optional).
63
+ """
64
+ text_content = escape_text(text_content)
65
+ owner = get_urn(token)
66
+
67
+ headers = {
68
+ "LinkedIn-Version": "202401",
69
+ "X-RestLi-Protocol-Version": "2.0.0",
70
+ "Content-Type": "application/json",
71
+ "Authorization": f"Bearer {token}",
72
+ }
73
+
74
+ image_urn = None
75
+ if image_path:
76
+ if image_path.startswith('sandbox'):
77
+ image_path = image_path.split(':')[1]
78
+ image_path = image_path.strip()
79
+
80
+ # Initialize image upload
81
+ init_url = "https://api.linkedin.com/rest/images?action=initializeUpload"
82
+ init_data = json.dumps({"initializeUploadRequest": {"owner": f'urn:li:person:{owner}'}})
83
+ init_response = requests.post(init_url, headers=headers, data=init_data)
84
+ if init_response.status_code != 200:
85
+ raise Exception(f"Failed to initialize upload: {init_response.text}")
86
+
87
+ init_response_data = init_response.json()["value"]
88
+ upload_url = init_response_data["uploadUrl"]
89
+ image_urn = init_response_data["image"]
90
+
91
+ # Upload the file
92
+ with open(image_path, "rb") as f:
93
+ upload_response = requests.post(upload_url, files={"file": f})
94
+ if upload_response.status_code not in [200, 201]:
95
+ raise Exception(f"Failed to upload file: {upload_response.text}")
96
+
97
+ # Create the post
98
+ post_url = "https://api.linkedin.com/rest/posts"
99
+ post_data = {
100
+ "author": f'urn:li:person:{owner}',
101
+ "commentary": text_content,
102
+ "visibility": "PUBLIC",
103
+ "distribution": {
104
+ "feedDistribution": "MAIN_FEED",
105
+ "targetEntities": [],
106
+ "thirdPartyDistributionChannels": [],
107
+ },
108
+ "lifecycleState": "PUBLISHED",
109
+ "isReshareDisabledByAuthor": False,
110
+ }
111
+
112
+ if image_urn:
113
+ post_data["content"] = {
114
+ "media": {
115
+ "title": title,
116
+ "id": image_urn,
117
+ }
118
+ }
119
+
120
+ post_data_json = json.dumps(post_data)
121
+ post_response = requests.post(post_url, headers=headers, data=post_data_json)
122
+ if post_response.status_code in [200, 201]:
123
+ return "LinkedIn post generated and posted to user LinkedIn account successfully!"
124
+ else:
125
+ raise Exception(f"Failed to post article: {post_response.text}")
utils.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+ # import requests
32
+ # from bs4 import BeautifulSoup
33
+ # import os
34
+ # import shutil
35
+ # import re
36
+
37
+ # import google.generativeai as genai
38
+
39
+ # def download_image(img_url, folder):
40
+ # try:
41
+ # response = requests.get(img_url, stream=True)
42
+ # filename = os.path.join(folder, img_url.split("/")[-1])
43
+ # with open(filename, 'wb') as file:
44
+ # for chunk in response.iter_content(1024):
45
+ # file.write(chunk)
46
+ # print(f"Downloaded {filename}")
47
+ # except Exception as e:
48
+ # print(f"Failed to download {img_url}. Reason: {e}")
49
+
50
+ # def is_logo(img_url):
51
+ # logo_keywords = ['logo', 'brand', 'icon', 'favicon']
52
+ # return any(keyword in img_url.lower() for keyword in logo_keywords)
53
+
54
+ # def extract_images(url, folder):
55
+ # if os.path.exists(folder):
56
+ # shutil.rmtree(folder)
57
+ # os.makedirs(folder)
58
+
59
+ # response = requests.get(url)
60
+ # soup = BeautifulSoup(response.text, 'html.parser')
61
+
62
+ # images = soup.find_all('img')
63
+ # img_urls = [img['src'] for img in images if 'src' in img.attrs]
64
+
65
+ # for img_url in img_urls:
66
+ # if img_url.startswith('http'):
67
+ # if not is_logo(img_url):
68
+ # download_image(img_url, folder)
69
+ # else:
70
+ # img_url = requests.compat.urljoin(url, img_url)
71
+ # if not is_logo(img_url):
72
+ # download_image(img_url, folder)
73
+
74
+
75
+ # def process_script(script):
76
+ # """Used to process the script into dictionary format"""
77
+ # dict = {}
78
+ # title_matches = re.findall(r'<title>(.*?)</title>', script, re.DOTALL)
79
+ # description_matches = re.findall(r'<description>(.*?)</description>', script, re.DOTALL)
80
+ # dict['title'] = title_matches[0] if title_matches else "No title found"
81
+ # dict['description'] = description_matches[0] if description_matches else "No description found"
82
+ # return dict
83
+
84
+ # def analyse_images(url):
85
+ # imgs_dicts = []
86
+
87
+ # genai.configure(api_key='AIzaSyBKo19PtvV9oSMRr4R1wJUueyWOL4n5e5c')
88
+
89
+ # model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest")
90
+
91
+ # files = [ os.path.join('downloaded_images', file) for file in os.listdir('downloaded_images')]
92
+
93
+ # for img in files:
94
+ # sample_file = genai.upload_file(path=img)
95
+ # file = genai.get_file(name=sample_file.name)
96
+ # response = model.generate_content([sample_file, f"short description of the image from the website {url} and give a title for the image with title in <title> tag and description in <description> tag"])
97
+ # img_dict = process_script(response.text)
98
+ # img_dict['img_path'] = img
99
+ # imgs_dicts.append(img_dict)
100
+ # print(img_dict)
101
+
102
+ # return imgs_dicts