Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- Dockerfile +7 -0
- agents.py +170 -0
Dockerfile
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
WORKDIR /
|
3 |
+
COPY requirements.txt .
|
4 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
5 |
+
COPY . .
|
6 |
+
EXPOSE 5000
|
7 |
+
CMD ["gunicorn", "--bind", "0.0.0.0:7860", "test2:app"]
|
agents.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_google_genai import GoogleGenerativeAI
|
2 |
+
from langchain_core.prompts import ChatPromptTemplate
|
3 |
+
from langchain.chains import LLMChain
|
4 |
+
|
5 |
+
class SocialMediaAgents:
|
6 |
+
PLATFORM_LIMITS = {
|
7 |
+
"twitter": {"chars": 280, "words": None},
|
8 |
+
"instagram": {"chars": None, "words": 400},
|
9 |
+
"linkedin": {"chars": None, "words": 600},
|
10 |
+
"facebook": {"chars": None, "words": 1000}
|
11 |
+
}
|
12 |
+
|
13 |
+
def __init__(self, api_key: str):
|
14 |
+
"""Initialize the agent with a Google API key."""
|
15 |
+
self.llm = GoogleGenerativeAI(model="gemini-1.5-flash", google_api_key=api_key)
|
16 |
+
|
17 |
+
def _create_chain(self, template: str) -> LLMChain:
|
18 |
+
"""Create an LLM chain with the given prompt template."""
|
19 |
+
prompt = ChatPromptTemplate.from_template(template)
|
20 |
+
return LLMChain(llm=self.llm, prompt=prompt)
|
21 |
+
|
22 |
+
def _enforce_limits(self, text: str, platform: str) -> str:
|
23 |
+
"""Enforce platform-specific character or word limits."""
|
24 |
+
limits = self.PLATFORM_LIMITS[platform.lower()]
|
25 |
+
if limits["chars"] and len(text) > limits["chars"]:
|
26 |
+
return text[:limits["chars"]-3] + "..."
|
27 |
+
if limits["words"]:
|
28 |
+
words = text.split()
|
29 |
+
if len(words) > limits["words"]:
|
30 |
+
return " ".join(words[:limits["words"]]) + "..."
|
31 |
+
return text
|
32 |
+
|
33 |
+
# def twitter_transform(self, title: str, description: str) -> dict:
|
34 |
+
# """Transform content for Twitter."""
|
35 |
+
# link = "https://www.eye-on.ai/podcast-archive"
|
36 |
+
# template = """Transform this into a Twitter post (280 characters max):
|
37 |
+
# - Attention-grabbing message
|
38 |
+
# - 1-2 relevant hashtags
|
39 |
+
# - Essential information only
|
40 |
+
|
41 |
+
# Format output EXACTLY like this:
|
42 |
+
# New Title: [transformed title]
|
43 |
+
# ---
|
44 |
+
# New Description: [transformed description]
|
45 |
+
|
46 |
+
# add this line after descripttion and make link clickable listen to full podcast on {link}
|
47 |
+
|
48 |
+
# Original Content:
|
49 |
+
# Title: {title}
|
50 |
+
# Description: {description}"""
|
51 |
+
# chain = self._create_chain(template)
|
52 |
+
# response = chain.invoke({"title": title, "description": description, "link": link})
|
53 |
+
|
54 |
+
def twitter_transform(self, title: str, description: str,link:str) -> dict:
|
55 |
+
"""Transform content for Twitter with a clickable link and within 280 characters."""
|
56 |
+
template = """
|
57 |
+
Transform this into a Twitter post (max 280 characters total):
|
58 |
+
- Create an attention-grabbing single-line tweet using key info from the title and description
|
59 |
+
- Include 1-2 relevant hashtags
|
60 |
+
- End with this line exactly: Listen to full podcast: {link}
|
61 |
+
- Ensure the ENTIRE result is no more than 280 characters TOTAL (including the link line)
|
62 |
+
- if character more than 280 characters manage limit and exclude description character
|
63 |
+
- Don't short {link} i want full link
|
64 |
+
Return in this format:
|
65 |
+
New Title: [transformed title]
|
66 |
+
---
|
67 |
+
New Description: [tweet content]
|
68 |
+
|
69 |
+
Original Content:
|
70 |
+
Title: {title}
|
71 |
+
Description: {description}
|
72 |
+
"""
|
73 |
+
chain = self._create_chain(template)
|
74 |
+
response = chain.invoke({"title": title, "description": description, "link": link})
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
parts = response['text'].split('---')
|
79 |
+
result = {
|
80 |
+
"new_title": parts[0].replace('New Title:', '').strip(),
|
81 |
+
"new_description": parts[1].replace('New Description:', '').strip()
|
82 |
+
}
|
83 |
+
combined_text = f"{result['new_title']} {result['new_description']}"
|
84 |
+
limited_text = self._enforce_limits(combined_text, "twitter")
|
85 |
+
if len(limited_text) < len(combined_text):
|
86 |
+
result['new_title'] = ""
|
87 |
+
result['new_description'] = limited_text
|
88 |
+
return result
|
89 |
+
|
90 |
+
def instagram_transform(self, title: str, description: str) -> dict:
|
91 |
+
"""Transform content for Instagram."""
|
92 |
+
template = """Transform this into an Instagram post (400 words max):
|
93 |
+
- Catchy title with relevant emojis
|
94 |
+
- Engaging description
|
95 |
+
- 3-5 relevant hashtags
|
96 |
+
|
97 |
+
Format output EXACTLY like this:
|
98 |
+
New Title: [transformed title]
|
99 |
+
---
|
100 |
+
New Description: [transformed description]
|
101 |
+
|
102 |
+
Original Content:
|
103 |
+
Title: {title}
|
104 |
+
Description: {description}"""
|
105 |
+
chain = self._create_chain(template)
|
106 |
+
response = chain.invoke({"title": title, "description": description})
|
107 |
+
parts = response['text'].split('---')
|
108 |
+
result = {
|
109 |
+
"new_title": parts[0].replace('New Title:', '').strip(),
|
110 |
+
"new_description": parts[1].replace('New Description:', '').strip()
|
111 |
+
}
|
112 |
+
result['new_description'] = self._enforce_limits(result['new_description'], "instagram")
|
113 |
+
return result
|
114 |
+
|
115 |
+
def linkedin_transform(self, title: str, description: str,link) -> dict:
|
116 |
+
"""Transform content for LinkedIn."""
|
117 |
+
|
118 |
+
template = """Transform this into a LinkedIn post (600 words max):
|
119 |
+
- Professional title
|
120 |
+
- Detailed description with business insights
|
121 |
+
- 2-3 relevant hashtags
|
122 |
+
- Professional tone
|
123 |
+
- End with this line exactly: Listen to full podcast: {link}
|
124 |
+
- Don't change link format and words.
|
125 |
+
- Ensure the ENTIRE result is no more than 600 words TOTAL (including the link line)
|
126 |
+
- if character more than 600 words manage limit and exclude description character
|
127 |
+
|
128 |
+
Format output EXACTLY like this:
|
129 |
+
New Title: [transformed title]
|
130 |
+
---
|
131 |
+
New Description: [transformed description]
|
132 |
+
|
133 |
+
Original Content:
|
134 |
+
Title: {title}
|
135 |
+
Description: {description}"""
|
136 |
+
chain = self._create_chain(template)
|
137 |
+
response = chain.invoke({"title": title, "description": description, "link": link})
|
138 |
+
parts = response['text'].split('---')
|
139 |
+
result = {
|
140 |
+
"new_title": parts[0].replace('New Title:', '').strip(),
|
141 |
+
"new_description": parts[1].replace('New Description:', '').strip()
|
142 |
+
}
|
143 |
+
result['new_description'] = self._enforce_limits(result['new_description'], "linkedin")
|
144 |
+
return result
|
145 |
+
|
146 |
+
def facebook_transform(self, title: str, description: str) -> dict:
|
147 |
+
"""Transform content for Facebook."""
|
148 |
+
template = """Transform this into a Facebook post (1000 words max):
|
149 |
+
- Engaging title
|
150 |
+
- Conversational description
|
151 |
+
- Call to action for engagement
|
152 |
+
- 1-2 relevant hashtags
|
153 |
+
|
154 |
+
Format output EXACTLY like this:
|
155 |
+
New Title: [transformed title]
|
156 |
+
---
|
157 |
+
New Description: [transformed description]
|
158 |
+
|
159 |
+
Original Content:
|
160 |
+
Title: {title}
|
161 |
+
Description: {description}"""
|
162 |
+
chain = self._create_chain(template)
|
163 |
+
response = chain.invoke({"title": title, "description": description})
|
164 |
+
parts = response['text'].split('---')
|
165 |
+
result = {
|
166 |
+
"new_title": parts[0].replace('New Title:', '').strip(),
|
167 |
+
"new_description": parts[1].replace('New Description:', '').strip()
|
168 |
+
}
|
169 |
+
result['new_description'] = self._enforce_limits(result['new_description'], "facebook")
|
170 |
+
return result
|