File size: 5,506 Bytes
1a93d7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""配置模块,管理API密钥、代理设置和OpenAI客户端配置。

此模块包含以下主要功能:
- OpenAI API配置
- 代理服务器设置
- OpenAI客户端初始化
- API调用工具函数
- GPT响应解析函数
"""

import os
import json
from openai import OpenAI
from typing import List, Dict, Optional, Any, Union, Tuple

# API配置
# 注意:在实际生产环境中,应该从环境变量或配置文件中读取API密钥

# GeoNames API配置
GEONAMES_USERNAME = "demo"  # 替换为你的GeoNames用户名
GEONAMES_API_BASE = "http://api.geonames.org"

# OpenAI API配置
# 从环境变量中获取API密钥,如果不存在则使用默认值(仅用于本地开发)
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")

# 使用的GPT模型版本
GPT_MODEL = "gpt-4.1-mini"

# Proxy Configuration
# 从环境变量中获取代理设置,如果已经设置则不覆盖
if not os.environ.get('https_proxy'):
    os.environ['https_proxy'] = os.environ.get('HTTPS_PROXY', '')
if not os.environ.get('http_proxy'):
    os.environ['http_proxy'] = os.environ.get('HTTP_PROXY', '')

# Initialize OpenAI client
client = OpenAI(api_key=OPENAI_API_KEY)

def get_completion(messages: List[Dict[str, str]], model: str = GPT_MODEL, temperature: float = 0.5) -> Optional[str]:
    """调用OpenAI API获取回复。

    使用配置的OpenAI客户端发送请求并获取回复。支持自定义模型和temperature参数。

    Args:
        messages (List[Dict[str, str]]): 消息列表,每个消息包含role和content
        model (str, optional): 使用的GPT模型名称。默认为配置中的GPT_MODEL
        temperature (float, optional): 采样温度,控制输出的随机性。默认为0.2

    Returns:
        Optional[str]: API返回的文本回复。如果请求失败则返回None
    """
    try:
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=temperature
        )
        return response.choices[0].message.content
    except Exception as e:
        print(f"Error in API call: {e}")
        return None


def extract_json_from_markdown(response: str) -> str:
    """从Markdown代码块中提取JSON内容。

    Args:
        response (str): 可能包含Markdown代码块的响应文本

    Returns:
        str: 提取的JSON内容或原始响应
    """
    if response and response.strip().startswith('```') and '```' in response:
        # 提取代码块内容
        code_content = response.split('```', 2)[1]
        if code_content.startswith('json'):
            code_content = code_content[4:].strip()
        response = code_content.strip()
    return response


def parse_json_response(response: str, default_value: Any = None) -> Any:
    """解析JSON响应,处理可能的解析错误。

    Args:
        response (str): JSON格式的响应文本
        default_value (Any, optional): 解析失败时返回的默认值

    Returns:
        Any: 解析后的JSON对象或默认值
    """
    if not response:
        return default_value
    
    # 首先尝试从Markdown中提取JSON
    response = extract_json_from_markdown(response)
    
    try:
        return json.loads(response)
    except json.JSONDecodeError as e:
        print(f"\nWarning: Failed to parse JSON response: {e}")
        print(f"Response was: {response[:100]}..." if len(response) > 100 else f"Response was: {response}")
        return default_value


def parse_gpt_response(response: str, expected_fields: List[str] = None, field_defaults: Dict[str, Any] = None) -> Dict[str, Any]:
    """解析GPT响应,提取预期字段并应用默认值。

    Args:
        response (str): GPT响应文本
        expected_fields (List[str], optional): 预期的字段列表
        field_defaults (Dict[str, Any], optional): 字段默认值字典

    Returns:
        Dict[str, Any]: 包含所有预期字段的字典
    """
    if field_defaults is None:
        field_defaults = {}
    
    # 解析JSON响应
    result = parse_json_response(response, {})
    
    # 如果没有指定预期字段,直接返回解析结果
    if not expected_fields:
        return result
    
    # 确保返回所有预期字段
    output = {}
    for field in expected_fields:
        output[field] = result.get(field, field_defaults.get(field))
    
    return output


def parse_nested_json_response(response: str) -> Tuple[Dict[str, Any], bool]:
    """解析可能嵌套的JSON响应。

    处理可能嵌套在Markdown代码块中的JSON字符串表示的JSON对象。

    Args:
        response (str): 可能包含嵌套JSON的响应文本

    Returns:
        Tuple[Dict[str, Any], bool]: 解析后的JSON对象和是否成功解析的标志
    """
    # 首先从Markdown中提取内容
    extracted = extract_json_from_markdown(response)
    
    # 尝试解析JSON
    try:
        result = json.loads(extracted)
        
        # 检查是否是JSON字符串表示的JSON对象
        if isinstance(result, dict) and len(result) == 1 and next(iter(result.values())).startswith('{'):
            key = next(iter(result.keys()))
            try:
                nested_json = json.loads(result[key])
                return nested_json, True
            except json.JSONDecodeError:
                pass
        
        return result, True
    except json.JSONDecodeError as e:
        print(f"\nWarning: Failed to parse JSON response: {e}")
        return {}, False