feat: 添加 .env.example 配置示例 & 全环境变量支持
- 新增 .env.example 配置模板,含使用教程和所有供应商参考 - 所有 API 路由支持环境变量 fallback (API_KEY/GEMINI_API_KEY/CLAUDE_API_KEY/OPENAI_API_KEY 等) - 支持自定义端口 (PORT 环境变量) - Electron 启动时自动加载 .env.local - .gitignore 排除 .env.example 以确保模板被追踪
This commit is contained in:
1 parent
5dde77474b
commit
aa6b74d450
7 files changed
+147
-12
No files matched your search
+110
@@ -0,0 +1,110 @@
|
||||
# ============================================
|
||||
# Author App — 环境变量配置
|
||||
# ============================================
|
||||
#
|
||||
# 📖 使用教程:
|
||||
#
|
||||
# 1. 复制本文件并重命名:
|
||||
# 将 .env.example 复制一份,命名为 .env.local
|
||||
# (Windows: 复制粘贴后重命名; 命令行: copy .env.example .env.local)
|
||||
#
|
||||
# 2. 编辑 .env.local:
|
||||
# 取消你需要的配置项的注释(删掉行首的 #),填入你自己的值
|
||||
# 例如想用智谱AI,只需修改 API_KEY 那一行
|
||||
#
|
||||
# 3. 启动应用:
|
||||
# 配置会自动生效,无需其他操作
|
||||
#
|
||||
# ⚠️ 注意事项:
|
||||
# - 不要直接编辑 .env.example,它只是模板
|
||||
# - .env.local 已被 .gitignore 忽略,不会泄露你的 Key
|
||||
# - 如果同时在应用内 ⚙️ 设置了配置,应用内设置优先
|
||||
# - 只需配置你使用的那一个供应商,不需要全部填写
|
||||
#
|
||||
# ============================================
|
||||
|
||||
|
||||
# ==================== 服务端口 ====================
|
||||
|
||||
# 自定义服务端口(默认 3000,被占用时自动递增查找)
|
||||
# PORT=3000
|
||||
|
||||
|
||||
# ==================== OpenAI 兼容 API ====================
|
||||
# 适用于: 智谱AI / DeepSeek / SiliconFlow / 火山引擎 / Moonshot 等
|
||||
# 所有兼容 OpenAI /v1/chat/completions 格式的供应商均可使用
|
||||
|
||||
# API_KEY=你的Key
|
||||
# API_BASE_URL=https://open.bigmodel.cn/api/paas/v4
|
||||
# API_MODEL=glm-4-flash
|
||||
|
||||
# 各供应商 Base URL 参考:
|
||||
# 智谱AI: https://open.bigmodel.cn/api/paas/v4
|
||||
# DeepSeek: https://api.deepseek.com/v1
|
||||
# OpenAI: https://api.openai.com/v1
|
||||
# SiliconFlow: https://api.siliconflow.cn/v1
|
||||
# 火山引擎: https://ark.cn-beijing.volces.com/api/v3
|
||||
# Moonshot: https://api.moonshot.cn/v1
|
||||
|
||||
# 各供应商推荐模型:
|
||||
# 智谱AI: glm-4-flash (免费) / glm-4-plus / glm-4-long / glm-4
|
||||
# DeepSeek: deepseek-chat / deepseek-reasoner
|
||||
# SiliconFlow: deepseek-ai/DeepSeek-V3 / Qwen/Qwen2.5-72B-Instruct
|
||||
# Moonshot: moonshot-v1-8k / moonshot-v1-32k / moonshot-v1-128k
|
||||
|
||||
# 兼容旧版变量名(优先使用 API_KEY)
|
||||
# ZHIPU_API_KEY=
|
||||
|
||||
|
||||
# ==================== Google Gemini ====================
|
||||
# 官网: https://aistudio.google.com
|
||||
|
||||
# GEMINI_API_KEY=你的Key
|
||||
# GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
|
||||
# GEMINI_MODEL=gemini-2.0-flash
|
||||
|
||||
# 可选模型: gemini-2.0-flash-lite / gemini-1.5-flash / gemini-1.5-pro
|
||||
# OpenAI 兼容模式也可用,将 Base URL 改为:
|
||||
# https://generativelanguage.googleapis.com/v1beta/openai
|
||||
# 然后使用上方 API_KEY/API_BASE_URL/API_MODEL 配置即可
|
||||
|
||||
|
||||
# ==================== Claude (Anthropic) ====================
|
||||
# 官网: https://console.anthropic.com
|
||||
|
||||
# CLAUDE_API_KEY=你的Key
|
||||
# CLAUDE_BASE_URL=https://api.anthropic.com
|
||||
# CLAUDE_MODEL=claude-sonnet-4-20250514
|
||||
|
||||
# 可选模型: claude-3-7-sonnet-20250219 / claude-3-5-haiku-20241022
|
||||
|
||||
|
||||
# ==================== OpenAI Responses API ====================
|
||||
# 适用于 OpenAI /v1/responses 格式
|
||||
|
||||
# OPENAI_API_KEY=你的Key
|
||||
# OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# OPENAI_MODEL=gpt-4o-mini
|
||||
|
||||
# 可选模型: gpt-4o / gpt-4-turbo / gpt-3.5-turbo
|
||||
|
||||
|
||||
# ==================== 快速配置示例 ====================
|
||||
#
|
||||
# 🔹 示例1: 用智谱AI免费模型(最简配置,只需一行)
|
||||
# API_KEY=你的智谱Key
|
||||
#
|
||||
# 🔹 示例2: 用DeepSeek
|
||||
# API_KEY=你的DeepSeek_Key
|
||||
# API_BASE_URL=https://api.deepseek.com/v1
|
||||
# API_MODEL=deepseek-chat
|
||||
#
|
||||
# 🔹 示例3: 用Gemini
|
||||
# GEMINI_API_KEY=你的Gemini_Key
|
||||
#
|
||||
# 🔹 示例4: 用Claude
|
||||
# CLAUDE_API_KEY=你的Claude_Key
|
||||
#
|
||||
# 🔹 示例5: 自定义端口 + 智谱AI
|
||||
# PORT=8080
|
||||
# API_KEY=你的智谱Key
|
||||
BIN
Binary file not shown.
@@ -7,9 +7,9 @@ export async function POST(request) {
|
||||
try {
|
||||
const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP, reasoningEffort } = await request.json();
|
||||
|
||||
const apiKey = apiConfig?.apiKey;
|
||||
const baseUrl = (apiConfig?.baseUrl || 'https://api.anthropic.com').replace(/\/$/, '');
|
||||
const model = apiConfig?.model || 'claude-sonnet-4-20250514';
|
||||
const apiKey = apiConfig?.apiKey || process.env.CLAUDE_API_KEY;
|
||||
const baseUrl = (apiConfig?.baseUrl || process.env.CLAUDE_BASE_URL || 'https://api.anthropic.com').replace(/\/$/, '');
|
||||
const model = apiConfig?.model || process.env.CLAUDE_MODEL || 'claude-sonnet-4-20250514';
|
||||
|
||||
if (!apiKey) {
|
||||
return new Response(
|
||||
|
||||
@@ -10,10 +10,10 @@ export async function POST(request) {
|
||||
const apiKey = apiConfig?.apiKey || process.env.GEMINI_API_KEY;
|
||||
let rawBaseUrl = apiConfig?.baseUrl;
|
||||
if (!rawBaseUrl || rawBaseUrl.includes('open.bigmodel.cn')) {
|
||||
rawBaseUrl = 'https://generativelanguage.googleapis.com/v1beta';
|
||||
rawBaseUrl = process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta';
|
||||
}
|
||||
const baseUrl = rawBaseUrl.replace(/\/$/, '');
|
||||
const model = apiConfig?.model || 'gemini-2.0-flash';
|
||||
const model = apiConfig?.model || process.env.GEMINI_MODEL || 'gemini-2.0-flash';
|
||||
|
||||
if (!apiKey) {
|
||||
return new Response(
|
||||
|
||||
@@ -7,9 +7,9 @@ export async function POST(request) {
|
||||
try {
|
||||
const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP } = await request.json();
|
||||
|
||||
const apiKey = apiConfig?.apiKey;
|
||||
const baseUrl = (apiConfig?.baseUrl || 'https://api.openai.com/v1').replace(/\/$/, '');
|
||||
const model = apiConfig?.model || 'gpt-4o-mini';
|
||||
const apiKey = apiConfig?.apiKey || process.env.OPENAI_API_KEY;
|
||||
const baseUrl = (apiConfig?.baseUrl || process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1').replace(/\/$/, '');
|
||||
const model = apiConfig?.model || process.env.OPENAI_MODEL || 'gpt-4o-mini';
|
||||
|
||||
if (!apiKey) {
|
||||
return new Response(
|
||||
|
||||
+3
-3
@@ -7,9 +7,9 @@ export async function POST(request) {
|
||||
try {
|
||||
const { systemPrompt, userPrompt, apiConfig, maxTokens, temperature, topP, reasoningEffort } = await request.json();
|
||||
|
||||
const apiKey = apiConfig?.apiKey || process.env.ZHIPU_API_KEY;
|
||||
const baseUrl = apiConfig?.baseUrl || 'https://open.bigmodel.cn/api/paas/v4';
|
||||
const model = apiConfig?.model || 'glm-4-flash';
|
||||
const apiKey = apiConfig?.apiKey || process.env.API_KEY || process.env.ZHIPU_API_KEY;
|
||||
const baseUrl = apiConfig?.baseUrl || process.env.API_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4';
|
||||
const model = apiConfig?.model || process.env.API_MODEL || 'glm-4-flash';
|
||||
|
||||
if (!apiKey) {
|
||||
return new Response(
|
||||
|
||||
+26
-1
@@ -7,6 +7,31 @@ const net = require('net');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
|
||||
// 加载 .env.local(轻量实现,无需 dotenv 依赖)
|
||||
(function loadEnvFile() {
|
||||
const envPaths = [
|
||||
path.join(__dirname, '..', '.env.local'),
|
||||
path.join(__dirname, '..', '.env'),
|
||||
];
|
||||
for (const envPath of envPaths) {
|
||||
if (fs.existsSync(envPath)) {
|
||||
const lines = fs.readFileSync(envPath, 'utf8').split('\n');
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const eqIdx = trimmed.indexOf('=');
|
||||
if (eqIdx === -1) continue;
|
||||
const key = trimmed.slice(0, eqIdx).trim();
|
||||
const value = trimmed.slice(eqIdx + 1).trim();
|
||||
if (key && !process.env[key]) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
break; // 只加载第一个找到的文件
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// 日志文件 - 写到用户桌面方便查看
|
||||
const logFile = path.join(app.getPath('desktop'), 'author-debug.log');
|
||||
function log(msg) {
|
||||
@@ -27,7 +52,7 @@ let mainWindow;
|
||||
let serverProcess;
|
||||
|
||||
const isDev = process.argv.includes('--dev');
|
||||
const BASE_PORT = 3000;
|
||||
const BASE_PORT = parseInt(process.env.PORT, 10) || 3000;
|
||||
let actualPort = BASE_PORT;
|
||||
let loadRetries = 0;
|
||||
const MAX_LOAD_RETRIES = 10;
|
||||
|
||||
Reference in new issue
Block a user