fix(code-review): 修復 Hermes 401 與 OpenClaw GEMINI_API_KEY 缺失
All checks were successful
CD Pipeline / deploy (push) Successful in 1m17s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m17s
Hermes 掃描:改直呼內網 http://192.168.0.111:11434/api/generate (棄用 ai_provider_service,避開公網 Ollama 401 認證問題) OpenClaw 評估:Gemini 優先,降級用 elephant_service(OpenRouter) (容器內無 GEMINI_API_KEY,但 OPENROUTER_API_KEY 一定存在) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -189,10 +189,10 @@ class CodeReviewPipeline:
|
||||
# ── Step 2:Hermes 掃描 ───────────────────────────────────────────────────
|
||||
|
||||
def _hermes_scan(self, files: Dict[str, str]) -> List[Dict]:
|
||||
"""直呼內網 Ollama(http://192.168.0.111:11434),免認證"""
|
||||
try:
|
||||
from services.ai_provider import ai_provider_service
|
||||
import requests as _req
|
||||
|
||||
# 最多送 4 個檔案給 Hermes,避免 context overflow
|
||||
files_text = "\n\n".join(
|
||||
f"### {name}\n```python\n{content}\n```"
|
||||
for name, content in list(files.items())[:4]
|
||||
@@ -212,23 +212,21 @@ class CodeReviewPipeline:
|
||||
|
||||
只輸出 JSON 陣列,不含其他文字。無問題時輸出 []"""
|
||||
|
||||
resp = ai_provider_service.generate(
|
||||
prompt=prompt,
|
||||
provider="ollama",
|
||||
model="hermes3:latest",
|
||||
temperature=0.1,
|
||||
resp = _req.post(
|
||||
"http://192.168.0.111:11434/api/generate",
|
||||
json={"model": "hermes3:latest", "prompt": prompt,
|
||||
"stream": False, "options": {"temperature": 0.1}},
|
||||
timeout=120,
|
||||
)
|
||||
if not (resp and resp.success):
|
||||
logger.warning("[CodeReview] Hermes 未回應: %s", getattr(resp, "error", ""))
|
||||
return []
|
||||
resp.raise_for_status()
|
||||
raw = resp.json().get("response", "").strip()
|
||||
|
||||
match = re.search(r"\[.*\]", resp.content, re.DOTALL)
|
||||
match = re.search(r"\[.*\]", raw, re.DOTALL)
|
||||
if not match:
|
||||
logger.warning("[CodeReview] Hermes 回應無 JSON: %s", raw[:200])
|
||||
return []
|
||||
findings = json.loads(match.group())
|
||||
|
||||
# 更新 severity 計數
|
||||
for f in findings:
|
||||
sev = f.get("severity", "LOW").lower()
|
||||
if sev in self.state["severity_summary"]:
|
||||
@@ -244,46 +242,64 @@ class CodeReviewPipeline:
|
||||
# ── Step 3:OpenClaw 評估 ──────────────────────────────────────────────────
|
||||
|
||||
def _openclaw_assess(self, files: Dict[str, str], findings: List[Dict]) -> str:
|
||||
if not GEMINI_API_KEY:
|
||||
logger.warning("[CodeReview] GEMINI_API_KEY 未設定,跳過 OpenClaw")
|
||||
return ""
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
genai.configure(api_key=GEMINI_API_KEY)
|
||||
model = genai.GenerativeModel(
|
||||
model_name=REVIEW_MODEL,
|
||||
generation_config=genai.types.GenerationConfig(
|
||||
temperature=0.3, max_output_tokens=1500,
|
||||
),
|
||||
system_instruction=(
|
||||
"你是 OpenClaw 程式碼品質戰略分析師,以技術主管視角評估部署後程式碼。"
|
||||
"語言:繁體中文。風格:精準、數據導向、可執行建議。"
|
||||
),
|
||||
)
|
||||
sev = self.state["severity_summary"]
|
||||
findings_json = json.dumps(findings[:8], ensure_ascii=False, indent=2)
|
||||
files_list = "\n".join(f"- {k} ({len(v)} 字元)" for k, v in list(files.items())[:5])
|
||||
"""
|
||||
優先用 Gemini(GEMINI_API_KEY),降級用 ElephantAlpha via OpenRouter
|
||||
(容器內 OPENROUTER_API_KEY 一定存在)
|
||||
"""
|
||||
sev = self.state["severity_summary"]
|
||||
findings_json = json.dumps(findings[:8], ensure_ascii=False, indent=2)
|
||||
files_list = "\n".join(f"- {k} ({len(v)} 字元)" for k, v in list(files.items())[:5])
|
||||
|
||||
prompt = f"""【部署資訊】Commit {self.commit_sha[:8]} @ {self.branch}
|
||||
system = (
|
||||
"你是 OpenClaw 程式碼品質戰略分析師,以技術主管視角評估部署後程式碼。"
|
||||
"語言:繁體中文。風格:精準、數據導向、可執行建議。"
|
||||
)
|
||||
user_prompt = f"""【部署】Commit {self.commit_sha[:8]} @ {self.branch}
|
||||
【變更檔案】
|
||||
{files_list}
|
||||
|
||||
【Hermes 掃描摘要】CRITICAL={sev['critical']} HIGH={sev['high']} MEDIUM={sev['medium']} LOW={sev['low']}
|
||||
【Hermes 詳細問題】
|
||||
【問題明細】
|
||||
{findings_json}
|
||||
|
||||
請產出程式碼品質評估(使用 HTML <b> 標題,150字以內):
|
||||
<b>🔍 整體風險等級</b>(一句理由)
|
||||
<b>⚠️ 最需關注問題</b>(TOP 2)
|
||||
<b>💡 架構優化方向</b>(1條長期建議)
|
||||
<b>✅ 本次部署亮點</b>"""
|
||||
|
||||
<b>🔍 整體風險等級</b>(CRITICAL / HIGH / MEDIUM / LOW,一句理由)
|
||||
<b>⚠️ 最需關注問題</b>(TOP 2,具體說明)
|
||||
<b>💡 架構優化方向</b>(1 條長期建議)
|
||||
<b>✅ 本次部署亮點</b>(值得肯定的地方)"""
|
||||
# 優先 Gemini
|
||||
if GEMINI_API_KEY:
|
||||
try:
|
||||
import google.generativeai as genai
|
||||
genai.configure(api_key=GEMINI_API_KEY)
|
||||
model = genai.GenerativeModel(
|
||||
model_name=REVIEW_MODEL,
|
||||
generation_config=genai.types.GenerationConfig(
|
||||
temperature=0.3, max_output_tokens=1500,
|
||||
),
|
||||
system_instruction=system,
|
||||
)
|
||||
resp = model.generate_content(user_prompt, request_options={"timeout": 90})
|
||||
return resp.text or ""
|
||||
except Exception as e:
|
||||
logger.warning("[CodeReview] OpenClaw Gemini 失敗,降級 ElephantAlpha: %s", e)
|
||||
|
||||
resp = model.generate_content(prompt, request_options={"timeout": 90})
|
||||
return resp.text or ""
|
||||
# 降級:ElephantAlpha via OpenRouter(OPENROUTER_API_KEY 容器內一定有)
|
||||
try:
|
||||
from services.elephant_service import elephant_service
|
||||
resp = elephant_service.generate(
|
||||
prompt=user_prompt,
|
||||
system_prompt=system,
|
||||
temperature=0.3,
|
||||
timeout=90,
|
||||
)
|
||||
if resp.success:
|
||||
return resp.content or ""
|
||||
except Exception as e:
|
||||
logger.warning("[CodeReview] OpenClaw 評估失敗: %s", e)
|
||||
return ""
|
||||
logger.warning("[CodeReview] OpenClaw ElephantAlpha 降級也失敗: %s", e)
|
||||
|
||||
return ""
|
||||
|
||||
# ── Step 4:ElephantAlpha 決策 ─────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user