Replace ChatGPT with Google Gemini
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
"allow": [
|
"allow": [
|
||||||
"Bash(tree:*)",
|
"Bash(tree:*)",
|
||||||
"Bash(mvn clean compile:*)",
|
"Bash(mvn clean compile:*)",
|
||||||
"WebFetch(domain:github.com)"
|
"WebFetch(domain:github.com)",
|
||||||
|
"Bash(rm:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
# OpenAI API Configuration
|
# Google Gemini API Configuration
|
||||||
OPENAI_API_KEY=your_openai_api_key_here
|
# Get your free API key from: https://aistudio.google.com/app/apikey
|
||||||
|
GEMINI_API_KEY=your_gemini_api_key_here
|
||||||
|
|
||||||
# Twitter API Configuration (OAuth 2.0)
|
# Twitter API Configuration (OAuth 1.0a)
|
||||||
|
# Get your credentials from Twitter Developer Portal: https://developer.twitter.com/
|
||||||
TWITTER_API_KEY=your_twitter_api_key_here
|
TWITTER_API_KEY=your_twitter_api_key_here
|
||||||
TWITTER_API_SECRET=your_twitter_api_secret_here
|
TWITTER_API_SECRET=your_twitter_api_secret_here
|
||||||
TWITTER_ACCESS_TOKEN=your_twitter_access_token_here
|
TWITTER_ACCESS_TOKEN=your_twitter_access_token_here
|
||||||
TWITTER_ACCESS_TOKEN_SECRET=your_twitter_access_token_secret_here
|
TWITTER_ACCESS_TOKEN_SECRET=your_twitter_access_token_secret_here
|
||||||
TWITTER_BEARER_TOKEN=your_twitter_bearer_token_here
|
|
||||||
|
|
||||||
# Tweet Generation Configuration
|
# Tweet Generation Configuration
|
||||||
TWEET_PROMPT=Write a short, engaging tweet about technology trends
|
TWEET_PROMPT=Write a short, engaging tweet about technology trends
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
# Environment variables (IMPORTANT: Never commit API keys!)
|
# Environment variables (IMPORTANT: Never commit API keys!)
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# OAuth 2.0 tokens (IMPORTANT: Never commit access tokens!)
|
||||||
|
.twitter_tokens.json
|
||||||
|
|
||||||
# Maven
|
# Maven
|
||||||
target/
|
target/
|
||||||
pom.xml.tag
|
pom.xml.tag
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -1,10 +1,10 @@
|
|||||||
# TweetBot - AI-Powered Twitter Bot
|
# TweetBot - AI-Powered Twitter Bot
|
||||||
|
|
||||||
An automated Twitter bot that generates and posts tweets using OpenAI's ChatGPT API. This Java application allows you to create engaging social media content with custom prompts.
|
An automated Twitter bot that generates and posts tweets using Google Gemini's free API. This Java application allows you to create engaging social media content with custom prompts.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Generate tweet content using ChatGPT (GPT-3.5-turbo)
|
- Generate tweet content using Google Gemini (gemini-2.0-flash-exp) - **Free Tier**
|
||||||
- **Three operation modes:**
|
- **Three operation modes:**
|
||||||
- Interactive mode with manual approval
|
- Interactive mode with manual approval
|
||||||
- Auto-post mode for one-time tweets
|
- Auto-post mode for one-time tweets
|
||||||
@@ -22,17 +22,24 @@ An automated Twitter bot that generates and posts tweets using OpenAI's ChatGPT
|
|||||||
|
|
||||||
- Java 17 or higher
|
- Java 17 or higher
|
||||||
- Maven 3.6 or higher
|
- Maven 3.6 or higher
|
||||||
- OpenAI API key
|
- Google Gemini API key (free tier available)
|
||||||
- Twitter Developer Account with API credentials
|
- Twitter Developer Account with API credentials
|
||||||
|
|
||||||
## Setup Instructions
|
## Setup Instructions
|
||||||
|
|
||||||
### 1. Get OpenAI API Key
|
### 1. Get Google Gemini API Key (Free)
|
||||||
|
|
||||||
1. Go to [OpenAI Platform](https://platform.openai.com/)
|
1. Go to [Google AI Studio](https://aistudio.google.com/app/apikey)
|
||||||
2. Sign up or log in to your account
|
2. Sign in with your Google account
|
||||||
3. Navigate to API keys section
|
3. Click "Create API Key"
|
||||||
4. Create a new API key and save it securely
|
4. Select or create a Google Cloud project
|
||||||
|
5. Copy the API key and save it securely
|
||||||
|
|
||||||
|
**Note:** The free tier of Google Gemini includes:
|
||||||
|
- 15 requests per minute
|
||||||
|
- 1 million tokens per minute
|
||||||
|
- 1,500 requests per day
|
||||||
|
- More than enough for a tweet bot!
|
||||||
|
|
||||||
### 2. Get Twitter API Credentials
|
### 2. Get Twitter API Credentials
|
||||||
|
|
||||||
@@ -44,7 +51,6 @@ An automated Twitter bot that generates and posts tweets using OpenAI's ChatGPT
|
|||||||
- API Secret (Consumer Secret)
|
- API Secret (Consumer Secret)
|
||||||
- Access Token
|
- Access Token
|
||||||
- Access Token Secret
|
- Access Token Secret
|
||||||
- Bearer Token
|
|
||||||
|
|
||||||
**Important:** Ensure your Twitter app has **Read and Write** permissions:
|
**Important:** Ensure your Twitter app has **Read and Write** permissions:
|
||||||
- Go to your app settings
|
- Go to your app settings
|
||||||
@@ -60,12 +66,11 @@ An automated Twitter bot that generates and posts tweets using OpenAI's ChatGPT
|
|||||||
|
|
||||||
2. Edit `.env` and add your API credentials:
|
2. Edit `.env` and add your API credentials:
|
||||||
```
|
```
|
||||||
OPENAI_API_KEY=sk-your-openai-api-key-here
|
GEMINI_API_KEY=your-gemini-api-key-here
|
||||||
TWITTER_API_KEY=your-twitter-api-key
|
TWITTER_API_KEY=your-twitter-api-key
|
||||||
TWITTER_API_SECRET=your-twitter-api-secret
|
TWITTER_API_SECRET=your-twitter-api-secret
|
||||||
TWITTER_ACCESS_TOKEN=your-twitter-access-token
|
TWITTER_ACCESS_TOKEN=your-twitter-access-token
|
||||||
TWITTER_ACCESS_TOKEN_SECRET=your-twitter-access-token-secret
|
TWITTER_ACCESS_TOKEN_SECRET=your-twitter-access-token-secret
|
||||||
TWITTER_BEARER_TOKEN=your-twitter-bearer-token
|
|
||||||
TWEET_PROMPT=Write a short, engaging tweet about technology trends
|
TWEET_PROMPT=Write a short, engaging tweet about technology trends
|
||||||
IMAGE_PATH=/path/to/your/image.jpg
|
IMAGE_PATH=/path/to/your/image.jpg
|
||||||
```
|
```
|
||||||
@@ -80,7 +85,7 @@ An automated Twitter bot that generates and posts tweets using OpenAI's ChatGPT
|
|||||||
- Supported formats: JPEG, PNG, GIF
|
- Supported formats: JPEG, PNG, GIF
|
||||||
- Maximum file size: 5MB (Twitter limit)
|
- Maximum file size: 5MB (Twitter limit)
|
||||||
|
|
||||||
### 5. Build the Project
|
### 4. Build the Project
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mvn clean package
|
mvn clean package
|
||||||
@@ -216,7 +221,7 @@ tweetbot/
|
|||||||
│ ├── config/
|
│ ├── config/
|
||||||
│ │ └── Config.java # Configuration loader
|
│ │ └── Config.java # Configuration loader
|
||||||
│ └── service/
|
│ └── service/
|
||||||
│ ├── OpenAIService.java # ChatGPT integration
|
│ ├── GeminiService.java # Google Gemini integration
|
||||||
│ └── TwitterService.java # Twitter API integration
|
│ └── TwitterService.java # Twitter API integration
|
||||||
└── resources/
|
└── resources/
|
||||||
└── logback.xml # Logging configuration
|
└── logback.xml # Logging configuration
|
||||||
@@ -228,12 +233,11 @@ tweetbot/
|
|||||||
|
|
||||||
| Variable | Required | Description |
|
| Variable | Required | Description |
|
||||||
|----------|----------|-------------|
|
|----------|----------|-------------|
|
||||||
| `OPENAI_API_KEY` | Yes | Your OpenAI API key |
|
| `GEMINI_API_KEY` | Yes | Your Google Gemini API key (free tier available) |
|
||||||
| `TWITTER_API_KEY` | Yes | Twitter API Key (Consumer Key) |
|
| `TWITTER_API_KEY` | Yes | Twitter API Key (Consumer Key) |
|
||||||
| `TWITTER_API_SECRET` | Yes | Twitter API Secret (Consumer Secret) |
|
| `TWITTER_API_SECRET` | Yes | Twitter API Secret (Consumer Secret) |
|
||||||
| `TWITTER_ACCESS_TOKEN` | Yes | Twitter Access Token |
|
| `TWITTER_ACCESS_TOKEN` | Yes | Twitter Access Token |
|
||||||
| `TWITTER_ACCESS_TOKEN_SECRET` | Yes | Twitter Access Token Secret |
|
| `TWITTER_ACCESS_TOKEN_SECRET` | Yes | Twitter Access Token Secret |
|
||||||
| `TWITTER_BEARER_TOKEN` | Yes | Twitter Bearer Token |
|
|
||||||
| `TWEET_PROMPT` | No | Default prompt for tweet generation |
|
| `TWEET_PROMPT` | No | Default prompt for tweet generation |
|
||||||
| `IMAGE_PATH` | No | Path to image file to attach to every tweet (jpg, png, gif) |
|
| `IMAGE_PATH` | No | Path to image file to attach to every tweet (jpg, png, gif) |
|
||||||
|
|
||||||
@@ -371,9 +375,10 @@ Ensure your `.env` file exists and contains all required variables.
|
|||||||
|
|
||||||
### "Failed to generate tweet"
|
### "Failed to generate tweet"
|
||||||
|
|
||||||
1. Verify your OpenAI API key is valid
|
1. Verify your Gemini API key is valid
|
||||||
2. Check that you have sufficient API credits
|
2. Check that you're within the free tier rate limits (15 RPM, 1500 RPD)
|
||||||
3. Review the error message in logs
|
3. Review the error message in logs
|
||||||
|
4. Ensure your Google Cloud project is properly configured
|
||||||
|
|
||||||
### Twitter API Rate Limits
|
### Twitter API Rate Limits
|
||||||
|
|
||||||
@@ -385,9 +390,7 @@ Twitter API has rate limits:
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- **Twitter API Java SDK** (2.0.3) - Twitter API client
|
- **OkHttp** (4.12.0) - HTTP client for API requests
|
||||||
- **OpenAI GPT-3 Java** (0.18.2) - OpenAI API client
|
|
||||||
- **OkHttp** (4.12.0) - HTTP client
|
|
||||||
- **Jackson** (2.16.1) - JSON processing
|
- **Jackson** (2.16.1) - JSON processing
|
||||||
- **SLF4J & Logback** (2.0.9) - Logging
|
- **SLF4J & Logback** (2.0.9) - Logging
|
||||||
- **Dotenv** (3.0.0) - Environment variable management
|
- **Dotenv** (3.0.0) - Environment variable management
|
||||||
@@ -406,7 +409,6 @@ private static final int SCHEDULE_INTERVAL_MINUTES = 30; // Change this value
|
|||||||
|
|
||||||
### Other Enhancement Ideas
|
### Other Enhancement Ideas
|
||||||
|
|
||||||
- Add support for images and media attachments
|
|
||||||
- Implement tweet threading for longer content
|
- Implement tweet threading for longer content
|
||||||
- Add sentiment analysis before posting
|
- Add sentiment analysis before posting
|
||||||
- Create multiple prompt templates with rotation
|
- Create multiple prompt templates with rotation
|
||||||
@@ -429,4 +431,4 @@ For issues or questions:
|
|||||||
1. Check the troubleshooting section
|
1. Check the troubleshooting section
|
||||||
2. Review application logs in `tweetbot.log`
|
2. Review application logs in `tweetbot.log`
|
||||||
3. Verify API credentials and permissions
|
3. Verify API credentials and permissions
|
||||||
4. Check Twitter and OpenAI API status pages
|
4. Check Twitter and Google AI Studio status pages
|
||||||
|
|||||||
9
pom.xml
9
pom.xml
@@ -11,7 +11,7 @@
|
|||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>TweetBot</name>
|
<name>TweetBot</name>
|
||||||
<description>Auto-posting tweets with ChatGPT generated content</description>
|
<description>Auto-posting tweets with Google Gemini generated content</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
@@ -20,13 +20,6 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- OpenAI Java Client -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.theokanning.openai-gpt3-java</groupId>
|
|
||||||
<artifactId>service</artifactId>
|
|
||||||
<version>0.18.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- OkHttp for HTTP requests -->
|
<!-- OkHttp for HTTP requests -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okhttp3</groupId>
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.voidcode.tweetbot;
|
package com.voidcode.tweetbot;
|
||||||
|
|
||||||
import com.voidcode.tweetbot.config.Config;
|
import com.voidcode.tweetbot.config.Config;
|
||||||
import com.voidcode.tweetbot.service.OpenAIService;
|
import com.voidcode.tweetbot.service.GeminiService;
|
||||||
import com.voidcode.tweetbot.service.TwitterService;
|
import com.voidcode.tweetbot.service.TwitterService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class TweetBot {
|
public class TweetBot {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(TweetBot.class);
|
private static final Logger logger = LoggerFactory.getLogger(TweetBot.class);
|
||||||
private static final int SCHEDULE_INTERVAL_MINUTES = 30;
|
private static final int SCHEDULE_INTERVAL_MINUTES = 30;
|
||||||
private static OpenAIService openAIService;
|
private static GeminiService geminiService;
|
||||||
private static TwitterService twitterService;
|
private static TwitterService twitterService;
|
||||||
private static String tweetPrompt;
|
private static String tweetPrompt;
|
||||||
private static String imagePath;
|
private static String imagePath;
|
||||||
@@ -48,7 +48,7 @@ public class TweetBot {
|
|||||||
|
|
||||||
// Load configuration
|
// Load configuration
|
||||||
logger.info("Loading configuration...");
|
logger.info("Loading configuration...");
|
||||||
String openAIApiKey = Config.getOpenAIApiKey();
|
String geminiApiKey = Config.getGeminiApiKey();
|
||||||
String twitterApiKey = Config.getTwitterApiKey();
|
String twitterApiKey = Config.getTwitterApiKey();
|
||||||
String twitterApiSecret = Config.getTwitterApiSecret();
|
String twitterApiSecret = Config.getTwitterApiSecret();
|
||||||
String twitterAccessToken = Config.getTwitterAccessToken();
|
String twitterAccessToken = Config.getTwitterAccessToken();
|
||||||
@@ -66,7 +66,7 @@ public class TweetBot {
|
|||||||
|
|
||||||
// Initialize services
|
// Initialize services
|
||||||
logger.info("Initializing services...");
|
logger.info("Initializing services...");
|
||||||
openAIService = new OpenAIService(openAIApiKey);
|
geminiService = new GeminiService(geminiApiKey);
|
||||||
twitterService = new TwitterService(
|
twitterService = new TwitterService(
|
||||||
twitterApiKey,
|
twitterApiKey,
|
||||||
twitterApiSecret,
|
twitterApiSecret,
|
||||||
@@ -114,8 +114,8 @@ public class TweetBot {
|
|||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
logger.info("Shutdown signal received, stopping TweetBot...");
|
logger.info("Shutdown signal received, stopping TweetBot...");
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
if (openAIService != null) {
|
if (geminiService != null) {
|
||||||
openAIService.shutdown();
|
geminiService.shutdown();
|
||||||
}
|
}
|
||||||
logger.info("TweetBot stopped gracefully");
|
logger.info("TweetBot stopped gracefully");
|
||||||
}));
|
}));
|
||||||
@@ -157,7 +157,7 @@ public class TweetBot {
|
|||||||
try {
|
try {
|
||||||
// Generate tweet content
|
// Generate tweet content
|
||||||
logger.info("Generating tweet content...");
|
logger.info("Generating tweet content...");
|
||||||
String tweetContent = openAIService.generateTweet(tweetPrompt);
|
String tweetContent = geminiService.generateTweet(tweetPrompt);
|
||||||
|
|
||||||
// Display generated content
|
// Display generated content
|
||||||
System.out.println("\n" + "=".repeat(60));
|
System.out.println("\n" + "=".repeat(60));
|
||||||
@@ -196,8 +196,8 @@ public class TweetBot {
|
|||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
if (openAIService != null) {
|
if (geminiService != null) {
|
||||||
openAIService.shutdown();
|
geminiService.shutdown();
|
||||||
}
|
}
|
||||||
logger.info("TweetBot finished");
|
logger.info("TweetBot finished");
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ public class TweetBot {
|
|||||||
logger.info("[{}] Starting scheduled tweet posting...", timestamp);
|
logger.info("[{}] Starting scheduled tweet posting...", timestamp);
|
||||||
|
|
||||||
// Generate tweet content
|
// Generate tweet content
|
||||||
String tweetContent = openAIService.generateTweet(tweetPrompt);
|
String tweetContent = geminiService.generateTweet(tweetPrompt);
|
||||||
logger.info("Generated tweet: {}", tweetContent);
|
logger.info("Generated tweet: {}", tweetContent);
|
||||||
|
|
||||||
// Post tweet
|
// Post tweet
|
||||||
@@ -233,7 +233,7 @@ public class TweetBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void printUsage() {
|
private static void printUsage() {
|
||||||
System.out.println("TweetBot - Automated Twitter posting with ChatGPT");
|
System.out.println("TweetBot - Automated Twitter posting with Google Gemini");
|
||||||
System.out.println("\nUsage:");
|
System.out.println("\nUsage:");
|
||||||
System.out.println(" java -jar tweetbot.jar [OPTIONS] [CUSTOM_PROMPT]");
|
System.out.println(" java -jar tweetbot.jar [OPTIONS] [CUSTOM_PROMPT]");
|
||||||
System.out.println("\nOptions:");
|
System.out.println("\nOptions:");
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ public class Config {
|
|||||||
.ignoreIfMissing()
|
.ignoreIfMissing()
|
||||||
.load();
|
.load();
|
||||||
|
|
||||||
// OpenAI Configuration
|
// Google Gemini Configuration
|
||||||
public static String getOpenAIApiKey() {
|
public static String getGeminiApiKey() {
|
||||||
return getEnvOrThrow("OPENAI_API_KEY");
|
return getEnvOrThrow("GEMINI_API_KEY");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Twitter Configuration
|
// Twitter Configuration (OAuth 1.0a)
|
||||||
public static String getTwitterApiKey() {
|
public static String getTwitterApiKey() {
|
||||||
return getEnvOrThrow("TWITTER_API_KEY");
|
return getEnvOrThrow("TWITTER_API_KEY");
|
||||||
}
|
}
|
||||||
@@ -30,10 +30,6 @@ public class Config {
|
|||||||
return getEnvOrThrow("TWITTER_ACCESS_TOKEN_SECRET");
|
return getEnvOrThrow("TWITTER_ACCESS_TOKEN_SECRET");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTwitterBearerToken() {
|
|
||||||
return getEnvOrThrow("TWITTER_BEARER_TOKEN");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tweet Generation Configuration
|
// Tweet Generation Configuration
|
||||||
public static String getTweetPrompt() {
|
public static String getTweetPrompt() {
|
||||||
return dotenv.get("TWEET_PROMPT", "Write a short, engaging tweet about technology");
|
return dotenv.get("TWEET_PROMPT", "Write a short, engaging tweet about technology");
|
||||||
|
|||||||
132
src/main/java/com/voidcode/tweetbot/service/GeminiService.java
Normal file
132
src/main/java/com/voidcode/tweetbot/service/GeminiService.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package com.voidcode.tweetbot.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class GeminiService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GeminiService.class);
|
||||||
|
private static final int MAX_TWEET_LENGTH = 280;
|
||||||
|
private static final String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent";
|
||||||
|
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
private final String apiKey;
|
||||||
|
private final OkHttpClient httpClient;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public GeminiService(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.httpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
logger.info("Gemini service initialized with model: gemini-2.0-flash-exp");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate tweet content using Google Gemini
|
||||||
|
* @param prompt The prompt to generate the tweet
|
||||||
|
* @return Generated tweet text
|
||||||
|
*/
|
||||||
|
public String generateTweet(String prompt) {
|
||||||
|
try {
|
||||||
|
logger.info("Generating tweet with prompt: {}", prompt);
|
||||||
|
|
||||||
|
// Build the request body
|
||||||
|
String systemInstruction = "You are a creative social media content creator. Generate engaging tweets that are concise, " +
|
||||||
|
"interesting, and within Twitter's character limit. Do not include hashtags unless specifically " +
|
||||||
|
"requested. Keep it under 280 characters.";
|
||||||
|
|
||||||
|
String userPrompt = prompt + " Keep it under " + MAX_TWEET_LENGTH + " characters.";
|
||||||
|
|
||||||
|
String jsonBody = String.format(
|
||||||
|
"{\"contents\":[{\"parts\":[{\"text\":\"%s\\n\\n%s\"}]}],\"generationConfig\":{\"temperature\":0.8,\"maxOutputTokens\":100}}",
|
||||||
|
escapeJson(systemInstruction),
|
||||||
|
escapeJson(userPrompt)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build the request
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(GEMINI_API_URL + "?key=" + apiKey)
|
||||||
|
.post(RequestBody.create(jsonBody, JSON))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Execute the request
|
||||||
|
try (Response response = httpClient.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
String errorBody = response.body() != null ? response.body().string() : "No error body";
|
||||||
|
logger.error("Gemini API request failed: {} - {}", response.code(), errorBody);
|
||||||
|
throw new IOException("Gemini API request failed: " + response.code() + " - " + errorBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseBody = response.body().string();
|
||||||
|
logger.debug("Gemini API response: {}", responseBody);
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
JsonNode rootNode = objectMapper.readTree(responseBody);
|
||||||
|
JsonNode candidates = rootNode.get("candidates");
|
||||||
|
|
||||||
|
if (candidates == null || candidates.isEmpty()) {
|
||||||
|
throw new RuntimeException("No candidates in Gemini response");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode content = candidates.get(0).get("content");
|
||||||
|
if (content == null) {
|
||||||
|
throw new RuntimeException("No content in Gemini response");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode parts = content.get("parts");
|
||||||
|
if (parts == null || parts.isEmpty()) {
|
||||||
|
throw new RuntimeException("No parts in Gemini response");
|
||||||
|
}
|
||||||
|
|
||||||
|
String generatedText = parts.get(0).get("text").asText().trim();
|
||||||
|
|
||||||
|
// Remove quotes if the AI wrapped the tweet in quotes
|
||||||
|
generatedText = generatedText.replaceAll("^[\"']|[\"']$", "");
|
||||||
|
|
||||||
|
// Ensure it's within Twitter's character limit
|
||||||
|
if (generatedText.length() > MAX_TWEET_LENGTH) {
|
||||||
|
logger.warn("Generated tweet exceeds {} characters, truncating", MAX_TWEET_LENGTH);
|
||||||
|
generatedText = generatedText.substring(0, MAX_TWEET_LENGTH - 3) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Generated tweet: {}", generatedText);
|
||||||
|
return generatedText;
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error generating tweet", e);
|
||||||
|
throw new RuntimeException("Failed to generate tweet: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape special characters for JSON
|
||||||
|
*/
|
||||||
|
private String escapeJson(String text) {
|
||||||
|
return text.replace("\\", "\\\\")
|
||||||
|
.replace("\"", "\\\"")
|
||||||
|
.replace("\n", "\\n")
|
||||||
|
.replace("\r", "\\r")
|
||||||
|
.replace("\t", "\\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the Gemini service
|
||||||
|
*/
|
||||||
|
public void shutdown() {
|
||||||
|
if (httpClient != null) {
|
||||||
|
httpClient.dispatcher().executorService().shutdown();
|
||||||
|
httpClient.connectionPool().evictAll();
|
||||||
|
logger.info("Gemini service shut down");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package com.voidcode.tweetbot.service;
|
|
||||||
|
|
||||||
import com.theokanning.openai.completion.chat.ChatCompletionRequest;
|
|
||||||
import com.theokanning.openai.completion.chat.ChatCompletionResult;
|
|
||||||
import com.theokanning.openai.completion.chat.ChatMessage;
|
|
||||||
import com.theokanning.openai.completion.chat.ChatMessageRole;
|
|
||||||
import com.theokanning.openai.service.OpenAiService;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class OpenAIService {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(OpenAIService.class);
|
|
||||||
private final OpenAiService openAiService;
|
|
||||||
private static final int MAX_TWEET_LENGTH = 280;
|
|
||||||
|
|
||||||
public OpenAIService(String apiKey) {
|
|
||||||
this.openAiService = new OpenAiService(apiKey, Duration.ofSeconds(60));
|
|
||||||
logger.info("OpenAI service initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate tweet content using ChatGPT
|
|
||||||
* @param prompt The prompt to generate the tweet
|
|
||||||
* @return Generated tweet text
|
|
||||||
*/
|
|
||||||
public String generateTweet(String prompt) {
|
|
||||||
try {
|
|
||||||
logger.info("Generating tweet with prompt: {}", prompt);
|
|
||||||
|
|
||||||
// Create the system message to set context
|
|
||||||
ChatMessage systemMessage = new ChatMessage(
|
|
||||||
ChatMessageRole.SYSTEM.value(),
|
|
||||||
"You are a creative social media content creator. Generate engaging tweets that are concise, " +
|
|
||||||
"interesting, and within Twitter's character limit. Do not include hashtags unless specifically " +
|
|
||||||
"requested. Keep it under 280 characters."
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create the user message with the prompt
|
|
||||||
ChatMessage userMessage = new ChatMessage(
|
|
||||||
ChatMessageRole.USER.value(),
|
|
||||||
prompt + " Keep it under " + MAX_TWEET_LENGTH + " characters."
|
|
||||||
);
|
|
||||||
|
|
||||||
List<ChatMessage> messages = new ArrayList<>();
|
|
||||||
messages.add(systemMessage);
|
|
||||||
messages.add(userMessage);
|
|
||||||
|
|
||||||
// Create the chat completion request
|
|
||||||
ChatCompletionRequest request = ChatCompletionRequest.builder()
|
|
||||||
.model("gpt-3.5-turbo")
|
|
||||||
.messages(messages)
|
|
||||||
.temperature(0.8)
|
|
||||||
.maxTokens(100)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Get the response
|
|
||||||
ChatCompletionResult result = openAiService.createChatCompletion(request);
|
|
||||||
String generatedText = result.getChoices().get(0).getMessage().getContent().trim();
|
|
||||||
|
|
||||||
// Remove quotes if the AI wrapped the tweet in quotes
|
|
||||||
generatedText = generatedText.replaceAll("^[\"']|[\"']$", "");
|
|
||||||
|
|
||||||
// Ensure it's within Twitter's character limit
|
|
||||||
if (generatedText.length() > MAX_TWEET_LENGTH) {
|
|
||||||
logger.warn("Generated tweet exceeds {} characters, truncating", MAX_TWEET_LENGTH);
|
|
||||||
generatedText = generatedText.substring(0, MAX_TWEET_LENGTH - 3) + "...";
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Generated tweet: {}", generatedText);
|
|
||||||
return generatedText;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Error generating tweet", e);
|
|
||||||
throw new RuntimeException("Failed to generate tweet: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shutdown the OpenAI service
|
|
||||||
*/
|
|
||||||
public void shutdown() {
|
|
||||||
if (openAiService != null) {
|
|
||||||
openAiService.shutdownExecutor();
|
|
||||||
logger.info("OpenAI service shut down");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user