Files
pj_llama/llama_external_api.py
aken1023 e71495ece4 重構為外網連接版本
主要變更:
- 移除所有內網 IP (192.168.x.x)
- 改用外網端點 (https://llama.theaken.com)
- 新增 llama_external_api.py 專門處理外網連接
- 更新所有文檔為外網版本
- 加入備用端點自動切換機制
- 優化錯誤處理和超時設定
2025-09-19 22:04:10 +08:00

270 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Llama API 外網連接程式
使用外網端點進行 AI 對話
"""
from openai import OpenAI
import requests
import sys
import re
from datetime import datetime
# API 金鑰
API_KEY = "paVrIT+XU1NhwCAOb0X4aYi75QKogK5YNMGvQF1dCyo="
# 外網 API 端點配置
ENDPOINTS = [
{
"name": "Llama 通用端點",
"url": "https://llama.theaken.com/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
},
{
"name": "GPT-OSS 專用端點",
"url": "https://llama.theaken.com/v1/gpt-oss-120b",
"models": ["gpt-oss-120b"]
},
{
"name": "DeepSeek 專用端點",
"url": "https://llama.theaken.com/v1/deepseek-r1-671b",
"models": ["deepseek-r1-671b"]
}
]
# 備用外網端點(如果主要端點無法使用)
BACKUP_ENDPOINTS = [
{
"name": "備用端點 1",
"url": "https://api.llama.theaken.com/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
},
{
"name": "備用端點 2",
"url": "https://llama-api.theaken.com/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
}
]
def clean_response(text):
"""清理 AI 回應中的特殊標記"""
if not text:
return text
# 移除思考標記
if "<think>" in text:
text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
# 移除 channel 標記
if "<|channel|>" in text:
parts = text.split("<|message|>")
if len(parts) > 1:
text = parts[-1]
# 移除結束標記
text = text.replace("<|end|>", "").replace("<|start|>", "")
# 清理多餘空白
text = text.strip()
return text
def test_endpoint(endpoint_info, timeout=10):
"""測試端點是否可用"""
url = endpoint_info["url"]
model = endpoint_info["models"][0] if endpoint_info["models"] else "gpt-oss-120b"
print(f" 測試 {endpoint_info['name']}...", end="", flush=True)
try:
# 處理特殊的模型端點 URL
if url.endswith("/gpt-oss-120b") or url.endswith("/deepseek-r1-671b"):
base_url = url.rsplit("/", 1)[0]
else:
base_url = url
client = OpenAI(
api_key=API_KEY,
base_url=base_url,
timeout=timeout
)
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "test"}],
max_tokens=5
)
print(" ✓ 可用")
return True
except Exception as e:
error_msg = str(e)
if "502" in error_msg:
print(" ✗ 伺服器暫時無法使用 (502)")
elif "timeout" in error_msg.lower():
print(" ✗ 連接超時")
elif "connection" in error_msg.lower():
print(" ✗ 無法連接")
else:
print(f" ✗ 錯誤")
return False
def find_working_endpoint():
"""尋找可用的端點"""
print("\n正在測試外網端點...")
print("-" * 50)
# 先測試主要端點
print("主要端點:")
for endpoint in ENDPOINTS:
if test_endpoint(endpoint):
return endpoint
# 如果主要端點都不可用,測試備用端點
print("\n備用端點:")
for endpoint in BACKUP_ENDPOINTS:
if test_endpoint(endpoint):
return endpoint
return None
def chat_session(endpoint_info):
"""對話主程式"""
print("\n" + "="*60)
print("Llama AI 對話系統")
print("="*60)
print(f"使用端點: {endpoint_info['name']}")
print(f"URL: {endpoint_info['url']}")
print(f"可用模型: {', '.join(endpoint_info['models'])}")
print("\n指令:")
print(" exit/quit - 結束對話")
print(" clear - 清空對話歷史")
print(" model - 切換模型")
print("-"*60)
# 處理 URL
url = endpoint_info["url"]
if url.endswith("/gpt-oss-120b") or url.endswith("/deepseek-r1-671b"):
base_url = url.rsplit("/", 1)[0]
else:
base_url = url
client = OpenAI(api_key=API_KEY, base_url=base_url)
# 選擇模型
if len(endpoint_info['models']) == 1:
current_model = endpoint_info['models'][0]
else:
print("\n選擇模型:")
for i, model in enumerate(endpoint_info['models'], 1):
print(f" {i}. {model}")
choice = input("選擇 (預設: 1): ").strip()
if choice.isdigit() and 1 <= int(choice) <= len(endpoint_info['models']):
current_model = endpoint_info['models'][int(choice)-1]
else:
current_model = endpoint_info['models'][0]
print(f"\n使用模型: {current_model}")
messages = []
while True:
try:
user_input = input("\n你: ").strip()
if not user_input:
continue
if user_input.lower() in ['exit', 'quit']:
print("再見!")
break
if user_input.lower() == 'clear':
messages = []
print("[系統] 對話歷史已清空")
continue
if user_input.lower() == 'model':
if len(endpoint_info['models']) == 1:
print(f"[系統] 此端點只支援 {endpoint_info['models'][0]}")
else:
print("\n可用模型:")
for i, m in enumerate(endpoint_info['models'], 1):
print(f" {i}. {m}")
choice = input("選擇: ").strip()
if choice.isdigit() and 1 <= int(choice) <= len(endpoint_info['models']):
current_model = endpoint_info['models'][int(choice)-1]
print(f"[系統] 已切換到 {current_model}")
continue
messages.append({"role": "user", "content": user_input})
print("\nAI 思考中...", end="", flush=True)
try:
response = client.chat.completions.create(
model=current_model,
messages=messages,
temperature=0.7,
max_tokens=1000
)
ai_response = response.choices[0].message.content
ai_response = clean_response(ai_response)
print("\r" + " "*20 + "\r", end="")
print(f"AI: {ai_response}")
messages.append({"role": "assistant", "content": ai_response})
except Exception as e:
print(f"\r[錯誤] {str(e)[:100]}")
messages.pop()
except KeyboardInterrupt:
print("\n\n[中斷] 使用 exit 命令正常退出")
continue
except EOFError:
print("\n再見!")
break
def main():
print("="*60)
print("Llama AI 外網對話程式")
print(f"時間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*60)
# 尋找可用端點
working_endpoint = find_working_endpoint()
if not working_endpoint:
print("\n" + "="*60)
print("錯誤:無法連接到任何外網端點")
print("="*60)
print("\n可能的原因:")
print("1. 外網 API 伺服器暫時離線")
print("2. 網路連接問題")
print("3. 防火牆或代理設定")
print("\n建議:")
print("1. 稍後再試10-30分鐘後")
print("2. 檢查網路連接")
print("3. 聯繫 API 管理員")
sys.exit(1)
print("\n" + "="*60)
print(f"成功連接到: {working_endpoint['name']}")
print("="*60)
# 開始對話
chat_session(working_endpoint)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n程式已退出")
except Exception as e:
print(f"\n[錯誤] {e}")
import traceback
traceback.print_exc()
sys.exit(1)