A serverless LINE chatbot that provides real-time Japanese transportation information with bilingual station names (Traditional Chinese/Japanese). Powered by Google Apps Script and Gemini 2.5 Flash with Google Search grounding.
- ๐ Real-time Transit Data - Leverages Gemini 2.5 Flash with Google Search for up-to-date train schedules
- ๐ Bilingual Station Names - All stations displayed as "ไธญๆ (ๆฅๆ)" for easy navigation
- ๐ฌ LINE Integration - Instant queries through familiar LINE messaging interface
- ๐ก๏ธ Robust Error Handling - Graceful degradation with user-friendly error messages
- ๐ Serverless Architecture - Zero-cost hosting on Google Apps Script
- ๐ Structured Responses - Clean, bullet-point formatted transit information
User Query:
ๆๆฅ 09:00 ๆฑไบฌๅฐ่ผไบๆพค
Bot Response:
ใๆจ่ฆ็ญๆฌกใ
* ่ทฏ็ทๅ็จฑ๏ผๅ้ธๆฐๅนน็ท - ๆทบ้่ (ใใใพ 605ๅท)
* ๅบ็ผๆ้๏ผ09:04 ๅพ ๆฑไบฌ (ๆฑไบฌ) ๅบ็ผ
* ๆต้ๆ้๏ผ10:16 ๅฐ้ ่ผไบๆพค (่ปฝไบๆฒข)
* ไน่ปๆๅฐ๏ผ20-23 ่ๆฐๅนน็ทๆๅฐ
* ็ฎ็ๅฐ๏ผ้ท้ (้ท้) ๆนๅ
graph LR
A[LINE User] -->|Message| B[LINE Platform]
B -->|Webhook| C[Google Apps Script]
C -->|Query| D[Gemini 2.5 Flash]
D -->|Search| E[Google Search]
E -->|Results| D
D -->|Response| C
C -->|Reply| B
B -->|Message| A
Tech Stack:
- Frontend: LINE Messaging API
- Backend: Google Apps Script (JavaScript)
- AI: Google Gemini 2.5 Flash API
- Data Source: Google Search (real-time grounding)
- Deployment: Google Cloud Platform
-
Clone the repository
git clone https://github.com/sean1093/jp-transit-bot.git
-
Create a new Apps Script project
- Visit Google Apps Script
- Click New Project
- Name it "JP-Transit Bot"
-
Copy the code
- Copy contents from
Code.gsto the editor - Create
appsscript.jsonand copy its contents
- Copy contents from
-
Configure API credentials
- Go to Project Settings โ Script Properties
- Add:
GEMINI_API_KEY: Your Gemini API keyLINE_CHANNEL_ACCESS_TOKEN: Your LINE channel access token
-
Deploy as Web App
- Click Deploy โ Manage deployments
- Edit @HEAD deployment
- Set Who has access to Anyone
- Copy the Web App URL
-
Configure LINE Webhook
- In LINE Developers Console
- Go to Messaging API โ Webhook settings
- Paste the Web App URL
- Enable Use webhook
- Disable Auto-reply messages
# Clone and setup
git clone https://github.com/sean1093/jp-transit-bot.git
cd jp-transit-bot
# Install dependencies
npm install
# Install clasp globally (if not already installed)
npm install -g @google/clasp
# Login to Google
clasp login
# Build TypeScript and push to Apps Script
npm run push
# Configure credentials in Apps Script UI
# Then deploy as Web App (see step 5-6 above)Note: This project uses TypeScript for type safety. The npm run push command automatically compiles TypeScript to JavaScript and pushes to Google Apps Script.
- Add the bot as a LINE friend (scan QR code in LINE Developers Console)
- Send a query in natural language:
ๆๅคฉๆฉไธ9้ปๅพๆฑไบฌๅฐ่ผไบๆพคไปๅคฉไธๅๅพๆฐๅฎฟๅฐ็ฎฑๆ นๅพๅคฉ 14:00 ๅคง้ชๅฐไบฌ้ฝ
- Receive instant response with train details and bilingual station names
jp-transit-bot/
โโโ src/
โ โโโ Code.ts # Main application source (TypeScript)
โ โโโ appsscript.json # Apps Script manifest (timezone: Asia/Tokyo)
โโโ build/ # Compiled JavaScript (auto-generated, gitignored)
โ โโโ Code.js # Compiled from Code.ts
โ โโโ appsscript.json # Copied from src/
โโโ package.json # npm dependencies and scripts
โโโ tsconfig.json # TypeScript configuration
โโโ .clasp.json # Clasp configuration (gitignored)
โโโ .claspignore # Clasp deployment exclusions
โโโ .env.example # Environment variables template
โโโ .gitignore # Git exclusions
โโโ SPEC.md # Technical specification
โโโ LICENSE # MIT License
โโโ README.md # This file
All source code is written in TypeScript for type safety and better developer experience.
| Function | Description | Parameters |
|---|---|---|
doPost(e) |
Webhook handler for LINE messages | GoogleAppsScript.Events.DoPost |
doGet(e) |
Health check endpoint | GoogleAppsScript.Events.DoGet |
getGeminiResponse(text) |
Gemini API integration with Google Search | text: string |
sendLineMessage(token, text) |
LINE reply message sender | token: string, text: string |
testGemini() |
Local testing function | void |
| Variable | Description | Example |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key | AIza... |
LINE_CHANNEL_ACCESS_TOKEN |
LINE Messaging API token | eyJh... |
{
model: "gemini-2.5-flash",
temperature: 0.0, // Factual consistency
maxOutputTokens: 8192,
tools: [{ googleSearch: {} }] // Real-time grounding
}The bot is configured with strict prompts to ensure:
- Traditional Chinese output only
- Bilingual station format:
ไธญๆ (ๆฅๆ) - Structured bullet-point responses
- Factual data only (no conversational fluff)
| Limit | Value |
|---|---|
| Requests per minute | 15 |
| Requests per day | 1,500 |
| Tokens per minute | 1,000,000 |
Estimated capacity: ~1,500 transit queries per day
// In Apps Script Editor
// Select testGemini() and click Runcurl https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec
# Expected: {"status":"ok","message":"JP-Transit Bot is running",...}- Add bot as friend via QR code
- Send test message
- Check Apps Script Executions tab for logs
Webhook Returns 302 Error
- Ensure deployment "Who has access" is set to Anyone
- Verify URL ends with
/exec - Redeploy by editing @HEAD deployment
No Response from Bot
- Check Executions tab in Apps Script for errors
- Verify Script Properties are set correctly
- Ensure Use webhook is enabled in LINE console
- Confirm Auto-reply messages is disabled
API Quota Exceeded
- Monitor usage at Google AI Studio
- Consider upgrading to pay-as-you-go (~$0.30 per 1,000 queries)
- Free tier resets daily at UTC 00:00
Wrong Language or Format
- Temperature is set to 0.0 for consistency
- Check
SYSTEM_INSTRUCTIONin src/Code.ts - Verify Gemini API is using correct model
- โ No hardcoded credentials - All API keys stored in Script Properties
- โ
Gitignored secrets -
.clasp.jsonexcluded from repository - โ HTTPS only - All API calls encrypted
- โ Input validation - Webhook payload verification
- โ Error isolation - Individual message processing with try-catch
# 1. Install dependencies (first time only)
npm install
# 2. Make changes to src/Code.ts locally
# 3. Build and push to Apps Script
npm run push
# This compiles TypeScript and pushes to Google Apps Script
# 4. Test in Apps Script Editor or via LINE
# 5. Commit to Git
git add .
git commit -m "Your message"
git pushnpm run build # Compile TypeScript to JavaScript
npm run push # Build and push to Google Apps Script
npm run watch # Watch mode for development
npm run deploy # Build, push, and create new deployment
npm run clean # Remove build directory- Type Safety: Catch errors at compile time
- Better IDE Support: IntelliSense and autocomplete
- Google Apps Script Types: Full type definitions via
@types/google-apps-script - Modern JavaScript: Use latest ES features, compiled to ES2019
- Type Safety: Full TypeScript with strict mode
- Error Handling: Comprehensive try-catch with logging
- Documentation: JSDoc comments for all functions
- Interfaces: Well-defined types for LINE/Gemini APIs
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Maintain code style consistency
- Add tests for new features
- Update documentation
- Follow semantic versioning
This project is licensed under the MIT License - see the LICENSE file for details.
- Google Gemini - AI-powered transit information
- LINE Messaging API - Chat platform integration
- Google Apps Script - Serverless hosting
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation:
If you find this project useful, please consider giving it a star! โญ
Made with โค๏ธ for travelers exploring Japan