A simple Bluesky bot to make sense of the noise, with responses powered by Gemini, similar to Grok.

feat: model overload error

Changed files
+21 -11
src
+5 -2
docker-compose.yml
··· 6 environment: 7 - "AUTHORIZED_USERS=${AUTHORIZED_USERS}" 8 - "SERVICE=${SERVICE:?https://bsky.social}" 9 - - "DB_PATH=sqlite.db" 10 - "GEMINI_MODEL=${GEMINI_MODEL:-gemini-2.5-flash}" 11 - "DID=${DID:?}" 12 - "HANDLE=${HANDLE:?}" ··· 14 - "GEMINI_API_KEY=${GEMINI_API_KEY:?}" 15 - "USE_JETSTREAM=${USE_JETSTREAM:-false}" 16 volumes: 17 - - aero_db:/sqlite.db
··· 6 environment: 7 - "AUTHORIZED_USERS=${AUTHORIZED_USERS}" 8 - "SERVICE=${SERVICE:?https://bsky.social}" 9 + - DB_PATH=/data/sqlite.db 10 - "GEMINI_MODEL=${GEMINI_MODEL:-gemini-2.5-flash}" 11 - "DID=${DID:?}" 12 - "HANDLE=${HANDLE:?}" ··· 14 - "GEMINI_API_KEY=${GEMINI_API_KEY:?}" 15 - "USE_JETSTREAM=${USE_JETSTREAM:-false}" 16 volumes: 17 + - "aero_db:/data" 18 + 19 + volumes: 20 + aero_db:
+3
src/core.ts
··· 63 export const QUOTA_EXCEEDED_MESSAGE = 64 "You have exceeded your daily message quota (15). Please wait 24 hours before trying again."; 65 66 export const UNAUTHORIZED_MESSAGE = 67 "I can’t make sense of your noise just yet. You’ll need to be whitelisted before I can help."; 68
··· 63 export const QUOTA_EXCEEDED_MESSAGE = 64 "You have exceeded your daily message quota (15). Please wait 24 hours before trying again."; 65 66 + export const ERROR_MESSAGE = 67 + "Sorry, I ran into an issue analyzing that post. Please try again."; 68 + 69 export const UNAUTHORIZED_MESSAGE = 70 "I can’t make sense of your noise just yet. You’ll need to be whitelisted before I can help."; 71
+8 -3
src/handlers/messages.ts
··· 174 }); 175 } 176 } 177 - } catch (error) { 178 logger.error("Error in post handler:", error); 179 180 await conversation.sendMessage({ 181 - text: 182 - "Sorry, I ran into an issue analyzing that post. Please try again.", 183 }); 184 } 185 }
··· 174 }); 175 } 176 } 177 + } catch (error: any) { 178 logger.error("Error in post handler:", error); 179 + let errorMsg = c.ERROR_MESSAGE; 180 + 181 + if (error.error.code == 503) { 182 + errorMsg = 183 + "Sorry, the AI model is currently overloaded. Please try again later."; 184 + } 185 186 await conversation.sendMessage({ 187 + text: errorMsg, 188 }); 189 } 190 }
+2 -3
src/utils/conversation.ts
··· 8 import { conversations, messages } from "../db/schema"; 9 import { and, eq } from "drizzle-orm"; 10 import { env } from "../env"; 11 - import { bot, MAX_GRAPHEMES } from "../core"; 12 import { parsePost, parsePostImages, traverseThread } from "./post"; 13 14 /* ··· 137 }; 138 } catch (e) { 139 convo.sendMessage({ 140 - text: 141 - "Sorry, I ran into an issue analyzing that post. Please try again.", 142 }); 143 144 throw new Error("Failed to parse conversation");
··· 8 import { conversations, messages } from "../db/schema"; 9 import { and, eq } from "drizzle-orm"; 10 import { env } from "../env"; 11 + import { bot, ERROR_MESSAGE, MAX_GRAPHEMES } from "../core"; 12 import { parsePost, parsePostImages, traverseThread } from "./post"; 13 14 /* ··· 137 }; 138 } catch (e) { 139 convo.sendMessage({ 140 + text: ERROR_MESSAGE, 141 }); 142 143 throw new Error("Failed to parse conversation");
+3 -3
src/utils/post.ts
··· 42 ) return undefined; 43 44 const record = (post.embed as RecordEmbed || RecordWithMediaEmbed).record; 45 - console.log("embed: ", post.embed); 46 - console.log("record: ", record); 47 const embedPost = await c.bot.getPost(record.uri); 48 49 return await parsePost(embedPost, false); ··· 63 } 64 } 65 66 - return images.map((image, idx) => parseImage(image, idx + 1)); 67 } 68 69 function parseImage(image: EmbedImage, index: number) {
··· 42 ) return undefined; 43 44 const record = (post.embed as RecordEmbed || RecordWithMediaEmbed).record; 45 const embedPost = await c.bot.getPost(record.uri); 46 47 return await parsePost(embedPost, false); ··· 61 } 62 } 63 64 + return images.map((image, idx) => parseImage(image, idx + 1)).filter((img) => 65 + img.alt.length > 0 66 + ); 67 } 68 69 function parseImage(image: EmbedImage, index: number) {