Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
420 changes: 420 additions & 0 deletions GEMINI_SUPPORT.md

Large diffs are not rendered by default.

438 changes: 438 additions & 0 deletions INSTALL_DEPENDENCIES.md

Large diffs are not rendered by default.

788 changes: 788 additions & 0 deletions ROUTING_ARCHITECTURE.md

Large diffs are not rendered by default.

713 changes: 713 additions & 0 deletions TESTING.md

Large diffs are not rendered by default.

460 changes: 460 additions & 0 deletions UPGRADE_v2.md

Large diffs are not rendered by default.

177 changes: 177 additions & 0 deletions install-gemini-support.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/bin/bash

# ============================================================================
# Gemini API Support Installer for droid2api
# ============================================================================
# This script upgrades routes.js to add native Gemini API support
# ============================================================================

set -e

echo "=============================================="
echo " πŸ”§ Installing Gemini API Support"
echo "=============================================="
echo ""

# Check if routes.js exists
if [ ! -f "routes.js" ]; then
echo "❌ Error: routes.js not found in current directory"
echo "Please run this script from the droid2api root directory"
exit 1
fi

# Check if transformers exist
if [ ! -f "transformers/request-gemini.js" ] || [ ! -f "transformers/response-gemini.js" ]; then
echo "❌ Error: Gemini transformers not found"
echo "Please ensure request-gemini.js and response-gemini.js are in transformers/"
exit 1
fi

# Check if already installed
if grep -q "request-gemini" routes.js; then
echo "⚠️ Gemini support appears to be already installed"
read -p "Do you want to reinstall? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled"
exit 0
fi
fi

echo "πŸ“¦ Creating backup of routes.js..."
cp routes.js routes.js.backup.$(date +%Y%m%d_%H%M%S)
echo "βœ… Backup created"
echo ""

echo "πŸ” Analyzing routes.js structure..."

# Find the position to insert imports (after existing imports)
IMPORT_LINE=$(grep -n "^import.*from.*'./transformers" routes.js | tail -1 | cut -d: -f1)

if [ -z "$IMPORT_LINE" ]; then
echo "❌ Error: Could not find transformer imports in routes.js"
exit 1
fi

echo "πŸ“ Adding Gemini imports after line $IMPORT_LINE..."

# Create temp file with new imports
head -n "$IMPORT_LINE" routes.js > routes.js.tmp
cat >> routes.js.tmp << 'EOF'
import { geminiToOpenAI, openaiToGemini } from './transformers/request-gemini.js';
import { GeminiResponseTransformer } from './transformers/response-gemini.js';
EOF
tail -n +$((IMPORT_LINE + 1)) routes.js >> routes.js.tmp

# Find where to insert the Gemini route (before export default)
EXPORT_LINE=$(grep -n "^export default router" routes.js.tmp | head -1 | cut -d: -f1)

if [ -z "$EXPORT_LINE" ]; then
echo "❌ Error: Could not find 'export default router' in routes.js"
rm routes.js.tmp
exit 1
fi

echo "πŸ“ Adding Gemini endpoint before line $EXPORT_LINE..."

# Create final file with Gemini route
head -n $((EXPORT_LINE - 1)) routes.js.tmp > routes.js.new
cat >> routes.js.new << 'GEMINIROUTE'

// ============================================================================
// Gemini API Format Handler
// ============================================================================
router.post('/v1/generateContent', async (req, res) => {
logInfo('Gemini API request received');

try {
// Convert Gemini request to OpenAI format internally
const openaiRequest = geminiToOpenAI(req.body);

// Use existing processing logic
const { backendRequest, selectedModel } = await processRequest(
openaiRequest,
req.headers.authorization
);

logInfo('Processed Gemini request', { model: selectedModel.id });

// Handle streaming
if (backendRequest.stream) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

try {
const backendResponse = await forwardRequest(backendRequest, selectedModel);
const transformer = new GeminiResponseTransformer(selectedModel.id);

for await (const chunk of transformer.transformStream(backendResponse.body)) {
res.write(chunk);
}

res.end();
} catch (error) {
logError('Gemini streaming error', error);
res.status(500).json({
error: {
message: error.message,
type: 'internal_error'
}
});
}
} else {
// Non-streaming response
const backendResponse = await forwardRequest(backendRequest, selectedModel);
const openaiResponse = await backendResponse.json();

// Convert OpenAI response back to Gemini format
const geminiResponse = openaiToGemini(openaiResponse);

res.json(geminiResponse);
}
} catch (error) {
logError('Gemini request processing error', error);
res.status(error.status || 500).json({
error: {
message: error.message || 'Internal server error',
type: 'internal_error'
}
});
}
});

GEMINIROUTE

tail -n +$EXPORT_LINE routes.js.tmp >> routes.js.new

# Replace original with new version
mv routes.js.new routes.js
rm routes.js.tmp

echo "βœ… Gemini support installed successfully!"
echo ""
echo "=============================================="
echo " πŸ“‹ Installation Summary"
echo "=============================================="
echo ""
echo "βœ“ Added Gemini transformer imports"
echo "βœ“ Added /v1/generateContent endpoint"
echo "βœ“ Backup saved to routes.js.backup.*"
echo ""
echo "🎯 Gemini API is now available at:"
echo " POST /v1/generateContent"
echo ""
echo "πŸ“– Supported Gemini features:"
echo " β€’ contents/parts structure"
echo " β€’ systemInstruction"
echo " β€’ generationConfig"
echo " β€’ Streaming responses"
echo " β€’ Multi-modal (text + images)"
echo " β€’ Tool/function calling"
echo ""
echo "πŸš€ Restart droid2api to activate:"
echo " npm start"
echo ""
echo "Done! πŸŽ‰"

26 changes: 22 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
{
"name": "droid2api",
"version": "1.3.3",
"description": "OpenAI Compatible API Proxy",
"version": "2.0.0",
"description": "Universal AI API Gateway - OpenAI, Anthropic, Gemini Compatible",
"main": "server.js",
"type": "module",
"scripts": {
"start": "node server.js",
"dev": "node server.js"
"dev": "node server.js",
"install-deps": "npm install -g @anthropic-ai/claude-code @musistudio/claude-code-router"
},
"keywords": ["openai", "api", "proxy"],
"keywords": [
"openai",
"anthropic",
"gemini",
"api",
"proxy",
"gateway",
"claude",
"universal"
],
"author": "",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"node-fetch": "^3.3.2"
},
"optionalDependencies": {
"@anthropic-ai/claude-code": "latest",
"@musistudio/claude-code-router": "latest"
},
"peerDependencies": {
"@anthropic-ai/claude-code": ">=1.0.0",
"@musistudio/claude-code-router": ">=1.0.0"
}
}
Loading