Skip to content
Open
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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ CODEX_PATH=codex
CODEX_HOME=
CODEX_MODEL=gpt-5.6-sol
CODEX_TIMEOUT_SECONDS=300
AI_REQUEST_TIMEOUT_SECONDS=120
BASE_URL=
API_KEY=
MODEL=
Expand Down
1 change: 1 addition & 0 deletions doc/使用指南.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ AI 配置主要用于 Boss 直聘岗位匹配和打招呼语生成。常见字
| `HOOK_URL` | 企业微信机器人 webhook,用于推送运行消息 |
| `AI_PROVIDER` | 默认 `codex`,复用本机 Codex 登录;填写 `api` 时改用远程接口 |
| `CODEX_MODEL` | Codex CLI 模型,默认 `gpt-5.6-sol` |
| `AI_REQUEST_TIMEOUT_SECONDS` | 一次远程 AI 调用的总超时(含限流重试或兼容切换),默认 120 秒 |
| `BASE_URL` | 仅远程 API 模式使用的模型服务地址 |
| `API_KEY` | 仅远程 API 模式使用的密钥 |
| `MODEL` | 仅远程 API 模式使用的模型名称 |
Expand Down
15 changes: 15 additions & 0 deletions front/app/env-config/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default function EnvConfig() {
codexPath: 'codex',
codexModel: 'gpt-5.6-sol',
codexTimeoutSeconds: '300',
apiTimeoutSeconds: '120',
baseUrl: '',
apiKey: '',
model: '',
Expand Down Expand Up @@ -54,6 +55,7 @@ export default function EnvConfig() {
codexPath: result.data.CODEX_PATH || 'codex',
codexModel: result.data.CODEX_MODEL || 'gpt-5.6-sol',
codexTimeoutSeconds: result.data.CODEX_TIMEOUT_SECONDS || '300',
apiTimeoutSeconds: result.data.AI_REQUEST_TIMEOUT_SECONDS || '120',
baseUrl: result.data.BASE_URL || '',
apiKey: '',
model: result.data.MODEL || '',
Expand Down Expand Up @@ -90,6 +92,7 @@ export default function EnvConfig() {
CODEX_PATH: envConfig.codexPath,
CODEX_MODEL: envConfig.codexModel,
CODEX_TIMEOUT_SECONDS: envConfig.codexTimeoutSeconds,
AI_REQUEST_TIMEOUT_SECONDS: envConfig.apiTimeoutSeconds,
BASE_URL: envConfig.baseUrl,
MODEL: envConfig.model,
BOT_IS_SEND: String(envConfig.botIsSend ?? 0),
Expand Down Expand Up @@ -312,6 +315,18 @@ export default function EnvConfig() {
/>
<p className="text-xs text-muted-foreground">DeepSeek 推荐模型 deepseek-chat;也可以填写其他 OpenAI-compatible 模型名</p>
</div>
<div className="space-y-2">
<Label htmlFor="apiTimeout">远程 API 总超时(秒)</Label>
<Input
id="apiTimeout"
type="number"
min="1"
max="1800"
value={envConfig.apiTimeoutSeconds}
onChange={(e) => setEnvConfig({ ...envConfig, apiTimeoutSeconds: e.target.value })}
/>
<p className="text-xs text-muted-foreground">默认 120 秒;超时或网络中断不会自动重发,以避免重复计费。</p>
</div>
</div>
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,13 @@ public ResponseEntity<Map<String, Object>> savePriorityCompanies(
public ResponseEntity<Map<String, Object>> analyzeJob(@RequestBody JobAiAnalysisService.JobAnalysisRequest request) {
Map<String, Object> response = new HashMap<>();
try {
response.put("success", true);
response.put("data", jobAiAnalysisService.analyzeJob(request));
response.put("message", "AI岗位分析完成");
return ResponseEntity.ok(response);
JobAiAnalysisService.AnalysisResult result = jobAiAnalysisService.analyzeJob(request);
response.put("success", !result.isFailure());
response.put("data", result);
response.put("message", result.isFailure() ? result.getSummary() : "AI岗位分析完成");
return result.isFailure()
? ResponseEntity.status(502).body(response)
: ResponseEntity.ok(response);
} catch (Exception e) {
log.error("AI岗位分析失败", e);
response.put("success", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ public ResponseEntity<Map<String, Object>> generateBossAiKeywords(@RequestBody(r
"message", e.getMessage(),
"keywords", List.of()
));
} catch (RuntimeException e) {
log.warn("生成 Boss AI 关键词失败: {}", e.getMessage());
return ResponseEntity.status(502).body(Map.of(
"success", false,
"message", e.getMessage() == null ? "AI 关键词生成失败" : e.getMessage(),
"keywords", List.of()
));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.getjobs.application.service;

/**
* 不携带 Provider 原始响应的安全异常;可直接用于任务错误信息和本机 API 提示。
*/
public class AiProviderException extends RuntimeException {
private final Code code;
private final Integer httpStatus;
private final String clientRequestId;
private final String providerRequestId;
private final boolean outcomeUnknown;

public AiProviderException(Code code,
String message,
Integer httpStatus,
String clientRequestId,
String providerRequestId,
boolean outcomeUnknown,
Throwable cause) {
super(message, cause);
this.code = code;
this.httpStatus = httpStatus;
this.clientRequestId = clientRequestId;
this.providerRequestId = providerRequestId;
this.outcomeUnknown = outcomeUnknown;
}

public Code getCode() {
return code;
}

public Integer getHttpStatus() {
return httpStatus;
}

public String getClientRequestId() {
return clientRequestId;
}

public String getProviderRequestId() {
return providerRequestId;
}

public boolean isOutcomeUnknown() {
return outcomeUnknown;
}

public enum Code {
RATE_LIMITED,
HTTP_4XX,
HTTP_5XX,
TIMEOUT,
NETWORK,
EMPTY_RESPONSE,
INVALID_RESPONSE
}
}
Loading
Loading