Using Gemini v2.5 free tier

This commit is contained in:
2025-10-30 20:50:14 +09:00
parent 9b8e79877f
commit 48497b3c73
4 changed files with 30 additions and 30 deletions

View File

@@ -1,12 +0,0 @@
{
"permissions": {
"allow": [
"Bash(tree:*)",
"Bash(mvn clean compile:*)",
"WebFetch(domain:github.com)",
"Bash(rm:*)"
],
"deny": [],
"ask": []
}
}

1
.gitignore vendored
View File

@@ -45,3 +45,4 @@ tweetbot.log
# Java
hs_err_pid*
replay_pid*
/.claude/

View File

@@ -4,7 +4,7 @@ An automated Twitter bot that generates and posts tweets using Google Gemini's f
## Features
- Generate tweet content using Google Gemini (gemini-2.0-flash-exp) - **Free Tier**
- Generate tweet content using Google Gemini (gemini-2.5-flash) - **Free Tier**
- **Three operation modes:**
- Interactive mode with manual approval
- Auto-post mode for one-time tweets
@@ -35,10 +35,10 @@ An automated Twitter bot that generates and posts tweets using Google Gemini's f
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
**Note:** The free tier of Gemini 2.5 Flash includes:
- 10 requests per minute
- 250,000 tokens per minute
- 250 requests per day
- More than enough for a tweet bot!
### 2. Get Twitter API Credentials
@@ -382,7 +382,7 @@ This error means your Twitter API access level doesn't support v1.1 tweet postin
### "Failed to generate tweet"
1. Verify your Gemini API key is valid
2. Check that you're within the free tier rate limits (15 RPM, 1500 RPD)
2. Check that you're within the free tier rate limits (10 RPM, 250 RPD)
3. Review the error message in logs
4. Ensure your Google Cloud project is properly configured

View File

@@ -12,7 +12,7 @@ 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 String GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
private final String apiKey;
@@ -27,7 +27,7 @@ public class GeminiService {
.writeTimeout(60, TimeUnit.SECONDS)
.build();
this.objectMapper = new ObjectMapper();
logger.info("Gemini service initialized with model: gemini-2.0-flash-exp");
logger.info("Gemini service initialized with model: gemini-2.5-flash");
}
/**
@@ -39,19 +39,16 @@ public class GeminiService {
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.";
// Build the request body with simplified prompt
String fullPrompt = "You are a creative social media content creator. Generate an engaging tweet (under 280 characters) about: " + prompt;
String jsonBody = String.format(
"{\"contents\":[{\"parts\":[{\"text\":\"%s\\n\\n%s\"}]}],\"generationConfig\":{\"temperature\":0.8,\"maxOutputTokens\":100}}",
escapeJson(systemInstruction),
escapeJson(userPrompt)
"{\"contents\":[{\"parts\":[{\"text\":\"%s\"}]}],\"generationConfig\":{\"temperature\":0.8,\"maxOutputTokens\":100000}}",
escapeJson(fullPrompt)
);
logger.debug("Request body: {}", jsonBody);
// Build the request
Request request = new Request.Builder()
.url(GEMINI_API_URL + "?key=" + apiKey)
@@ -84,7 +81,21 @@ public class GeminiService {
JsonNode parts = content.get("parts");
if (parts == null || parts.isEmpty()) {
throw new RuntimeException("No parts in Gemini response");
// Check for finish reason to understand why content was blocked
JsonNode finishReason = candidates.get(0).get("finishReason");
JsonNode safetyRatings = candidates.get(0).get("safetyRatings");
String errorMsg = "No parts in Gemini response.";
if (finishReason != null) {
errorMsg += " Finish reason: " + finishReason.asText();
}
if (safetyRatings != null) {
errorMsg += " Safety ratings: " + safetyRatings.toString();
}
errorMsg += " Full candidate: " + candidates.get(0).toString();
logger.error(errorMsg);
throw new RuntimeException(errorMsg);
}
String generatedText = parts.get(0).get("text").asText().trim();