How to Use Penly
1. Create a Job from the Dashboard
Start by creating a new content job directly from your Penly dashboard. When setting up a job, you`'`ll need to specify the topic for your blog. This topic will guide Penly`'`s AI in exploring and identifying relevant news and trends to create content that is not only fresh but also highly engaging and topical. Setting the correct topic ensures that the generated content aligns with your desired focus areas.
2. Create Your First Blog
Use the job you`'`ve created to generate your first blog.
3. Create a Cluster
Clusters allow you to group multiple jobs for better organization and management. Create a cluster to keep your content jobs streamlined.
4. Add the Job to the Cluster
Add your newly created job to the cluster. This helps in managing various jobs under a single cluster, making monitoring and adjustments easier.
5. Create API Key for the Cluster
Generate an API key for your cluster. This key will be used to integrate Penly’s functionality with your website.
6. Add the Component to Your Website
Finally, embed the Penly component on your website and provide it with the API key of the cluster. This completes the setup, allowing Penly to automatically publish content to your site. below you can find example code to add the component to your website.
6.1. First if you are usng typescript create two types
export type Timestamp ={
_seconds: number;
_nanoseconds: number;
}
export type BlogRetrievedFromAPI ={
id: string;
topic: string;
text: string;
title: string;
createdAt: Timestamp | any;
updatedAt: Timestamp |any;
imgUrl: string;
shortSummary: string;
}
6.2. Create Two Endpoints in your backend
You need to create two endpoints in your backend to fetch all blogs and to fetch a single blog by id.
6.2.1. Fetch All Blogs
const response = await axios.post(
"http://penly.io/api/outside/getBlogs",
{page: 1, size: 10},
{
headers: {
"Content-Type": "application/json",
"penly-api-key": "YOUR API KEY"
},
}
);
6.2.2. Fetch Blog By Id
const response = await axios.post(
"http://penly.io/api/outside/getBlogById",
{id: "1"},
{
headers: {
"Content-Type": "application/json",
"penly-api-key": "YOUR API KEY"
},
}
);
6.3. Create a Blog Thumbnail Component
export function BlogThumb({
blog,
}: {
blog: BlogRetrievedFromAPI;
}) {
const router = useRouter();
const handleReadMore = () => {
// Implement or pass down this function to handle "Read More" action.
console.log("Redirect to blog details");
router.push(\`/blogs/${blog.id}\`);
};
return (
<div className="w-80 mx-auto">
<div className="bg-white border border-zinc-100 rounded-2xl overflow-hidden shadow hover:shadow-xl transition-shadow duration-200">
<div className="aspect-w-16 aspect-h-10">
<Image
src={blog.imgUrl}
alt="thumbnail"
width={400}
height={250}
objectFit="cover"
className="transition-transform duration-200 group-hover:scale-95"
/>
</div>
<div className="p-4">
<h2 className="text-lg font-bold text-zinc-700 my-4">
{blog.title}
</h2>
<p className="text-sm text-zinc-500 my-4">
{blog.shortSummary}
</p>
<div className="flex justify-between items-center mt-10">
<span className="text-sm text-gray-500">
{new Date(blog.createdAt._seconds * 1000).toDateString()}
</span>
<button
className="px-6 py-2 bg-black text-white font-bold rounded-xl text-xs"
onClick={handleReadMore}
>
Read More
</button>
</div>
</div>
</div>
</div>
);
}
6.4. Create a Page to Show All Blogs
const BlogsPage: React.FC = () =>{
const [blogs, setBlogs] = useState<BlogRetrievedFromAPI[]>([]);
const fetchBlogs = useCallback(() => {
return axios.post("api/get-generated-blogs")
.then((res) => res.data.data as BlogRetrievedFromAPI[]);
}, []);
useEffect(() => {
fetchBlogs().then(setBlogs).catch(console.error);
}, [fetchBlogs]);
return (
<Layout title="Blogs">
<div>
<Container>
<div className="flex flex-col items-center justify-center space-y-8">
<h1 className="text-4xl font-bold mb-3 mt-3">Blogs</h1>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{blogs.map((blog) => (
BlogThumb({blog})
))}
</div>
</div>
</Container>
</div>
</Layout>
);
};
6.5. Create a Page to Show Single Blog
export default function Page({ params }: { params: { id: string } }) {
const [blog, setBlog] = useState<BlogRetrievedFromAPI>();
const [moreBlogs, setMoreBlogs] = useState<BlogRetrievedFromAPI[]>([]);
useEffect(() => {
const fetchBlog = async () => {
const res = await axios.post("/api/get-generated-blog-by-id", {
blogID: params.id,
});
const data = res.data;
setBlog(data.blog);
if (data.relatedBlogs) {
setMoreBlogs(data.relatedBlogs);
}
};
fetchBlog();
}, [params.id]);
if (!blog) {
return <h1>Loading...</h1>;
}
return (
<Layout title="Home Page" footerMargin={false}>
<div className="xl:px-36 px-8">
<div dangerouslySetInnerHTML={{ __html: blog.text }} />
<div className="mt-10">
<h1 className=" text-4xl text-center mb-10 font-bold">More Blogs</h1>
<MoreBlogs blogs={moreBlogs} />
</div>
</div>
</Layout>
);
}