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.

Dashboard
Create Job Form

2. Create Your First Blog

Use the job you`'`ve created to generate your first blog.

Create 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.

Create Cluster

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.

Add Job to Cluster

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.

API Key for Cluster

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>
      );
    }