2.1.7, no langchain experimental

pull/128/head
Kye 1 year ago
parent 41e5f17115
commit a610ff7443

@ -1,4 +1,4 @@
<!-- Thank you for contributing to Swarms!
Thank you for contributing to Swarms!
Replace this comment with:
- Description: a description of the change,
@ -7,19 +7,23 @@ Replace this comment with:
- Tag maintainer: for a quicker response, tag the relevant maintainer (see below),
- Twitter handle: we announce bigger features on Twitter. If your PR gets announced and you'd like a mention, we'll gladly shout you out!
Please make sure your PR is passing linting and testing before submitting. Run `make format`, `make lint` and `make test` to check this locally.
See contribution guidelines for more information on how to write/run tests, lint, etc:
https://github.com/kyegomez/swarms/blob/master/CONTRIBUTING.md
If you're adding a new integration, please include:
1. a test for the integration, preferably unit tests that do not rely on network access,
2. an example notebook showing its use.
Maintainer responsibilities:
- General / Misc / if you don't know who to tag: kye@apac.ai
- DataLoaders / VectorStores / Retrievers: kye@apac.ai
- Models / Prompts: kye@apac.ai
- Memory: kye@apac.ai
- Agents / Tools / Toolkits: kye@apac.ai
- Tracing / Callbacks: kye@apac.ai
- Async: kye@apac.ai
- swarms.models: kye@apac.ai
- swarms.memory: kye@apac.ai
- swarms.structures: kye@apac.ai
If no one reviews your PR within a few days, feel free to kye@apac.ai
If no one reviews your PR within a few days, feel free to email Kye at kye@apac.ai
See contribution guidelines for more information on how to write/run tests, lint, etc: https://github.com/kyegomez/swarms

@ -14,257 +14,23 @@ Review Agent:
Distribution Agent:
- Social Media posts for the article.
# TODO
- Add shorter and better topic generator prompt
- Optimize writer prompt to create longer and more enjoyeable blogs
- Use Local Models like Storywriter
"""
from swarms.models import OpenAIChat
from termcolor import colored
from swarms.models import OpenAIChat
from swarms.prompts.autoblogen import (
DRAFT_AGENT_SYSTEM_PROMPT,
REVIEW_PROMPT,
SOCIAL_MEDIA_SYSTEM_PROMPT_AGENT,
TOPIC_GENERATOR,
)
import os
TOPIC_GENERATOR = f"""
First search for a list of topics on the web based their relevance to Positive Med's long term vision then rank than based on the goals this month, then output a single headline title for a blog for the next autonomous agent to write the blog, utilize the SOP below to help you strategically select topics. Output a single topic that will be the foundation for a blog.
VISION: Emphasis on exotic healthcare for improved health using Taoism, Ayurveda, and other ancient practices.
GOALS THIS MONTH: Clicks and engagement
Rank the topics on a scale from 0.0 to 1.0 on how likely it is to achieve the goal and then return the single most likely topic to satisfy the goals this month.
########### Standard Operating Procedure for Topic Selection for PositiveMed.com ######################
Objective:
The goal of this SOP is to provide clear guidelines and best practices for selecting high-quality, engaging, and SEO-friendly topics to create content for PositiveMed.com. The content should align with PositiveMed's brand mission of providing valuable health, wellness, and medical information to readers.
Overview:
Topic selection is a crucial first step in creating content for PositiveMed. Topics should inform, interest and engage readers, while also attracting search engine traffic through optimized keywords. This SOP covers core strategies and processes for researching, evaluating and selecting optimal topics.
Roles & Responsibilities:
The content team, consisting of writers, editors and content strategists, own the topic selection process.
The content team is responsible for:
- Monitoring health, medical, wellness trends and current events
- Conducting keyword research
- Assessing site analytics and reader feedback
- Crowdsourcing topic ideas from internal team and external contributors
- Maintaining editorial calendar with upcoming topics
- Pitching and selecting topics for content approval
The editorial team is responsible for:
- Providing final approval on topics based on brand suitability, reader interest, and potential traffic/engagement
- Ensuring selected topics are differentiated and not duplicative of existing content
- Reviewing and updating keyword opportunities tied to topics
Topic Sourcing
A strong content calendar begins with investing time into researching and generating promising topics. Here are key tactics and guidelines for sourcing topics:
Monitor Trends:
- Set Google Alerts for relevant keywords like "health news," "fitness trends," "nutrition research" etc. to receive daily updates.
- Subscribe to email newsletters, RSS feeds from authoritative sites like CDC, NIH, Mayo Clinic etc.
- Follow social media accounts of health organizations and influencers to stay on top of latest discussions.
- Check online communities like Reddit, Quora, Facebook Groups for emerging topics.
- Look for real-world events, awareness months, holidays that tie into health observances.
Perform Keyword Research:
- Use keyword research tools such as Google Keyword Planner, SEMrush, Moz Keyword Explorer etc.
- Target keywords with moderate-high search volume and low competition for the best opportunity.
- Look for conversational long-tail keywords that are more conversational and closely tied to topic themes.
- Ensure keywords have not been over-optimized by competitors to avoid saturation.
- Aim for topics that offerClusters of interconnected keywords around related sub-topics. This allows targeting several keywords with one piece of content.
Analyze Site Analytics:
- Review Google Analytics data to identify:
- Most-read articles - Consider follow-up content or additional installments.
- Highest-traffic landing pages - Expand on topics driving site visitors.
- Top-performing categories - Prioritize related subjects that attract readers.
- Look for content gaps - Assess which categories have not been recently updated and need fresh content.
Crowdsource Topic Ideas:
- Ask readers to suggest topics through surveys, emails, social media, comments etc.
- Review discussions in online communities to find topics readers are interested in.
- Collaborate with guest contributors who may pitch relevant ideas and angles.
- Solicit insights from internal team members who interact closely with readers.
Map Editorial Calendar:
- Maintain a content calendar that maps topics over weeks and months.
- Ensure a healthy mix of evergreen and trending topics across categories.
- Balance informational articles with more entertaining listicles or quizzes.
- Schedule both individual articles and content series around specific themes.
- Revisit calendar routinely to incorporate new topics as they emerge.
Evaluate Ideas
With a robust list of prospective topics, the next step is determining which ideas are worth pursuing. Use these criteria when assessing the merit of topics:
Reader Interest:
- Would the topic pique the curiosity of PositiveMed's target audience?
- Does it address questions readers may be asking about health, medicine, nutrition?
- Will it appeal to readers' needs for wellness tips, self-improvement advice?
- Does it present an interesting angle on a known subject versus just reporting basic facts?
Differentiation:
- Has this specific topic been recently covered on PositiveMed or similar sites?
- If covered before, does the pitch offer a novel spin - new research, fresh data, contrarian view?
- Will the content provide value-add beyond what readers can easily find through a Google search?
Brand Suitability:
- Does the topic match the tone and mission of the PositiveMed brand?
- Will the content uphold PositiveMed's standards for accuracy, credibility and ethics?
- Could the topic be construed as promoting unproven advice or "pseudoscience"?
Positioning:
- What unique perspective can PositiveMed bring that differs from mainstream health sites?
- Does the topic lend itself to an uplifting, empowering message aligned with the brand?
- Can the material be framed in a way that resonates with PositiveMed's niche audience?
Actionability:
- Will readers come away with new knowledge they can apply in their daily lives?
- Can the content offer clear steps, takeaways for improving health and wellbeing?
- Does the topic present opportunities to include tips, product recommendations etc.?
Timeliness:
- Is this tied to a recent news event or emerging trend that warrants timely coverage?
- For evergreen topics, are there new studies, pop culture references etc. that can make it timely?
- Does the angle offer a way to make an old topic feel fresh and relevant?
Competition:
- How saturated is the topic market? Who has top-ranking content on this topic?
- Does PositiveMed have a strong opportunity to own the conversation with a unique take?
- What value can be added versus competitor content on this subject?
Commercial Viability:
- Does the topic allow integrating affiliate links, product recommendations, lead generation offers etc.?
- Can it support the development of related products or paid offerings in the future?
- Will it attract engagement and social shares to increase traffic?
Keyword Integration
With promising topics identified, the next step is integrating keywords into content plans and outlines.
Conduct Keyword Research:
- Identify primary target keyword for topic that has:
- Moderate-to-high search volume
- Low-to-medium competition
- Relevance to topic and PositiveMed's niche
Find Supporting Keywords:
- Build a cluster of 3-5 secondary keywords around topic including:
- Related searches and questions
- Semantically connected words/phrases
- Keyword variations (long tail, alternate wording etc.)
- Stay within minimum monthly search volumes
Map Out Keywords:
- Determine optimal keyword placement for outlined sections e.g.:
- Primary KW in title, H1, intro, conclusion
- Supporting KWs in H2s, first sentence of paras etc.
- Include keywords naturally - no over-optimization
Check Cannibalization:
- Compare suggested keywords against existing content to avoid targeting same terms.
- Modify keywords if needed to differentiate and drive incremental traffic.
Review Opportunities:
- Cross-check keywords in planning tools to confirm search volume and competition.
- Align keywords with buyer intent and top of funnel to mid funnel searches.
- Ensure keywords are entered into analytics to track conversions.
Style and Tone Guidelines
In line with PositiveMed's brand voice, content should adopt an:
Educational yet conversational tone:
- Explain health topics, science and research simply without over-simplifying complex issues.
- Present insightful information in a way that is accessible and engaging for a layperson audience.
Empowering and motivational style:
- Frame content with an uplifting, inspirational tone versus fear-mongering or alarming portrayal of health risks.
- Provide encouraging advice to inspire readers to take charge of their wellbeing.
Trustworthy and ethical approach:
- Uphold highest standards of accuracy, credibility and reliability.
- Cite legitimate sources. Avoid promoting unverified claims or exaggerated benefits.
- Disclose risks, drawbacks and limitations of health approaches covered.
Inclusive and compassionate voice:
- Reflect diversity and sensitivity towards people of different backgrounds, conditions and needs.
- Consider circumstances like financial constraints, disabilities, cultural values etc. that impact health choices.
Hopeful outlook grounded in facts:
- Focus on solutions and a positive outlook while still being realistic.
- Counter misinformation; clarify myths vs facts.
"""
REVIEW_PROMPT = """
You are responsible for refining an article to meet PositiveMeds stringent publication standards.
Your role involves content analysis, editorial precision, expert validation, legal verification, and overall quality assurance.
# ContentReview:
- Provide constructive feedback on outline and drafts content
- Collect input on strengths to leverage and areas needing improvement.
# Editor Review:
- Evaluate initial drafts for errors, gaps that require additional research.
- Provide guidance on better organizing structure and flow.
- Assess tone, voice and brand alignment.
# Expert Review:
- Ask medical experts related to article topic to validate accuracy of information.
- Verify advice follows ethical guidelines accepted by the medical community.
- Request quotes that lend credibility and reinforce key points.
# Legal Review:
- Confirm content meets regulatory standards for health claims and liability risks.
- Address any recommended edits to mitigate brand reputation risk.
# Quality Checklist: Scrutinize final draft against PositiveMed's standards:
- Medical accuracy - error-free facts/statistics, supported claims
- Logical flow - smooth transitions, complementary sections
- Reader value - insightful analysis beyond fluffy content
- Brand alignment - uplifting tone, inclusive messaging
- Strong conclusion - memorable takeaways, relevant next steps/resources for readers
# ARTICLE TO REVIEW:
{{ARTICLE}}
# OUTPUT:
Re-Write the article, taking into account all review instructions and standards
"""
SOCIAL_MEDIA_SYSTEM_PROMPT_AGENT = """
You're the Social Media System Agent. Your job is to create social media posts for the article below.
Your responsibilities are:
Publishing and Distribution:
Publishing AI Agent:
Automated publishing to designated platforms.
Formatting checks for platform compatibility.
Distribution:
Automated sharing to social media channels.
Email distribution to subscriber list.
Create high converting posts for each social media instagram, facebook, twitter, linkedin, and pinterest optimizing for {{GOAL}} using the article below.
Denote the social media's by using the social media name in HTML like tags
<FACEBOOK> POST CONTENT </FACEBOOK>
<TWITTER> POST CONTENT </TWITTER>
<INSTAGRAM> POST CONTENT </INSTAGRAM>
######### ARTICLE #######
{{ARTICLE}}
"""
llm = OpenAIChat(openai_api_key="")
api_key = os.environ["OPENAI_API_KEY"]
llm = OpenAIChat(openai_api_key=api_key)
def get_review_prompt(article):
@ -302,44 +68,6 @@ dashboard = print(
)
)
# Agent that generates blogs
DRAFT_AGENT_SYSTEM_PROMPT = f"""
Write a 5,000+ word long narrative essay on the highest rated topic from a list of topics for positivemed.com,
their vision is: to democratize health wisdom to modern young professionals in a healthy and conversational and friendly manner,
be nice and reference research papers and other data where you pull from.
You don't have a word limit, you can write as you wish.
--------------------------- Your Responsibilities: -----------------------------
Outline Content:
- Organize research into logical sections and subsections for smooth flow.
- Ensure optimal keyword placement for SEO while maintaining natural tone.
- Structure content to focus on most valuable information upfront.
Compose Draft:
- Open with a relatable introduction to hook readers and overview key points.
- Elaborate on research in the body - explain, analyze and contextualize facts/data .
- Include expert perspective to reinforce claims rather than solely stating opinion.
- Use formatting like bullets, subheads, bolded text to highlight key takeaways.
Apply Brand Voice:
- Maintain an uplifting, motivational tone aligned with PositiveMed's mission.
- Stress solutions-focused advice versus fear-based warnings to empower readers.
- Use inclusive language and culturally sensitive medical references.
Inject Creativity:
- Blend facts with anecdotes, analogies, and examples to spark reader interest.
- Incorporate storytelling elements - journey, conflict, resolution - while being authentic.
- Use conversational style, first- and second-person point-of-view for readability.
Check Accuracy:
- Verify all medical statements against legitimate sources like CDC, Mayo Clinic, NIH.
- Scrutinize cited data for relevance and statistical significance.
- Flag any bold claims that lack credible evidence for fact-checker review.
"""
draft_blog = llm(DRAFT_AGENT_SYSTEM_PROMPT)
draft_out = print(

@ -0,0 +1,26 @@
"""
Swarm Flow
Topic selection agent -> draft agent -> review agent -> distribution agent
Topic Selection Agent:
- Generate 10 topics on gaining mental clarity using Taosim and Christian meditation
Draft Agent:
- Write a 100% unique, creative and in human-like style article of a minimum of 5,000 words using headings and sub-headings.
Review Agent:
- Refine the article to meet PositiveMeds stringent publication standards.
Distribution Agent:
- Social Media posts for the article.
# TODO
- Add shorter and better topic generator prompt
- Optimize writer prompt to create longer and more enjoyeable blogs
- Use Local Models like Storywriter
"""
from swarms.models import OpenAIChat
from termcolor import colored

@ -1,5 +1,5 @@
"""
Autonomous swarm that optimizes UI autonomously
GPT4Vision ->> GPT4 ->> UI
GPT4Vision ->> GPT4 ->> UI Code
"""

@ -0,0 +1,5 @@
from swarms.models.openai_chat import ChatOpenAI
model = ChatOpenAI()
print(model("Hello, my name is", 5))

@ -19,6 +19,3 @@ tasks = ["A painting of a dog", "A painting of a cat"]
results = dalle3.process_batch_concurrently(tasks)
# print(results)

@ -1,4 +1,4 @@
from swarms.agents.omni_modal_agent import OmniModalAgent
# from swarms.agents.omni_modal_agent import OmniModalAgent
from swarms.agents.hf_agents import HFAgent
from swarms.agents.message import Message
@ -12,7 +12,7 @@ from swarms.agents.simple_agent import SimpleAgent
"""Agent Infrastructure, models, memory, utils, tools"""
__all__ = [
"OmniModalAgent",
# "OmniModalAgent",
"HFAgent",
"Message",
"AbstractAgent",

@ -2,7 +2,8 @@
from swarms.models.anthropic import Anthropic
from swarms.models.petals import Petals
from swarms.models.mistral import Mistral
from swarms.models.openai_models import OpenAI, AzureOpenAI, OpenAIChat
# from swarms.models.openai_models import OpenAI, AzureOpenAI, OpenAIChat
from swarms.models.zephyr import Zephyr
from swarms.models.biogpt import BioGPT
from swarms.models.huggingface import HuggingfaceLLM
@ -30,9 +31,9 @@ __all__ = [
"Anthropic",
"Petals",
"Mistral",
"OpenAI",
"AzureOpenAI",
"OpenAIChat",
# "OpenAI",
# "AzureOpenAI",
# "OpenAIChat",
"Zephyr",
"Idefics",
"Kosmos",

@ -25,14 +25,14 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def handle_errors(self, function):
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception as error:
logger.error(error)
raise
raise
return wrapper
@ -115,7 +115,7 @@ class Dalle3:
img.save(byte_stream, format=format)
byte_array = byte_stream.getvalue()
return byte_array
@backoff.on_exception(backoff.expo, Exception, max_time=max_time_seconds)
def __call__(self, task: str):
"""
@ -162,7 +162,7 @@ class Dalle3:
img_path = os.path.join(self.save_path, filename)
self.cache[task] = img_path
return img_path
except openai.OpenAIError as error:
# Handling exceptions and printing the errors details
@ -195,7 +195,7 @@ class Dalle3:
full_path = os.path.join(self.save_path, filename)
response = requests.get(img_url)
if response.status_code == 200:
with open(full_path, 'wb') as file:
with open(full_path, "wb") as file:
file.write(response.content)
else:
raise ValueError(f"Failed to download image from {img_url}")
@ -244,9 +244,7 @@ class Dalle3:
print(colored(f"Error running Dalle3: {error.error}", "red"))
raise error
def print_dashboard(
self
):
def print_dashboard(self):
"""Print the Dalle3 dashboard"""
print(
colored(
@ -273,15 +271,11 @@ class Dalle3:
)
)
def process_batch_concurrently(
self,
tasks: List[str],
max_workers: int = 5
):
def process_batch_concurrently(self, tasks: List[str], max_workers: int = 5):
"""
Process a batch of tasks concurrently
Args:
tasks (List[str]): A list of tasks to be processed
max_workers (int): The maximum number of workers to use for the concurrent processing
@ -297,11 +291,9 @@ class Dalle3:
>>> results = dalle3.process_batch_concurrently(tasks)
>>> print(results)
['https://cdn.openai.com/dall-e/encoded/feats/feats_01J9J5ZKJZJY9.png',
"""
with concurrent.futures.ThreadPoolExecutor(
max_workers=max_workers
) as executor:
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_task = {executor.submit(self, task): task for task in tasks}
results = []
for future in concurrent.futures.as_completed(future_to_task):
@ -324,6 +316,7 @@ class Dalle3:
print(colored(f"Error running Dalle3: {error.http_status}", "red"))
print(colored(f"Error running Dalle3: {error.error}", "red"))
raise error
def _generate_uuid(self):
"""Generate a uuid"""
return str(uuid.uuid4())
@ -331,12 +324,12 @@ class Dalle3:
def __repr__(self):
"""Repr method for the Dalle3 class"""
return f"Dalle3(image_url={self.image_url})"
def __str__(self):
"""Str method for the Dalle3 class"""
return f"Dalle3(image_url={self.image_url})"
@backoff.on_exception(backoff.expo, Exception, max_tries=max_retries)
def rate_limited_call(self, task: str):
"""Rate limited call to the Dalle3 API"""
return self.__call__(task)
return self.__call__(task)

@ -0,0 +1,676 @@
"""OpenAI chat wrapper."""
from __future__ import annotations
import logging
import os
import sys
from typing import (
TYPE_CHECKING,
Any,
AsyncIterator,
Callable,
Dict,
Iterator,
List,
Mapping,
Optional,
Sequence,
Tuple,
Type,
Union,
)
from langchain.adapters.openai import convert_dict_to_message, convert_message_to_dict
from langchain.callbacks.manager import (
AsyncCallbackManagerForLLMRun,
CallbackManagerForLLMRun,
)
from langchain.chat_models.base import (
BaseChatModel,
)
from langchain.llms.base import create_base_retry_decorator
from langchain.pydantic_v1 import BaseModel, Field, root_validator
from langchain.schema import ChatGeneration, ChatResult
from langchain.schema.language_model import LanguageModelInput
from langchain.schema.messages import (
AIMessageChunk,
BaseMessage,
BaseMessageChunk,
ChatMessageChunk,
FunctionMessageChunk,
HumanMessageChunk,
SystemMessageChunk,
ToolMessageChunk,
)
from langchain.schema.output import ChatGenerationChunk
from langchain.schema.runnable import Runnable
from langchain.utils import (
get_from_dict_or_env,
get_pydantic_field_names,
)
from langchain.utils.openai import is_openai_v1
if TYPE_CHECKING:
import tiktoken
logger = logging.getLogger(__name__)
def _generate_from_stream(stream: Iterator[ChatGenerationChunk]) -> ChatResult:
generation: Optional[ChatGenerationChunk] = None
for chunk in stream:
if generation is None:
generation = chunk
else:
generation += chunk
assert generation is not None
return ChatResult(generations=[generation])
async def _agenerate_from_stream(
stream: AsyncIterator[ChatGenerationChunk],
) -> ChatResult:
generation: Optional[ChatGenerationChunk] = None
async for chunk in stream:
if generation is None:
generation = chunk
else:
generation += chunk
assert generation is not None
return ChatResult(generations=[generation])
def _import_tiktoken() -> Any:
try:
import tiktoken
except ImportError:
raise ValueError(
"Could not import tiktoken python package. "
"This is needed in order to calculate get_token_ids. "
"Please install it with `pip install tiktoken`."
)
return tiktoken
def _create_retry_decorator(
llm: OpenAIChat,
run_manager: Optional[
Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun]
] = None,
) -> Callable[[Any], Any]:
import openai
errors = [
openai.error.Timeout,
openai.error.APIError,
openai.error.APIConnectionError,
openai.error.RateLimitError,
openai.error.ServiceUnavailableError,
]
return create_base_retry_decorator(
error_types=errors, max_retries=llm.max_retries, run_manager=run_manager
)
async def acompletion_with_retry(
llm: OpenAIChat,
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> Any:
"""Use tenacity to retry the async completion call."""
if is_openai_v1():
return await llm.async_client.create(**kwargs)
retry_decorator = _create_retry_decorator(llm, run_manager=run_manager)
@retry_decorator
async def _completion_with_retry(**kwargs: Any) -> Any:
# Use OpenAI's async api https://github.com/openai/openai-python#async-api
return await llm.client.acreate(**kwargs)
return await _completion_with_retry(**kwargs)
def _convert_delta_to_message_chunk(
_dict: Mapping[str, Any], default_class: Type[BaseMessageChunk]
) -> BaseMessageChunk:
role = _dict.get("role")
content = _dict.get("content") or ""
additional_kwargs: Dict = {}
if _dict.get("function_call"):
function_call = dict(_dict["function_call"])
if "name" in function_call and function_call["name"] is None:
function_call["name"] = ""
additional_kwargs["function_call"] = function_call
if _dict.get("tool_calls"):
additional_kwargs["tool_calls"] = _dict["tool_calls"]
if role == "user" or default_class == HumanMessageChunk:
return HumanMessageChunk(content=content)
elif role == "assistant" or default_class == AIMessageChunk:
return AIMessageChunk(content=content, additional_kwargs=additional_kwargs)
elif role == "system" or default_class == SystemMessageChunk:
return SystemMessageChunk(content=content)
elif role == "function" or default_class == FunctionMessageChunk:
return FunctionMessageChunk(content=content, name=_dict["name"])
elif role == "tool" or default_class == ToolMessageChunk:
return ToolMessageChunk(content=content, tool_call_id=_dict["tool_call_id"])
elif role or default_class == ChatMessageChunk:
return ChatMessageChunk(content=content, role=role)
else:
return default_class(content=content)
class OpenAIChat(BaseChatModel):
"""`OpenAI` Chat large language models API.
To use, you should have the ``openai`` python package installed, and the
environment variable ``OPENAI_API_KEY`` set with your API key.
Any parameters that are valid to be passed to the openai.create call can be passed
in, even if not explicitly saved on this class.
Example:
.. code-block:: python
from swarms.models import ChatOpenAI
openai = ChatOpenAI(model_name="gpt-3.5-turbo")
"""
@property
def lc_secrets(self) -> Dict[str, str]:
return {"openai_api_key": "OPENAI_API_KEY"}
@property
def lc_attributes(self) -> Dict[str, Any]:
attributes: Dict[str, Any] = {}
if self.openai_organization:
attributes["openai_organization"] = self.openai_organization
if self.openai_api_base:
attributes["openai_api_base"] = self.openai_api_base
if self.openai_proxy:
attributes["openai_proxy"] = self.openai_proxy
return attributes
@classmethod
def is_lc_serializable(cls) -> bool:
"""Return whether this model can be serialized by Langchain."""
return True
client: Any = None #: :meta private:
async_client: Any = None #: :meta private:
model_name: str = Field(default="gpt-3.5-turbo", alias="model")
"""Model name to use."""
temperature: float = 0.7
"""What sampling temperature to use."""
model_kwargs: Dict[str, Any] = Field(default_factory=dict)
"""Holds any model parameters valid for `create` call not explicitly specified."""
# When updating this to use a SecretStr
# Check for classes that derive from this class (as some of them
# may assume openai_api_key is a str)
openai_api_key: Optional[str] = Field(default=None, alias="api_key")
"""Automatically inferred from env var `OPENAI_API_KEY` if not provided."""
openai_api_base: Optional[str] = Field(default=None, alias="base_url")
"""Base URL path for API requests, leave blank if not using a proxy or service
emulator."""
openai_organization: Optional[str] = Field(default=None, alias="organization")
"""Automatically inferred from env var `OPENAI_ORG_ID` if not provided."""
# to support explicit proxy for OpenAI
openai_proxy: Optional[str] = None
request_timeout: Union[float, Tuple[float, float], Any, None] = Field(
default=None, alias="timeout"
)
"""Timeout for requests to OpenAI completion API. Can be float, httpx.Timeout or
None."""
max_retries: int = 2
"""Maximum number of retries to make when generating."""
streaming: bool = False
"""Whether to stream the results or not."""
n: int = 1
"""Number of chat completions to generate for each prompt."""
max_tokens: Optional[int] = None
"""Maximum number of tokens to generate."""
tiktoken_model_name: Optional[str] = None
"""The model name to pass to tiktoken when using this class.
Tiktoken is used to count the number of tokens in documents to constrain
them to be under a certain limit. By default, when set to None, this will
be the same as the embedding model name. However, there are some cases
where you may want to use this Embedding class with a model name not
supported by tiktoken. This can include when using Azure embeddings or
when using one of the many model providers that expose an OpenAI-like
API but with different models. In those cases, in order to avoid erroring
when tiktoken is called, you can specify a model name to use here."""
default_headers: Union[Mapping[str, str], None] = None
default_query: Union[Mapping[str, object], None] = None
# Configure a custom httpx client. See the
# [httpx documentation](https://www.python-httpx.org/api/#client) for more details.
http_client: Union[Any, None] = None
"""Optional httpx.Client."""
class Config:
"""Configuration for this pydantic object."""
allow_population_by_field_name = True
@root_validator(pre=True)
def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]:
"""Build extra kwargs from additional params that were passed in."""
all_required_field_names = get_pydantic_field_names(cls)
extra = values.get("model_kwargs", {})
for field_name in list(values):
if field_name in extra:
raise ValueError(f"Found {field_name} supplied twice.")
if field_name not in all_required_field_names:
logger.warning(
f"""WARNING! {field_name} is not default parameter.
{field_name} was transferred to model_kwargs.
Please confirm that {field_name} is what you intended."""
)
extra[field_name] = values.pop(field_name)
invalid_model_kwargs = all_required_field_names.intersection(extra.keys())
if invalid_model_kwargs:
raise ValueError(
f"Parameters {invalid_model_kwargs} should be specified explicitly. "
f"Instead they were passed in as part of `model_kwargs` parameter."
)
values["model_kwargs"] = extra
return values
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate that api key and python package exists in environment."""
if values["n"] < 1:
raise ValueError("n must be at least 1.")
if values["n"] > 1 and values["streaming"]:
raise ValueError("n must be 1 when streaming.")
values["openai_api_key"] = get_from_dict_or_env(
values, "openai_api_key", "OPENAI_API_KEY"
)
# Check OPENAI_ORGANIZATION for backwards compatibility.
values["openai_organization"] = (
values["openai_organization"]
or os.getenv("OPENAI_ORG_ID")
or os.getenv("OPENAI_ORGANIZATION")
)
values["openai_api_base"] = values["openai_api_base"] or os.getenv(
"OPENAI_API_BASE"
)
values["openai_proxy"] = get_from_dict_or_env(
values,
"openai_proxy",
"OPENAI_PROXY",
default="",
)
try:
import openai
except ImportError:
raise ImportError(
"Could not import openai python package. "
"Please install it with `pip install openai`."
)
if is_openai_v1():
client_params = {
"api_key": values["openai_api_key"],
"organization": values["openai_organization"],
"base_url": values["openai_api_base"],
"timeout": values["request_timeout"],
"max_retries": values["max_retries"],
"default_headers": values["default_headers"],
"default_query": values["default_query"],
"http_client": values["http_client"],
}
values["client"] = openai.OpenAI(**client_params).chat.completions
values["async_client"] = openai.AsyncOpenAI(
**client_params
).chat.completions
else:
values["client"] = openai.ChatCompletion
return values
@property
def _default_params(self) -> Dict[str, Any]:
"""Get the default parameters for calling OpenAI API."""
params = {
"model": self.model_name,
"stream": self.streaming,
"n": self.n,
"temperature": self.temperature,
**self.model_kwargs,
}
if self.max_tokens is not None:
params["max_tokens"] = self.max_tokens
if self.request_timeout is not None and not is_openai_v1():
params["request_timeout"] = self.request_timeout
return params
def completion_with_retry(
self, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any
) -> Any:
"""Use tenacity to retry the completion call."""
if is_openai_v1():
return self.client.create(**kwargs)
retry_decorator = _create_retry_decorator(self, run_manager=run_manager)
@retry_decorator
def _completion_with_retry(**kwargs: Any) -> Any:
return self.client.create(**kwargs)
return _completion_with_retry(**kwargs)
def _combine_llm_outputs(self, llm_outputs: List[Optional[dict]]) -> dict:
overall_token_usage: dict = {}
system_fingerprint = None
for output in llm_outputs:
if output is None:
# Happens in streaming
continue
token_usage = output["token_usage"]
for k, v in token_usage.items():
if k in overall_token_usage:
overall_token_usage[k] += v
else:
overall_token_usage[k] = v
if system_fingerprint is None:
system_fingerprint = output.get("system_fingerprint")
combined = {"token_usage": overall_token_usage, "model_name": self.model_name}
if system_fingerprint:
combined["system_fingerprint"] = system_fingerprint
return combined
def _stream(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> Iterator[ChatGenerationChunk]:
message_dicts, params = self._create_message_dicts(messages, stop)
params = {**params, **kwargs, "stream": True}
default_chunk_class = AIMessageChunk
for chunk in self.completion_with_retry(
messages=message_dicts, run_manager=run_manager, **params
):
if not isinstance(chunk, dict):
chunk = chunk.dict()
if len(chunk["choices"]) == 0:
continue
choice = chunk["choices"][0]
chunk = _convert_delta_to_message_chunk(
choice["delta"], default_chunk_class
)
finish_reason = choice.get("finish_reason")
generation_info = (
dict(finish_reason=finish_reason) if finish_reason is not None else None
)
default_chunk_class = chunk.__class__
chunk = ChatGenerationChunk(message=chunk, generation_info=generation_info)
yield chunk
if run_manager:
run_manager.on_llm_new_token(chunk.text, chunk=chunk)
def _generate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
stream: Optional[bool] = None,
**kwargs: Any,
) -> ChatResult:
should_stream = stream if stream is not None else self.streaming
if should_stream:
stream_iter = self._stream(
messages, stop=stop, run_manager=run_manager, **kwargs
)
return _generate_from_stream(stream_iter)
message_dicts, params = self._create_message_dicts(messages, stop)
params = {**params, **kwargs}
response = self.completion_with_retry(
messages=message_dicts, run_manager=run_manager, **params
)
return self._create_chat_result(response)
def _create_message_dicts(
self, messages: List[BaseMessage], stop: Optional[List[str]]
) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
params = self._client_params
if stop is not None:
if "stop" in params:
raise ValueError("`stop` found in both the input and default params.")
params["stop"] = stop
message_dicts = [convert_message_to_dict(m) for m in messages]
return message_dicts, params
def _create_chat_result(self, response: Union[dict, BaseModel]) -> ChatResult:
generations = []
if not isinstance(response, dict):
response = response.dict()
for res in response["choices"]:
message = convert_dict_to_message(res["message"])
gen = ChatGeneration(
message=message,
generation_info=dict(finish_reason=res.get("finish_reason")),
)
generations.append(gen)
token_usage = response.get("usage", {})
llm_output = {
"token_usage": token_usage,
"model_name": self.model_name,
"system_fingerprint": response.get("system_fingerprint", ""),
}
return ChatResult(generations=generations, llm_output=llm_output)
async def _astream(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> AsyncIterator[ChatGenerationChunk]:
message_dicts, params = self._create_message_dicts(messages, stop)
params = {**params, **kwargs, "stream": True}
default_chunk_class = AIMessageChunk
async for chunk in await acompletion_with_retry(
self, messages=message_dicts, run_manager=run_manager, **params
):
if not isinstance(chunk, dict):
chunk = chunk.dict()
if len(chunk["choices"]) == 0:
continue
choice = chunk["choices"][0]
chunk = _convert_delta_to_message_chunk(
choice["delta"], default_chunk_class
)
finish_reason = choice.get("finish_reason")
generation_info = (
dict(finish_reason=finish_reason) if finish_reason is not None else None
)
default_chunk_class = chunk.__class__
chunk = ChatGenerationChunk(message=chunk, generation_info=generation_info)
yield chunk
if run_manager:
await run_manager.on_llm_new_token(token=chunk.text, chunk=chunk)
async def _agenerate(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
stream: Optional[bool] = None,
**kwargs: Any,
) -> ChatResult:
should_stream = stream if stream is not None else self.streaming
if should_stream:
stream_iter = self._astream(
messages, stop=stop, run_manager=run_manager, **kwargs
)
return await _agenerate_from_stream(stream_iter)
message_dicts, params = self._create_message_dicts(messages, stop)
params = {**params, **kwargs}
response = await acompletion_with_retry(
self, messages=message_dicts, run_manager=run_manager, **params
)
return self._create_chat_result(response)
@property
def _identifying_params(self) -> Dict[str, Any]:
"""Get the identifying parameters."""
return {**{"model_name": self.model_name}, **self._default_params}
@property
def _client_params(self) -> Dict[str, Any]:
"""Get the parameters used for the openai client."""
openai_creds: Dict[str, Any] = {
"model": self.model_name,
}
if not is_openai_v1():
openai_creds.update(
{
"api_key": self.openai_api_key,
"api_base": self.openai_api_base,
"organization": self.openai_organization,
}
)
if self.openai_proxy:
import openai
openai.proxy = {"http": self.openai_proxy, "https": self.openai_proxy} # type: ignore[assignment] # noqa: E501
return {**self._default_params, **openai_creds}
def _get_invocation_params(
self, stop: Optional[List[str]] = None, **kwargs: Any
) -> Dict[str, Any]:
"""Get the parameters used to invoke the model."""
return {
"model": self.model_name,
**super()._get_invocation_params(stop=stop),
**self._default_params,
**kwargs,
}
@property
def _llm_type(self) -> str:
"""Return type of chat model."""
return "openai-chat"
def _get_encoding_model(self) -> Tuple[str, tiktoken.Encoding]:
tiktoken_ = _import_tiktoken()
if self.tiktoken_model_name is not None:
model = self.tiktoken_model_name
else:
model = self.model_name
if model == "gpt-3.5-turbo":
# gpt-3.5-turbo may change over time.
# Returning num tokens assuming gpt-3.5-turbo-0301.
model = "gpt-3.5-turbo-0301"
elif model == "gpt-4":
# gpt-4 may change over time.
# Returning num tokens assuming gpt-4-0314.
model = "gpt-4-0314"
# Returns the number of tokens used by a list of messages.
try:
encoding = tiktoken_.encoding_for_model(model)
except KeyError:
logger.warning("Warning: model not found. Using cl100k_base encoding.")
model = "cl100k_base"
encoding = tiktoken_.get_encoding(model)
return model, encoding
def get_token_ids(self, text: str) -> List[int]:
"""Get the tokens present in the text with tiktoken package."""
# tiktoken NOT supported for Python 3.7 or below
if sys.version_info[1] <= 7:
return super().get_token_ids(text)
_, encoding_model = self._get_encoding_model()
return encoding_model.encode(text)
def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
"""Calculate num tokens for gpt-3.5-turbo and gpt-4 with tiktoken package.
Official documentation: https://github.com/openai/openai-cookbook/blob/
main/examples/How_to_format_inputs_to_ChatGPT_models.ipynb"""
if sys.version_info[1] <= 7:
return super().get_num_tokens_from_messages(messages)
model, encoding = self._get_encoding_model()
if model.startswith("gpt-3.5-turbo-0301"):
# every message follows <im_start>{role/name}\n{content}<im_end>\n
tokens_per_message = 4
# if there's a name, the role is omitted
tokens_per_name = -1
elif model.startswith("gpt-3.5-turbo") or model.startswith("gpt-4"):
tokens_per_message = 3
tokens_per_name = 1
else:
raise NotImplementedError(
f"get_num_tokens_from_messages() is not presently implemented "
f"for model {model}."
"See https://github.com/openai/openai-python/blob/main/chatml.md for "
"information on how messages are converted to tokens."
)
num_tokens = 0
messages_dict = [convert_message_to_dict(m) for m in messages]
for message in messages_dict:
num_tokens += tokens_per_message
for key, value in message.items():
# Cast str(value) in case the message value is not a string
# This occurs with function messages
num_tokens += len(encoding.encode(str(value)))
if key == "name":
num_tokens += tokens_per_name
# every reply is primed with <im_start>assistant
num_tokens += 3
return num_tokens
def bind_functions(
self,
functions: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable]],
function_call: Optional[str] = None,
**kwargs: Any,
) -> Runnable[LanguageModelInput, BaseMessage]:
"""Bind functions (and other objects) to this chat model.
Args:
functions: A list of function definitions to bind to this chat model.
Can be a dictionary, pydantic model, or callable. Pydantic
models and callables will be automatically converted to
their schema dictionary representation.
function_call: Which function to require the model to call.
Must be the name of the single provided function or
"auto" to automatically determine which function to call
(if any).
kwargs: Any additional parameters to pass to the
:class:`~swarms.runnable.Runnable` constructor.
"""
from langchain.chains.openai_functions.base import convert_to_openai_function
formatted_functions = [convert_to_openai_function(fn) for fn in functions]
if function_call is not None:
if len(formatted_functions) != 1:
raise ValueError(
"When specifying `function_call`, you must provide exactly one "
"function."
)
if formatted_functions[0]["name"] != function_call:
raise ValueError(
f"Function call {function_call} was specified, but the only "
f"provided function was {formatted_functions[0]['name']}."
)
function_call_ = {"name": function_call}
kwargs = {**kwargs, "function_call": function_call_}
return super().bind(
functions=formatted_functions,
**kwargs,
)

@ -0,0 +1,276 @@
AUTOBLOG_GEN_GENERATOR = f"""
First search for a list of topics on the web based their relevance to Positive Med's long term vision then rank than based on the goals this month, then output a single headline title for a blog for the next autonomous agent to write the blog, utilize the SOP below to help you strategically select topics. Output a single topic that will be the foundation for a blog.
VISION: Emphasis on exotic healthcare for improved health using Taoism, Ayurveda, and other ancient practices.
GOALS THIS MONTH: Clicks and engagement
Rank the topics on a scale from 0.0 to 1.0 on how likely it is to achieve the goal and then return the single most likely topic to satisfy the goals this month.
########### Standard Operating Procedure for Topic Selection for PositiveMed.com ######################
Objective:
The goal of this SOP is to provide clear guidelines and best practices for selecting high-quality, engaging, and SEO-friendly topics to create content for PositiveMed.com. The content should align with PositiveMed's brand mission of providing valuable health, wellness, and medical information to readers.
Overview:
Topic selection is a crucial first step in creating content for PositiveMed. Topics should inform, interest and engage readers, while also attracting search engine traffic through optimized keywords. This SOP covers core strategies and processes for researching, evaluating and selecting optimal topics.
Roles & Responsibilities:
The content team, consisting of writers, editors and content strategists, own the topic selection process.
The content team is responsible for:
- Monitoring health, medical, wellness trends and current events
- Conducting keyword research
- Assessing site analytics and reader feedback
- Crowdsourcing topic ideas from internal team and external contributors
- Maintaining editorial calendar with upcoming topics
- Pitching and selecting topics for content approval
The editorial team is responsible for:
- Providing final approval on topics based on brand suitability, reader interest, and potential traffic/engagement
- Ensuring selected topics are differentiated and not duplicative of existing content
- Reviewing and updating keyword opportunities tied to topics
Topic Sourcing
A strong content calendar begins with investing time into researching and generating promising topics. Here are key tactics and guidelines for sourcing topics:
Monitor Trends:
- Set Google Alerts for relevant keywords like "health news," "fitness trends," "nutrition research" etc. to receive daily updates.
- Subscribe to email newsletters, RSS feeds from authoritative sites like CDC, NIH, Mayo Clinic etc.
- Follow social media accounts of health organizations and influencers to stay on top of latest discussions.
- Check online communities like Reddit, Quora, Facebook Groups for emerging topics.
- Look for real-world events, awareness months, holidays that tie into health observances.
Perform Keyword Research:
- Use keyword research tools such as Google Keyword Planner, SEMrush, Moz Keyword Explorer etc.
- Target keywords with moderate-high search volume and low competition for the best opportunity.
- Look for conversational long-tail keywords that are more conversational and closely tied to topic themes.
- Ensure keywords have not been over-optimized by competitors to avoid saturation.
- Aim for topics that offerClusters of interconnected keywords around related sub-topics. This allows targeting several keywords with one piece of content.
Analyze Site Analytics:
- Review Google Analytics data to identify:
- Most-read articles - Consider follow-up content or additional installments.
- Highest-traffic landing pages - Expand on topics driving site visitors.
- Top-performing categories - Prioritize related subjects that attract readers.
- Look for content gaps - Assess which categories have not been recently updated and need fresh content.
Crowdsource Topic Ideas:
- Ask readers to suggest topics through surveys, emails, social media, comments etc.
- Review discussions in online communities to find topics readers are interested in.
- Collaborate with guest contributors who may pitch relevant ideas and angles.
- Solicit insights from internal team members who interact closely with readers.
Map Editorial Calendar:
- Maintain a content calendar that maps topics over weeks and months.
- Ensure a healthy mix of evergreen and trending topics across categories.
- Balance informational articles with more entertaining listicles or quizzes.
- Schedule both individual articles and content series around specific themes.
- Revisit calendar routinely to incorporate new topics as they emerge.
Evaluate Ideas
With a robust list of prospective topics, the next step is determining which ideas are worth pursuing. Use these criteria when assessing the merit of topics:
Reader Interest:
- Would the topic pique the curiosity of PositiveMed's target audience?
- Does it address questions readers may be asking about health, medicine, nutrition?
- Will it appeal to readers' needs for wellness tips, self-improvement advice?
- Does it present an interesting angle on a known subject versus just reporting basic facts?
Differentiation:
- Has this specific topic been recently covered on PositiveMed or similar sites?
- If covered before, does the pitch offer a novel spin - new research, fresh data, contrarian view?
- Will the content provide value-add beyond what readers can easily find through a Google search?
Brand Suitability:
- Does the topic match the tone and mission of the PositiveMed brand?
- Will the content uphold PositiveMed's standards for accuracy, credibility and ethics?
- Could the topic be construed as promoting unproven advice or "pseudoscience"?
Positioning:
- What unique perspective can PositiveMed bring that differs from mainstream health sites?
- Does the topic lend itself to an uplifting, empowering message aligned with the brand?
- Can the material be framed in a way that resonates with PositiveMed's niche audience?
Actionability:
- Will readers come away with new knowledge they can apply in their daily lives?
- Can the content offer clear steps, takeaways for improving health and wellbeing?
- Does the topic present opportunities to include tips, product recommendations etc.?
Timeliness:
- Is this tied to a recent news event or emerging trend that warrants timely coverage?
- For evergreen topics, are there new studies, pop culture references etc. that can make it timely?
- Does the angle offer a way to make an old topic feel fresh and relevant?
Competition:
- How saturated is the topic market? Who has top-ranking content on this topic?
- Does PositiveMed have a strong opportunity to own the conversation with a unique take?
- What value can be added versus competitor content on this subject?
Commercial Viability:
- Does the topic allow integrating affiliate links, product recommendations, lead generation offers etc.?
- Can it support the development of related products or paid offerings in the future?
- Will it attract engagement and social shares to increase traffic?
Keyword Integration
With promising topics identified, the next step is integrating keywords into content plans and outlines.
Conduct Keyword Research:
- Identify primary target keyword for topic that has:
- Moderate-to-high search volume
- Low-to-medium competition
- Relevance to topic and PositiveMed's niche
Find Supporting Keywords:
- Build a cluster of 3-5 secondary keywords around topic including:
- Related searches and questions
- Semantically connected words/phrases
- Keyword variations (long tail, alternate wording etc.)
- Stay within minimum monthly search volumes
Map Out Keywords:
- Determine optimal keyword placement for outlined sections e.g.:
- Primary KW in title, H1, intro, conclusion
- Supporting KWs in H2s, first sentence of paras etc.
- Include keywords naturally - no over-optimization
Check Cannibalization:
- Compare suggested keywords against existing content to avoid targeting same terms.
- Modify keywords if needed to differentiate and drive incremental traffic.
Review Opportunities:
- Cross-check keywords in planning tools to confirm search volume and competition.
- Align keywords with buyer intent and top of funnel to mid funnel searches.
- Ensure keywords are entered into analytics to track conversions.
Style and Tone Guidelines
In line with PositiveMed's brand voice, content should adopt an:
Educational yet conversational tone:
- Explain health topics, science and research simply without over-simplifying complex issues.
- Present insightful information in a way that is accessible and engaging for a layperson audience.
Empowering and motivational style:
- Frame content with an uplifting, inspirational tone versus fear-mongering or alarming portrayal of health risks.
- Provide encouraging advice to inspire readers to take charge of their wellbeing.
Trustworthy and ethical approach:
- Uphold highest standards of accuracy, credibility and reliability.
- Cite legitimate sources. Avoid promoting unverified claims or exaggerated benefits.
- Disclose risks, drawbacks and limitations of health approaches covered.
Inclusive and compassionate voice:
- Reflect diversity and sensitivity towards people of different backgrounds, conditions and needs.
- Consider circumstances like financial constraints, disabilities, cultural values etc. that impact health choices.
Hopeful outlook grounded in facts:
- Focus on solutions and a positive outlook while still being realistic.
- Counter misinformation; clarify myths vs facts.
"""
AUTOBLOG_REVIEW_PROMPT = """
You are responsible for refining an article to meet PositiveMeds stringent publication standards.
Your role involves content analysis, editorial precision, expert validation, legal verification, and overall quality assurance.
# ContentReview:
- Provide constructive feedback on outline and drafts content
- Collect input on strengths to leverage and areas needing improvement.
# Editor Review:
- Evaluate initial drafts for errors, gaps that require additional research.
- Provide guidance on better organizing structure and flow.
- Assess tone, voice and brand alignment.
# Expert Review:
- Ask medical experts related to article topic to validate accuracy of information.
- Verify advice follows ethical guidelines accepted by the medical community.
- Request quotes that lend credibility and reinforce key points.
# Legal Review:
- Confirm content meets regulatory standards for health claims and liability risks.
- Address any recommended edits to mitigate brand reputation risk.
# Quality Checklist: Scrutinize final draft against PositiveMed's standards:
- Medical accuracy - error-free facts/statistics, supported claims
- Logical flow - smooth transitions, complementary sections
- Reader value - insightful analysis beyond fluffy content
- Brand alignment - uplifting tone, inclusive messaging
- Strong conclusion - memorable takeaways, relevant next steps/resources for readers
# ARTICLE TO REVIEW:
{{ARTICLE}}
# OUTPUT:
Re-Write the article, taking into account all review instructions and standards
"""
SOCIAL_MEDIA_SYSTEM_PROMPT_AGENT = """
You're the Social Media System Agent. Your job is to create social media posts for the article below.
Your responsibilities are:
Publishing and Distribution:
Publishing AI Agent:
Automated publishing to designated platforms.
Formatting checks for platform compatibility.
Distribution:
Automated sharing to social media channels.
Email distribution to subscriber list.
Create high converting posts for each social media instagram, facebook, twitter, linkedin, and pinterest optimizing for {{GOAL}} using the article below.
Denote the social media's by using the social media name in HTML like tags
<FACEBOOK> POST CONTENT </FACEBOOK>
<TWITTER> POST CONTENT </TWITTER>
<INSTAGRAM> POST CONTENT </INSTAGRAM>
######### ARTICLE #######
{{ARTICLE}}
"""
# Agent that generates blogs
DRAFT_AGENT_SYSTEM_PROMPT = f"""
Write a 5,000+ word long narrative essay on the highest rated topic from a list of topics for positivemed.com,
their vision is: to democratize health wisdom to modern young professionals in a healthy and conversational and friendly manner,
be nice and reference research papers and other data where you pull from.
You don't have a word limit, you can write as you wish.
--------------------------- Your Responsibilities: -----------------------------
Outline Content:
- Organize research into logical sections and subsections for smooth flow.
- Ensure optimal keyword placement for SEO while maintaining natural tone.
- Structure content to focus on most valuable information upfront.
Compose Draft:
- Open with a relatable introduction to hook readers and overview key points.
- Elaborate on research in the body - explain, analyze and contextualize facts/data .
- Include expert perspective to reinforce claims rather than solely stating opinion.
- Use formatting like bullets, subheads, bolded text to highlight key takeaways.
Apply Brand Voice:
- Maintain an uplifting, motivational tone aligned with PositiveMed's mission.
- Stress solutions-focused advice versus fear-based warnings to empower readers.
- Use inclusive language and culturally sensitive medical references.
Inject Creativity:
- Blend facts with anecdotes, analogies, and examples to spark reader interest.
- Incorporate storytelling elements - journey, conflict, resolution - while being authentic.
- Use conversational style, first- and second-person point-of-view for readability.
Check Accuracy:
- Verify all medical statements against legitimate sources like CDC, Mayo Clinic, NIH.
- Scrutinize cited data for relevance and statistical significance.
- Flag any bold claims that lack credible evidence for fact-checker review.
"""

@ -0,0 +1,136 @@
import concurrent.futures
import os
from termcolor import colored
from swarms.prompts.autoblogen import (
DRAFT_AGENT_SYSTEM_PROMPT,
REVIEW_PROMPT,
SOCIAL_MEDIA_SYSTEM_PROMPT_AGENT,
TOPIC_GENERATOR,
)
# Prompts
topic_selection_task = (
"Generate 10 topics on gaining mental clarity using ancient practices"
)
class AutoBlogGenSwarm:
"""
AutoBlogGenSwarm
Swarm Flow
Topic selection agent -> draft agent -> review agent -> distribution agent
Topic Selection Agent:
- Generate 10 topics on gaining mental clarity using Taosim and Christian meditation
Draft Agent:
- Write a 100% unique, creative and in human-like style article of a minimum of 5,000 words using headings and sub-headings.
Review Agent:
- Refine the article to meet PositiveMeds stringent publication standards.
Distribution Agent:
- Social Media posts for the article.
Example:
```
from swarms.autobloggen import AutoBlogGenSwarm
swarm = AutoBlogGenSwarm()
swarm.run()
```
"""
def __init__(
self,
llm,
objective: str = "Clicks and engagement",
iterations: int = 3,
topic_selection_task: str = topic_selection_task,
max_retries: int = 3,
retry_attempts: int = 3,
topic_selection_agent_prompt: str = f"Your System Instructions: {TOPIC_GENERATOR}, Your current task: {topic_selection_task}",
):
self.llm = llm()
self.topic_selection_task = topic_selection_task
self.topic_selection_agent_prompt = topic_selection_agent_prompt
self.objective = objective
self.iterations = iterations
self.max_retries = max_retries
self.retry_attempts = retry_attempts
def print_beautifully(self, subheader: str, text: str):
"""Prints the text beautifully"""
print(
colored(
f"""
------------------------------------
{subheader}
-----------------------------
{text}
""",
"blue",
)
)
def social_media_prompt(self, article: str):
"""Gets the social media prompt"""
prompt = SOCIAL_MEDIA_SYSTEM_PROMPT_AGENT.replace("{{ARTICLE}}", article).replace(
"{{GOAL}}", self.objective
)
return prompt
def get_review_prompt(self, article: str):
"""Gets the review prompt"""
prompt = REVIEW_PROMPT.replace("{{ARTICLE}}", article)
return prompt
def step(self):
"""Steps through the task"""
topic_selection_agent = self.llm(self.topic_selection_agent_prompt)
topic_selection_agent = self.print_beautifully(
"Topic Selection Agent", topic_selection_agent
)
draft_blog = self.llm(DRAFT_AGENT_SYSTEM_PROMPT)
draft_blog = self.print_beatiufully("Draft Agent", draft_blog)
# Agent that reviews the draft
review_agent = self.llm(self.get_review_prompt(draft_blog))
review_agent = self.print_beautifully("Review Agent", review_agent)
# Agent that publishes on social media
distribution_agent = self.llm(
self.social_media_prompt(article=review_agent)
)
distribution_agent = self.print_beautifully(
"Distribution Agent", distribution_agent
)
def run(self):
"""Runs the swarm"""
for attempt in range(self.retry_attempts):
try:
for i in range(self.iterations):
self.step()
except Exception as error:
print(colored(f"Error while running AutoBlogGenSwarm {error}", "red"))
if attempt == self.retry_attempts - 1:
raise
def update_task(self, new_task: str):
"""
Updates the task of the swarm
Args:
new_task (str): New task to be performed by the swarm
"""
self.topic_selection_agent = new_task

@ -19,7 +19,7 @@ from langchain.callbacks.manager import (
)
from langchain.load.serializable import Serializable
from langchain.pydantic_v1 import (
from pydantic import (
BaseModel,
Extra,
Field,
@ -29,7 +29,6 @@ from langchain.pydantic_v1 import (
)
from langchain.schema.runnable import Runnable, RunnableConfig, RunnableSerializable
class SchemaAnnotationError(TypeError):
"""Raised when 'args_schema' is missing or has an incorrect type annotation."""

Loading…
Cancel
Save