新增內網外網選擇功能

新增功能:
 llama_universal.py - 主程式支援內外網環境選擇
🌐 內網端點:http://192.168.0.6:21180-21182/v1
🌐 外網端點:https://llama.theaken.com/v1/*
🔄 對話中可使用 'switch' 指令切換環境
📱 智慧環境偵測和錯誤處理

更新內容:
- 新增網路環境選擇介面
- 支援內網三個端點 (21180, 21181, 21182)
- 支援外網三個端點(通用、GPT專用、DeepSeek專用)
- 新增 switch 指令可在對話中切換環境
- 完整的錯誤處理和重試機制
- 更新 README.md 說明新功能和使用方式

現在用戶可以根據所在網路環境自由選擇最適合的連接方式!
This commit is contained in:
2025-09-19 23:27:19 +08:00
parent 390a8cc7f7
commit ece261ed8a
2 changed files with 373 additions and 15 deletions

337
llama_universal.py Normal file
View File

@@ -0,0 +1,337 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Llama API 通用對話程式
支援內網和外網端點選擇
"""
from openai import OpenAI
import requests
import sys
import re
from datetime import datetime
# API 金鑰
API_KEY = "paVrIT+XU1NhwCAOb0X4aYi75QKogK5YNMGvQF1dCyo="
# 網路環境配置
NETWORK_CONFIG = {
"內網": {
"name": "內網環境",
"description": "公司/學校內部網路,使用內部 IP 地址",
"endpoints": [
{
"name": "內網端點 1",
"url": "http://192.168.0.6:21180/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
},
{
"name": "內網端點 2",
"url": "http://192.168.0.6:21181/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
},
{
"name": "內網端點 3",
"url": "http://192.168.0.6:21182/v1",
"models": ["gpt-oss-120b", "deepseek-r1-671b", "qwen3-embedding-8b"]
}
]
},
"外網": {
"name": "外網環境",
"description": "公開網際網路,使用外部域名",
"endpoints": [
{
"name": "通用端點",
"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"]
}
]
}
}
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=8):
"""測試端點是否可用"""
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(" [OK]")
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(" [錯誤]")
return False
def choose_network_environment():
"""選擇網路環境"""
print("\n" + "="*60)
print("選擇網路環境")
print("="*60)
print("\n可用環境:")
environments = list(NETWORK_CONFIG.keys())
for i, env in enumerate(environments, 1):
config = NETWORK_CONFIG[env]
print(f" {i}. {config['name']}")
print(f" 說明:{config['description']}")
print(f" 端點數量:{len(config['endpoints'])}")
while True:
try:
choice = input(f"\n請選擇環境 (1-{len(environments)}),預設為 1: ").strip()
if not choice:
choice = "1"
choice_num = int(choice)
if 1 <= choice_num <= len(environments):
selected_env = environments[choice_num - 1]
print(f"\n已選擇:{NETWORK_CONFIG[selected_env]['name']}")
return selected_env
else:
print(f"請輸入 1-{len(environments)} 之間的數字")
except ValueError:
print("請輸入有效的數字")
except KeyboardInterrupt:
print("\n\n程式已取消")
sys.exit(0)
def find_working_endpoint(environment):
"""尋找指定環境中的可用端點"""
config = NETWORK_CONFIG[environment]
print(f"\n正在測試 {config['name']} 的端點...")
print("-" * 50)
for endpoint in config['endpoints']:
if test_endpoint(endpoint):
return endpoint
return None
def chat_session(endpoint_info, environment):
"""對話主程式"""
print("\n" + "="*60)
print("Llama AI 對話系統")
print("="*60)
print(f"網路環境: {NETWORK_CONFIG[environment]['name']}")
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(" switch - 切換網路環境")
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() == 'switch':
print("[系統] 重新啟動程式以切換網路環境")
return "switch"
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
return "exit"
def main():
while True:
print("="*60)
print("Llama AI 通用對話程式")
print(f"時間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*60)
# 選擇網路環境
environment = choose_network_environment()
# 尋找可用端點
working_endpoint = find_working_endpoint(environment)
if not working_endpoint:
print("\n" + "="*60)
print(f"錯誤:無法連接到任何 {NETWORK_CONFIG[environment]['name']} 端點")
print("="*60)
print("\n可能的原因:")
if environment == "內網":
print("1. 不在內網環境或 IP 設定錯誤")
print("2. 內網 API 服務未啟動")
print("3. 防火牆阻擋連接")
print("\n建議:嘗試選擇外網環境")
else:
print("1. 外網 API 伺服器暫時離線")
print("2. 網路連接問題")
print("3. 防火牆或代理設定")
print("\n建議:嘗試選擇內網環境或稍後再試")
retry = input("\n是否重新選擇環境?(y/n預設: y): ").strip().lower()
if retry in ['n', 'no']:
break
continue
print("\n" + "="*60)
print(f"成功連接到: {working_endpoint['name']}")
print("="*60)
# 開始對話
result = chat_session(working_endpoint, environment)
if result == "exit":
break
elif result == "switch":
continue # 重新開始選擇環境
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)