• Resources
  • Auto Start a Discussion Using AI (Gemini, ChatGPT & more)

In this post, I’ll walk you through how to automate the creation of forum discussions using AI and the Flarum API. By integrating an AI language model, I have streamlined the process of generating relevant, engaging, and SEO-optimized discussions for my forum, making it easier to keep the community active and engaging.

API Integration: To get started, you will need the Flarum API Client. You can easily install this via SSH, similar to installing a Flarum extension. The process is well-documented, so you don't need to worry about complex configurations.

Run the following command in the root directory of your forum using SSH:

composer require maicol07/flarum-api-client

Documentation Resources:
Flarum API Client - PHP
Flarum API Client Documentation
Packagist - Flarum API Client

Setting Up the Database Table: You need to create a table in your database to store the keywords and track the progress of the posts. Below is the SQL command that will create the ai_queue table in your database. I’m using Flarum’s own database for this purpose, but you can adapt it as needed.

CREATE TABLE `ai_queue` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `title` varchar(500) NOT NULL,
  `seen` int(1) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  KEY `title` (`title`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

COMMIT;

Create Your Flarum API Token: To authenticate your requests, you’ll need to create a token in the api_keys table of your Flarum database. A 40-character token is recommended.

For more details, refer to the Flarum REST API documentation.

Connecting to Your Database with PHP: Now that you have the database set up, let’s connect to it using PHP. In the next step, we will create two PHP files that handle database connections and content parsing. You can create the PHP file in the root directory or a subfolder of your forum.

File 1: details-txt.php
(You can change the filename, but make sure to adjust the reference in your code.)

<?php

$header = array(
  "Authorization: Token <<ENTER YOUR OWN FORUM TOKEN HERE>> ",
  "Content-Type: application/json"
);

// Create DB connection
$servername = "localhost";
$login = "DATABASE USERNAME";
$dbpw = "DATABASE PASSWORD";
$dbname = "DATABASE NAME";
$conn = new mysqli($servername, $login, $dbpw, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
else 
{
echo "Connected to database\n";
}
?>

File 2: txtparsergemini.php
(Again, you can change the filename, but make sure to adjust the reference in your code.)

<?php
include("details-txt.php");
require 'vendor/autoload.php';

// Enable detailed error reporting for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Define the API URL for content generation
$apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?key=<<ENTER YOUR OWN API KEY HERE>>';

// Specify the path to the keywords file
$filePath = 'keywords-gemini.txt';

// Read the file line by line and check for errors
if (!file_exists($filePath) || !is_readable($filePath)) {
    die("File not found or unreadable: " . $filePath);
}
$keywords = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

// Get the most recently added title from the database
$lastTitleStmt = $conn->prepare('SELECT title FROM ai_queue ORDER BY id DESC LIMIT 1');
if (!$lastTitleStmt) {
    die("Database preparation error: " . $conn->error);
}
$lastTitleStmt->execute();
$lastTitleStmt->bind_result($lastTitle);
$lastTitleStmt->fetch();
$lastTitleStmt->close();

echo "Last title in the database: $lastTitle\n";

// Find the next keyword in the list after the last title
$keywordIndex = array_search($lastTitle, $keywords);
if ($keywordIndex !== false && isset($keywords[$keywordIndex + 1])) {
    $keyword = $keywords[$keywordIndex + 1];
    echo "Next keyword: $keyword\n";
} else {
    // If the last title is not found in the keywords file, use the first keyword
    $keyword = $keywords[0];
    echo "First keyword: $keyword\n";
}

// Check if the keyword exists in the database before proceeding
$selectStmt = $conn->prepare('SELECT title FROM ai_queue WHERE title = ?');
$selectStmt->bind_param('s', $keyword);
$selectStmt->execute();
$selectStmt->store_result();

if ($selectStmt->num_rows === 0) {
    // If the keyword is not found, send a request to the Gemini API
    $prompt = "You will open a discussion on the FORUMNAME forum with the following keyword. You can use typos and abbreviations, avoid using punctuation marks. Focus on the keyword and avoid revealing that you're an AI. Use natural language, and do not use any formatting like Markdown, HTML, or tables. Please provide the response in the following format:\n\n"
        . "Topic: [Title text (should be less than 75 characters)]\n"
        . "Question: [Answer text]\n\n"
        . "Keyword: $keyword";

    // Prepare the request data in JSON format
    $requestData = [
        "contents" => [
            [
                "parts" => [
                    ["text" => $prompt]
                ]
            ]
        ]
    ];

    // cURL request
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $apiUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Content-Type: application/json",
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));

    $response = curl_exec($ch);

    // Error checking
    if (curl_errno($ch)) {
        echo "cURL Error: " . curl_error($ch) . "\n";
        return;
    }

    $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // Print the response
    echo "Gemini API Response:\n$response\n\n";

    if ($httpStatus !== 200) {
        echo "API Error: HTTP Status Code $httpStatus\n";
        return;
    }

    // Process the response and extract the title and question
    $responseData = json_decode($response, true);

    if (isset($responseData['candidates'][0]['content']['parts'][0]['text'])) {
        $geminiResponse = $responseData['candidates'][0]['content']['parts'][0]['text'];

        // Extract the title and question from the response
        if (preg_match('/^Topic: (.+)\nQuestion: (.+)$/s', $geminiResponse, $matches)) {
            $title = trim($matches[1]);
            $body = trim($matches[2]);

            // Use the Flarum API to add the new topic to the forum
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://forum.siteurl.com/api/discussions');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(array(
                'data' => array(
                    'type' => "discussions",
                    'attributes' => array(
                        'title' => "$title",  // Use the title from the response
                        'content' => "$body"   // Use the body from the response
                    ),
                    'relationships' => array(
                        'tags' => array(
                            'data' => array(
                                array(
                                    'type' => 'tags',
                                    'id' => "2"  // Use a fixed tag ID for a specific category
                                )
                            )
                        )
                    )
                )
            )));
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
            $result = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if ($httpCode != 201) {
                echo "HTTP Error Code: " . $httpCode . "\n";
                echo "API Response: " . $result . "\n";
                die("Forum API request failed.\n");
            }
            if (curl_errno($ch)) {
                echo 'Curl error: ' . curl_error($ch) . "\n";
            }
            curl_close($ch);
            echo "New topic created on the forum: $title\n";

            // If successful, add the new record to the database
            $insertStmt = $conn->prepare('INSERT INTO ai_queue (title, seen) VALUES (?, 1)');
            $insertStmt->bind_param("s", $keyword);
            $insertStmt->execute();
            $insertStmt->close();

            echo "New keyword added to the database: " . $keyword . "\n";
        } else {
            echo "The response from Gemini API is not in the expected format.\n";
        }
    } else {
        echo "Could not retrieve valid content from Gemini API.\n";
    }
} else {
    echo "Title already exists, skipping: " . $keyword . "\n";
}
$selectStmt->close();
?>

Create a file named keywords-gemini.txt in the same directory and list one keyword per line. Do not enclose the keywords in quotation marks, and avoid adding commas at the end. You can leave spaces as needed.

Example:

keyword 1
keyword 2
keyword 3

Finally, every time you send an HTTP request to this PHP file, a new discussion will be started. Therefore, you can connect this PHP file to a CRON job using the URL method. A new discussion will be created at the desired minute.

The user who will create the discussion is the ID of the token you added in the api_keys table.

Credit: This was inspired by the following discussion: https://discuss.flarum.org/d/24017-create-posts-from-rss-feeds

This method ensures that fresh, SEO-optimized, and relevant topics are regularly posted on the forum without manual intervention.

Why This Is Useful:

  • Save Time: Automates the repetitive task of creating forum posts.

  • SEO-Friendly: The AI generates SEO-focused content.

  • Consistency: Posts are made regularly with minimal effort, ensuring active community engagement.

Feel free to ask questions or share your experiences with automating forum posts!

    A great guide, it would be great if those who have experience and success could write about it.

    huseyinfiliz Getting a 500 Error when using, followed the instructions to the T.

    [19-Mar-2025 04:00:07 UTC] PHP Deprecated:  Creation of dynamic property Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter::$root is deprecated in /home/treyb/cobbtalk.com/vendor/nao-pon/flysystem-google-drive/src/GoogleDriveAdapter.php on line 164
    [19-Mar-2025 04:00:07 UTC] PHP Deprecated:  Calling get_class() without arguments is deprecated in /home/treyb/cobbtalk.com/vendor/google/apiclient/src/Http/REST.php on line 58

      treyb The error you received seems to be related to the PHP version, but I don’t understand the connection between this guide and nao-pon/flysystem-google-drive.

      Let's start with this: What is your PHP version?

        huseyinfiliz Php 8.3 on this one, and CLI as well.

        PHP 8.3.17 (cli) (built: Feb 13 2025 00:00:00) (NTS)
        Copyright (c) The PHP Group
        Zend Engine v4.3.17, Copyright (c) Zend Technologies
            with the ionCube PHP Loader v13.3.1, Copyright (c) 2002-2024, by ionCube Ltd.
            with Zend OPcache v8.3.17, Copyright (c), by Zend Technologies

          treyb Honestly, I couldn't understand the reason for this error. I'm sorry that I couldn't help. I couldn't find the connection between this error and this guide.

            huseyinfiliz If we ignore the Google Drive part, any ideas? The 500 Error is odd.

            I am now, only getting this error when visiting site.com/txtparsergemini.php

            [19-Mar-2025 04:00:09 UTC] PHP Deprecated: Calling get_class() without arguments is deprecated in /home/treyb/cobbtalk.com/vendor/google/apiclient/src/Http/REST.php on line 58

              treyb The issue seems to indicate that there is unsupported code in the mentioned file for PHP 8+. However, the code I provided should not reference that file. I don't understand the problem.

              Tomorrow, I will perform a fresh Flarum installation and follow this guide again. If I encounter any issues, I will let you know the solution.

              SychO I did this, and now it just doesn't work with and nothing is added to the error log.

                Just a note... I think that AI generated content has great impact on SEO success in negative way. If that is something that you care of, of course.

                  treyb I think the HTTP 500 error would appear in the server log rather than the Flarum log. Do you see any errors there?

                  Also, when you open the first PHP file, does the message "Database connection successful" appear on the screen?

                    Silvestrus If you have a niche forum rather than a general one (if your forum is in English, a niche industry might not work), I think it helps people discover your forum.

                    This is purely my personal opinion.

                    huseyinfiliz Yes, I will keep playing around and see if I can get anything going.

                    @huseyinfiliz I updated the API link to this, and it works now.
                    https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=

                      treyb Ah, yes, you need to obtain that link from Gemini AI Studio specifically for yourself.